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