]>
Commit | Line | Data |
---|---|---|
3840d6ba | 1 | /* |
0a968cfb | 2 | * "$Id: main.c,v 1.57.2.37 2003/03/14 21:43:34 mike Exp $" |
3840d6ba | 3 | * |
e5cf24b2 | 4 | * Scheduler main loop for the Common UNIX Printing System (CUPS). |
3840d6ba | 5 | * |
1d9595ab | 6 | * Copyright 1997-2003 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... | |
38743560 | 28 | * HoldSignals() - Hold child and termination signals. |
d7845573 | 29 | * IgnoreChildSignals() - Ignore SIGCHLD signals... |
38743560 | 30 | * ReleaseSignals() - Release signals for delivery. |
36992080 | 31 | * SetString() - Set a string value. |
32 | * SetStringf() - Set a formatted string value. | |
d7845573 | 33 | * sigchld_handler() - Handle 'child' signals from old processes. |
34 | * sighup_handler() - Handle 'hangup' signals to reconfigure the scheduler. | |
35 | * sigterm_handler() - Handle 'terminate' signals that stop the scheduler. | |
36 | * usage() - Show scheduler usage. | |
3840d6ba | 37 | */ |
38 | ||
39 | /* | |
40 | * Include necessary headers... | |
41 | */ | |
42 | ||
43 | #define _MAIN_C_ | |
44 | #include "cupsd.h" | |
8b43895a | 45 | #include <sys/resource.h> |
a3e17a89 | 46 | #include <syslog.h> |
daeeb91c | 47 | #include <grp.h> |
3840d6ba | 48 | |
2bdd1992 | 49 | #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) |
8c57ced1 | 50 | # include <malloc.h> |
2bdd1992 | 51 | #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */ |
8c57ced1 | 52 | |
3840d6ba | 53 | |
54 | /* | |
fd8b1cf8 | 55 | * Local functions... |
56 | */ | |
57 | ||
e5cf24b2 | 58 | static void sigchld_handler(int sig); |
fd8b1cf8 | 59 | static void sighup_handler(int sig); |
a3e17a89 | 60 | static void sigterm_handler(int sig); |
5fe35f41 | 61 | static void sigusr1_handler(int sig); |
fd8b1cf8 | 62 | static void usage(void); |
63 | ||
64 | ||
38743560 | 65 | /* |
66 | * Local globals... | |
67 | */ | |
68 | ||
69 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
70 | static sigset_t oldmask; /* Old POSIX signal mask */ | |
71 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
72 | ||
73 | ||
fd8b1cf8 | 74 | /* |
75 | * 'main()' - Main entry for the CUPS scheduler. | |
3840d6ba | 76 | */ |
77 | ||
38743560 | 78 | int /* O - Exit status */ |
79 | main(int argc, /* I - Number of command-line arguments */ | |
80 | char *argv[]) /* I - Command-line arguments */ | |
3840d6ba | 81 | { |
82 | int i; /* Looping var */ | |
fd8b1cf8 | 83 | char *opt; /* Option character */ |
a3e17a89 | 84 | int fg; /* Run in the foreground */ |
f3bc1068 | 85 | fd_set *input, /* Input set for select() */ |
86 | *output; /* Output set for select() */ | |
fd8b1cf8 | 87 | client_t *con; /* Current client */ |
6abc7437 | 88 | job_t *job, /* Current job */ |
89 | *next; /* Next job */ | |
fd8b1cf8 | 90 | listener_t *lis; /* Current listener */ |
992cf15a | 91 | time_t activity; /* Activity timer */ |
05ca02bc | 92 | time_t senddoc_time; /* Send-Document time */ |
2bdd1992 | 93 | #ifdef HAVE_MALLINFO |
94 | time_t mallinfo_time; /* Malloc information time */ | |
95 | #endif /* HAVE_MALLINFO */ | |
3840d6ba | 96 | struct timeval timeout; /* select() timeout */ |
8b43895a | 97 | struct rlimit limit; /* Runtime limit */ |
8a2c2126 | 98 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) |
e5cf24b2 | 99 | struct sigaction action; /* Actions for POSIX signals */ |
8a2c2126 | 100 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ |
cb9d2abc | 101 | #ifdef __sgi |
102 | FILE *fp; /* Fake lpsched lock file */ | |
103 | #endif /* __sgi */ | |
3840d6ba | 104 | |
105 | ||
fd8b1cf8 | 106 | /* |
107 | * Check for command-line arguments... | |
108 | */ | |
109 | ||
a3e17a89 | 110 | fg = 0; |
111 | ||
fd8b1cf8 | 112 | for (i = 1; i < argc; i ++) |
113 | if (argv[i][0] == '-') | |
114 | for (opt = argv[i] + 1; *opt != '\0'; opt ++) | |
115 | switch (*opt) | |
116 | { | |
117 | case 'c' : /* Configuration file */ | |
118 | i ++; | |
119 | if (i >= argc) | |
120 | usage(); | |
121 | ||
a3e17a89 | 122 | if (argv[i][0] == '/') |
123 | { | |
124 | /* | |
125 | * Absolute directory... | |
126 | */ | |
127 | ||
36992080 | 128 | SetString(&ConfigurationFile, argv[i]); |
a3e17a89 | 129 | } |
130 | else | |
131 | { | |
132 | /* | |
133 | * Relative directory... | |
134 | */ | |
135 | ||
36992080 | 136 | char current[1024]; /* Current directory */ |
137 | ||
138 | ||
139 | getcwd(current, sizeof(current)); | |
140 | SetStringf(&ConfigurationFile, "%s/%s", current, argv[i]); | |
a3e17a89 | 141 | } |
142 | break; | |
143 | ||
144 | case 'f' : /* Run in foreground... */ | |
145 | fg = 1; | |
fd8b1cf8 | 146 | break; |
147 | ||
5fe35f41 | 148 | case 'F' : /* Run in foreground, but still disconnect from terminal... */ |
149 | fg = -1; | |
150 | break; | |
151 | ||
fd8b1cf8 | 152 | default : /* Unknown option */ |
153 | fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n", *opt); | |
154 | usage(); | |
155 | break; | |
156 | } | |
157 | else | |
158 | { | |
159 | fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]); | |
160 | usage(); | |
161 | } | |
162 | ||
beb575a9 | 163 | if (!ConfigurationFile) |
164 | SetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf"); | |
165 | ||
992cf15a | 166 | /* |
a3e17a89 | 167 | * If the user hasn't specified "-f", run in the background... |
992cf15a | 168 | */ |
169 | ||
a3e17a89 | 170 | if (!fg) |
171 | { | |
172 | if (fork() > 0) | |
5fe35f41 | 173 | { |
174 | /* | |
58c40fb3 | 175 | * OK, wait for the child to startup and send us SIGUSR1... We |
176 | * also need to ignore SIGHUP which might be sent by the init | |
177 | * script to restart the scheduler... | |
5fe35f41 | 178 | */ |
05e63c18 | 179 | |
5fe35f41 | 180 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ |
181 | sigset(SIGUSR1, sigusr1_handler); | |
58c40fb3 | 182 | |
183 | sigset(SIGHUP, SIG_IGN); | |
5fe35f41 | 184 | #elif defined(HAVE_SIGACTION) |
759f5023 | 185 | memset(&action, 0, sizeof(action)); |
5fe35f41 | 186 | sigemptyset(&action.sa_mask); |
187 | sigaddset(&action.sa_mask, SIGUSR1); | |
188 | action.sa_handler = sigusr1_handler; | |
189 | sigaction(SIGUSR1, &action, NULL); | |
58c40fb3 | 190 | |
191 | sigemptyset(&action.sa_mask); | |
192 | action.sa_handler = SIG_IGN; | |
193 | sigaction(SIGHUP, &action, NULL); | |
5fe35f41 | 194 | #else |
195 | signal(SIGUSR1, sigusr1_handler); | |
58c40fb3 | 196 | |
197 | signal(SIGHUP, SIG_IGN); | |
5fe35f41 | 198 | #endif /* HAVE_SIGSET */ |
199 | ||
200 | if (wait(&i) < 0) | |
201 | i = 0; | |
202 | ||
203 | if (i == 0) | |
204 | return (0); | |
205 | ||
206 | if (i >= 256) | |
207 | fprintf(stderr, "cupsd: Child exited with status %d!\n", i / 256); | |
208 | else | |
209 | fprintf(stderr, "cupsd: Child exited on signal %d!\n", i); | |
210 | ||
211 | return (i); | |
212 | } | |
213 | } | |
214 | ||
215 | if (fg < 1) | |
216 | { | |
a3e17a89 | 217 | /* |
218 | * Make sure we aren't tying up any filesystems... | |
219 | */ | |
220 | ||
221 | chdir("/"); | |
992cf15a | 222 | |
8b43895a | 223 | #ifndef DEBUG |
a3e17a89 | 224 | /* |
225 | * Disable core dumps... | |
226 | */ | |
227 | ||
228 | getrlimit(RLIMIT_CORE, &limit); | |
229 | limit.rlim_cur = 0; | |
230 | setrlimit(RLIMIT_CORE, &limit); | |
231 | ||
232 | /* | |
233 | * Disconnect from the controlling terminal... | |
234 | */ | |
235 | ||
236 | close(0); | |
237 | close(1); | |
238 | close(2); | |
8b43895a | 239 | |
a3e17a89 | 240 | setsid(); |
241 | #endif /* DEBUG */ | |
242 | } | |
147ddbb6 | 243 | |
244 | /* | |
a3e17a89 | 245 | * Set the timezone info... |
147ddbb6 | 246 | */ |
247 | ||
a3e17a89 | 248 | if (getenv("TZ") != NULL) |
36992080 | 249 | SetStringf(&TZ, "TZ=%s", getenv("TZ")); |
861062bf | 250 | else |
36992080 | 251 | SetString(&TZ, ""); |
a3e17a89 | 252 | |
253 | tzset(); | |
8b43895a | 254 | |
d0e4469d | 255 | #ifdef LC_TIME |
256 | setlocale(LC_TIME, ""); | |
257 | #endif /* LC_TIME */ | |
258 | ||
8b43895a | 259 | /* |
260 | * Set the maximum number of files... | |
261 | */ | |
262 | ||
263 | getrlimit(RLIMIT_NOFILE, &limit); | |
a351bcb0 | 264 | |
265 | if (limit.rlim_max > CUPS_MAX_FDS) | |
266 | MaxFDs = CUPS_MAX_FDS; | |
267 | else | |
268 | MaxFDs = limit.rlim_max; | |
269 | ||
270 | limit.rlim_cur = MaxFDs; | |
271 | ||
8b43895a | 272 | setrlimit(RLIMIT_NOFILE, &limit); |
273 | ||
f3bc1068 | 274 | /* |
275 | * Allocate memory for the input and output sets... | |
276 | */ | |
277 | ||
278 | SetSize = (MaxFDs + 7) / 8; | |
279 | InputSet = (fd_set *)calloc(1, SetSize); | |
280 | OutputSet = (fd_set *)calloc(1, SetSize); | |
281 | input = (fd_set *)calloc(1, SetSize); | |
282 | output = (fd_set *)calloc(1, SetSize); | |
283 | ||
284 | if (InputSet == NULL || OutputSet == NULL || input == NULL || output == NULL) | |
285 | { | |
286 | syslog(LOG_LPR, "Unable to allocate memory for select() sets - exiting!"); | |
287 | return (1); | |
288 | } | |
289 | ||
3840d6ba | 290 | /* |
2bffb563 | 291 | * Catch hangup and child signals and ignore broken pipes... |
3840d6ba | 292 | */ |
293 | ||
e5cf24b2 | 294 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ |
f3890b95 | 295 | if (RunAsUser) |
296 | sigset(SIGHUP, sigterm_handler); | |
297 | else | |
0b50ddbc | 298 | sigset(SIGHUP, sighup_handler); |
f3bc1068 | 299 | |
e5cf24b2 | 300 | sigset(SIGPIPE, SIG_IGN); |
a3e17a89 | 301 | sigset(SIGTERM, sigterm_handler); |
e5cf24b2 | 302 | #elif defined(HAVE_SIGACTION) |
2bffb563 | 303 | memset(&action, 0, sizeof(action)); |
304 | ||
f3890b95 | 305 | sigemptyset(&action.sa_mask); |
306 | sigaddset(&action.sa_mask, SIGHUP); | |
307 | ||
308 | if (RunAsUser) | |
309 | action.sa_handler = sigterm_handler; | |
310 | else | |
0b50ddbc | 311 | action.sa_handler = sighup_handler; |
f3890b95 | 312 | |
313 | sigaction(SIGHUP, &action, NULL); | |
2bffb563 | 314 | |
e5cf24b2 | 315 | sigemptyset(&action.sa_mask); |
2bffb563 | 316 | action.sa_handler = SIG_IGN; |
317 | sigaction(SIGPIPE, &action, NULL); | |
a3e17a89 | 318 | |
319 | sigemptyset(&action.sa_mask); | |
320 | sigaddset(&action.sa_mask, SIGTERM); | |
879062a9 | 321 | sigaddset(&action.sa_mask, SIGCHLD); |
a3e17a89 | 322 | action.sa_handler = sigterm_handler; |
323 | sigaction(SIGTERM, &action, NULL); | |
e5cf24b2 | 324 | #else |
f3890b95 | 325 | if (RunAsUser) |
326 | signal(SIGHUP, sigterm_handler); | |
327 | else | |
0b50ddbc | 328 | signal(SIGHUP, sighup_handler); |
f3890b95 | 329 | |
e5cf24b2 | 330 | signal(SIGPIPE, SIG_IGN); |
a3e17a89 | 331 | signal(SIGTERM, sigterm_handler); |
e5cf24b2 | 332 | #endif /* HAVE_SIGSET */ |
3840d6ba | 333 | |
c47e97cc | 334 | /* |
335 | * Read configuration... | |
336 | */ | |
337 | ||
338 | if (!ReadConfiguration()) | |
339 | { | |
340 | syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", | |
341 | ConfigurationFile); | |
342 | return (1); | |
343 | } | |
344 | ||
cb9d2abc | 345 | #ifdef __sgi |
346 | /* | |
347 | * Try to create a fake lpsched lock file if one is not already there. | |
348 | * Some Adobe applications need it under IRIX in order to enable | |
349 | * printing... | |
350 | */ | |
351 | ||
352 | if ((fp = fopen("/var/spool/lp/SCHEDLOCK", "a")) == NULL) | |
353 | { | |
354 | syslog(LOG_LPR, "Unable to create fake lpsched lock file " | |
355 | "\"/var/spool/lp/SCHEDLOCK\"\' - %s!", | |
356 | strerror(errno)); | |
357 | } | |
358 | else | |
359 | { | |
360 | fclose(fp); | |
361 | ||
362 | chmod("/var/spool/lp/SCHEDLOCK", 0644); | |
363 | chown("/var/spool/lp/SCHEDLOCK", User, Group); | |
364 | } | |
365 | #endif /* __sgi */ | |
366 | ||
1049abbe | 367 | /* |
c802720f | 368 | * Initialize authentication certificates... |
1049abbe | 369 | */ |
370 | ||
23bba0c3 | 371 | InitCerts(); |
372 | ||
c802720f | 373 | /* |
5fe35f41 | 374 | * If we are running in the background, signal the parent process that |
375 | * we are up and running... | |
c802720f | 376 | */ |
377 | ||
5fe35f41 | 378 | if (!fg) |
379 | kill(getppid(), SIGUSR1); | |
1049abbe | 380 | |
50f63f23 | 381 | /* |
382 | * If the administrator has configured the server to run as an unpriviledged | |
383 | * user, change to that user now... | |
384 | */ | |
385 | ||
386 | if (RunAsUser) | |
387 | { | |
388 | setgid(Group); | |
389 | setgroups(0, NULL); | |
390 | setuid(User); | |
391 | } | |
392 | ||
3840d6ba | 393 | /* |
394 | * Loop forever... | |
395 | */ | |
396 | ||
05ca02bc | 397 | senddoc_time = time(NULL); |
398 | ||
b6ea8f29 | 399 | #ifdef HAVE_MALLINFO |
400 | mallinfo_time = 0; | |
401 | #endif /* HAVE_MALLINFO */ | |
402 | ||
a74b005d | 403 | for (;;) |
3840d6ba | 404 | { |
fd8b1cf8 | 405 | /* |
406 | * Check if we need to load the server configuration file... | |
407 | */ | |
408 | ||
409 | if (NeedReload) | |
410 | { | |
411 | if (NumClients > 0) | |
412 | { | |
413 | for (i = NumClients, con = Clients; i > 0; i --, con ++) | |
a74b005d | 414 | if (con->http.state == HTTP_WAITING) |
fd8b1cf8 | 415 | { |
416 | CloseClient(con); | |
417 | con --; | |
418 | } | |
419 | else | |
93894a43 | 420 | con->http.keep_alive = HTTP_KEEPALIVE_OFF; |
fd8b1cf8 | 421 | |
d236cb49 | 422 | PauseListening(); |
fd8b1cf8 | 423 | } |
424 | else if (!ReadConfiguration()) | |
425 | { | |
a3e17a89 | 426 | syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", |
427 | ConfigurationFile); | |
d2122fde | 428 | break; |
fd8b1cf8 | 429 | } |
430 | } | |
431 | ||
3840d6ba | 432 | /* |
433 | * Check for available input or ready output. If select() returns | |
434 | * 0 or -1, something bad happened and we should exit immediately. | |
435 | * | |
42d48bd2 | 436 | * Note that we at least have one listening socket open at all |
3840d6ba | 437 | * times. |
438 | */ | |
439 | ||
f3bc1068 | 440 | memcpy(input, InputSet, SetSize); |
441 | memcpy(output, OutputSet, SetSize); | |
3840d6ba | 442 | |
fd8b1cf8 | 443 | for (i = NumClients, con = Clients; i > 0; i --, con ++) |
a74b005d | 444 | if (con->http.used > 0) |
d9e72533 | 445 | break; |
446 | ||
447 | if (i) | |
448 | { | |
449 | timeout.tv_sec = 0; | |
450 | timeout.tv_usec = 0; | |
451 | } | |
452 | else | |
453 | { | |
454 | /* | |
455 | * If we have no pending data from a client, see when we really | |
456 | * need to wake up... | |
457 | */ | |
458 | ||
459 | timeout.tv_sec = 1; | |
460 | timeout.tv_usec = 0; | |
461 | } | |
3840d6ba | 462 | |
f3bc1068 | 463 | if ((i = select(MaxFDs, input, output, NULL, &timeout)) < 0) |
fd8b1cf8 | 464 | { |
d236cb49 | 465 | char s[16384], /* String buffer */ |
466 | *sptr; /* Pointer into buffer */ | |
467 | int slen; /* Length of string buffer */ | |
468 | ||
469 | ||
886c59e2 | 470 | /* |
471 | * Got an error from select! | |
472 | */ | |
473 | ||
474 | if (errno == EINTR) /* Just interrupted by a signal */ | |
fd8b1cf8 | 475 | continue; |
476 | ||
886c59e2 | 477 | /* |
d236cb49 | 478 | * Log all sorts of debug info to help track down the problem. |
886c59e2 | 479 | */ |
480 | ||
b5cb0608 | 481 | LogMessage(L_EMERG, "select() failed - %s!", strerror(errno)); |
d236cb49 | 482 | |
483 | strcpy(s, "InputSet ="); | |
6cd03542 | 484 | slen = 10; |
485 | sptr = s + 10; | |
d236cb49 | 486 | |
93336dbc | 487 | for (i = 0; i < MaxFDs; i ++) |
f3bc1068 | 488 | if (FD_ISSET(i, InputSet)) |
6cd03542 | 489 | { |
04de52f8 | 490 | snprintf(sptr, sizeof(s) - slen, " %d", i); |
6cd03542 | 491 | slen += strlen(sptr); |
492 | sptr += strlen(sptr); | |
493 | } | |
bfa1abf0 | 494 | |
b5cb0608 | 495 | LogMessage(L_EMERG, s); |
bfa1abf0 | 496 | |
d236cb49 | 497 | strcpy(s, "OutputSet ="); |
6cd03542 | 498 | slen = 11; |
499 | sptr = s + 11; | |
d236cb49 | 500 | |
93336dbc | 501 | for (i = 0; i < MaxFDs; i ++) |
f3bc1068 | 502 | if (FD_ISSET(i, OutputSet)) |
6cd03542 | 503 | { |
04de52f8 | 504 | snprintf(sptr, sizeof(s) - slen, " %d", i); |
6cd03542 | 505 | slen += strlen(sptr); |
506 | sptr += strlen(sptr); | |
507 | } | |
d236cb49 | 508 | |
b5cb0608 | 509 | LogMessage(L_EMERG, s); |
886c59e2 | 510 | |
882031b3 | 511 | for (i = 0, con = Clients; i < NumClients; i ++, con ++) |
b5cb0608 | 512 | LogMessage(L_EMERG, "Clients[%d] = %d, file = %d, state = %d", |
df47c6ae | 513 | i, con->http.fd, con->file, con->http.state); |
886c59e2 | 514 | |
515 | for (i = 0, lis = Listeners; i < NumListeners; i ++, lis ++) | |
b5cb0608 | 516 | LogMessage(L_EMERG, "Listeners[%d] = %d", i, lis->fd); |
886c59e2 | 517 | |
b5cb0608 | 518 | LogMessage(L_EMERG, "BrowseSocket = %d", BrowseSocket); |
886c59e2 | 519 | |
520 | for (job = Jobs; job != NULL; job = job->next) | |
a2fc3d31 | 521 | LogMessage(L_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]", |
522 | job->id, job->status_pipe, | |
523 | job->print_pipes[0], job->print_pipes[1], | |
524 | job->back_pipes[0], job->back_pipes[1]); | |
bfa1abf0 | 525 | |
3840d6ba | 526 | break; |
fd8b1cf8 | 527 | } |
3840d6ba | 528 | |
fd8b1cf8 | 529 | for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) |
f3bc1068 | 530 | if (FD_ISSET(lis->fd, input)) |
fd8b1cf8 | 531 | AcceptClient(lis); |
3840d6ba | 532 | |
fd8b1cf8 | 533 | for (i = NumClients, con = Clients; i > 0; i --, con ++) |
3840d6ba | 534 | { |
3840d6ba | 535 | /* |
536 | * Process the input buffer... | |
537 | */ | |
538 | ||
f3bc1068 | 539 | if (FD_ISSET(con->http.fd, input) || con->http.used) |
fd8b1cf8 | 540 | if (!ReadClient(con)) |
3840d6ba | 541 | { |
542 | con --; | |
3840d6ba | 543 | continue; |
544 | } | |
545 | ||
546 | /* | |
547 | * Write data as needed... | |
548 | */ | |
549 | ||
f3bc1068 | 550 | if (FD_ISSET(con->http.fd, output) && |
551 | (!con->pipe_pid || FD_ISSET(con->file, input))) | |
fd8b1cf8 | 552 | if (!WriteClient(con)) |
3840d6ba | 553 | { |
554 | con --; | |
992cf15a | 555 | continue; |
3840d6ba | 556 | } |
992cf15a | 557 | |
558 | /* | |
fd8b1cf8 | 559 | * Check the activity and close old clients... |
992cf15a | 560 | */ |
561 | ||
df47c6ae | 562 | activity = time(NULL) - Timeout; |
563 | if (con->http.activity < activity && !con->pipe_pid) | |
992cf15a | 564 | { |
de218675 | 565 | LogMessage(L_DEBUG, "Closing client %d after %d seconds of inactivity...", |
566 | con->http.fd, Timeout); | |
567 | ||
fd8b1cf8 | 568 | CloseClient(con); |
992cf15a | 569 | con --; |
992cf15a | 570 | continue; |
571 | } | |
3840d6ba | 572 | } |
6abc7437 | 573 | |
574 | /* | |
575 | * Check for status info from job filters... | |
576 | */ | |
577 | ||
578 | for (job = Jobs; job != NULL; job = next) | |
579 | { | |
580 | next = job->next; | |
581 | ||
f3bc1068 | 582 | if (job->status_pipe >= 0 && FD_ISSET(job->status_pipe, input)) |
b5cb0608 | 583 | { |
584 | /* | |
585 | * Clear the input bit to avoid updating the next job | |
586 | * using the same status pipe file descriptor... | |
587 | */ | |
588 | ||
f3bc1068 | 589 | FD_CLR(job->status_pipe, input); |
b5cb0608 | 590 | |
591 | /* | |
592 | * Read any status messages from the filters... | |
593 | */ | |
594 | ||
6abc7437 | 595 | UpdateJob(job); |
b5cb0608 | 596 | } |
6abc7437 | 597 | } |
d6de4648 | 598 | |
0a968cfb | 599 | /* |
600 | * Update CGI messages as needed... | |
601 | */ | |
602 | ||
603 | if (CGIPipes[0] >= 0 && FD_ISSET(CGIPipes[0], input)) | |
604 | UpdateCGI(); | |
605 | ||
d6de4648 | 606 | /* |
607 | * Update the browse list as needed... | |
608 | */ | |
609 | ||
151718ce | 610 | if (Browsing && BrowseProtocols) |
a40c1c6f | 611 | { |
f3bc1068 | 612 | if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, input)) |
753453e4 | 613 | UpdateCUPSBrowse(); |
614 | ||
f3bc1068 | 615 | if (PollPipe >= 0 && FD_ISSET(PollPipe, input)) |
5f46b7d1 | 616 | UpdatePolling(); |
617 | ||
753453e4 | 618 | #ifdef HAVE_LIBSLP |
619 | if ((BrowseProtocols & BROWSE_SLP) && BrowseSLPRefresh <= time(NULL)) | |
620 | UpdateSLPBrowse(); | |
621 | #endif /* HAVE_LIBSLP */ | |
d6de4648 | 622 | |
a40c1c6f | 623 | SendBrowseList(); |
624 | } | |
d2122fde | 625 | |
05ca02bc | 626 | /* |
627 | * Update any pending multi-file documents... | |
628 | */ | |
629 | ||
f3c3b479 | 630 | if ((time(NULL) - senddoc_time) >= 10) |
05ca02bc | 631 | { |
632 | CheckJobs(); | |
633 | senddoc_time = time(NULL); | |
634 | } | |
635 | ||
2bdd1992 | 636 | #ifdef HAVE_MALLINFO |
d2122fde | 637 | /* |
2bdd1992 | 638 | * Log memory usage every minute... |
d2122fde | 639 | */ |
640 | ||
2bdd1992 | 641 | if ((time(NULL) - mallinfo_time) >= 60 && LogLevel >= L_DEBUG) |
d2122fde | 642 | { |
8c57ced1 | 643 | struct mallinfo mem; /* Malloc information */ |
644 | ||
645 | ||
8c57ced1 | 646 | mem = mallinfo(); |
647 | LogMessage(L_DEBUG, "mallinfo: arena = %d, used = %d, free = %d\n", | |
648 | mem.arena, mem.usmblks + mem.uordblks, | |
649 | mem.fsmblks + mem.fordblks); | |
2bdd1992 | 650 | mallinfo_time = time(NULL); |
651 | } | |
652 | #endif /* HAVE_MALLINFO */ | |
8c57ced1 | 653 | |
2bdd1992 | 654 | /* |
655 | * Update the root certificate once every 5 minutes... | |
656 | */ | |
657 | ||
d9e72533 | 658 | if ((time(NULL) - RootCertTime) >= RootCertDuration && RootCertDuration) |
2bdd1992 | 659 | { |
8c57ced1 | 660 | /* |
661 | * Update the root certificate... | |
662 | */ | |
663 | ||
d2122fde | 664 | DeleteCert(0); |
665 | AddCert(0, "root"); | |
666 | } | |
3840d6ba | 667 | } |
668 | ||
669 | /* | |
670 | * If we get here something very bad happened and we need to exit | |
671 | * immediately. | |
672 | */ | |
673 | ||
18fe941f | 674 | StopBrowsing(); |
675 | StopAllJobs(); | |
d2122fde | 676 | DeleteAllCerts(); |
fd8b1cf8 | 677 | CloseAllClients(); |
678 | StopListening(); | |
679 | ||
680 | return (1); | |
681 | } | |
3840d6ba | 682 | |
3840d6ba | 683 | |
d7845573 | 684 | /* |
685 | * 'CatchChildSignals()' - Catch SIGCHLD signals... | |
686 | */ | |
687 | ||
688 | void | |
689 | CatchChildSignals(void) | |
690 | { | |
691 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
692 | struct sigaction action; /* Actions for POSIX signals */ | |
693 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
694 | ||
695 | ||
696 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
697 | sigset(SIGCHLD, sigchld_handler); | |
698 | #elif defined(HAVE_SIGACTION) | |
699 | memset(&action, 0, sizeof(action)); | |
700 | ||
701 | sigemptyset(&action.sa_mask); | |
879062a9 | 702 | sigaddset(&action.sa_mask, SIGTERM); |
d7845573 | 703 | sigaddset(&action.sa_mask, SIGCHLD); |
704 | action.sa_handler = sigchld_handler; | |
705 | sigaction(SIGCHLD, &action, NULL); | |
706 | #else | |
707 | signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */ | |
708 | #endif /* HAVE_SIGSET */ | |
709 | } | |
710 | ||
711 | ||
36992080 | 712 | /* |
713 | * 'ClearString()' - Clear a string. | |
714 | */ | |
715 | ||
716 | void | |
717 | ClearString(char **s) /* O - String value */ | |
718 | { | |
719 | if (s && *s) | |
720 | { | |
721 | free(*s); | |
722 | *s = NULL; | |
723 | } | |
724 | } | |
725 | ||
726 | ||
38743560 | 727 | /* |
728 | * 'HoldSignals()' - Hold child and termination signals. | |
729 | */ | |
730 | ||
731 | void | |
732 | HoldSignals(void) | |
733 | { | |
734 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
735 | sigset_t newmask; /* New POSIX signal mask */ | |
736 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
737 | ||
738 | ||
739 | #ifdef HAVE_SIGSET | |
740 | sighold(SIGTERM); | |
741 | sighold(SIGCHLD); | |
742 | #elif defined(HAVE_SIGACTION) | |
743 | sigemptyset(&newmask); | |
744 | sigaddset(&newmask, SIGTERM); | |
745 | sigaddset(&newmask, SIGCHLD); | |
746 | sigprocmask(SIG_BLOCK, &newmask, &oldmask); | |
747 | #endif /* HAVE_SIGSET */ | |
748 | } | |
749 | ||
750 | ||
d7845573 | 751 | /* |
752 | * 'IgnoreChildSignals()' - Ignore SIGCHLD signals... | |
5a0aab69 | 753 | * |
754 | * We don't really ignore them, we set the signal handler to SIG_DFL, | |
755 | * since some OS's rely on signals for the wait4() function to work. | |
d7845573 | 756 | */ |
757 | ||
758 | void | |
759 | IgnoreChildSignals(void) | |
760 | { | |
761 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
762 | struct sigaction action; /* Actions for POSIX signals */ | |
763 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
764 | ||
38743560 | 765 | |
d7845573 | 766 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ |
5a0aab69 | 767 | sigset(SIGCHLD, SIG_DFL); |
d7845573 | 768 | #elif defined(HAVE_SIGACTION) |
769 | memset(&action, 0, sizeof(action)); | |
770 | ||
771 | sigemptyset(&action.sa_mask); | |
772 | sigaddset(&action.sa_mask, SIGCHLD); | |
5a0aab69 | 773 | action.sa_handler = SIG_DFL; |
d7845573 | 774 | sigaction(SIGCHLD, &action, NULL); |
775 | #else | |
5a0aab69 | 776 | signal(SIGCLD, SIG_DFL); /* No, SIGCLD isn't a typo... */ |
d7845573 | 777 | #endif /* HAVE_SIGSET */ |
778 | } | |
779 | ||
780 | ||
38743560 | 781 | /* |
782 | * 'ReleaseSignals()' - Release signals for delivery. | |
783 | */ | |
784 | ||
785 | void | |
786 | ReleaseSignals(void) | |
787 | { | |
788 | #ifdef HAVE_SIGSET | |
789 | sigrelse(SIGTERM); | |
790 | sigrelse(SIGCHLD); | |
791 | #elif defined(HAVE_SIGACTION) | |
792 | sigprocmask(SIG_SETMASK, &oldmask, NULL); | |
793 | #endif /* HAVE_SIGSET */ | |
794 | } | |
795 | ||
796 | ||
36992080 | 797 | /* |
798 | * 'SetString()' - Set a string value. | |
799 | */ | |
800 | ||
801 | void | |
802 | SetString(char **s, /* O - New string */ | |
803 | const char *v) /* I - String value */ | |
804 | { | |
471f1564 | 805 | if (!s || *s == v) |
36992080 | 806 | return; |
807 | ||
808 | if (*s) | |
809 | free(*s); | |
810 | ||
811 | if (v) | |
812 | *s = strdup(v); | |
813 | else | |
814 | *s = NULL; | |
815 | } | |
816 | ||
817 | ||
818 | /* | |
819 | * 'SetStringf()' - Set a formatted string value. | |
820 | */ | |
821 | ||
822 | void | |
823 | SetStringf(char **s, /* O - New string */ | |
824 | const char *f, /* I - Printf-style format string */ | |
825 | ...) /* I - Additional args as needed */ | |
826 | { | |
827 | char v[1024]; /* Formatting string value */ | |
828 | va_list ap; /* Argument pointer */ | |
471f1564 | 829 | char *olds; /* Old string */ |
36992080 | 830 | |
831 | ||
832 | if (!s) | |
833 | return; | |
834 | ||
471f1564 | 835 | olds = *s; |
36992080 | 836 | |
837 | if (f) | |
838 | { | |
839 | va_start(ap, f); | |
840 | vsnprintf(v, sizeof(v), f, ap); | |
841 | va_end(ap); | |
842 | ||
843 | *s = strdup(v); | |
844 | } | |
845 | else | |
846 | *s = NULL; | |
471f1564 | 847 | |
848 | if (olds) | |
849 | free(olds); | |
36992080 | 850 | } |
851 | ||
852 | ||
6abc7437 | 853 | /* |
e5cf24b2 | 854 | * 'sigchld_handler()' - Handle 'child' signals from old processes. |
6abc7437 | 855 | */ |
856 | ||
857 | static void | |
e5cf24b2 | 858 | sigchld_handler(int sig) /* I - Signal number */ |
6abc7437 | 859 | { |
bdbaa675 | 860 | int olderrno; /* Old errno value */ |
e5cf24b2 | 861 | int status; /* Exit status of child */ |
862 | int pid; /* Process ID of child */ | |
863 | job_t *job; /* Current job */ | |
864 | int i; /* Looping var */ | |
6abc7437 | 865 | |
866 | ||
867 | (void)sig; | |
868 | ||
bdbaa675 | 869 | /* |
870 | * Save the original error value (wait might overwrite it...) | |
871 | */ | |
872 | ||
873 | olderrno = errno; | |
874 | ||
e5cf24b2 | 875 | #ifdef HAVE_WAITPID |
876 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) | |
877 | #elif defined(HAVE_WAIT3) | |
878 | while ((pid = wait3(&status, WNOHANG, NULL)) > 0) | |
879 | #else | |
880 | if ((pid = wait(&status)) > 0) | |
881 | #endif /* HAVE_WAITPID */ | |
882 | { | |
5fe35f41 | 883 | DEBUG_printf(("sigchld_handler: pid = %d, status = %d\n", pid, status)); |
6abc7437 | 884 | |
d2122fde | 885 | /* |
886 | * Ignore SIGTERM errors - that comes when a job is cancelled... | |
887 | */ | |
888 | ||
6bc08d08 | 889 | if (status == SIGTERM) |
890 | status = 0; | |
891 | ||
892 | if (status) | |
893 | { | |
a2fc3d31 | 894 | if (WIFEXITED(status)) |
6d8b6788 | 895 | LogMessage(L_ERROR, "PID %d stopped with status %d!", pid, |
a2fc3d31 | 896 | WEXITSTATUS(status)); |
897 | else | |
898 | LogMessage(L_ERROR, "PID %d crashed on signal %d!", pid, | |
899 | WTERMSIG(status)); | |
deb855a2 | 900 | |
901 | if (LogLevel < L_DEBUG) | |
902 | LogMessage(L_INFO, "Hint: Try setting the LogLevel to \"debug\" to find out more."); | |
6bc08d08 | 903 | } |
434ddc80 | 904 | else |
905 | LogMessage(L_DEBUG2, "PID %d exited with no errors.", pid); | |
906 | ||
907 | /* | |
908 | * Delete certificates for CGI processes... | |
909 | */ | |
910 | ||
911 | if (pid) | |
912 | DeleteCert(pid); | |
913 | ||
914 | /* | |
915 | * Lookup the PID in the jobs list... | |
916 | */ | |
e5b7bd9c | 917 | |
e5cf24b2 | 918 | for (job = Jobs; job != NULL; job = job->next) |
879062a9 | 919 | if (job->state != NULL && |
920 | job->state->values[0].integer == IPP_JOB_PROCESSING) | |
6abc7437 | 921 | { |
a2fc3d31 | 922 | for (i = 0; job->filters[i]; i ++) |
923 | if (job->filters[i] == pid) | |
e5cf24b2 | 924 | break; |
6abc7437 | 925 | |
a2fc3d31 | 926 | if (job->filters[i] || job->backend == pid) |
bfa1abf0 | 927 | { |
928 | /* | |
e5cf24b2 | 929 | * OK, this process has gone away; what's left? |
bfa1abf0 | 930 | */ |
6abc7437 | 931 | |
a2fc3d31 | 932 | if (job->filters[i]) |
933 | job->filters[i] = -pid; | |
934 | else | |
935 | job->backend = -pid; | |
6abc7437 | 936 | |
bd84e0d1 | 937 | if (status && job->status >= 0) |
e5cf24b2 | 938 | { |
939 | /* | |
bd84e0d1 | 940 | * An error occurred; save the exit status so we know to stop |
941 | * the printer or cancel the job when all of the filters finish... | |
942 | * | |
943 | * A negative status indicates that the backend failed and the | |
944 | * printer needs to be stopped. | |
e5cf24b2 | 945 | */ |
946 | ||
a2fc3d31 | 947 | if (job->filters[i]) |
bd84e0d1 | 948 | job->status = status; /* Filter failed */ |
a2fc3d31 | 949 | else |
950 | job->status = -status; /* Backend failed */ | |
e5cf24b2 | 951 | } |
e5cf24b2 | 952 | break; |
953 | } | |
6abc7437 | 954 | } |
e5cf24b2 | 955 | } |
956 | ||
bdbaa675 | 957 | /* |
958 | * Restore the original error value... | |
959 | */ | |
960 | ||
961 | errno = olderrno; | |
962 | ||
e5cf24b2 | 963 | #ifdef HAVE_SIGSET |
964 | sigset(SIGCHLD, sigchld_handler); | |
965 | #elif !defined(HAVE_SIGACTION) | |
966 | signal(SIGCLD, sigchld_handler); | |
967 | #endif /* HAVE_SIGSET */ | |
6abc7437 | 968 | } |
969 | ||
970 | ||
fd8b1cf8 | 971 | /* |
972 | * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler. | |
973 | */ | |
974 | ||
975 | static void | |
976 | sighup_handler(int sig) /* I - Signal number */ | |
977 | { | |
93894a43 | 978 | (void)sig; |
979 | ||
fd8b1cf8 | 980 | NeedReload = TRUE; |
a3e17a89 | 981 | |
982 | #ifdef HAVE_SIGSET | |
983 | sigset(SIGHUP, sighup_handler); | |
984 | #elif !defined(HAVE_SIGACTION) | |
985 | signal(SIGHUP, sighup_handler); | |
986 | #endif /* HAVE_SIGSET */ | |
987 | } | |
988 | ||
989 | ||
990 | /* | |
991 | * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler. | |
992 | */ | |
993 | ||
994 | static void | |
5fe35f41 | 995 | sigterm_handler(int sig) /* I - Signal */ |
a3e17a89 | 996 | { |
cb9d2abc | 997 | #ifdef __sgi |
998 | struct stat statbuf; /* Needed for checking lpsched FIFO */ | |
999 | #endif /* __sgi */ | |
1000 | ||
1001 | ||
d74efa25 | 1002 | (void)sig; /* remove compiler warnings... */ |
1003 | ||
a3e17a89 | 1004 | /* |
1005 | * Log an error... | |
1006 | */ | |
1007 | ||
1008 | LogMessage(L_ERROR, "Scheduler shutting down due to SIGTERM."); | |
1009 | ||
1010 | /* | |
1011 | * Close all network clients and stop all jobs... | |
1012 | */ | |
1013 | ||
1014 | CloseAllClients(); | |
1015 | StopListening(); | |
1016 | StopPolling(); | |
1017 | StopBrowsing(); | |
1018 | ||
1019 | if (Clients != NULL) | |
1020 | free(Clients); | |
1021 | ||
5fe35f41 | 1022 | FreeAllJobs(); |
a3e17a89 | 1023 | |
1024 | if (AccessFile != NULL) | |
1025 | fclose(AccessFile); | |
1026 | ||
1027 | if (ErrorFile != NULL) | |
1028 | fclose(ErrorFile); | |
1029 | ||
1030 | if (PageFile != NULL) | |
1031 | fclose(PageFile); | |
1032 | ||
1033 | DeleteAllLocations(); | |
1034 | ||
1035 | DeleteAllClasses(); | |
1036 | ||
1037 | if (Devices) | |
1038 | ippDelete(Devices); | |
1039 | ||
1040 | if (PPDs) | |
1041 | ippDelete(PPDs); | |
1042 | ||
1043 | DeleteAllPrinters(); | |
1044 | ||
1045 | if (MimeDatabase != NULL) | |
1046 | mimeDelete(MimeDatabase); | |
1047 | ||
cb9d2abc | 1048 | #ifdef __sgi |
1049 | /* | |
1050 | * Remove the fake IRIX lpsched lock file, but only if the existing | |
1051 | * file is not a FIFO which indicates that the real IRIX lpsched is | |
1052 | * running... | |
1053 | */ | |
1054 | ||
1055 | if (!stat("/var/spool/lp/FIFO", &statbuf)) | |
1056 | if (!S_ISFIFO(statbuf.st_mode)) | |
1057 | unlink("/var/spool/lp/SCHEDLOCK"); | |
1058 | #endif /* __sgi */ | |
1059 | ||
a3e17a89 | 1060 | exit(1); |
3840d6ba | 1061 | } |
1062 | ||
fd8b1cf8 | 1063 | |
5fe35f41 | 1064 | /* |
1065 | * 'sigusr1_handler()' - Catch USR1 signals... | |
1066 | */ | |
1067 | ||
1068 | static void | |
1069 | sigusr1_handler(int sig) /* I - Signal */ | |
1070 | { | |
1071 | (void)sig; /* remove compiler warnings... */ | |
1072 | } | |
1073 | ||
1074 | ||
fd8b1cf8 | 1075 | /* |
1076 | * 'usage()' - Show scheduler usage. | |
1077 | */ | |
1078 | ||
1079 | static void | |
1080 | usage(void) | |
1081 | { | |
a3e17a89 | 1082 | fputs("Usage: cupsd [-c config-file] [-f]\n", stderr); |
fd8b1cf8 | 1083 | exit(1); |
1084 | } | |
1085 | ||
1086 | ||
3840d6ba | 1087 | /* |
0a968cfb | 1088 | * End of "$Id: main.c,v 1.57.2.37 2003/03/14 21:43:34 mike Exp $". |
3840d6ba | 1089 | */ |