]>
Commit | Line | Data |
---|---|---|
3840d6ba | 1 | /* |
b5cb0608 | 2 | * "$Id: main.c,v 1.57.2.1 2001/05/13 18:38:37 mike Exp $" |
3840d6ba | 3 | * |
e5cf24b2 | 4 | * Scheduler main loop for the Common UNIX Printing System (CUPS). |
3840d6ba | 5 | * |
d2935a0f | 6 | * Copyright 1997-2001 by Easy Software Products, all rights reserved. |
3840d6ba | 7 | * |
fd8b1cf8 | 8 | * These coded instructions, statements, and computer programs are the |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
3840d6ba | 14 | * |
fd8b1cf8 | 15 | * Attn: CUPS Licensing Information |
16 | * Easy Software Products | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
fd8b1cf8 | 18 | * Hollywood, Maryland 20636-3111 USA |
3840d6ba | 19 | * |
fd8b1cf8 | 20 | * Voice: (301) 373-9603 |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
992cf15a | 23 | * |
fd8b1cf8 | 24 | * Contents: |
3840d6ba | 25 | * |
d7845573 | 26 | * main() - Main entry for the CUPS scheduler. |
27 | * CatchChildSignals() - Catch SIGCHLD signals... | |
28 | * IgnoreChildSignals() - Ignore SIGCHLD signals... | |
29 | * sigchld_handler() - Handle 'child' signals from old processes. | |
30 | * sighup_handler() - Handle 'hangup' signals to reconfigure the scheduler. | |
31 | * sigterm_handler() - Handle 'terminate' signals that stop the scheduler. | |
32 | * usage() - Show scheduler usage. | |
3840d6ba | 33 | */ |
34 | ||
35 | /* | |
36 | * Include necessary headers... | |
37 | */ | |
38 | ||
39 | #define _MAIN_C_ | |
40 | #include "cupsd.h" | |
8b43895a | 41 | #include <sys/resource.h> |
a3e17a89 | 42 | #include <syslog.h> |
3840d6ba | 43 | |
2bdd1992 | 44 | #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) |
8c57ced1 | 45 | # include <malloc.h> |
2bdd1992 | 46 | #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */ |
8c57ced1 | 47 | |
5ec612d5 | 48 | #ifndef FD_SETSIZE |
49 | # define FD_SETSIZE 1024 | |
50 | #endif /* !FD_SETSIZE */ | |
51 | ||
3840d6ba | 52 | |
53 | /* | |
fd8b1cf8 | 54 | * Local functions... |
55 | */ | |
56 | ||
e5cf24b2 | 57 | static void sigchld_handler(int sig); |
fd8b1cf8 | 58 | static void sighup_handler(int sig); |
a3e17a89 | 59 | static void sigterm_handler(int sig); |
fd8b1cf8 | 60 | static void usage(void); |
61 | ||
62 | ||
63 | /* | |
64 | * 'main()' - Main entry for the CUPS scheduler. | |
3840d6ba | 65 | */ |
66 | ||
67 | int /* O - Exit status */ | |
68 | main(int argc, /* I - Number of command-line arguments */ | |
69 | char *argv[]) /* I - Command-line arguments */ | |
70 | { | |
71 | int i; /* Looping var */ | |
fd8b1cf8 | 72 | char *opt; /* Option character */ |
a3e17a89 | 73 | int fg; /* Run in the foreground */ |
3840d6ba | 74 | fd_set input, /* Input set for select() */ |
75 | output; /* Output set for select() */ | |
fd8b1cf8 | 76 | client_t *con; /* Current client */ |
6abc7437 | 77 | job_t *job, /* Current job */ |
78 | *next; /* Next job */ | |
fd8b1cf8 | 79 | listener_t *lis; /* Current listener */ |
992cf15a | 80 | time_t activity; /* Activity timer */ |
05ca02bc | 81 | time_t senddoc_time; /* Send-Document time */ |
2bdd1992 | 82 | #ifdef HAVE_MALLINFO |
83 | time_t mallinfo_time; /* Malloc information time */ | |
84 | #endif /* HAVE_MALLINFO */ | |
3840d6ba | 85 | struct timeval timeout; /* select() timeout */ |
8b43895a | 86 | struct rlimit limit; /* Runtime limit */ |
8a2c2126 | 87 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) |
e5cf24b2 | 88 | struct sigaction action; /* Actions for POSIX signals */ |
8a2c2126 | 89 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ |
3840d6ba | 90 | |
91 | ||
fd8b1cf8 | 92 | /* |
93 | * Check for command-line arguments... | |
94 | */ | |
95 | ||
a3e17a89 | 96 | fg = 0; |
97 | ||
fd8b1cf8 | 98 | for (i = 1; i < argc; i ++) |
99 | if (argv[i][0] == '-') | |
100 | for (opt = argv[i] + 1; *opt != '\0'; opt ++) | |
101 | switch (*opt) | |
102 | { | |
103 | case 'c' : /* Configuration file */ | |
104 | i ++; | |
105 | if (i >= argc) | |
106 | usage(); | |
107 | ||
a3e17a89 | 108 | if (argv[i][0] == '/') |
109 | { | |
110 | /* | |
111 | * Absolute directory... | |
112 | */ | |
113 | ||
114 | strncpy(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1); | |
115 | ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0'; | |
116 | } | |
117 | else | |
118 | { | |
119 | /* | |
120 | * Relative directory... | |
121 | */ | |
122 | ||
123 | getcwd(ConfigurationFile, sizeof(ConfigurationFile)); | |
124 | strncat(ConfigurationFile, "/", sizeof(ConfigurationFile) - 1); | |
125 | strncat(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1); | |
126 | ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0'; | |
127 | } | |
128 | break; | |
129 | ||
130 | case 'f' : /* Run in foreground... */ | |
131 | fg = 1; | |
fd8b1cf8 | 132 | break; |
133 | ||
134 | default : /* Unknown option */ | |
135 | fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n", *opt); | |
136 | usage(); | |
137 | break; | |
138 | } | |
139 | else | |
140 | { | |
141 | fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]); | |
142 | usage(); | |
143 | } | |
144 | ||
992cf15a | 145 | /* |
a3e17a89 | 146 | * If the user hasn't specified "-f", run in the background... |
992cf15a | 147 | */ |
148 | ||
a3e17a89 | 149 | if (!fg) |
150 | { | |
151 | if (fork() > 0) | |
152 | return (0); | |
05e63c18 | 153 | |
a3e17a89 | 154 | /* |
155 | * Make sure we aren't tying up any filesystems... | |
156 | */ | |
157 | ||
158 | chdir("/"); | |
992cf15a | 159 | |
8b43895a | 160 | #ifndef DEBUG |
a3e17a89 | 161 | /* |
162 | * Disable core dumps... | |
163 | */ | |
164 | ||
165 | getrlimit(RLIMIT_CORE, &limit); | |
166 | limit.rlim_cur = 0; | |
167 | setrlimit(RLIMIT_CORE, &limit); | |
168 | ||
169 | /* | |
170 | * Disconnect from the controlling terminal... | |
171 | */ | |
172 | ||
173 | close(0); | |
174 | close(1); | |
175 | close(2); | |
8b43895a | 176 | |
a3e17a89 | 177 | setsid(); |
178 | #endif /* DEBUG */ | |
179 | } | |
147ddbb6 | 180 | |
181 | /* | |
a3e17a89 | 182 | * Set the timezone info... |
147ddbb6 | 183 | */ |
184 | ||
a3e17a89 | 185 | if (getenv("TZ") != NULL) |
a6988fb1 | 186 | snprintf(TZ, sizeof(TZ), "TZ=%s", getenv("TZ")); |
a3e17a89 | 187 | |
188 | tzset(); | |
8b43895a | 189 | |
190 | /* | |
191 | * Set the maximum number of files... | |
192 | */ | |
193 | ||
194 | getrlimit(RLIMIT_NOFILE, &limit); | |
5ec612d5 | 195 | if (limit.rlim_max > FD_SETSIZE) /* Can't exceed size of FD set! */ |
196 | MaxFDs = FD_SETSIZE; | |
197 | else | |
198 | MaxFDs = limit.rlim_max; | |
199 | ||
200 | limit.rlim_cur = MaxFDs; | |
8b43895a | 201 | setrlimit(RLIMIT_NOFILE, &limit); |
202 | ||
3840d6ba | 203 | /* |
2bffb563 | 204 | * Catch hangup and child signals and ignore broken pipes... |
3840d6ba | 205 | */ |
206 | ||
e5cf24b2 | 207 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ |
f3890b95 | 208 | if (RunAsUser) |
209 | sigset(SIGHUP, sigterm_handler); | |
210 | else | |
0b50ddbc | 211 | sigset(SIGHUP, sighup_handler); |
e5cf24b2 | 212 | sigset(SIGPIPE, SIG_IGN); |
a3e17a89 | 213 | sigset(SIGTERM, sigterm_handler); |
e5cf24b2 | 214 | #elif defined(HAVE_SIGACTION) |
2bffb563 | 215 | memset(&action, 0, sizeof(action)); |
216 | ||
f3890b95 | 217 | sigemptyset(&action.sa_mask); |
218 | sigaddset(&action.sa_mask, SIGHUP); | |
219 | ||
220 | if (RunAsUser) | |
221 | action.sa_handler = sigterm_handler; | |
222 | else | |
0b50ddbc | 223 | action.sa_handler = sighup_handler; |
f3890b95 | 224 | |
225 | sigaction(SIGHUP, &action, NULL); | |
2bffb563 | 226 | |
e5cf24b2 | 227 | sigemptyset(&action.sa_mask); |
2bffb563 | 228 | action.sa_handler = SIG_IGN; |
229 | sigaction(SIGPIPE, &action, NULL); | |
a3e17a89 | 230 | |
231 | sigemptyset(&action.sa_mask); | |
232 | sigaddset(&action.sa_mask, SIGTERM); | |
233 | action.sa_handler = sigterm_handler; | |
234 | sigaction(SIGTERM, &action, NULL); | |
e5cf24b2 | 235 | #else |
f3890b95 | 236 | if (RunAsUser) |
237 | signal(SIGHUP, sigterm_handler); | |
238 | else | |
0b50ddbc | 239 | signal(SIGHUP, sighup_handler); |
f3890b95 | 240 | |
e5cf24b2 | 241 | signal(SIGPIPE, SIG_IGN); |
a3e17a89 | 242 | signal(SIGTERM, sigterm_handler); |
e5cf24b2 | 243 | #endif /* HAVE_SIGSET */ |
3840d6ba | 244 | |
1049abbe | 245 | /* |
246 | * Read configuration... | |
247 | */ | |
248 | ||
249 | if (!ReadConfiguration()) | |
250 | { | |
a3e17a89 | 251 | syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", |
252 | ConfigurationFile); | |
253 | return (1); | |
1049abbe | 254 | } |
255 | ||
23bba0c3 | 256 | InitCerts(); |
257 | ||
1049abbe | 258 | LoadAllJobs(); |
259 | ||
3840d6ba | 260 | /* |
261 | * Loop forever... | |
262 | */ | |
263 | ||
05ca02bc | 264 | senddoc_time = time(NULL); |
265 | ||
b6ea8f29 | 266 | #ifdef HAVE_MALLINFO |
267 | mallinfo_time = 0; | |
268 | #endif /* HAVE_MALLINFO */ | |
269 | ||
a74b005d | 270 | for (;;) |
3840d6ba | 271 | { |
fd8b1cf8 | 272 | /* |
273 | * Check if we need to load the server configuration file... | |
274 | */ | |
275 | ||
276 | if (NeedReload) | |
277 | { | |
278 | if (NumClients > 0) | |
279 | { | |
280 | for (i = NumClients, con = Clients; i > 0; i --, con ++) | |
a74b005d | 281 | if (con->http.state == HTTP_WAITING) |
fd8b1cf8 | 282 | { |
283 | CloseClient(con); | |
284 | con --; | |
285 | } | |
286 | else | |
93894a43 | 287 | con->http.keep_alive = HTTP_KEEPALIVE_OFF; |
fd8b1cf8 | 288 | |
d236cb49 | 289 | PauseListening(); |
fd8b1cf8 | 290 | } |
291 | else if (!ReadConfiguration()) | |
292 | { | |
a3e17a89 | 293 | syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", |
294 | ConfigurationFile); | |
d2122fde | 295 | break; |
fd8b1cf8 | 296 | } |
297 | } | |
298 | ||
3840d6ba | 299 | /* |
300 | * Check for available input or ready output. If select() returns | |
301 | * 0 or -1, something bad happened and we should exit immediately. | |
302 | * | |
42d48bd2 | 303 | * Note that we at least have one listening socket open at all |
3840d6ba | 304 | * times. |
305 | */ | |
306 | ||
307 | input = InputSet; | |
308 | output = OutputSet; | |
309 | ||
f736c0e3 | 310 | timeout.tv_sec = 1; |
311 | timeout.tv_usec = 0; | |
312 | ||
fd8b1cf8 | 313 | for (i = NumClients, con = Clients; i > 0; i --, con ++) |
a74b005d | 314 | if (con->http.used > 0) |
f736c0e3 | 315 | { |
316 | timeout.tv_sec = 0; | |
3840d6ba | 317 | break; |
f736c0e3 | 318 | } |
3840d6ba | 319 | |
93336dbc | 320 | if ((i = select(MaxFDs, &input, &output, NULL, &timeout)) < 0) |
fd8b1cf8 | 321 | { |
d236cb49 | 322 | char s[16384], /* String buffer */ |
323 | *sptr; /* Pointer into buffer */ | |
324 | int slen; /* Length of string buffer */ | |
325 | ||
326 | ||
886c59e2 | 327 | /* |
328 | * Got an error from select! | |
329 | */ | |
330 | ||
331 | if (errno == EINTR) /* Just interrupted by a signal */ | |
fd8b1cf8 | 332 | continue; |
333 | ||
886c59e2 | 334 | /* |
d236cb49 | 335 | * Log all sorts of debug info to help track down the problem. |
886c59e2 | 336 | */ |
337 | ||
b5cb0608 | 338 | LogMessage(L_EMERG, "select() failed - %s!", strerror(errno)); |
d236cb49 | 339 | |
340 | strcpy(s, "InputSet ="); | |
341 | slen = 9; | |
342 | sptr = s + 9; | |
343 | ||
93336dbc | 344 | for (i = 0; i < MaxFDs; i ++) |
d236cb49 | 345 | if (FD_ISSET(i, &InputSet)) |
04de52f8 | 346 | snprintf(sptr, sizeof(s) - slen, " %d", i); |
bfa1abf0 | 347 | |
b5cb0608 | 348 | LogMessage(L_EMERG, s); |
bfa1abf0 | 349 | |
d236cb49 | 350 | strcpy(s, "OutputSet ="); |
351 | slen = 10; | |
352 | sptr = s + 10; | |
353 | ||
93336dbc | 354 | for (i = 0; i < MaxFDs; i ++) |
d236cb49 | 355 | if (FD_ISSET(i, &OutputSet)) |
04de52f8 | 356 | snprintf(sptr, sizeof(s) - slen, " %d", i); |
d236cb49 | 357 | |
b5cb0608 | 358 | LogMessage(L_EMERG, s); |
886c59e2 | 359 | |
882031b3 | 360 | for (i = 0, con = Clients; i < NumClients; i ++, con ++) |
b5cb0608 | 361 | LogMessage(L_EMERG, "Clients[%d] = %d, file = %d, state = %d", |
df47c6ae | 362 | i, con->http.fd, con->file, con->http.state); |
886c59e2 | 363 | |
364 | for (i = 0, lis = Listeners; i < NumListeners; i ++, lis ++) | |
b5cb0608 | 365 | LogMessage(L_EMERG, "Listeners[%d] = %d", i, lis->fd); |
886c59e2 | 366 | |
b5cb0608 | 367 | LogMessage(L_EMERG, "BrowseSocket = %d", BrowseSocket); |
886c59e2 | 368 | |
369 | for (job = Jobs; job != NULL; job = job->next) | |
b5cb0608 | 370 | LogMessage(L_EMERG, "Jobs[%d] = %d", job->id, job->pipe); |
bfa1abf0 | 371 | |
3840d6ba | 372 | break; |
fd8b1cf8 | 373 | } |
3840d6ba | 374 | |
fd8b1cf8 | 375 | for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) |
376 | if (FD_ISSET(lis->fd, &input)) | |
377 | AcceptClient(lis); | |
3840d6ba | 378 | |
fd8b1cf8 | 379 | for (i = NumClients, con = Clients; i > 0; i --, con ++) |
3840d6ba | 380 | { |
3840d6ba | 381 | /* |
382 | * Process the input buffer... | |
383 | */ | |
384 | ||
a74b005d | 385 | if (FD_ISSET(con->http.fd, &input) || con->http.used) |
fd8b1cf8 | 386 | if (!ReadClient(con)) |
3840d6ba | 387 | { |
388 | con --; | |
3840d6ba | 389 | continue; |
390 | } | |
391 | ||
392 | /* | |
393 | * Write data as needed... | |
394 | */ | |
395 | ||
96df88bb | 396 | if (FD_ISSET(con->http.fd, &output) && |
397 | (!con->pipe_pid || FD_ISSET(con->file, &input))) | |
fd8b1cf8 | 398 | if (!WriteClient(con)) |
3840d6ba | 399 | { |
400 | con --; | |
992cf15a | 401 | continue; |
3840d6ba | 402 | } |
992cf15a | 403 | |
404 | /* | |
fd8b1cf8 | 405 | * Check the activity and close old clients... |
992cf15a | 406 | */ |
407 | ||
df47c6ae | 408 | activity = time(NULL) - Timeout; |
409 | if (con->http.activity < activity && !con->pipe_pid) | |
992cf15a | 410 | { |
fd8b1cf8 | 411 | CloseClient(con); |
992cf15a | 412 | con --; |
992cf15a | 413 | continue; |
414 | } | |
3840d6ba | 415 | } |
6abc7437 | 416 | |
417 | /* | |
418 | * Check for status info from job filters... | |
419 | */ | |
420 | ||
421 | for (job = Jobs; job != NULL; job = next) | |
422 | { | |
423 | next = job->next; | |
424 | ||
425 | if (job->pipe && FD_ISSET(job->pipe, &input)) | |
b5cb0608 | 426 | { |
427 | /* | |
428 | * Clear the input bit to avoid updating the next job | |
429 | * using the same status pipe file descriptor... | |
430 | */ | |
431 | ||
432 | FD_CLR(job->pipe, &input); | |
433 | ||
434 | /* | |
435 | * Read any status messages from the filters... | |
436 | */ | |
437 | ||
6abc7437 | 438 | UpdateJob(job); |
b5cb0608 | 439 | } |
6abc7437 | 440 | } |
d6de4648 | 441 | |
442 | /* | |
443 | * Update the browse list as needed... | |
444 | */ | |
445 | ||
f63a2256 | 446 | if (Browsing) |
a40c1c6f | 447 | { |
448 | if (FD_ISSET(BrowseSocket, &input)) | |
449 | UpdateBrowseList(); | |
d6de4648 | 450 | |
a40c1c6f | 451 | SendBrowseList(); |
452 | } | |
d2122fde | 453 | |
05ca02bc | 454 | /* |
455 | * Update any pending multi-file documents... | |
456 | */ | |
457 | ||
f3c3b479 | 458 | if ((time(NULL) - senddoc_time) >= 10) |
05ca02bc | 459 | { |
460 | CheckJobs(); | |
461 | senddoc_time = time(NULL); | |
462 | } | |
463 | ||
2bdd1992 | 464 | #ifdef HAVE_MALLINFO |
d2122fde | 465 | /* |
2bdd1992 | 466 | * Log memory usage every minute... |
d2122fde | 467 | */ |
468 | ||
2bdd1992 | 469 | if ((time(NULL) - mallinfo_time) >= 60 && LogLevel >= L_DEBUG) |
d2122fde | 470 | { |
8c57ced1 | 471 | struct mallinfo mem; /* Malloc information */ |
472 | ||
473 | ||
8c57ced1 | 474 | mem = mallinfo(); |
475 | LogMessage(L_DEBUG, "mallinfo: arena = %d, used = %d, free = %d\n", | |
476 | mem.arena, mem.usmblks + mem.uordblks, | |
477 | mem.fsmblks + mem.fordblks); | |
2bdd1992 | 478 | mallinfo_time = time(NULL); |
479 | } | |
480 | #endif /* HAVE_MALLINFO */ | |
8c57ced1 | 481 | |
2bdd1992 | 482 | /* |
483 | * Update the root certificate once every 5 minutes... | |
484 | */ | |
485 | ||
486 | if ((time(NULL) - RootCertTime) >= 300) | |
487 | { | |
8c57ced1 | 488 | /* |
489 | * Update the root certificate... | |
490 | */ | |
491 | ||
d2122fde | 492 | DeleteCert(0); |
493 | AddCert(0, "root"); | |
494 | } | |
3840d6ba | 495 | } |
496 | ||
497 | /* | |
498 | * If we get here something very bad happened and we need to exit | |
499 | * immediately. | |
500 | */ | |
501 | ||
d2122fde | 502 | DeleteAllCerts(); |
fd8b1cf8 | 503 | CloseAllClients(); |
504 | StopListening(); | |
505 | ||
506 | return (1); | |
507 | } | |
3840d6ba | 508 | |
3840d6ba | 509 | |
d7845573 | 510 | /* |
511 | * 'CatchChildSignals()' - Catch SIGCHLD signals... | |
512 | */ | |
513 | ||
514 | void | |
515 | CatchChildSignals(void) | |
516 | { | |
517 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
518 | struct sigaction action; /* Actions for POSIX signals */ | |
519 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
520 | ||
521 | ||
522 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
523 | sigset(SIGCHLD, sigchld_handler); | |
524 | #elif defined(HAVE_SIGACTION) | |
525 | memset(&action, 0, sizeof(action)); | |
526 | ||
527 | sigemptyset(&action.sa_mask); | |
528 | sigaddset(&action.sa_mask, SIGCHLD); | |
529 | action.sa_handler = sigchld_handler; | |
530 | sigaction(SIGCHLD, &action, NULL); | |
531 | #else | |
532 | signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */ | |
533 | #endif /* HAVE_SIGSET */ | |
534 | } | |
535 | ||
536 | ||
537 | /* | |
538 | * 'IgnoreChildSignals()' - Ignore SIGCHLD signals... | |
539 | */ | |
540 | ||
541 | void | |
542 | IgnoreChildSignals(void) | |
543 | { | |
544 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
545 | struct sigaction action; /* Actions for POSIX signals */ | |
546 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
547 | ||
548 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
549 | sigset(SIGCHLD, SIG_IGN); | |
550 | #elif defined(HAVE_SIGACTION) | |
551 | memset(&action, 0, sizeof(action)); | |
552 | ||
553 | sigemptyset(&action.sa_mask); | |
554 | sigaddset(&action.sa_mask, SIGCHLD); | |
555 | action.sa_handler = SIG_IGN; | |
556 | sigaction(SIGCHLD, &action, NULL); | |
557 | #else | |
558 | signal(SIGCLD, SIG_IGN); /* No, SIGCLD isn't a typo... */ | |
559 | #endif /* HAVE_SIGSET */ | |
560 | } | |
561 | ||
562 | ||
6abc7437 | 563 | /* |
e5cf24b2 | 564 | * 'sigchld_handler()' - Handle 'child' signals from old processes. |
6abc7437 | 565 | */ |
566 | ||
567 | static void | |
e5cf24b2 | 568 | sigchld_handler(int sig) /* I - Signal number */ |
6abc7437 | 569 | { |
e5cf24b2 | 570 | int status; /* Exit status of child */ |
571 | int pid; /* Process ID of child */ | |
572 | job_t *job; /* Current job */ | |
573 | int i; /* Looping var */ | |
6abc7437 | 574 | |
575 | ||
576 | (void)sig; | |
577 | ||
e5cf24b2 | 578 | #ifdef HAVE_WAITPID |
579 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) | |
580 | #elif defined(HAVE_WAIT3) | |
581 | while ((pid = wait3(&status, WNOHANG, NULL)) > 0) | |
582 | #else | |
583 | if ((pid = wait(&status)) > 0) | |
584 | #endif /* HAVE_WAITPID */ | |
585 | { | |
586 | DEBUG_printf(("sigcld_handler: pid = %d, status = %d\n", pid, status)); | |
6abc7437 | 587 | |
d2122fde | 588 | /* |
589 | * Delete certificates for CGI processes... | |
590 | */ | |
591 | ||
592 | if (pid) | |
593 | DeleteCert(pid); | |
594 | ||
595 | /* | |
596 | * Ignore SIGTERM errors - that comes when a job is cancelled... | |
597 | */ | |
598 | ||
6bc08d08 | 599 | if (status == SIGTERM) |
600 | status = 0; | |
601 | ||
602 | if (status) | |
603 | { | |
604 | if (status < 256) | |
5ea8888e | 605 | LogMessage(L_ERROR, "PID %d crashed on signal %d!", pid, status); |
6bc08d08 | 606 | else |
6d8b6788 | 607 | LogMessage(L_ERROR, "PID %d stopped with status %d!", pid, |
6bc08d08 | 608 | status / 256); |
609 | } | |
e5b7bd9c | 610 | |
e5cf24b2 | 611 | for (job = Jobs; job != NULL; job = job->next) |
1049abbe | 612 | if (job->state->values[0].integer == IPP_JOB_PROCESSING) |
6abc7437 | 613 | { |
e5cf24b2 | 614 | for (i = 0; job->procs[i]; i ++) |
615 | if (job->procs[i] == pid) | |
616 | break; | |
6abc7437 | 617 | |
e5cf24b2 | 618 | if (job->procs[i]) |
bfa1abf0 | 619 | { |
620 | /* | |
e5cf24b2 | 621 | * OK, this process has gone away; what's left? |
bfa1abf0 | 622 | */ |
6abc7437 | 623 | |
e5cf24b2 | 624 | job->procs[i] = -pid; |
6abc7437 | 625 | |
bd84e0d1 | 626 | if (status && job->status >= 0) |
e5cf24b2 | 627 | { |
628 | /* | |
bd84e0d1 | 629 | * An error occurred; save the exit status so we know to stop |
630 | * the printer or cancel the job when all of the filters finish... | |
631 | * | |
632 | * A negative status indicates that the backend failed and the | |
633 | * printer needs to be stopped. | |
e5cf24b2 | 634 | */ |
635 | ||
bd84e0d1 | 636 | if (!job->procs[i + 1]) |
637 | job->status = -status; /* Backend failed */ | |
638 | else | |
639 | job->status = status; /* Filter failed */ | |
e5cf24b2 | 640 | } |
e5cf24b2 | 641 | break; |
642 | } | |
6abc7437 | 643 | } |
e5cf24b2 | 644 | } |
645 | ||
646 | #ifdef HAVE_SIGSET | |
647 | sigset(SIGCHLD, sigchld_handler); | |
648 | #elif !defined(HAVE_SIGACTION) | |
649 | signal(SIGCLD, sigchld_handler); | |
650 | #endif /* HAVE_SIGSET */ | |
6abc7437 | 651 | } |
652 | ||
653 | ||
fd8b1cf8 | 654 | /* |
655 | * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler. | |
656 | */ | |
657 | ||
658 | static void | |
659 | sighup_handler(int sig) /* I - Signal number */ | |
660 | { | |
93894a43 | 661 | (void)sig; |
662 | ||
fd8b1cf8 | 663 | NeedReload = TRUE; |
a3e17a89 | 664 | |
665 | #ifdef HAVE_SIGSET | |
666 | sigset(SIGHUP, sighup_handler); | |
667 | #elif !defined(HAVE_SIGACTION) | |
668 | signal(SIGHUP, sighup_handler); | |
669 | #endif /* HAVE_SIGSET */ | |
670 | } | |
671 | ||
672 | ||
673 | /* | |
674 | * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler. | |
675 | */ | |
676 | ||
677 | static void | |
678 | sigterm_handler(int sig) | |
679 | { | |
d74efa25 | 680 | (void)sig; /* remove compiler warnings... */ |
681 | ||
a3e17a89 | 682 | /* |
683 | * Log an error... | |
684 | */ | |
685 | ||
686 | LogMessage(L_ERROR, "Scheduler shutting down due to SIGTERM."); | |
687 | ||
688 | /* | |
689 | * Close all network clients and stop all jobs... | |
690 | */ | |
691 | ||
692 | CloseAllClients(); | |
693 | StopListening(); | |
694 | StopPolling(); | |
695 | StopBrowsing(); | |
696 | ||
697 | if (Clients != NULL) | |
698 | free(Clients); | |
699 | ||
700 | StopAllJobs(); | |
701 | ||
702 | if (AccessFile != NULL) | |
703 | fclose(AccessFile); | |
704 | ||
705 | if (ErrorFile != NULL) | |
706 | fclose(ErrorFile); | |
707 | ||
708 | if (PageFile != NULL) | |
709 | fclose(PageFile); | |
710 | ||
711 | DeleteAllLocations(); | |
712 | ||
713 | DeleteAllClasses(); | |
714 | ||
715 | if (Devices) | |
716 | ippDelete(Devices); | |
717 | ||
718 | if (PPDs) | |
719 | ippDelete(PPDs); | |
720 | ||
721 | DeleteAllPrinters(); | |
722 | ||
723 | if (MimeDatabase != NULL) | |
724 | mimeDelete(MimeDatabase); | |
725 | ||
726 | exit(1); | |
3840d6ba | 727 | } |
728 | ||
fd8b1cf8 | 729 | |
730 | /* | |
731 | * 'usage()' - Show scheduler usage. | |
732 | */ | |
733 | ||
734 | static void | |
735 | usage(void) | |
736 | { | |
a3e17a89 | 737 | fputs("Usage: cupsd [-c config-file] [-f]\n", stderr); |
fd8b1cf8 | 738 | exit(1); |
739 | } | |
740 | ||
741 | ||
3840d6ba | 742 | /* |
b5cb0608 | 743 | * End of "$Id: main.c,v 1.57.2.1 2001/05/13 18:38:37 mike Exp $". |
3840d6ba | 744 | */ |