]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/main.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / scheduler / main.c
CommitLineData
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 58static void sigchld_handler(int sig);
fd8b1cf8 59static void sighup_handler(int sig);
a3e17a89 60static void sigterm_handler(int sig);
5fe35f41 61static void sigusr1_handler(int sig);
fd8b1cf8 62static void usage(void);
63
64
38743560 65/*
66 * Local globals...
67 */
68
69#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
70static 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 78int /* O - Exit status */
79main(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
688void
689CatchChildSignals(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
716void
717ClearString(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
731void
732HoldSignals(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
758void
759IgnoreChildSignals(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
785void
786ReleaseSignals(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
801void
802SetString(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
822void
823SetStringf(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
857static void
e5cf24b2 858sigchld_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
975static void
976sighup_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
994static void
5fe35f41 995sigterm_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
1068static void
1069sigusr1_handler(int sig) /* I - Signal */
1070{
1071 (void)sig; /* remove compiler warnings... */
1072}
1073
1074
fd8b1cf8 1075/*
1076 * 'usage()' - Show scheduler usage.
1077 */
1078
1079static void
1080usage(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 */