]>
Commit | Line | Data |
---|---|---|
3840d6ba | 1 | /* |
17438bf4 | 2 | * "$Id: main.c,v 1.72 2002/05/16 13:45:02 mike Exp $" |
3840d6ba | 3 | * |
e5cf24b2 | 4 | * Scheduler main loop for the Common UNIX Printing System (CUPS). |
3840d6ba | 5 | * |
efb2f309 | 6 | * Copyright 1997-2002 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 */ |
d646a352 | 90 | #ifdef __sgi |
91 | FILE *fp; /* Fake lpsched lock file */ | |
92 | #endif /* __sgi */ | |
3840d6ba | 93 | |
94 | ||
fd8b1cf8 | 95 | /* |
96 | * Check for command-line arguments... | |
97 | */ | |
98 | ||
a3e17a89 | 99 | fg = 0; |
100 | ||
fd8b1cf8 | 101 | for (i = 1; i < argc; i ++) |
102 | if (argv[i][0] == '-') | |
103 | for (opt = argv[i] + 1; *opt != '\0'; opt ++) | |
104 | switch (*opt) | |
105 | { | |
106 | case 'c' : /* Configuration file */ | |
107 | i ++; | |
108 | if (i >= argc) | |
109 | usage(); | |
110 | ||
a3e17a89 | 111 | if (argv[i][0] == '/') |
112 | { | |
113 | /* | |
114 | * Absolute directory... | |
115 | */ | |
116 | ||
17438bf4 | 117 | strlcpy(ConfigurationFile, argv[i], sizeof(ConfigurationFile)); |
a3e17a89 | 118 | } |
119 | else | |
120 | { | |
121 | /* | |
122 | * Relative directory... | |
123 | */ | |
124 | ||
125 | getcwd(ConfigurationFile, sizeof(ConfigurationFile)); | |
17438bf4 | 126 | strlcat(ConfigurationFile, "/", sizeof(ConfigurationFile)); |
127 | strlcat(ConfigurationFile, argv[i], sizeof(ConfigurationFile)); | |
a3e17a89 | 128 | } |
129 | break; | |
130 | ||
131 | case 'f' : /* Run in foreground... */ | |
132 | fg = 1; | |
fd8b1cf8 | 133 | break; |
134 | ||
135 | default : /* Unknown option */ | |
136 | fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n", *opt); | |
137 | usage(); | |
138 | break; | |
139 | } | |
140 | else | |
141 | { | |
142 | fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]); | |
143 | usage(); | |
144 | } | |
145 | ||
992cf15a | 146 | /* |
a3e17a89 | 147 | * If the user hasn't specified "-f", run in the background... |
992cf15a | 148 | */ |
149 | ||
a3e17a89 | 150 | if (!fg) |
151 | { | |
152 | if (fork() > 0) | |
153 | return (0); | |
05e63c18 | 154 | |
a3e17a89 | 155 | /* |
156 | * Make sure we aren't tying up any filesystems... | |
157 | */ | |
158 | ||
159 | chdir("/"); | |
992cf15a | 160 | |
8b43895a | 161 | #ifndef DEBUG |
a3e17a89 | 162 | /* |
163 | * Disable core dumps... | |
164 | */ | |
165 | ||
166 | getrlimit(RLIMIT_CORE, &limit); | |
167 | limit.rlim_cur = 0; | |
168 | setrlimit(RLIMIT_CORE, &limit); | |
169 | ||
170 | /* | |
171 | * Disconnect from the controlling terminal... | |
172 | */ | |
173 | ||
174 | close(0); | |
175 | close(1); | |
176 | close(2); | |
8b43895a | 177 | |
a3e17a89 | 178 | setsid(); |
179 | #endif /* DEBUG */ | |
180 | } | |
147ddbb6 | 181 | |
182 | /* | |
a3e17a89 | 183 | * Set the timezone info... |
147ddbb6 | 184 | */ |
185 | ||
a3e17a89 | 186 | if (getenv("TZ") != NULL) |
a6988fb1 | 187 | snprintf(TZ, sizeof(TZ), "TZ=%s", getenv("TZ")); |
a3e17a89 | 188 | |
189 | tzset(); | |
8b43895a | 190 | |
191 | /* | |
192 | * Set the maximum number of files... | |
193 | */ | |
194 | ||
195 | getrlimit(RLIMIT_NOFILE, &limit); | |
5ec612d5 | 196 | if (limit.rlim_max > FD_SETSIZE) /* Can't exceed size of FD set! */ |
197 | MaxFDs = FD_SETSIZE; | |
198 | else | |
199 | MaxFDs = limit.rlim_max; | |
200 | ||
201 | limit.rlim_cur = MaxFDs; | |
8b43895a | 202 | setrlimit(RLIMIT_NOFILE, &limit); |
203 | ||
3840d6ba | 204 | /* |
2bffb563 | 205 | * Catch hangup and child signals and ignore broken pipes... |
3840d6ba | 206 | */ |
207 | ||
e5cf24b2 | 208 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ |
f3890b95 | 209 | if (RunAsUser) |
210 | sigset(SIGHUP, sigterm_handler); | |
211 | else | |
0b50ddbc | 212 | sigset(SIGHUP, sighup_handler); |
e5cf24b2 | 213 | sigset(SIGPIPE, SIG_IGN); |
a3e17a89 | 214 | sigset(SIGTERM, sigterm_handler); |
e5cf24b2 | 215 | #elif defined(HAVE_SIGACTION) |
2bffb563 | 216 | memset(&action, 0, sizeof(action)); |
217 | ||
f3890b95 | 218 | sigemptyset(&action.sa_mask); |
219 | sigaddset(&action.sa_mask, SIGHUP); | |
220 | ||
221 | if (RunAsUser) | |
222 | action.sa_handler = sigterm_handler; | |
223 | else | |
0b50ddbc | 224 | action.sa_handler = sighup_handler; |
f3890b95 | 225 | |
226 | sigaction(SIGHUP, &action, NULL); | |
2bffb563 | 227 | |
e5cf24b2 | 228 | sigemptyset(&action.sa_mask); |
2bffb563 | 229 | action.sa_handler = SIG_IGN; |
230 | sigaction(SIGPIPE, &action, NULL); | |
a3e17a89 | 231 | |
232 | sigemptyset(&action.sa_mask); | |
233 | sigaddset(&action.sa_mask, SIGTERM); | |
234 | action.sa_handler = sigterm_handler; | |
235 | sigaction(SIGTERM, &action, NULL); | |
e5cf24b2 | 236 | #else |
f3890b95 | 237 | if (RunAsUser) |
238 | signal(SIGHUP, sigterm_handler); | |
239 | else | |
0b50ddbc | 240 | signal(SIGHUP, sighup_handler); |
f3890b95 | 241 | |
e5cf24b2 | 242 | signal(SIGPIPE, SIG_IGN); |
a3e17a89 | 243 | signal(SIGTERM, sigterm_handler); |
e5cf24b2 | 244 | #endif /* HAVE_SIGSET */ |
3840d6ba | 245 | |
902cb359 | 246 | /* |
247 | * Read configuration... | |
248 | */ | |
249 | ||
250 | if (!ReadConfiguration()) | |
251 | { | |
252 | syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", | |
253 | ConfigurationFile); | |
254 | return (1); | |
255 | } | |
256 | ||
d646a352 | 257 | #ifdef __sgi |
258 | /* | |
259 | * Try to create a fake lpsched lock file if one is not already there. | |
260 | * Some Adobe applications need it under IRIX in order to enable | |
261 | * printing... | |
262 | */ | |
263 | ||
264 | if ((fp = fopen("/var/spool/lp/SCHEDLOCK", "a")) == NULL) | |
265 | { | |
266 | syslog(LOG_LPR, "Unable to create fake lpsched lock file " | |
267 | "\"/var/spool/lp/SCHEDLOCK\"\' - %s!", | |
268 | strerror(errno)); | |
269 | } | |
270 | else | |
271 | { | |
272 | fclose(fp); | |
273 | ||
274 | chmod("/var/spool/lp/SCHEDLOCK", 0644); | |
275 | chown("/var/spool/lp/SCHEDLOCK", User, Group); | |
276 | } | |
277 | #endif /* __sgi */ | |
278 | ||
1049abbe | 279 | /* |
a98634ce | 280 | * Initialize authentication certificates... |
1049abbe | 281 | */ |
282 | ||
23bba0c3 | 283 | InitCerts(); |
284 | ||
a98634ce | 285 | /* |
286 | * Load all the jobs... | |
287 | */ | |
288 | ||
1049abbe | 289 | LoadAllJobs(); |
290 | ||
3840d6ba | 291 | /* |
292 | * Loop forever... | |
293 | */ | |
294 | ||
05ca02bc | 295 | senddoc_time = time(NULL); |
296 | ||
b6ea8f29 | 297 | #ifdef HAVE_MALLINFO |
298 | mallinfo_time = 0; | |
299 | #endif /* HAVE_MALLINFO */ | |
300 | ||
a74b005d | 301 | for (;;) |
3840d6ba | 302 | { |
fd8b1cf8 | 303 | /* |
304 | * Check if we need to load the server configuration file... | |
305 | */ | |
306 | ||
307 | if (NeedReload) | |
308 | { | |
309 | if (NumClients > 0) | |
310 | { | |
311 | for (i = NumClients, con = Clients; i > 0; i --, con ++) | |
a74b005d | 312 | if (con->http.state == HTTP_WAITING) |
fd8b1cf8 | 313 | { |
314 | CloseClient(con); | |
315 | con --; | |
316 | } | |
317 | else | |
93894a43 | 318 | con->http.keep_alive = HTTP_KEEPALIVE_OFF; |
fd8b1cf8 | 319 | |
d236cb49 | 320 | PauseListening(); |
fd8b1cf8 | 321 | } |
322 | else if (!ReadConfiguration()) | |
323 | { | |
a3e17a89 | 324 | syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", |
325 | ConfigurationFile); | |
d2122fde | 326 | break; |
fd8b1cf8 | 327 | } |
328 | } | |
329 | ||
3840d6ba | 330 | /* |
331 | * Check for available input or ready output. If select() returns | |
332 | * 0 or -1, something bad happened and we should exit immediately. | |
333 | * | |
42d48bd2 | 334 | * Note that we at least have one listening socket open at all |
3840d6ba | 335 | * times. |
336 | */ | |
337 | ||
338 | input = InputSet; | |
339 | output = OutputSet; | |
340 | ||
f736c0e3 | 341 | timeout.tv_sec = 1; |
342 | timeout.tv_usec = 0; | |
343 | ||
fd8b1cf8 | 344 | for (i = NumClients, con = Clients; i > 0; i --, con ++) |
a74b005d | 345 | if (con->http.used > 0) |
f736c0e3 | 346 | { |
347 | timeout.tv_sec = 0; | |
3840d6ba | 348 | break; |
f736c0e3 | 349 | } |
3840d6ba | 350 | |
93336dbc | 351 | if ((i = select(MaxFDs, &input, &output, NULL, &timeout)) < 0) |
fd8b1cf8 | 352 | { |
d236cb49 | 353 | char s[16384], /* String buffer */ |
354 | *sptr; /* Pointer into buffer */ | |
355 | int slen; /* Length of string buffer */ | |
356 | ||
357 | ||
886c59e2 | 358 | /* |
359 | * Got an error from select! | |
360 | */ | |
361 | ||
362 | if (errno == EINTR) /* Just interrupted by a signal */ | |
fd8b1cf8 | 363 | continue; |
364 | ||
886c59e2 | 365 | /* |
d236cb49 | 366 | * Log all sorts of debug info to help track down the problem. |
886c59e2 | 367 | */ |
368 | ||
5236f873 | 369 | LogMessage(L_EMERG, "select() failed - %s!", strerror(errno)); |
d236cb49 | 370 | |
371 | strcpy(s, "InputSet ="); | |
024012d6 | 372 | slen = 10; |
373 | sptr = s + 10; | |
d236cb49 | 374 | |
93336dbc | 375 | for (i = 0; i < MaxFDs; i ++) |
d236cb49 | 376 | if (FD_ISSET(i, &InputSet)) |
024012d6 | 377 | { |
04de52f8 | 378 | snprintf(sptr, sizeof(s) - slen, " %d", i); |
024012d6 | 379 | slen += strlen(sptr); |
380 | sptr += strlen(sptr); | |
381 | } | |
bfa1abf0 | 382 | |
5236f873 | 383 | LogMessage(L_EMERG, s); |
bfa1abf0 | 384 | |
d236cb49 | 385 | strcpy(s, "OutputSet ="); |
024012d6 | 386 | slen = 11; |
387 | sptr = s + 11; | |
d236cb49 | 388 | |
93336dbc | 389 | for (i = 0; i < MaxFDs; i ++) |
d236cb49 | 390 | if (FD_ISSET(i, &OutputSet)) |
024012d6 | 391 | { |
04de52f8 | 392 | snprintf(sptr, sizeof(s) - slen, " %d", i); |
024012d6 | 393 | slen += strlen(sptr); |
394 | sptr += strlen(sptr); | |
395 | } | |
d236cb49 | 396 | |
5236f873 | 397 | LogMessage(L_EMERG, s); |
886c59e2 | 398 | |
882031b3 | 399 | for (i = 0, con = Clients; i < NumClients; i ++, con ++) |
5236f873 | 400 | LogMessage(L_EMERG, "Clients[%d] = %d, file = %d, state = %d", |
df47c6ae | 401 | i, con->http.fd, con->file, con->http.state); |
886c59e2 | 402 | |
403 | for (i = 0, lis = Listeners; i < NumListeners; i ++, lis ++) | |
5236f873 | 404 | LogMessage(L_EMERG, "Listeners[%d] = %d", i, lis->fd); |
886c59e2 | 405 | |
5236f873 | 406 | LogMessage(L_EMERG, "BrowseSocket = %d", BrowseSocket); |
886c59e2 | 407 | |
408 | for (job = Jobs; job != NULL; job = job->next) | |
5236f873 | 409 | LogMessage(L_EMERG, "Jobs[%d] = %d", job->id, job->pipe); |
bfa1abf0 | 410 | |
3840d6ba | 411 | break; |
fd8b1cf8 | 412 | } |
3840d6ba | 413 | |
fd8b1cf8 | 414 | for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) |
415 | if (FD_ISSET(lis->fd, &input)) | |
416 | AcceptClient(lis); | |
3840d6ba | 417 | |
fd8b1cf8 | 418 | for (i = NumClients, con = Clients; i > 0; i --, con ++) |
3840d6ba | 419 | { |
3840d6ba | 420 | /* |
421 | * Process the input buffer... | |
422 | */ | |
423 | ||
a74b005d | 424 | if (FD_ISSET(con->http.fd, &input) || con->http.used) |
fd8b1cf8 | 425 | if (!ReadClient(con)) |
3840d6ba | 426 | { |
427 | con --; | |
3840d6ba | 428 | continue; |
429 | } | |
430 | ||
431 | /* | |
432 | * Write data as needed... | |
433 | */ | |
434 | ||
96df88bb | 435 | if (FD_ISSET(con->http.fd, &output) && |
436 | (!con->pipe_pid || FD_ISSET(con->file, &input))) | |
fd8b1cf8 | 437 | if (!WriteClient(con)) |
3840d6ba | 438 | { |
439 | con --; | |
992cf15a | 440 | continue; |
3840d6ba | 441 | } |
992cf15a | 442 | |
443 | /* | |
fd8b1cf8 | 444 | * Check the activity and close old clients... |
992cf15a | 445 | */ |
446 | ||
df47c6ae | 447 | activity = time(NULL) - Timeout; |
448 | if (con->http.activity < activity && !con->pipe_pid) | |
992cf15a | 449 | { |
fd8b1cf8 | 450 | CloseClient(con); |
992cf15a | 451 | con --; |
992cf15a | 452 | continue; |
453 | } | |
3840d6ba | 454 | } |
6abc7437 | 455 | |
456 | /* | |
457 | * Check for status info from job filters... | |
458 | */ | |
459 | ||
460 | for (job = Jobs; job != NULL; job = next) | |
461 | { | |
462 | next = job->next; | |
463 | ||
464 | if (job->pipe && FD_ISSET(job->pipe, &input)) | |
5236f873 | 465 | { |
466 | /* | |
467 | * Clear the input bit to avoid updating the next job | |
468 | * using the same status pipe file descriptor... | |
469 | */ | |
470 | ||
471 | FD_CLR(job->pipe, &input); | |
472 | ||
473 | /* | |
474 | * Read any status messages from the filters... | |
475 | */ | |
476 | ||
6abc7437 | 477 | UpdateJob(job); |
5236f873 | 478 | } |
6abc7437 | 479 | } |
d6de4648 | 480 | |
481 | /* | |
482 | * Update the browse list as needed... | |
483 | */ | |
484 | ||
dded8a26 | 485 | if (Browsing && BrowseProtocols) |
a40c1c6f | 486 | { |
dded8a26 | 487 | if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, &input)) |
1012752f | 488 | UpdateCUPSBrowse(); |
d6de4648 | 489 | |
1be73957 | 490 | if (PollPipe >= 0 && FD_ISSET(PollPipe, &input)) |
38f52966 | 491 | UpdatePolling(); |
492 | ||
25d465a4 | 493 | #ifdef HAVE_LIBSLP |
494 | if ((BrowseProtocols & BROWSE_SLP) && BrowseSLPRefresh <= time(NULL)) | |
495 | UpdateSLPBrowse(); | |
496 | #endif /* HAVE_LIBSLP */ | |
497 | ||
a40c1c6f | 498 | SendBrowseList(); |
499 | } | |
d2122fde | 500 | |
05ca02bc | 501 | /* |
502 | * Update any pending multi-file documents... | |
503 | */ | |
504 | ||
f3c3b479 | 505 | if ((time(NULL) - senddoc_time) >= 10) |
05ca02bc | 506 | { |
507 | CheckJobs(); | |
508 | senddoc_time = time(NULL); | |
509 | } | |
510 | ||
2bdd1992 | 511 | #ifdef HAVE_MALLINFO |
d2122fde | 512 | /* |
2bdd1992 | 513 | * Log memory usage every minute... |
d2122fde | 514 | */ |
515 | ||
2bdd1992 | 516 | if ((time(NULL) - mallinfo_time) >= 60 && LogLevel >= L_DEBUG) |
d2122fde | 517 | { |
8c57ced1 | 518 | struct mallinfo mem; /* Malloc information */ |
519 | ||
520 | ||
8c57ced1 | 521 | mem = mallinfo(); |
522 | LogMessage(L_DEBUG, "mallinfo: arena = %d, used = %d, free = %d\n", | |
523 | mem.arena, mem.usmblks + mem.uordblks, | |
524 | mem.fsmblks + mem.fordblks); | |
2bdd1992 | 525 | mallinfo_time = time(NULL); |
526 | } | |
527 | #endif /* HAVE_MALLINFO */ | |
8c57ced1 | 528 | |
2bdd1992 | 529 | /* |
530 | * Update the root certificate once every 5 minutes... | |
531 | */ | |
532 | ||
533 | if ((time(NULL) - RootCertTime) >= 300) | |
534 | { | |
8c57ced1 | 535 | /* |
536 | * Update the root certificate... | |
537 | */ | |
538 | ||
d2122fde | 539 | DeleteCert(0); |
540 | AddCert(0, "root"); | |
541 | } | |
3840d6ba | 542 | } |
543 | ||
544 | /* | |
545 | * If we get here something very bad happened and we need to exit | |
546 | * immediately. | |
547 | */ | |
548 | ||
d2122fde | 549 | DeleteAllCerts(); |
fd8b1cf8 | 550 | CloseAllClients(); |
551 | StopListening(); | |
552 | ||
553 | return (1); | |
554 | } | |
3840d6ba | 555 | |
3840d6ba | 556 | |
d7845573 | 557 | /* |
558 | * 'CatchChildSignals()' - Catch SIGCHLD signals... | |
559 | */ | |
560 | ||
561 | void | |
562 | CatchChildSignals(void) | |
563 | { | |
564 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
565 | struct sigaction action; /* Actions for POSIX signals */ | |
566 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
567 | ||
568 | ||
569 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
570 | sigset(SIGCHLD, sigchld_handler); | |
571 | #elif defined(HAVE_SIGACTION) | |
572 | memset(&action, 0, sizeof(action)); | |
573 | ||
574 | sigemptyset(&action.sa_mask); | |
575 | sigaddset(&action.sa_mask, SIGCHLD); | |
576 | action.sa_handler = sigchld_handler; | |
577 | sigaction(SIGCHLD, &action, NULL); | |
578 | #else | |
579 | signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */ | |
580 | #endif /* HAVE_SIGSET */ | |
581 | } | |
582 | ||
583 | ||
584 | /* | |
585 | * 'IgnoreChildSignals()' - Ignore SIGCHLD signals... | |
586 | */ | |
587 | ||
588 | void | |
589 | IgnoreChildSignals(void) | |
590 | { | |
591 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
592 | struct sigaction action; /* Actions for POSIX signals */ | |
593 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
594 | ||
595 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
596 | sigset(SIGCHLD, SIG_IGN); | |
597 | #elif defined(HAVE_SIGACTION) | |
598 | memset(&action, 0, sizeof(action)); | |
599 | ||
600 | sigemptyset(&action.sa_mask); | |
601 | sigaddset(&action.sa_mask, SIGCHLD); | |
602 | action.sa_handler = SIG_IGN; | |
603 | sigaction(SIGCHLD, &action, NULL); | |
604 | #else | |
605 | signal(SIGCLD, SIG_IGN); /* No, SIGCLD isn't a typo... */ | |
606 | #endif /* HAVE_SIGSET */ | |
607 | } | |
608 | ||
609 | ||
6abc7437 | 610 | /* |
e5cf24b2 | 611 | * 'sigchld_handler()' - Handle 'child' signals from old processes. |
6abc7437 | 612 | */ |
613 | ||
614 | static void | |
e5cf24b2 | 615 | sigchld_handler(int sig) /* I - Signal number */ |
6abc7437 | 616 | { |
e5cf24b2 | 617 | int status; /* Exit status of child */ |
618 | int pid; /* Process ID of child */ | |
619 | job_t *job; /* Current job */ | |
620 | int i; /* Looping var */ | |
6abc7437 | 621 | |
622 | ||
623 | (void)sig; | |
624 | ||
e5cf24b2 | 625 | #ifdef HAVE_WAITPID |
626 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) | |
627 | #elif defined(HAVE_WAIT3) | |
628 | while ((pid = wait3(&status, WNOHANG, NULL)) > 0) | |
629 | #else | |
630 | if ((pid = wait(&status)) > 0) | |
631 | #endif /* HAVE_WAITPID */ | |
632 | { | |
633 | DEBUG_printf(("sigcld_handler: pid = %d, status = %d\n", pid, status)); | |
6abc7437 | 634 | |
d2122fde | 635 | /* |
636 | * Delete certificates for CGI processes... | |
637 | */ | |
638 | ||
639 | if (pid) | |
640 | DeleteCert(pid); | |
641 | ||
642 | /* | |
643 | * Ignore SIGTERM errors - that comes when a job is cancelled... | |
644 | */ | |
645 | ||
6bc08d08 | 646 | if (status == SIGTERM) |
647 | status = 0; | |
648 | ||
649 | if (status) | |
650 | { | |
651 | if (status < 256) | |
5ea8888e | 652 | LogMessage(L_ERROR, "PID %d crashed on signal %d!", pid, status); |
6bc08d08 | 653 | else |
6d8b6788 | 654 | LogMessage(L_ERROR, "PID %d stopped with status %d!", pid, |
6bc08d08 | 655 | status / 256); |
656 | } | |
e5b7bd9c | 657 | |
e5cf24b2 | 658 | for (job = Jobs; job != NULL; job = job->next) |
1049abbe | 659 | if (job->state->values[0].integer == IPP_JOB_PROCESSING) |
6abc7437 | 660 | { |
e5cf24b2 | 661 | for (i = 0; job->procs[i]; i ++) |
662 | if (job->procs[i] == pid) | |
663 | break; | |
6abc7437 | 664 | |
e5cf24b2 | 665 | if (job->procs[i]) |
bfa1abf0 | 666 | { |
667 | /* | |
e5cf24b2 | 668 | * OK, this process has gone away; what's left? |
bfa1abf0 | 669 | */ |
6abc7437 | 670 | |
e5cf24b2 | 671 | job->procs[i] = -pid; |
6abc7437 | 672 | |
bd84e0d1 | 673 | if (status && job->status >= 0) |
e5cf24b2 | 674 | { |
675 | /* | |
bd84e0d1 | 676 | * An error occurred; save the exit status so we know to stop |
677 | * the printer or cancel the job when all of the filters finish... | |
678 | * | |
679 | * A negative status indicates that the backend failed and the | |
680 | * printer needs to be stopped. | |
e5cf24b2 | 681 | */ |
682 | ||
bd84e0d1 | 683 | if (!job->procs[i + 1]) |
684 | job->status = -status; /* Backend failed */ | |
685 | else | |
686 | job->status = status; /* Filter failed */ | |
e5cf24b2 | 687 | } |
e5cf24b2 | 688 | break; |
689 | } | |
6abc7437 | 690 | } |
e5cf24b2 | 691 | } |
692 | ||
693 | #ifdef HAVE_SIGSET | |
694 | sigset(SIGCHLD, sigchld_handler); | |
695 | #elif !defined(HAVE_SIGACTION) | |
696 | signal(SIGCLD, sigchld_handler); | |
697 | #endif /* HAVE_SIGSET */ | |
6abc7437 | 698 | } |
699 | ||
700 | ||
fd8b1cf8 | 701 | /* |
702 | * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler. | |
703 | */ | |
704 | ||
705 | static void | |
706 | sighup_handler(int sig) /* I - Signal number */ | |
707 | { | |
93894a43 | 708 | (void)sig; |
709 | ||
fd8b1cf8 | 710 | NeedReload = TRUE; |
a3e17a89 | 711 | |
712 | #ifdef HAVE_SIGSET | |
713 | sigset(SIGHUP, sighup_handler); | |
714 | #elif !defined(HAVE_SIGACTION) | |
715 | signal(SIGHUP, sighup_handler); | |
716 | #endif /* HAVE_SIGSET */ | |
717 | } | |
718 | ||
719 | ||
720 | /* | |
721 | * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler. | |
722 | */ | |
723 | ||
724 | static void | |
725 | sigterm_handler(int sig) | |
726 | { | |
d646a352 | 727 | #ifdef __sgi |
728 | struct stat statbuf; /* Needed for checking lpsched FIFO */ | |
729 | #endif /* __sgi */ | |
730 | ||
731 | ||
d74efa25 | 732 | (void)sig; /* remove compiler warnings... */ |
733 | ||
a3e17a89 | 734 | /* |
735 | * Log an error... | |
736 | */ | |
737 | ||
738 | LogMessage(L_ERROR, "Scheduler shutting down due to SIGTERM."); | |
739 | ||
740 | /* | |
741 | * Close all network clients and stop all jobs... | |
742 | */ | |
743 | ||
744 | CloseAllClients(); | |
745 | StopListening(); | |
746 | StopPolling(); | |
747 | StopBrowsing(); | |
748 | ||
749 | if (Clients != NULL) | |
750 | free(Clients); | |
751 | ||
752 | StopAllJobs(); | |
753 | ||
754 | if (AccessFile != NULL) | |
755 | fclose(AccessFile); | |
756 | ||
757 | if (ErrorFile != NULL) | |
758 | fclose(ErrorFile); | |
759 | ||
760 | if (PageFile != NULL) | |
761 | fclose(PageFile); | |
762 | ||
763 | DeleteAllLocations(); | |
764 | ||
765 | DeleteAllClasses(); | |
766 | ||
767 | if (Devices) | |
768 | ippDelete(Devices); | |
769 | ||
770 | if (PPDs) | |
771 | ippDelete(PPDs); | |
772 | ||
773 | DeleteAllPrinters(); | |
774 | ||
775 | if (MimeDatabase != NULL) | |
776 | mimeDelete(MimeDatabase); | |
777 | ||
d646a352 | 778 | #ifdef __sgi |
779 | /* | |
780 | * Remove the fake IRIX lpsched lock file, but only if the existing | |
781 | * file is not a FIFO which indicates that the real IRIX lpsched is | |
782 | * running... | |
783 | */ | |
784 | ||
785 | if (!stat("/var/spool/lp/FIFO", &statbuf)) | |
786 | if (!S_ISFIFO(statbuf.st_mode)) | |
787 | unlink("/var/spool/lp/SCHEDLOCK"); | |
788 | #endif /* __sgi */ | |
789 | ||
a3e17a89 | 790 | exit(1); |
3840d6ba | 791 | } |
792 | ||
fd8b1cf8 | 793 | |
794 | /* | |
795 | * 'usage()' - Show scheduler usage. | |
796 | */ | |
797 | ||
798 | static void | |
799 | usage(void) | |
800 | { | |
a3e17a89 | 801 | fputs("Usage: cupsd [-c config-file] [-f]\n", stderr); |
fd8b1cf8 | 802 | exit(1); |
803 | } | |
804 | ||
805 | ||
3840d6ba | 806 | /* |
17438bf4 | 807 | * End of "$Id: main.c,v 1.72 2002/05/16 13:45:02 mike Exp $". |
3840d6ba | 808 | */ |