]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/main.c
Clean up localizations throughout.
[thirdparty/cups.git] / scheduler / main.c
CommitLineData
3840d6ba 1/*
b2e10895 2 * "$Id$"
3840d6ba 3 *
89813a30 4 * Main loop for the CUPS scheduler.
3840d6ba 5 *
650ede88 6 * Copyright 2007-2012 by Apple Inc.
baccdba8 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
3840d6ba 8 *
fd8b1cf8 9 * These coded instructions, statements, and computer programs are the
4e8d321f 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
fd8b1cf8 12 * "LICENSE" which should have been included with this file. If this
4e8d321f 13 * file is missing or damaged, see the license at "http://www.cups.org/".
992cf15a 14 *
fd8b1cf8 15 * Contents:
3840d6ba 16 *
96336986 17 * main() - Main entry for the CUPS scheduler.
18 * cupsdAddString() - Copy and add a string to an array.
19 * cupsdCheckProcess() - Tell the main loop to check for dead children.
20 * cupsdClearString() - Clear a string.
96336986 21 * cupsdFreeStrings() - Free an array of strings.
22 * cupsdHoldSignals() - Hold child and termination signals.
96336986 23 * cupsdReleaseSignals() - Release signals for delivery.
24 * cupsdSetString() - Set a string value.
25 * cupsdSetStringf() - Set a formatted string value.
96336986 26 * launchd_checkin() - Check-in with launchd and collect the listening
27 * fds.
28 * launchd_checkout() - Update the launchd KeepAlive file as needed.
29 * parent_handler() - Catch USR1/CHLD signals...
30 * process_children() - Process all dead children...
31 * select_timeout() - Calculate the select timeout value.
32 * sigchld_handler() - Handle 'child' signals from old processes.
33 * sighup_handler() - Handle 'hangup' signals to reconfigure the
34 * 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
5db6985b 49#ifdef HAVE_LAUNCH_H
50# include <launch.h>
51# include <libgen.h>
53f4f77a 52# define CUPS_KEEPALIVE CUPS_CACHEDIR "/org.cups.cupsd"
686aff43 53 /* Name of the launchd KeepAlive file */
54# ifndef LAUNCH_JOBKEY_KEEPALIVE
55# define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
56# endif /* !LAUNCH_JOBKEY_KEEPALIVE */
57# ifndef LAUNCH_JOBKEY_PATHSTATE
58# define LAUNCH_JOBKEY_PATHSTATE "PathState"
59# endif /* !LAUNCH_JOBKEY_PATHSTATE */
60# ifndef LAUNCH_JOBKEY_SERVICEIPC
61# define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC"
62# endif /* !LAUNCH_JOBKEY_SERVICEIPC */
5db6985b 63#endif /* HAVE_LAUNCH_H */
64
2bdd1992 65#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
8c57ced1 66# include <malloc.h>
2bdd1992 67#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
beda8626 68#ifdef HAVE_NOTIFY_H
69# include <notify.h>
70#endif /* HAVE_NOTIFY_H */
8c57ced1 71
3840d6ba 72
73/*
fd8b1cf8 74 * Local functions...
75 */
76
5db6985b 77#ifdef HAVE_LAUNCHD
5d69c5d6 78static void launchd_checkin(void);
686aff43 79static void launchd_checkout(void);
5db6985b 80#endif /* HAVE_LAUNCHD */
5d69c5d6 81static void parent_handler(int sig);
82static void process_children(void);
83static void sigchld_handler(int sig);
84static void sighup_handler(int sig);
85static void sigterm_handler(int sig);
86static long select_timeout(int fds);
1cad5897 87static void usage(int status) __attribute__((noreturn));
fd8b1cf8 88
89
38743560 90/*
91 * Local globals...
92 */
93
5d69c5d6 94static int parent_signal = 0;
95 /* Set to signal number from child */
96static int holdcount = 0; /* Number of times "hold" was called */
38743560 97#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
5d69c5d6 98static sigset_t holdmask; /* Old POSIX signal mask */
38743560 99#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
5d69c5d6 100static int dead_children = 0;
101 /* Dead children? */
102static int stop_scheduler = 0;
103 /* Should the scheduler stop? */
104
38743560 105
fd8b1cf8 106/*
107 * 'main()' - Main entry for the CUPS scheduler.
3840d6ba 108 */
109
38743560 110int /* O - Exit status */
c7445b9f 111main(int argc, /* I - Number of command-line args */
38743560 112 char *argv[]) /* I - Command-line arguments */
3840d6ba 113{
114 int i; /* Looping var */
fd8b1cf8 115 char *opt; /* Option character */
a3e17a89 116 int fg; /* Run in the foreground */
c7445b9f 117 int fds; /* Number of ready descriptors */
f3e786fc 118 cupsd_client_t *con; /* Current client */
119 cupsd_job_t *job; /* Current job */
120 cupsd_listener_t *lis; /* Current listener */
150ba5b1 121 time_t current_time, /* Current time */
5db6985b 122 activity, /* Client activity timer */
150ba5b1 123 senddoc_time, /* Send-Document time */
87c85a78 124 expire_time, /* Subscription expire time */
728d3284 125 report_time, /* Malloc/client/job report time */
3d5f2a94 126 event_time; /* Last event notification time */
9d4830a3 127 long timeout; /* Timeout for cupsdDoSelect() */
8b43895a 128 struct rlimit limit; /* Runtime limit */
8a2c2126 129#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
e5cf24b2 130 struct sigaction action; /* Actions for POSIX signals */
8a2c2126 131#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
cb9d2abc 132#ifdef __sgi
7b0fde61 133 cups_file_t *fp; /* Fake lpsched lock file */
52a9a175 134 struct stat statbuf; /* Needed for checking lpsched FIFO */
cb9d2abc 135#endif /* __sgi */
c8a52cb5 136 int run_as_child = 0;
137 /* Needed for background fork/exec */
f0f71900 138#ifdef __APPLE__
c8a52cb5 139 int use_sysman = !getuid();
ee0d93d7 140 /* Use system management functions? */
fb8bf313 141#else
142 time_t netif_time = 0; /* Time since last network update */
f0f71900 143#endif /* __APPLE__ */
5db6985b 144#if HAVE_LAUNCHD
dfeef8b5 145 int launchd_idle_exit;
5db6985b 146 /* Idle exit on select timeout? */
147#endif /* HAVE_LAUNCHD */
3840d6ba 148
149
eb183ae1 150#ifdef HAVE_GETEUID
151 /*
152 * Check for setuid invocation, which we do not support!
153 */
154
155 if (getuid() != geteuid())
156 {
157fcea9 157 fputs("cupsd: Cannot run as a setuid program\n", stderr);
eb183ae1 158 return (1);
159 }
160#endif /* HAVE_GETEUID */
161
fd8b1cf8 162 /*
163 * Check for command-line arguments...
164 */
165
dfeef8b5 166 fg = 0;
a3e17a89 167
18cff779 168#ifdef HAVE_LAUNCHD
169 if (getenv("CUPSD_LAUNCHD"))
170 {
171 Launchd = 1;
172 fg = 1;
173 }
174#endif /* HAVE_LAUNCHD */
175
fd8b1cf8 176 for (i = 1; i < argc; i ++)
177 if (argv[i][0] == '-')
178 for (opt = argv[i] + 1; *opt != '\0'; opt ++)
179 switch (*opt)
180 {
f0f71900 181 case 'C' : /* Run as child with config file */
182 run_as_child = 1;
183 fg = -1;
f0f71900 184
fd8b1cf8 185 case 'c' : /* Configuration file */
186 i ++;
187 if (i >= argc)
00a1fad8 188 {
189 _cupsLangPuts(stderr, _("cupsd: Expected config filename "
4c4eea89 190 "after \"-c\" option."));
00a1fad8 191 usage(1);
192 }
fd8b1cf8 193
a3e17a89 194 if (argv[i][0] == '/')
195 {
196 /*
197 * Absolute directory...
198 */
199
589eb420 200 cupsdSetString(&ConfigurationFile, argv[i]);
a3e17a89 201 }
202 else
203 {
204 /*
205 * Relative directory...
206 */
207
6de33945 208 char *current; /* Current directory */
36992080 209
210
6de33945 211 /*
212 * Allocate a buffer for the current working directory to
213 * reduce run-time stack usage; this approximates the
214 * behavior of some implementations of getcwd() when they
215 * are passed a NULL pointer.
216 */
217
09751e0f 218 if ((current = malloc(1024)) == NULL)
219 {
220 _cupsLangPuts(stderr,
4c4eea89 221 _("cupsd: Unable to get current directory."));
09751e0f 222 return (1);
223 }
224
225 if (!getcwd(current, 1024))
226 {
227 _cupsLangPuts(stderr,
4c4eea89 228 _("cupsd: Unable to get current directory."));
09751e0f 229 free(current);
230 return (1);
231 }
6de33945 232
589eb420 233 cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]);
6de33945 234 free(current);
a3e17a89 235 }
236 break;
237
238 case 'f' : /* Run in foreground... */
239 fg = 1;
fd8b1cf8 240 break;
241
c7445b9f 242 case 'F' : /* Run in foreground, but disconnect from terminal... */
5fe35f41 243 fg = -1;
244 break;
245
00a1fad8 246 case 'h' : /* Show usage/help */
247 usage(0);
248 break;
249
5db6985b 250 case 'l' : /* Started by launchd... */
00a1fad8 251#ifdef HAVE_LAUNCHD
dfeef8b5 252 Launchd = 1;
5db6985b 253 fg = 1;
00a1fad8 254#else
255 _cupsLangPuts(stderr, _("cupsd: launchd(8) support not compiled "
4c4eea89 256 "in, running in normal mode."));
00a1fad8 257 fg = 0;
5db6985b 258#endif /* HAVE_LAUNCHD */
00a1fad8 259 break;
5db6985b 260
2cc0f19a 261 case 'p' : /* Stop immediately for profiling */
3d5f2a94 262 fputs("cupsd: -p (startup profiling) is for internal testing "
263 "use only!\n", stderr);
2cc0f19a 264 stop_scheduler = 1;
265 fg = 1;
266 break;
267
eb63d8a1 268 case 'P' : /* Disable security profiles */
3d5f2a94 269 fputs("cupsd: -P (disable security profiles) is for internal "
270 "testing use only!\n", stderr);
eb63d8a1 271 UseProfiles = 0;
272 break;
273
c8a52cb5 274#ifdef __APPLE__
275 case 'S' : /* Disable system management functions */
3d5f2a94 276 fputs("cupsd: -S (disable system management) for internal "
277 "testing use only!\n", stderr);
c8a52cb5 278 use_sysman = 0;
279 break;
280#endif /* __APPLE__ */
281
cd0b47e5 282 case 't' : /* Test the cupsd.conf file... */
283 TestConfigFile = 1;
284 fg = 1;
285 break;
286
fd8b1cf8 287 default : /* Unknown option */
00a1fad8 288 _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
4c4eea89 289 "aborting."), *opt);
00a1fad8 290 usage(1);
fd8b1cf8 291 break;
292 }
293 else
294 {
4c4eea89 295 _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting."),
00a1fad8 296 argv[i]);
297 usage(1);
fd8b1cf8 298 }
299
beb575a9 300 if (!ConfigurationFile)
589eb420 301 cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf");
beb575a9 302
992cf15a 303 /*
a3e17a89 304 * If the user hasn't specified "-f", run in the background...
992cf15a 305 */
306
a3e17a89 307 if (!fg)
308 {
7f797921 309 /*
310 * Setup signal handlers for the parent...
311 */
05e63c18 312
5fe35f41 313#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
af57319f 314 sigset(SIGUSR1, parent_handler);
315 sigset(SIGCHLD, parent_handler);
58c40fb3 316
7f797921 317 sigset(SIGHUP, SIG_IGN);
5fe35f41 318#elif defined(HAVE_SIGACTION)
7f797921 319 memset(&action, 0, sizeof(action));
320 sigemptyset(&action.sa_mask);
321 sigaddset(&action.sa_mask, SIGUSR1);
af57319f 322 action.sa_handler = parent_handler;
7f797921 323 sigaction(SIGUSR1, &action, NULL);
af57319f 324 sigaction(SIGCHLD, &action, NULL);
7f797921 325
326 sigemptyset(&action.sa_mask);
327 action.sa_handler = SIG_IGN;
328 sigaction(SIGHUP, &action, NULL);
5fe35f41 329#else
af57319f 330 signal(SIGUSR1, parent_handler);
331 signal(SIGCLD, parent_handler);
58c40fb3 332
7f797921 333 signal(SIGHUP, SIG_IGN);
5fe35f41 334#endif /* HAVE_SIGSET */
335
7f797921 336 if (fork() > 0)
337 {
338 /*
af57319f 339 * OK, wait for the child to startup and send us SIGUSR1 or to crash
340 * and the OS send us SIGCHLD... We also need to ignore SIGHUP which
341 * might be sent by the init script to restart the scheduler...
7f797921 342 */
343
af57319f 344 for (; parent_signal == 0;)
345 sleep(1);
5fe35f41 346
af57319f 347 if (parent_signal == SIGUSR1)
5fe35f41 348 return (0);
349
af57319f 350 if (wait(&i) < 0)
351 {
352 perror("cupsd");
f2d1c59d 353 return (1);
354 }
355 else if (WIFEXITED(i))
356 {
157fcea9 357 fprintf(stderr, "cupsd: Child exited with status %d\n",
c7445b9f 358 WEXITSTATUS(i));
f2d1c59d 359 return (2);
af57319f 360 }
5fe35f41 361 else
f2d1c59d 362 {
157fcea9 363 fprintf(stderr, "cupsd: Child exited on signal %d\n", WTERMSIG(i));
f2d1c59d 364 return (3);
365 }
5fe35f41 366 }
f0f71900 367
c8a52cb5 368#ifdef __OpenBSD__
f0f71900 369 /*
c8a52cb5 370 * Call _thread_sys_closefrom() so the child process doesn't reset the
371 * parent's file descriptors to be blocking. This is a workaround for a
372 * limitation of userland libpthread on OpenBSD.
373 */
f7923037 374
c8a52cb5 375 _thread_sys_closefrom(0);
376#endif /* __OpenBSD__ */
377
378 /*
379 * Since CoreFoundation and DBUS both create fork-unsafe data on execution of
380 * a program, and since this kind of really unfriendly behavior seems to be
381 * more common these days in system libraries, we need to re-execute the
382 * background cupsd with the "-C" option to avoid problems. Unfortunately,
383 * we also have to assume that argv[0] contains the name of the cupsd
384 * executable - there is no portable way to get the real pathname...
f0f71900 385 */
386
387 execlp(argv[0], argv[0], "-C", ConfigurationFile, (char *)0);
388 exit(errno);
5fe35f41 389 }
390
391 if (fg < 1)
392 {
a3e17a89 393 /*
394 * Make sure we aren't tying up any filesystems...
395 */
396
397 chdir("/");
992cf15a 398
8b43895a 399#ifndef DEBUG
a3e17a89 400 /*
401 * Disable core dumps...
402 */
403
404 getrlimit(RLIMIT_CORE, &limit);
405 limit.rlim_cur = 0;
406 setrlimit(RLIMIT_CORE, &limit);
407
408 /*
409 * Disconnect from the controlling terminal...
410 */
411
a3e17a89 412 setsid();
da77a142 413
414 /*
415 * Close all open files...
416 */
417
418 getrlimit(RLIMIT_NOFILE, &limit);
419
5ba28a19 420 for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
da77a142 421 close(i);
619b6af0 422
423 /*
424 * Redirect stdin/out/err to /dev/null...
425 */
426
c8a52cb5 427 if ((i = open("/dev/null", O_RDONLY)) != 0)
428 {
429 dup2(i, 0);
430 close(i);
431 }
432
433 if ((i = open("/dev/null", O_WRONLY)) != 1)
434 {
435 dup2(i, 1);
436 close(i);
437 }
438
439 if ((i = open("/dev/null", O_WRONLY)) != 2)
440 {
441 dup2(i, 2);
442 close(i);
443 }
a3e17a89 444#endif /* DEBUG */
445 }
147ddbb6 446
447 /*
a3e17a89 448 * Set the timezone info...
147ddbb6 449 */
450
a3e17a89 451 tzset();
8b43895a 452
d0e4469d 453#ifdef LC_TIME
454 setlocale(LC_TIME, "");
455#endif /* LC_TIME */
456
8b43895a 457 /*
458 * Set the maximum number of files...
459 */
460
461 getrlimit(RLIMIT_NOFILE, &limit);
a351bcb0 462
9d4830a3 463#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
a99d043e 464 if (limit.rlim_max > FD_SETSIZE)
465 MaxFDs = FD_SETSIZE;
a351bcb0 466 else
9d4830a3 467#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
468#ifdef RLIM_INFINITY
469 if (limit.rlim_max == RLIM_INFINITY)
470 MaxFDs = 16384;
471 else
472#endif /* RLIM_INFINITY */
a351bcb0 473 MaxFDs = limit.rlim_max;
474
475 limit.rlim_cur = MaxFDs;
476
8b43895a 477 setrlimit(RLIMIT_NOFILE, &limit);
478
9d4830a3 479 cupsdStartSelect();
f3bc1068 480
2e6bce36 481 /*
482 * Read configuration...
483 */
484
589eb420 485 if (!cupsdReadConfiguration())
2e6bce36 486 {
cd0b47e5 487 if (TestConfigFile)
488 printf("%s contains errors\n", ConfigurationFile);
489 else
490 syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
491 ConfigurationFile);
2e6bce36 492 return (1);
493 }
cd0b47e5 494 else if (TestConfigFile)
495 {
496 printf("%s is OK\n", ConfigurationFile);
497 return (0);
498 }
2e6bce36 499
53f4f77a 500 /*
501 * Clean out old temp files and printer cache data.
502 */
a3e95b7e 503
53f4f77a 504 if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
85aaec5c 505 cupsdCleanFiles(TempDir, NULL);
a3e95b7e 506
85aaec5c 507 cupsdCleanFiles(CacheDir, "*.ipp");
a3e95b7e 508
5db6985b 509#if HAVE_LAUNCHD
dfeef8b5 510 if (Launchd)
5db6985b 511 {
512 /*
f49512cc 513 * If we were started by launchd get the listen sockets file descriptors...
686aff43 514 */
5db6985b 515
516 launchd_checkin();
e5c929b9 517 launchd_checkout();
5db6985b 518 }
519#endif /* HAVE_LAUNCHD */
520
521 /*
522 * Startup the server...
523 */
524
89813a30 525 httpInitialize();
526
5db6985b 527 cupsdStartServer();
528
3840d6ba 529 /*
2bffb563 530 * Catch hangup and child signals and ignore broken pipes...
3840d6ba 531 */
532
e5cf24b2 533#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
bd58a948 534 sigset(SIGCHLD, sigchld_handler);
c3d37ff1 535 sigset(SIGHUP, sighup_handler);
e5cf24b2 536 sigset(SIGPIPE, SIG_IGN);
a3e17a89 537 sigset(SIGTERM, sigterm_handler);
e5cf24b2 538#elif defined(HAVE_SIGACTION)
2bffb563 539 memset(&action, 0, sizeof(action));
540
bd58a948 541 sigemptyset(&action.sa_mask);
542 sigaddset(&action.sa_mask, SIGTERM);
543 sigaddset(&action.sa_mask, SIGCHLD);
544 action.sa_handler = sigchld_handler;
545 sigaction(SIGCHLD, &action, NULL);
546
f3890b95 547 sigemptyset(&action.sa_mask);
548 sigaddset(&action.sa_mask, SIGHUP);
c3d37ff1 549 action.sa_handler = sighup_handler;
f3890b95 550 sigaction(SIGHUP, &action, NULL);
2bffb563 551
e5cf24b2 552 sigemptyset(&action.sa_mask);
2bffb563 553 action.sa_handler = SIG_IGN;
554 sigaction(SIGPIPE, &action, NULL);
a3e17a89 555
556 sigemptyset(&action.sa_mask);
557 sigaddset(&action.sa_mask, SIGTERM);
879062a9 558 sigaddset(&action.sa_mask, SIGCHLD);
a3e17a89 559 action.sa_handler = sigterm_handler;
560 sigaction(SIGTERM, &action, NULL);
e5cf24b2 561#else
bd58a948 562 signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
c3d37ff1 563 signal(SIGHUP, sighup_handler);
e5cf24b2 564 signal(SIGPIPE, SIG_IGN);
a3e17a89 565 signal(SIGTERM, sigterm_handler);
e5cf24b2 566#endif /* HAVE_SIGSET */
3840d6ba 567
cb9d2abc 568#ifdef __sgi
569 /*
570 * Try to create a fake lpsched lock file if one is not already there.
571 * Some Adobe applications need it under IRIX in order to enable
572 * printing...
573 */
574
7b0fde61 575 if ((fp = cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL)
cb9d2abc 576 {
577 syslog(LOG_LPR, "Unable to create fake lpsched lock file "
578 "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
579 strerror(errno));
580 }
581 else
582 {
7b0fde61 583 fchmod(cupsFileNumber(fp), 0644);
584 fchown(cupsFileNumber(fp), User, Group);
cb9d2abc 585
7b0fde61 586 cupsFileClose(fp);
cb9d2abc 587 }
588#endif /* __sgi */
589
1049abbe 590 /*
c802720f 591 * Initialize authentication certificates...
1049abbe 592 */
593
589eb420 594 cupsdInitCerts();
23bba0c3 595
c802720f 596 /*
5fe35f41 597 * If we are running in the background, signal the parent process that
598 * we are up and running...
c802720f 599 */
600
f0f71900 601 if (!fg || run_as_child)
c9ac4d3a 602 {
603 /*
604 * Send a signal to the parent process, but only if the parent is
605 * not PID 1 (init). This avoids accidentally shutting down the
606 * system on OpenBSD if you CTRL-C the server before it is up...
607 */
608
609 i = getppid(); /* Save parent PID to avoid race condition */
610
611 if (i != 1)
612 kill(i, SIGUSR1);
613 }
1049abbe 614
bd58a948 615#ifdef __APPLE__
6de33945 616 /*
617 * Start power management framework...
618 */
619
eb63d8a1 620 if (use_sysman)
621 cupsdStartSystemMonitor();
bd58a948 622#endif /* __APPLE__ */
25392f52 623
16c8c08e 624 /*
625 * Send server-started event...
626 */
627
628#ifdef HAVE_LAUNCHD
629 if (Launchd)
630 cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
631 "Scheduler started via launchd.");
632 else
633#endif /* HAVE_LAUNCHD */
634 if (fg)
635 cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
636 "Scheduler started in foreground.");
637 else
638 cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
639 "Scheduler started in background.");
640
598aeabc 641 /*
642 * Start any pending print jobs...
643 */
644
589eb420 645 cupsdCheckJobs();
598aeabc 646
3840d6ba 647 /*
648 * Loop forever...
649 */
650
728d3284 651 current_time = time(NULL);
728d3284 652 event_time = current_time;
653 expire_time = current_time;
045a79ad 654 fds = 1;
15da5ff1 655 report_time = 0;
728d3284 656 senddoc_time = current_time;
b6ea8f29 657
52a9a175 658 while (!stop_scheduler)
3840d6ba 659 {
2d417cb3 660 /*
661 * Check if there are dead children to handle...
662 */
663
664 if (dead_children)
665 process_children();
666
fd8b1cf8 667 /*
668 * Check if we need to load the server configuration file...
669 */
670
671 if (NeedReload)
672 {
a782f61f 673 /*
674 * Close any idle clients...
675 */
676
c7445b9f 677 if (cupsArrayCount(Clients) > 0)
fd8b1cf8 678 {
c7445b9f 679 for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
680 con;
681 con = (cupsd_client_t *)cupsArrayNext(Clients))
a74b005d 682 if (con->http.state == HTTP_WAITING)
589eb420 683 cupsdCloseClient(con);
fd8b1cf8 684 else
93894a43 685 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
fd8b1cf8 686
589eb420 687 cupsdPauseListening();
fd8b1cf8 688 }
a782f61f 689
a782f61f 690 /*
691 * Restart if all clients are closed and all jobs finished, or
bcd9e019 692 * if the reload timeout has elapsed...
a782f61f 693 */
694
c7445b9f 695 if ((cupsArrayCount(Clients) == 0 &&
f48ed6e4 696 (cupsArrayCount(PrintingJobs) == 0 || NeedReload != RELOAD_ALL)) ||
bcd9e019 697 (time(NULL) - ReloadTime) >= ReloadTimeout)
fd8b1cf8 698 {
5db6985b 699 /*
700 * Shutdown the server...
701 */
702
986bf7e8 703 DoingShutdown = 1;
704
5db6985b 705 cupsdStopServer();
706
707 /*
708 * Read configuration...
709 */
710
589eb420 711 if (!cupsdReadConfiguration())
a782f61f 712 {
713 syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
714 ConfigurationFile);
715 break;
716 }
5db6985b 717
718#if HAVE_LAUNCHD
dfeef8b5 719 if (Launchd)
5db6985b 720 {
f49512cc 721 /*
3d5f2a94 722 * If we were started by launchd, get the listen socket file
723 * descriptors...
f49512cc 724 */
725
5db6985b 726 launchd_checkin();
e5c929b9 727 launchd_checkout();
5db6985b 728 }
729#endif /* HAVE_LAUNCHD */
730
731 /*
732 * Startup the server...
733 */
734
986bf7e8 735 DoingShutdown = 0;
736
5db6985b 737 cupsdStartServer();
16c8c08e 738
739 /*
740 * Send a server-restarted event...
741 */
742
743 cupsdAddEvent(CUPSD_EVENT_SERVER_RESTARTED, NULL, NULL,
744 "Scheduler restarted.");
fd8b1cf8 745 }
746 }
747
3840d6ba 748 /*
9d4830a3 749 * Check for available input or ready output. If cupsdDoSelect()
750 * returns 0 or -1, something bad happened and we should exit
751 * immediately.
3840d6ba 752 *
42d48bd2 753 * Note that we at least have one listening socket open at all
3840d6ba 754 * times.
755 */
756
728d3284 757 if ((timeout = select_timeout(fds)) > 1 && LastEvent)
758 timeout = 1;
d9e72533 759
5db6985b 760#if HAVE_LAUNCHD
761 /*
762 * If no other work is scheduled and we're being controlled by
5d69c5d6 763 * launchd then timeout after 'LaunchdTimeout' seconds of
5db6985b 764 * inactivity...
765 */
766
33bd0142 767 if (timeout == 86400 && Launchd && LaunchdTimeout &&
3893fa0e 768 !cupsArrayCount(ActiveJobs) &&
33bd0142 769 (!Browsing || !BrowseLocalProtocols || !cupsArrayCount(Printers)))
5db6985b 770 {
686aff43 771 timeout = LaunchdTimeout;
5db6985b 772 launchd_idle_exit = 1;
773 }
774 else
775 launchd_idle_exit = 0;
776#endif /* HAVE_LAUNCHD */
777
9d4830a3 778 if ((fds = cupsdDoSelect(timeout)) < 0)
fd8b1cf8 779 {
886c59e2 780 /*
781 * Got an error from select!
782 */
783
2344229d 784#ifdef HAVE_DNSSD
785 cupsd_printer_t *p; /* Current printer */
786#endif /* HAVE_DNSSD */
787
788
789 if (errno == EINTR) /* Just interrupted by a signal */
fd8b1cf8 790 continue;
791
886c59e2 792 /*
d236cb49 793 * Log all sorts of debug info to help track down the problem.
886c59e2 794 */
795
9d4830a3 796 cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
f3e786fc 797 strerror(errno));
d236cb49 798
c7445b9f 799 for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
800 con;
801 i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
f3e786fc 802 cupsdLogMessage(CUPSD_LOG_EMERG,
803 "Clients[%d] = %d, file = %d, state = %d",
804 i, con->http.fd, con->file, con->http.state);
886c59e2 805
c7445b9f 806 for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
807 lis;
808 i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
f3e786fc 809 cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);
886c59e2 810
3dc8027b 811 cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);
812
6de33945 813#ifdef __APPLE__
814 cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
815 SysEventPipes[0]);
816#endif /* __APPLE__ */
817
589eb420 818 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
82306f04 819 job;
589eb420 820 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
f3e786fc 821 cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]",
822 job->id,
823 job->status_buffer ? job->status_buffer->fd : -1,
824 job->print_pipes[0], job->print_pipes[1],
825 job->back_pipes[0], job->back_pipes[1]);
2344229d 826
827#ifdef HAVE_DNSSD
828 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
829 p;
830 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ad9fc101 831 cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name,
832 p->reg_name ? p->reg_name : "(null)");
2344229d 833#endif /* HAVE_DNSSD */
834
3840d6ba 835 break;
fd8b1cf8 836 }
3840d6ba 837
150ba5b1 838 current_time = time(NULL);
839
5f8fccd6 840 /*
841 * Write dirty config/state files...
842 */
843
844 if (DirtyCleanTime && current_time >= DirtyCleanTime)
5f8fccd6 845 cupsdCleanDirty();
5f8fccd6 846
03cf93ef 847#ifdef __APPLE__
848 /*
849 * If we are going to sleep and still have pending jobs, stop them after
850 * a period of time...
851 */
852
853 if (SleepJobs > 0 && current_time >= SleepJobs &&
854 cupsArrayCount(PrintingJobs) > 0)
855 {
856 SleepJobs = 0;
22eaa49e 857 cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5);
03cf93ef 858 }
859#endif /* __APPLE__ */
860
fb8bf313 861#ifndef __APPLE__
862 /*
863 * Update the network interfaces once a minute...
864 */
865
866 if ((current_time - netif_time) >= 60)
867 {
868 netif_time = current_time;
869 NetIFUpdate = 1;
870 }
871#endif /* !__APPLE__ */
872
5db6985b 873#if HAVE_LAUNCHD
874 /*
5d69c5d6 875 * If no other work was scheduled and we're being controlled by launchd
5db6985b 876 * then timeout after 'LaunchdTimeout' seconds of inactivity...
877 */
878
879 if (!fds && launchd_idle_exit)
880 {
881 cupsdLogMessage(CUPSD_LOG_INFO,
882 "Printer sharing is off and there are no jobs pending, "
883 "will restart on demand.");
884 stop_scheduler = 1;
885 break;
886 }
887#endif /* HAVE_LAUNCHD */
888
deea78c9 889 /*
890 * Resume listening for new connections as needed...
891 */
892
893 if (ListeningPaused && ListeningPaused <= current_time &&
894 cupsArrayCount(Clients) < MaxClients)
895 cupsdResumeListening();
896
150ba5b1 897 /*
8daa67c7 898 * Expire subscriptions and unload completed jobs as needed...
150ba5b1 899 */
900
8daa67c7 901 if (current_time > expire_time)
150ba5b1 902 {
8daa67c7 903 if (cupsArrayCount(Subscriptions) > 0)
904 cupsdExpireSubscriptions(NULL, NULL);
905
906 cupsdUnloadCompletedJobs();
150ba5b1 907
908 expire_time = current_time;
909 }
910
eac663d2 911#ifndef HAVE_AUTHORIZATION_H
b8020256 912 /*
913 * Update the root certificate once every 5 minutes if we have client
914 * connections...
915 */
916
917 if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
918 !RunUser && cupsArrayCount(Clients))
919 {
920 /*
921 * Update the root certificate...
922 */
923
924 cupsdDeleteCert(0);
465abde2 925 cupsdAddCert(0, "root", NULL);
b8020256 926 }
eac663d2 927#endif /* !HAVE_AUTHORIZATION_H */
b8020256 928
ab22a3f1 929 /*
930 * Check for new data on the client sockets...
931 */
932
c7445b9f 933 for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
934 con;
935 con = (cupsd_client_t *)cupsArrayNext(Clients))
3840d6ba 936 {
3840d6ba 937 /*
9d4830a3 938 * Process pending data in the input buffer...
3840d6ba 939 */
940
9d4830a3 941 if (con->http.used)
ab652145 942 {
9d4830a3 943 cupsdReadClient(con);
944 continue;
1c9a0923 945 }
992cf15a 946
947 /*
fd8b1cf8 948 * Check the activity and close old clients...
992cf15a 949 */
950
150ba5b1 951 activity = current_time - Timeout;
df47c6ae 952 if (con->http.activity < activity && !con->pipe_pid)
992cf15a 953 {
f3e786fc 954 cupsdLogMessage(CUPSD_LOG_DEBUG,
955 "Closing client %d after %d seconds of inactivity...",
956 con->http.fd, Timeout);
de218675 957
589eb420 958 cupsdCloseClient(con);
992cf15a 959 continue;
960 }
3840d6ba 961 }
6abc7437 962
05ca02bc 963 /*
964 * Update any pending multi-file documents...
965 */
966
150ba5b1 967 if ((current_time - senddoc_time) >= 10)
05ca02bc 968 {
589eb420 969 cupsdCheckJobs();
150ba5b1 970 senddoc_time = current_time;
05ca02bc 971 }
972
b7772b03 973 /*
974 * Clean job history...
975 */
976
977 if (JobHistoryUpdate && current_time >= JobHistoryUpdate)
978 cupsdCleanJobs();
979
d2122fde 980 /*
15da5ff1 981 * Log statistics at most once a minute when in debug mode...
d2122fde 982 */
983
15da5ff1 984 if ((current_time - report_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
d2122fde 985 {
15da5ff1 986 size_t string_count, /* String count */
987 alloc_bytes, /* Allocated string bytes */
988 total_bytes; /* Total string bytes */
fc957d47 989#ifdef HAVE_MALLINFO
15da5ff1 990 struct mallinfo mem; /* Malloc information */
8c57ced1 991
992
8c57ced1 993 mem = mallinfo();
15da5ff1 994 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-arena=%lu", mem.arena);
995 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-used=%lu",
996 mem.usmblks + mem.uordblks);
997 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-free=%lu",
f3e786fc 998 mem.fsmblks + mem.fordblks);
fc957d47 999#endif /* HAVE_MALLINFO */
1000
15da5ff1 1001 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: clients=%d",
1002 cupsArrayCount(Clients));
1003 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs=%d",
1004 cupsArrayCount(Jobs));
1005 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs-active=%d",
1006 cupsArrayCount(ActiveJobs));
1007 cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d",
1008 cupsArrayCount(Printers));
15da5ff1 1009
a70992a9 1010 string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
15da5ff1 1011 cupsdLogMessage(CUPSD_LOG_DEBUG,
1012 "Report: stringpool-string-count=" CUPS_LLFMT,
1013 CUPS_LLCAST string_count);
1014 cupsdLogMessage(CUPSD_LOG_DEBUG,
1015 "Report: stringpool-alloc-bytes=" CUPS_LLFMT,
1016 CUPS_LLCAST alloc_bytes);
1017 cupsdLogMessage(CUPSD_LOG_DEBUG,
1018 "Report: stringpool-total-bytes=" CUPS_LLFMT,
fc957d47 1019 CUPS_LLCAST total_bytes);
1020
15da5ff1 1021 report_time = current_time;
2bdd1992 1022 }
8c57ced1 1023
beda8626 1024 /*
1025 * Handle OS-specific event notification for any events that have
1026 * accumulated. Don't send these more than once a second...
1027 */
1028
728d3284 1029 if (LastEvent && (current_time - event_time) >= 1)
beda8626 1030 {
1031#ifdef HAVE_NOTIFY_POST
0672fd21 1032 if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
1033 CUPSD_EVENT_PRINTER_DELETED |
1034 CUPSD_EVENT_PRINTER_MODIFIED))
beda8626 1035 {
960e5ba0 1036 cupsdLogMessage(CUPSD_LOG_DEBUG2,
beda8626 1037 "notify_post(\"com.apple.printerListChange\")");
1038 notify_post("com.apple.printerListChange");
1039 }
1040
1041 if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
1042 {
960e5ba0 1043 cupsdLogMessage(CUPSD_LOG_DEBUG2,
beda8626 1044 "notify_post(\"com.apple.printerHistoryChange\")");
1045 notify_post("com.apple.printerHistoryChange");
1046 }
1047
1048 if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
1049 CUPSD_EVENT_JOB_CONFIG_CHANGED |
1050 CUPSD_EVENT_JOB_PROGRESS))
1051 {
960e5ba0 1052 cupsdLogMessage(CUPSD_LOG_DEBUG2,
beda8626 1053 "notify_post(\"com.apple.jobChange\")");
1054 notify_post("com.apple.jobChange");
1055 }
1056#endif /* HAVE_NOTIFY_POST */
1057
1058 /*
7e826c4a 1059 * Reset the accumulated events...
beda8626 1060 */
1061
728d3284 1062 LastEvent = CUPSD_EVENT_NONE;
1063 event_time = current_time;
beda8626 1064 }
3840d6ba 1065 }
1066
1067 /*
52a9a175 1068 * Log a message based on what happened...
3840d6ba 1069 */
1070
52a9a175 1071 if (stop_scheduler)
16c8c08e 1072 {
f3e786fc 1073 cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally.");
16c8c08e 1074 cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
1075 "Scheduler shutting down normally.");
1076 }
52a9a175 1077 else
16c8c08e 1078 {
f3e786fc 1079 cupsdLogMessage(CUPSD_LOG_ERROR,
1080 "Scheduler shutting down due to program error.");
16c8c08e 1081 cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
1082 "Scheduler shutting down due to program error.");
1083 }
52a9a175 1084
1085 /*
825d723a 1086 * Close all network clients...
52a9a175 1087 */
1088
986bf7e8 1089 DoingShutdown = 1;
1090
589eb420 1091 cupsdStopServer();
52a9a175 1092
825d723a 1093#ifdef HAVE_LAUNCHD
1094 /*
1095 * Update the launchd KeepAlive file as needed...
1096 */
1097
1098 if (Launchd)
1099 launchd_checkout();
1100#endif /* HAVE_LAUNCHD */
1101
1102 /*
1103 * Stop all jobs...
1104 */
1105
d10c7a3d 1106 cupsdFreeAllJobs();
fd8b1cf8 1107
bd58a948 1108#ifdef __APPLE__
825d723a 1109 /*
1110 * Stop monitoring system event monitoring...
1111 */
1112
eb63d8a1 1113 if (use_sysman)
1114 cupsdStopSystemMonitor();
bd58a948 1115#endif /* __APPLE__ */
6de33945 1116
e89971c6 1117#ifdef HAVE_GSSAPI
825d723a 1118 /*
1119 * Free the scheduler's Kerberos context...
1120 */
1121
e89971c6 1122# ifdef __APPLE__
1123 /*
1124 * If the weak-linked GSSAPI/Kerberos library is not present, don't try
1125 * to use it...
1126 */
1127
1128 if (krb5_init_context != NULL)
1129# endif /* __APPLE__ */
7b8558ae 1130 if (KerberosContext)
1131 krb5_free_context(KerberosContext);
e89971c6 1132#endif /* HAVE_GSSAPI */
1133
52a9a175 1134#ifdef __sgi
1135 /*
1136 * Remove the fake IRIX lpsched lock file, but only if the existing
1137 * file is not a FIFO which indicates that the real IRIX lpsched is
1138 * running...
1139 */
1140
1141 if (!stat("/var/spool/lp/FIFO", &statbuf))
1142 if (!S_ISFIFO(statbuf.st_mode))
1143 unlink("/var/spool/lp/SCHEDLOCK");
1144#endif /* __sgi */
1145
9d4830a3 1146 cupsdStopSelect();
cf859e99 1147
52a9a175 1148 return (!stop_scheduler);
fd8b1cf8 1149}
3840d6ba 1150
3840d6ba 1151
96336986 1152/*
1153 * 'cupsdAddString()' - Copy and add a string to an array.
1154 */
1155
be589d75 1156int /* O - 1 on success, 0 on failure */
1157cupsdAddString(cups_array_t **a, /* IO - String array */
1158 const char *s) /* I - String to copy and add */
96336986 1159{
be589d75 1160 if (!*a)
1161 *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
1162 (cups_ahash_func_t)NULL, 0,
1163 (cups_acopy_func_t)_cupsStrAlloc,
1164 (cups_afree_func_t)_cupsStrFree);
1165
1166 return (cupsArrayAdd(*a, (char *)s));
96336986 1167}
1168
1169
ee0d93d7 1170/*
1171 * 'cupsdCheckProcess()' - Tell the main loop to check for dead children.
1172 */
1173
1174void
1175cupsdCheckProcess(void)
1176{
1177 /*
1178 * Flag that we have dead children...
1179 */
1180
1181 dead_children = 1;
1182}
1183
1184
96336986 1185/*
1186 * 'cupsdClearString()' - Clear a string.
1187 */
1188
1189void
1190cupsdClearString(char **s) /* O - String value */
1191{
1192 if (s && *s)
1193 {
1194 _cupsStrFree(*s);
1195 *s = NULL;
1196 }
1197}
1198
1199
96336986 1200/*
1201 * 'cupsdFreeStrings()' - Free an array of strings.
1202 */
1203
1204void
be589d75 1205cupsdFreeStrings(cups_array_t **a) /* IO - String array */
96336986 1206{
be589d75 1207 if (*a)
1208 {
1209 cupsArrayDelete(*a);
1210 *a = NULL;
1211 }
96336986 1212}
1213
1214
1215/*
1216 * 'cupsdHoldSignals()' - Hold child and termination signals.
1217 */
1218
1219void
1220cupsdHoldSignals(void)
1221{
1222#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1223 sigset_t newmask; /* New POSIX signal mask */
1224#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1225
1226
1227 holdcount ++;
1228 if (holdcount > 1)
1229 return;
1230
1231#ifdef HAVE_SIGSET
1232 sighold(SIGTERM);
1233 sighold(SIGCHLD);
1234#elif defined(HAVE_SIGACTION)
1235 sigemptyset(&newmask);
1236 sigaddset(&newmask, SIGTERM);
1237 sigaddset(&newmask, SIGCHLD);
1238 sigprocmask(SIG_BLOCK, &newmask, &holdmask);
1239#endif /* HAVE_SIGSET */
1240}
1241
1242
38743560 1243/*
589eb420 1244 * 'cupsdReleaseSignals()' - Release signals for delivery.
38743560 1245 */
1246
1247void
589eb420 1248cupsdReleaseSignals(void)
38743560 1249{
3d72d58a 1250 holdcount --;
1251 if (holdcount > 0)
1252 return;
1253
38743560 1254#ifdef HAVE_SIGSET
1255 sigrelse(SIGTERM);
1256 sigrelse(SIGCHLD);
1257#elif defined(HAVE_SIGACTION)
3d72d58a 1258 sigprocmask(SIG_SETMASK, &holdmask, NULL);
38743560 1259#endif /* HAVE_SIGSET */
1260}
1261
1262
36992080 1263/*
589eb420 1264 * 'cupsdSetString()' - Set a string value.
36992080 1265 */
1266
1267void
589eb420 1268cupsdSetString(char **s, /* O - New string */
f3e786fc 1269 const char *v) /* I - String value */
36992080 1270{
471f1564 1271 if (!s || *s == v)
36992080 1272 return;
1273
1274 if (*s)
51cd7375 1275 _cupsStrFree(*s);
36992080 1276
1277 if (v)
51cd7375 1278 *s = _cupsStrAlloc(v);
36992080 1279 else
1280 *s = NULL;
1281}
1282
1283
1284/*
589eb420 1285 * 'cupsdSetStringf()' - Set a formatted string value.
36992080 1286 */
1287
1288void
589eb420 1289cupsdSetStringf(char **s, /* O - New string */
f3e786fc 1290 const char *f, /* I - Printf-style format string */
1291 ...) /* I - Additional args as needed */
36992080 1292{
291355eb 1293 char v[4096]; /* Formatting string value */
36992080 1294 va_list ap; /* Argument pointer */
471f1564 1295 char *olds; /* Old string */
36992080 1296
1297
1298 if (!s)
1299 return;
1300
471f1564 1301 olds = *s;
36992080 1302
1303 if (f)
1304 {
1305 va_start(ap, f);
1306 vsnprintf(v, sizeof(v), f, ap);
1307 va_end(ap);
1308
51cd7375 1309 *s = _cupsStrAlloc(v);
36992080 1310 }
1311 else
1312 *s = NULL;
471f1564 1313
1314 if (olds)
51cd7375 1315 _cupsStrFree(olds);
36992080 1316}
1317
1318
5db6985b 1319#ifdef HAVE_LAUNCHD
1320/*
1321 * 'launchd_checkin()' - Check-in with launchd and collect the listening fds.
1322 */
1323
1324static void
1325launchd_checkin(void)
1326{
50bcef02 1327 size_t i, /* Looping var */
2256cc12 1328 count; /* Number of listeners */
5db6985b 1329 launch_data_t ld_msg, /* Launch data message */
1330 ld_resp, /* Launch data response */
1331 ld_array, /* Launch data array */
1332 ld_sockets, /* Launch data sockets dictionary */
5db6985b 1333 tmp; /* Launch data */
1334 cupsd_listener_t *lis; /* Listeners array */
1335 http_addr_t addr; /* Address variable */
1336 socklen_t addrlen; /* Length of address */
686aff43 1337 int fd; /* File descriptor */
1338 char s[256]; /* String addresss */
5db6985b 1339
1340
1341 cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: pid=%d", (int)getpid());
1342
1343 /*
1344 * Check-in with launchd...
1345 */
1346
1347 ld_msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
1348 if ((ld_resp = launch_msg(ld_msg)) == NULL)
1349 {
c7445b9f 1350 cupsdLogMessage(CUPSD_LOG_ERROR,
5db6985b 1351 "launchd_checkin: launch_msg(\"" LAUNCH_KEY_CHECKIN
1352 "\") IPC failure");
1353 exit(EXIT_FAILURE);
4f24c8fb 1354 return; /* anti-compiler-warning */
5db6985b 1355 }
c7445b9f 1356
5db6985b 1357 if (launch_data_get_type(ld_resp) == LAUNCH_DATA_ERRNO)
1358 {
1359 errno = launch_data_get_errno(ld_resp);
1360 cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_checkin: Check-in failed: %s",
1361 strerror(errno));
1362 exit(EXIT_FAILURE);
4f24c8fb 1363 return; /* anti-compiler-warning */
5db6985b 1364 }
1365
5db6985b 1366 /*
1367 * Get the sockets dictionary...
1368 */
1369
4f24c8fb 1370 if ((ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS))
1371 == NULL)
5db6985b 1372 {
1373 cupsdLogMessage(CUPSD_LOG_ERROR,
1374 "launchd_checkin: No sockets found to answer requests on!");
1375 exit(EXIT_FAILURE);
4f24c8fb 1376 return; /* anti-compiler-warning */
5db6985b 1377 }
c7445b9f 1378
5db6985b 1379 /*
1380 * Get the array of listener sockets...
1381 */
1382
4f24c8fb 1383 if ((ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")) == NULL)
5db6985b 1384 {
1385 cupsdLogMessage(CUPSD_LOG_ERROR,
1386 "launchd_checkin: No sockets found to answer requests on!");
1387 exit(EXIT_FAILURE);
4f24c8fb 1388 return; /* anti-compiler-warning */
5db6985b 1389 }
1390
1391 /*
1392 * Add listening fd(s) to the Listener array...
1393 */
1394
1395 if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
1396 {
686aff43 1397 count = launch_data_array_get_count(ld_array);
c7445b9f 1398
1399 for (i = 0; i < count; i ++)
5db6985b 1400 {
1401 /*
686aff43 1402 * Get the launchd file descriptor and address...
5db6985b 1403 */
c7445b9f 1404
4f24c8fb 1405 if ((tmp = launch_data_array_get_index(ld_array, i)) != NULL)
c7445b9f 1406 {
4f24c8fb 1407 fd = launch_data_get_fd(tmp);
1408 addrlen = sizeof(addr);
c7445b9f 1409
4f24c8fb 1410 if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
1411 {
1412 cupsdLogMessage(CUPSD_LOG_ERROR,
1413 "launchd_checkin: Unable to get local address - %s",
1414 strerror(errno));
1415 continue;
1416 }
c7445b9f 1417
4f24c8fb 1418 /*
1419 * Try to match the launchd socket address to one of the listeners...
1420 */
5db6985b 1421
4f24c8fb 1422 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1423 lis;
1424 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1425 if (httpAddrEqual(&lis->address, &addr))
1426 break;
686aff43 1427
4f24c8fb 1428 /*
1429 * Add a new listener If there's no match...
1430 */
686aff43 1431
4f24c8fb 1432 if (lis)
1433 {
f7923037 1434 cupsdLogMessage(CUPSD_LOG_DEBUG,
4f24c8fb 1435 "launchd_checkin: Matched existing listener %s with fd %d...",
1436 httpAddrString(&(lis->address), s, sizeof(s)), fd);
1437 }
1438 else
1439 {
f7923037 1440 cupsdLogMessage(CUPSD_LOG_DEBUG,
4f24c8fb 1441 "launchd_checkin: Adding new listener %s with fd %d...",
1442 httpAddrString(&addr, s, sizeof(s)), fd);
686aff43 1443
4f24c8fb 1444 if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
1445 {
1446 cupsdLogMessage(CUPSD_LOG_ERROR,
3d5f2a94 1447 "launchd_checkin: Unable to allocate listener - "
1448 "%s.", strerror(errno));
4f24c8fb 1449 exit(EXIT_FAILURE);
1450 }
686aff43 1451
4f24c8fb 1452 cupsArrayAdd(Listeners, lis);
c7445b9f 1453
4f24c8fb 1454 memcpy(&lis->address, &addr, sizeof(lis->address));
1455 }
1456
1457 lis->fd = fd;
686aff43 1458
5db6985b 1459# ifdef HAVE_SSL
f0aa54a1 1460 if (_httpAddrPort(&(lis->address)) == 443)
4f24c8fb 1461 lis->encryption = HTTP_ENCRYPT_ALWAYS;
5db6985b 1462# endif /* HAVE_SSL */
4f24c8fb 1463 }
5db6985b 1464 }
1465 }
1466
5db6985b 1467 launch_data_free(ld_msg);
1468 launch_data_free(ld_resp);
1469}
1470
1471
686aff43 1472/*
1473 * 'launchd_checkout()' - Update the launchd KeepAlive file as needed.
1474 */
1475
1476static void
1477launchd_checkout(void)
1478{
1479 int fd; /* File descriptor */
1480
1481
1482 /*
1483 * Create or remove the launchd KeepAlive file based on whether
f7923037 1484 * there are active jobs, polling, browsing for remote printers or
686aff43 1485 * shared printers to advertise...
1486 */
1487
33bd0142 1488 if (cupsArrayCount(ActiveJobs) ||
1489 (Browsing && BrowseLocalProtocols && cupsArrayCount(Printers)))
686aff43 1490 {
1491 cupsdLogMessage(CUPSD_LOG_DEBUG,
3d5f2a94 1492 "Creating launchd keepalive file \"" CUPS_KEEPALIVE
1493 "\"...");
686aff43 1494
1495 if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
1496 close(fd);
1497 }
1498 else
1499 {
1500 cupsdLogMessage(CUPSD_LOG_DEBUG,
3d5f2a94 1501 "Removing launchd keepalive file \"" CUPS_KEEPALIVE
1502 "\"...");
686aff43 1503
1504 unlink(CUPS_KEEPALIVE);
1505 }
1506}
5db6985b 1507#endif /* HAVE_LAUNCHD */
1508
1509
af57319f 1510/*
1511 * 'parent_handler()' - Catch USR1/CHLD signals...
1512 */
1513
1514static void
f3e786fc 1515parent_handler(int sig) /* I - Signal */
af57319f 1516{
1517 /*
1518 * Store the signal we got from the OS and return...
1519 */
1520
1521 parent_signal = sig;
1522}
1523
1524
6abc7437 1525/*
2d417cb3 1526 * 'process_children()' - Process all dead children...
6abc7437 1527 */
1528
1529static void
2d417cb3 1530process_children(void)
6abc7437 1531{
2b787e06 1532 int status; /* Exit status of child */
1533 int pid, /* Process ID of child */
1534 job_id; /* Job ID of child */
1535 cupsd_job_t *job; /* Current job */
1536 int i; /* Looping var */
1537 char name[1024]; /* Process name */
a0b638b8 1538 const char *type; /* Type of program */
6abc7437 1539
1540
f3e786fc 1541 cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");
25392f52 1542
daf8f5f0 1543 /*
2d417cb3 1544 * Reset the dead_children flag...
daf8f5f0 1545 */
1546
2d417cb3 1547 dead_children = 0;
daf8f5f0 1548
bdbaa675 1549 /*
2d417cb3 1550 * Collect the exit status of some children...
bdbaa675 1551 */
1552
e5cf24b2 1553#ifdef HAVE_WAITPID
1554 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
1555#elif defined(HAVE_WAIT3)
1556 while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
1557#else
1558 if ((pid = wait(&status)) > 0)
1559#endif /* HAVE_WAITPID */
1560 {
d2122fde 1561 /*
c452c19f 1562 * Collect the name of the process that finished...
d2122fde 1563 */
1564
ed88cacd 1565 cupsdFinishProcess(pid, name, sizeof(name), &job_id);
960e5ba0 1566
434ddc80 1567 /*
1568 * Delete certificates for CGI processes...
1569 */
1570
1571 if (pid)
589eb420 1572 cupsdDeleteCert(pid);
434ddc80 1573
1574 /*
6ffb1364 1575 * Handle completed job filters...
434ddc80 1576 */
e5b7bd9c 1577
0f63dc29 1578 if (job_id > 0)
1579 job = cupsdFindJob(job_id);
1580 else
a0b638b8 1581 job = NULL;
0f63dc29 1582
1583 if (job)
6ffb1364 1584 {
1585 for (i = 0; job->filters[i]; i ++)
1586 if (job->filters[i] == pid)
1587 break;
1588
1589 if (job->filters[i] || job->backend == pid)
6abc7437 1590 {
6ffb1364 1591 /*
1592 * OK, this process has gone away; what's left?
1593 */
6abc7437 1594
6ffb1364 1595 if (job->filters[i])
a0b638b8 1596 {
6ffb1364 1597 job->filters[i] = -pid;
a0b638b8 1598 type = "Filter";
1599 }
6ffb1364 1600 else
a0b638b8 1601 {
6ffb1364 1602 job->backend = -pid;
a0b638b8 1603 type = "Backend";
1604 }
6ffb1364 1605
2b787e06 1606 if (status && status != SIGTERM && status != SIGKILL &&
3d340348 1607 status != SIGPIPE)
bfa1abf0 1608 {
1609 /*
6ffb1364 1610 * An error occurred; save the exit status so we know to stop
1611 * the printer or cancel the job when all of the filters finish...
1612 *
1613 * A negative status indicates that the backend failed and the
1614 * printer needs to be stopped.
3d340348 1615 *
1616 * In order to preserve the most serious status, we always log
1617 * when a process dies due to a signal (e.g. SIGABRT, SIGSEGV,
1618 * and SIGBUS) and prefer to log the backend exit status over a
1619 * filter's.
bfa1abf0 1620 */
6abc7437 1621
3d340348 1622 int old_status = abs(job->status);
1623
1624 if (WIFSIGNALED(status) || /* This process crashed, or */
1625 !job->status || /* No process had a status, or */
1626 (!job->filters[i] && WIFEXITED(old_status)))
1627 { /* Backend and filter didn't crash */
1628 if (job->filters[i])
1629 job->status = status; /* Filter failed */
1630 else
1631 job->status = -status; /* Backend failed */
1632 }
6abc7437 1633
8bb56908 1634 if (job->state_value == IPP_JOB_PROCESSING &&
832f4e4b 1635 job->status_level > CUPSD_LOG_ERROR &&
1636 (job->filters[i] || !WIFEXITED(status)))
e5cf24b2 1637 {
9cc59cde 1638 char message[1024]; /* New printer-state-message */
1639
1640
6ffb1364 1641 job->status_level = CUPSD_LOG_ERROR;
e5cf24b2 1642
a0b638b8 1643 snprintf(message, sizeof(message), "%s failed", type);
9cc59cde 1644
a196504b 1645 if (job->printer)
1646 {
9cc59cde 1647 strlcpy(job->printer->state_message, message,
1648 sizeof(job->printer->state_message));
a196504b 1649 }
1650
1651 if (!job->attrs)
1652 cupsdLoadJob(job);
960e5ba0 1653
a196504b 1654 if (!job->printer_message && job->attrs)
960e5ba0 1655 {
ed88cacd 1656 if ((job->printer_message =
1657 ippFindAttribute(job->attrs, "job-printer-state-message",
1658 IPP_TAG_TEXT)) == NULL)
1659 job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
1660 IPP_TAG_TEXT,
6ffb1364 1661 "job-printer-state-message",
3d5f2a94 1662 NULL, NULL);
960e5ba0 1663 }
6ffb1364 1664
a196504b 1665 if (job->printer_message)
1666 cupsdSetString(&(job->printer_message->values[0].string.text),
9cc59cde 1667 message);
e5cf24b2 1668 }
6ffb1364 1669 }
017c50f3 1670
6ffb1364 1671 /*
1672 * If this is not the last file in a job, see if all of the
1673 * filters are done, and if so move to the next file.
1674 */
017c50f3 1675
3d5f2a94 1676 if (job->current_file < job->num_files && job->printer)
6ffb1364 1677 {
1678 for (i = 0; job->filters[i] < 0; i ++);
017c50f3 1679
a91b8845 1680 if (!job->filters[i] &&
1681 (!job->printer->pc || !job->printer->pc->single_file ||
1682 job->backend <= 0))
6ffb1364 1683 {
1684 /*
1685 * Process the next file...
1686 */
017c50f3 1687
24eb439d 1688 cupsdContinueJob(job);
017c50f3 1689 }
e5cf24b2 1690 }
3d5f2a94 1691 else if (job->state_value >= IPP_JOB_CANCELED)
a98a0f7b 1692 {
1693 /*
1694 * Remove the job from the active list if there are no processes still
1695 * running for it...
1696 */
1697
1698 for (i = 0; job->filters[i] < 0; i++);
1699
1700 if (!job->filters[i] && job->backend <= 0)
1701 cupsArrayRemove(ActiveJobs, job);
1702 }
6abc7437 1703 }
6ffb1364 1704 }
0309f5d9 1705
1706 /*
c452c19f 1707 * Show the exit status as needed, ignoring SIGTERM and SIGKILL errors
1708 * since they come when we kill/end a process...
0309f5d9 1709 */
1710
c452c19f 1711 if (status == SIGTERM || status == SIGKILL)
1712 {
0f63dc29 1713 cupsdLogJob(job, CUPSD_LOG_DEBUG,
1714 "PID %d (%s) was terminated normally with signal %d.", pid,
1715 name, status);
c452c19f 1716 }
661dac90 1717 else if (status == SIGPIPE)
1718 {
0f63dc29 1719 cupsdLogJob(job, CUPSD_LOG_DEBUG,
1720 "PID %d (%s) did not catch or ignore signal %d.", pid, name,
1721 status);
661dac90 1722 }
c452c19f 1723 else if (status)
0309f5d9 1724 {
1725 if (WIFEXITED(status))
b705bb00 1726 {
1727 int code = WEXITSTATUS(status); /* Exit code */
1728
1729 if (code > 100)
0f63dc29 1730 cupsdLogJob(job, CUPSD_LOG_DEBUG,
1731 "PID %d (%s) stopped with status %d (%s)", pid, name,
1732 code, strerror(code - 100));
b705bb00 1733 else
0f63dc29 1734 cupsdLogJob(job, CUPSD_LOG_DEBUG,
1735 "PID %d (%s) stopped with status %d.", pid, name, code);
b705bb00 1736 }
0309f5d9 1737 else
a0b638b8 1738 cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) crashed on signal %d.",
0f63dc29 1739 pid, name, WTERMSIG(status));
0309f5d9 1740
1741 if (LogLevel < CUPSD_LOG_DEBUG)
0f63dc29 1742 cupsdLogJob(job, CUPSD_LOG_INFO,
6839bf4e 1743 "Hint: Try setting the LogLevel to \"debug\" to find out "
0f63dc29 1744 "more.");
0309f5d9 1745 }
1746 else
0f63dc29 1747 cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
1748 pid, name);
e5cf24b2 1749 }
8bd13c30 1750
1751 /*
1752 * If wait*() is interrupted by a signal, tell main() to call us again...
1753 */
1754
1755 if (pid < 0 && errno == EINTR)
1756 dead_children = 1;
2d417cb3 1757}
1758
1759
045a79ad 1760/*
1761 * 'select_timeout()' - Calculate the select timeout value.
1762 *
1763 */
1764
1765static long /* O - Number of seconds */
c7445b9f 1766select_timeout(int fds) /* I - Number of descriptors returned */
045a79ad 1767{
045a79ad 1768 long timeout; /* Timeout for select */
1769 time_t now; /* Current time */
f3e786fc 1770 cupsd_client_t *con; /* Client information */
f3e786fc 1771 cupsd_job_t *job; /* Job information */
150ba5b1 1772 cupsd_subscription_t *sub; /* Subscription information */
045a79ad 1773 const char *why; /* Debugging aid */
1774
1775
670c9558 1776 cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: JobHistoryUpdate=%ld",
1777 (long)JobHistoryUpdate);
1778
045a79ad 1779 /*
1780 * Check to see if any of the clients have pending data to be
1781 * processed; if so, the timeout should be 0...
1782 */
1783
c7445b9f 1784 for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1785 con;
1786 con = (cupsd_client_t *)cupsArrayNext(Clients))
045a79ad 1787 if (con->http.used > 0)
1788 return (0);
1789
1790 /*
2115cd41 1791 * If select has been active in the last second (fds > 0) or we have
045a79ad 1792 * many resources in use then don't bother trying to optimize the
1793 * timeout, just make it 1 second.
1794 */
1795
2115cd41 1796 if (fds > 0 || cupsArrayCount(Clients) > 50)
045a79ad 1797 return (1);
1798
1799 /*
1800 * Otherwise, check all of the possible events that we need to wake for...
1801 */
1802
1803 now = time(NULL);
bcd9e019 1804 timeout = now + 86400; /* 86400 == 1 day */
045a79ad 1805 why = "do nothing";
1806
0010c38c 1807#ifdef __APPLE__
1808 /*
1809 * When going to sleep, wake up to cancel jobs that don't complete in time.
1810 */
1811
1812 if (SleepJobs > 0 && SleepJobs < timeout)
1813 {
1814 timeout = SleepJobs;
1815 why = "cancel jobs before sleeping";
1816 }
1817#endif /* __APPLE__ */
1818
deea78c9 1819 /*
1820 * Check whether we are accepting new connections...
1821 */
1822
1823 if (ListeningPaused > 0 && cupsArrayCount(Clients) < MaxClients &&
1824 ListeningPaused < timeout)
1825 {
1826 if (ListeningPaused <= now)
1827 timeout = now;
1828 else
1829 timeout = ListeningPaused;
1830
1831 why = "resume listening";
1832 }
1833
045a79ad 1834 /*
1835 * Check the activity and close old clients...
1836 */
1837
c7445b9f 1838 for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1839 con;
1840 con = (cupsd_client_t *)cupsArrayNext(Clients))
045a79ad 1841 if ((con->http.activity + Timeout) < timeout)
1842 {
1843 timeout = con->http.activity + Timeout;
1844 why = "timeout a client connection";
1845 }
1846
5f8fccd6 1847 /*
ec6fa4d8 1848 * Write out changes to configuration and state files...
5f8fccd6 1849 */
1850
1851 if (DirtyCleanTime && timeout > DirtyCleanTime)
1852 {
1853 timeout = DirtyCleanTime;
1854 why = "write dirty config/state files";
1855 }
1856
045a79ad 1857 /*
b7772b03 1858 * Check for any job activity...
045a79ad 1859 */
1860
b7772b03 1861 if (JobHistoryUpdate && timeout > JobHistoryUpdate)
1862 {
1863 timeout = JobHistoryUpdate;
1864 why = "update job history";
1865 }
1866
15ea9b70 1867 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
1868 job;
1869 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
045a79ad 1870 {
b7772b03 1871 if (job->cancel_time && job->cancel_time < timeout)
1872 {
1873 timeout = job->cancel_time;
1874 why = "cancel stuck jobs";
1875 }
1876
15ea9b70 1877 if (job->kill_time && job->kill_time < timeout)
1878 {
1879 timeout = job->kill_time;
1880 why = "kill unresponsive jobs";
1881 }
b7772b03 1882
1883 if (job->state_value == IPP_JOB_HELD && job->hold_until < timeout)
15ea9b70 1884 {
1885 timeout = job->hold_until;
1886 why = "release held jobs";
1887 }
b7772b03 1888
1889 if (job->state_value == IPP_JOB_PENDING && timeout > (now + 10))
15ea9b70 1890 {
1891 timeout = now + 10;
1892 why = "start pending jobs";
1893 break;
1894 }
045a79ad 1895 }
1896
1897#ifdef HAVE_MALLINFO
1898 /*
1899 * Log memory usage every minute...
1900 */
1901
f3e786fc 1902 if (LogLevel >= CUPSD_LOG_DEBUG && (mallinfo_time + 60) < timeout)
045a79ad 1903 {
1904 timeout = mallinfo_time + 60;
1905 why = "display memory usage";
1906 }
1907#endif /* HAVE_MALLINFO */
1908
150ba5b1 1909 /*
1910 * Expire subscriptions as needed...
1911 */
1912
c8b08d30 1913 for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
1914 sub;
1915 sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
9a47fdb1 1916 if (!sub->job && sub->expire && sub->expire < timeout)
150ba5b1 1917 {
1918 timeout = sub->expire;
1919 why = "expire subscription";
1920 }
150ba5b1 1921
045a79ad 1922 /*
02b750db 1923 * Adjust from absolute to relative time. We add 1 second to the timeout since
1924 * events occur after the timeout expires, and limit the timeout to 86400
1925 * seconds (1 day) to avoid select() timeout limits present on some operating
9214a473 1926 * systems...
045a79ad 1927 */
1928
bcd9e019 1929 timeout = timeout - now + 1;
045a79ad 1930
bcd9e019 1931 if (timeout < 1)
1932 timeout = 1;
9214a473 1933 else if (timeout > 86400)
1934 timeout = 86400;
045a79ad 1935
1936 /*
1937 * Log and return the timeout value...
1938 */
1939
2115cd41 1940 cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout(%d): %ld seconds to %s",
1941 fds, timeout, why);
045a79ad 1942
1943 return (timeout);
1944}
1945
1946
0010c38c 1947/*
1948 * 'sigchld_handler()' - Handle 'child' signals from old processes.
1949 */
1950
1951static void
1952sigchld_handler(int sig) /* I - Signal number */
1953{
1954 (void)sig;
1955
1956 /*
1957 * Flag that we have dead children...
1958 */
1959
1960 dead_children = 1;
1961
1962 /*
1963 * Reset the signal handler as needed...
1964 */
1965
1966#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1967 signal(SIGCLD, sigchld_handler);
1968#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1969}
1970
1971
1972/*
1973 * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
1974 */
1975
1976static void
1977sighup_handler(int sig) /* I - Signal number */
1978{
1979 (void)sig;
1980
1981 NeedReload = RELOAD_ALL;
1982 ReloadTime = time(NULL);
1983
1984#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1985 signal(SIGHUP, sighup_handler);
1986#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1987}
1988
1989
1990/*
1991 * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
1992 */
1993
1994static void
1995sigterm_handler(int sig) /* I - Signal number */
1996{
1997 (void)sig; /* remove compiler warnings... */
1998
1999 /*
2000 * Flag that we should stop and return...
2001 */
2002
2003 stop_scheduler = 1;
2004}
2005
2006
fd8b1cf8 2007/*
2008 * 'usage()' - Show scheduler usage.
2009 */
2010
2011static void
00a1fad8 2012usage(int status) /* O - Exit status */
fd8b1cf8 2013{
4c4eea89 2014 FILE *fp = status ? stderr : stdout; /* Output file */
2015
2016
2017 _cupsLangPuts(fp, _("Usage: cupsd [options]"));
2018 _cupsLangPuts(fp, _("Options:"));
d326343a 2019 _cupsLangPuts(fp, _(" -c cupsd.conf Set cupsd.conf file to use."));
9721cf74 2020 _cupsLangPuts(fp, _(" -f Run in the foreground."));
2021 _cupsLangPuts(fp, _(" -F Run in the foreground but "
2022 "detach from console."));
2023 _cupsLangPuts(fp, _(" -h Show this usage message."));
2024 _cupsLangPuts(fp, _(" -l Run cupsd from launchd(8)."));
2025 _cupsLangPuts(fp, _(" -t Test the configuration "
4c4eea89 2026 "file."));
4c4eea89 2027
00a1fad8 2028 exit(status);
fd8b1cf8 2029}
2030
2031
3840d6ba 2032/*
b2e10895 2033 * End of "$Id$".
3840d6ba 2034 */