]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/main.c
4 * Scheduler main loop for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Main entry for the CUPS scheduler.
27 * cupsdClosePipe() - Close a pipe as necessary.
28 * cupsdOpenPipe() - Create a pipe which is closed on exec.
29 * cupsdCatchChildSignals() - Catch SIGCHLD signals...
30 * cupsdHoldSignals() - Hold child and termination signals.
31 * cupsdIgnoreChildSignals() - Ignore SIGCHLD signals...
32 * cupsdReleaseSignals() - Release signals for delivery.
33 * cupsdSetString() - Set a string value.
34 * cupsdSetStringf() - Set a formatted string value.
35 * parent_handler() - Catch USR1/CHLD signals...
36 * process_children() - Process all dead children...
37 * sigchld_handler() - Handle 'child' signals from old processes.
38 * sighup_handler() - Handle 'hangup' signals to reconfigure the scheduler.
39 * sigterm_handler() - Handle 'terminate' signals that stop the scheduler.
40 * select_timeout() - Calculate the select timeout value.
41 * usage() - Show scheduler usage.
45 * Include necessary headers...
50 #include <sys/resource.h>
54 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
56 #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
63 static void parent_handler(int sig
);
64 static void process_children(void);
65 static void sigchld_handler(int sig
);
66 static void sighup_handler(int sig
);
67 static void sigterm_handler(int sig
);
68 static long select_timeout(int fds
);
69 static void usage(void);
76 static int parent_signal
= 0; /* Set to signal number from child */
77 static int holdcount
= 0; /* Number of times "hold" was called */
78 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
79 static sigset_t holdmask
; /* Old POSIX signal mask */
80 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
81 static int dead_children
= 0; /* Dead children? */
82 static int stop_scheduler
= 0; /* Should the scheduler stop? */
86 * 'main()' - Main entry for the CUPS scheduler.
89 int /* O - Exit status */
90 main(int argc
, /* I - Number of command-line arguments */
91 char *argv
[]) /* I - Command-line arguments */
93 int i
; /* Looping var */
94 char *opt
; /* Option character */
95 int fg
; /* Run in the foreground */
96 int fds
; /* Number of ready descriptors select returns */
97 fd_set
*input
, /* Input set for select() */
98 *output
; /* Output set for select() */
99 cupsd_client_t
*con
; /* Current client */
100 cupsd_job_t
*job
; /* Current job */
101 cupsd_listener_t
*lis
; /* Current listener */
102 time_t activity
; /* Activity timer */
103 time_t browse_time
; /* Next browse send time */
104 time_t senddoc_time
; /* Send-Document time */
106 time_t mallinfo_time
; /* Malloc information time */
107 #endif /* HAVE_MALLINFO */
108 struct timeval timeout
; /* select() timeout */
109 struct rlimit limit
; /* Runtime limit */
110 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
111 struct sigaction action
; /* Actions for POSIX signals */
112 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
114 cups_file_t
*fp
; /* Fake lpsched lock file */
115 struct stat statbuf
; /* Needed for checking lpsched FIFO */
120 * Check for command-line arguments...
125 for (i
= 1; i
< argc
; i
++)
126 if (argv
[i
][0] == '-')
127 for (opt
= argv
[i
] + 1; *opt
!= '\0'; opt
++)
130 case 'c' : /* Configuration file */
135 if (argv
[i
][0] == '/')
138 * Absolute directory...
141 cupsdSetString(&ConfigurationFile
, argv
[i
]);
146 * Relative directory...
149 char current
[1024]; /* Current directory */
152 getcwd(current
, sizeof(current
));
153 cupsdSetStringf(&ConfigurationFile
, "%s/%s", current
, argv
[i
]);
157 case 'f' : /* Run in foreground... */
161 case 'F' : /* Run in foreground, but still disconnect from terminal... */
165 default : /* Unknown option */
166 fprintf(stderr
, "cupsd: Unknown option \'%c\' - aborting!\n", *opt
);
172 fprintf(stderr
, "cupsd: Unknown argument \'%s\' - aborting!\n", argv
[i
]);
176 if (!ConfigurationFile
)
177 cupsdSetString(&ConfigurationFile
, CUPS_SERVERROOT
"/cupsd.conf");
180 * If the user hasn't specified "-f", run in the background...
186 * Setup signal handlers for the parent...
189 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
190 sigset(SIGUSR1
, parent_handler
);
191 sigset(SIGCHLD
, parent_handler
);
193 sigset(SIGHUP
, SIG_IGN
);
194 #elif defined(HAVE_SIGACTION)
195 memset(&action
, 0, sizeof(action
));
196 sigemptyset(&action
.sa_mask
);
197 sigaddset(&action
.sa_mask
, SIGUSR1
);
198 action
.sa_handler
= parent_handler
;
199 sigaction(SIGUSR1
, &action
, NULL
);
200 sigaction(SIGCHLD
, &action
, NULL
);
202 sigemptyset(&action
.sa_mask
);
203 action
.sa_handler
= SIG_IGN
;
204 sigaction(SIGHUP
, &action
, NULL
);
206 signal(SIGUSR1
, parent_handler
);
207 signal(SIGCLD
, parent_handler
);
209 signal(SIGHUP
, SIG_IGN
);
210 #endif /* HAVE_SIGSET */
215 * OK, wait for the child to startup and send us SIGUSR1 or to crash
216 * and the OS send us SIGCHLD... We also need to ignore SIGHUP which
217 * might be sent by the init script to restart the scheduler...
220 for (; parent_signal
== 0;)
223 if (parent_signal
== SIGUSR1
)
231 else if (WIFEXITED(i
))
233 fprintf(stderr
, "cupsd: Child exited with status %d!\n", WEXITSTATUS(i
));
238 fprintf(stderr
, "cupsd: Child exited on signal %d!\n", WTERMSIG(i
));
247 * Make sure we aren't tying up any filesystems...
254 * Disable core dumps...
257 getrlimit(RLIMIT_CORE
, &limit
);
259 setrlimit(RLIMIT_CORE
, &limit
);
262 * Disconnect from the controlling terminal...
268 * Close all open files...
271 getrlimit(RLIMIT_NOFILE
, &limit
);
273 for (i
= 0; i
< limit
.rlim_cur
; i
++)
279 * Set the timezone info...
285 setlocale(LC_TIME
, "");
289 * Set the maximum number of files...
292 getrlimit(RLIMIT_NOFILE
, &limit
);
294 if (limit
.rlim_max
> CUPS_MAX_FDS
)
295 MaxFDs
= CUPS_MAX_FDS
;
297 MaxFDs
= limit
.rlim_max
;
299 limit
.rlim_cur
= MaxFDs
;
301 setrlimit(RLIMIT_NOFILE
, &limit
);
304 * Allocate memory for the input and output sets...
307 SetSize
= (MaxFDs
+ 31) / 8 + 4;
308 if (SetSize
< sizeof(fd_set
))
309 SetSize
= sizeof(fd_set
);
311 InputSet
= (fd_set
*)calloc(1, SetSize
);
312 OutputSet
= (fd_set
*)calloc(1, SetSize
);
313 input
= (fd_set
*)calloc(1, SetSize
);
314 output
= (fd_set
*)calloc(1, SetSize
);
316 if (InputSet
== NULL
|| OutputSet
== NULL
|| input
== NULL
|| output
== NULL
)
318 syslog(LOG_LPR
, "Unable to allocate memory for select() sets - exiting!");
323 * Read configuration...
326 if (!cupsdReadConfiguration())
328 syslog(LOG_LPR
, "Unable to read configuration file \'%s\' - exiting!",
334 * Catch hangup and child signals and ignore broken pipes...
337 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
339 sigset(SIGHUP
, sigterm_handler
);
341 sigset(SIGHUP
, sighup_handler
);
343 sigset(SIGPIPE
, SIG_IGN
);
344 sigset(SIGTERM
, sigterm_handler
);
345 #elif defined(HAVE_SIGACTION)
346 memset(&action
, 0, sizeof(action
));
348 sigemptyset(&action
.sa_mask
);
349 sigaddset(&action
.sa_mask
, SIGHUP
);
352 action
.sa_handler
= sigterm_handler
;
354 action
.sa_handler
= sighup_handler
;
356 sigaction(SIGHUP
, &action
, NULL
);
358 sigemptyset(&action
.sa_mask
);
359 action
.sa_handler
= SIG_IGN
;
360 sigaction(SIGPIPE
, &action
, NULL
);
362 sigemptyset(&action
.sa_mask
);
363 sigaddset(&action
.sa_mask
, SIGTERM
);
364 sigaddset(&action
.sa_mask
, SIGCHLD
);
365 action
.sa_handler
= sigterm_handler
;
366 sigaction(SIGTERM
, &action
, NULL
);
369 signal(SIGHUP
, sigterm_handler
);
371 signal(SIGHUP
, sighup_handler
);
373 signal(SIGPIPE
, SIG_IGN
);
374 signal(SIGTERM
, sigterm_handler
);
375 #endif /* HAVE_SIGSET */
379 * Try to create a fake lpsched lock file if one is not already there.
380 * Some Adobe applications need it under IRIX in order to enable
384 if ((fp
= cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL
)
386 syslog(LOG_LPR
, "Unable to create fake lpsched lock file "
387 "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
392 fchmod(cupsFileNumber(fp
), 0644);
393 fchown(cupsFileNumber(fp
), User
, Group
);
400 * Initialize authentication certificates...
406 * If we are running in the background, signal the parent process that
407 * we are up and running...
413 * Send a signal to the parent process, but only if the parent is
414 * not PID 1 (init). This avoids accidentally shutting down the
415 * system on OpenBSD if you CTRL-C the server before it is up...
418 i
= getppid(); /* Save parent PID to avoid race condition */
425 * If the administrator has configured the server to run as an unpriviledged
426 * user, change to that user now...
432 setgroups(1, &Group
);
440 cupsdCatchChildSignals();
443 * Start any pending print jobs...
454 #endif /* HAVE_MALLINFO */
455 browse_time
= time(NULL
);
456 senddoc_time
= time(NULL
);
459 while (!stop_scheduler
)
462 cupsdLogMessage(L_DEBUG2
, "main: Top of loop, dead_children=%d, NeedReload=%d",
463 dead_children
, NeedReload
);
467 * Check if there are dead children to handle...
474 * Check if we need to load the server configuration file...
480 * Close any idle clients...
485 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
486 if (con
->http
.state
== HTTP_WAITING
)
488 cupsdCloseClient(con
);
492 con
->http
.keep_alive
= HTTP_KEEPALIVE_OFF
;
494 cupsdPauseListening();
498 * Check for any active jobs...
501 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
503 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
504 if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
508 * Restart if all clients are closed and all jobs finished, or
509 * if the reload timeout has elapsed...
512 if ((NumClients
== 0 && (!job
|| NeedReload
!= RELOAD_ALL
)) ||
513 (time(NULL
) - ReloadTime
) >= ReloadTimeout
)
515 if (!cupsdReadConfiguration())
517 syslog(LOG_LPR
, "Unable to read configuration file \'%s\' - exiting!",
525 * Check for available input or ready output. If select() returns
526 * 0 or -1, something bad happened and we should exit immediately.
528 * Note that we at least have one listening socket open at all
532 memcpy(input
, InputSet
, SetSize
);
533 memcpy(output
, OutputSet
, SetSize
);
535 timeout
.tv_sec
= select_timeout(fds
);
538 if ((fds
= select(MaxFDs
, input
, output
, NULL
, &timeout
)) < 0)
540 char s
[16384], /* String buffer */
541 *sptr
; /* Pointer into buffer */
542 int slen
; /* Length of string buffer */
546 * Got an error from select!
549 if (errno
== EINTR
) /* Just interrupted by a signal */
553 * Log all sorts of debug info to help track down the problem.
556 cupsdLogMessage(L_EMERG
, "select() failed - %s!", strerror(errno
));
558 strcpy(s
, "InputSet =");
562 for (i
= 0; i
< MaxFDs
; i
++)
563 if (FD_ISSET(i
, InputSet
))
565 snprintf(sptr
, sizeof(s
) - slen
, " %d", i
);
566 slen
+= strlen(sptr
);
567 sptr
+= strlen(sptr
);
570 cupsdLogMessage(L_EMERG
, s
);
572 strcpy(s
, "OutputSet =");
576 for (i
= 0; i
< MaxFDs
; i
++)
577 if (FD_ISSET(i
, OutputSet
))
579 snprintf(sptr
, sizeof(s
) - slen
, " %d", i
);
580 slen
+= strlen(sptr
);
581 sptr
+= strlen(sptr
);
584 cupsdLogMessage(L_EMERG
, s
);
586 for (i
= 0, con
= Clients
; i
< NumClients
; i
++, con
++)
587 cupsdLogMessage(L_EMERG
, "Clients[%d] = %d, file = %d, state = %d",
588 i
, con
->http
.fd
, con
->file
, con
->http
.state
);
590 for (i
= 0, lis
= Listeners
; i
< NumListeners
; i
++, lis
++)
591 cupsdLogMessage(L_EMERG
, "Listeners[%d] = %d", i
, lis
->fd
);
593 cupsdLogMessage(L_EMERG
, "BrowseSocket = %d", BrowseSocket
);
595 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
597 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
598 cupsdLogMessage(L_EMERG
, "Jobs[%d] = %d < [%d %d] > [%d %d]",
599 job
->id
, job
->status_buffer
? job
->status_buffer
->fd
: -1,
600 job
->print_pipes
[0], job
->print_pipes
[1],
601 job
->back_pipes
[0], job
->back_pipes
[1]);
606 * Check for status info from job filters...
609 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
611 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
612 if (job
->status_buffer
&& FD_ISSET(job
->status_buffer
->fd
, input
))
615 * Clear the input bit to avoid updating the next job
616 * using the same status pipe file descriptor...
619 FD_CLR(job
->status_buffer
->fd
, input
);
622 * Read any status messages from the filters...
629 * Update CGI messages as needed...
632 if (CGIPipes
[0] >= 0 && FD_ISSET(CGIPipes
[0], input
))
636 * Update the browse list as needed...
639 if (Browsing
&& (BrowseLocalProtocols
| BrowseRemoteProtocols
))
641 if (BrowseSocket
>= 0 && FD_ISSET(BrowseSocket
, input
))
642 cupsdUpdateCUPSBrowse();
644 if (PollPipe
>= 0 && FD_ISSET(PollPipe
, input
))
645 cupsdUpdatePolling();
648 if (((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_SLP
) &&
649 BrowseSLPRefresh
<= time(NULL
))
650 cupsdUpdateSLPBrowse();
651 #endif /* HAVE_LIBSLP */
653 if (time(NULL
) > browse_time
)
655 cupsdSendBrowseList();
656 browse_time
= time(NULL
);
661 * Check for new connections on the "listen" sockets...
664 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
665 if (FD_ISSET(lis
->fd
, input
))
667 FD_CLR(lis
->fd
, input
);
668 cupsdAcceptClient(lis
);
672 * Check for new data on the client sockets...
675 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
678 * Process the input buffer...
681 if (FD_ISSET(con
->http
.fd
, input
) || con
->http
.used
)
683 FD_CLR(con
->http
.fd
, input
);
685 if (!cupsdReadClient(con
))
688 FD_CLR(con
->file
, input
);
696 * Write data as needed...
699 if (con
->pipe_pid
&& FD_ISSET(con
->file
, input
))
702 * Keep track of pending input from the file/pipe separately
703 * so that we don't needlessly spin on select() when the web
704 * client is not ready to receive data...
707 FD_CLR(con
->file
, input
);
711 cupsdLogMessage(L_DEBUG2
, "main: Data ready file %d!", con
->file
);
714 if (!FD_ISSET(con
->http
.fd
, output
))
716 cupsdLogMessage(L_DEBUG2
, "main: Removing fd %d from InputSet...", con
->file
);
717 FD_CLR(con
->file
, InputSet
);
721 if (FD_ISSET(con
->http
.fd
, output
))
723 FD_CLR(con
->http
.fd
, output
);
725 if (!con
->pipe_pid
|| con
->file_ready
)
726 if (!cupsdWriteClient(con
))
734 * Check the activity and close old clients...
737 activity
= time(NULL
) - Timeout
;
738 if (con
->http
.activity
< activity
&& !con
->pipe_pid
)
740 cupsdLogMessage(L_DEBUG
, "Closing client %d after %d seconds of inactivity...",
741 con
->http
.fd
, Timeout
);
743 cupsdCloseClient(con
);
750 * Update any pending multi-file documents...
753 if ((time(NULL
) - senddoc_time
) >= 10)
756 senddoc_time
= time(NULL
);
761 * Log memory usage every minute...
764 if ((time(NULL
) - mallinfo_time
) >= 60 && LogLevel
>= L_DEBUG
)
766 struct mallinfo mem
; /* Malloc information */
770 cupsdLogMessage(L_DEBUG
, "mallinfo: arena = %d, used = %d, free = %d\n",
771 mem
.arena
, mem
.usmblks
+ mem
.uordblks
,
772 mem
.fsmblks
+ mem
.fordblks
);
773 mallinfo_time
= time(NULL
);
775 #endif /* HAVE_MALLINFO */
778 * Update the root certificate once every 5 minutes...
781 if ((time(NULL
) - RootCertTime
) >= RootCertDuration
&& RootCertDuration
&&
785 * Update the root certificate...
789 cupsdAddCert(0, "root");
794 * Log a message based on what happened...
798 cupsdLogMessage(L_INFO
, "Scheduler shutting down normally.");
800 cupsdLogMessage(L_ERROR
, "Scheduler shutting down due to program error.");
803 * Close all network clients and stop all jobs...
812 * Remove the fake IRIX lpsched lock file, but only if the existing
813 * file is not a FIFO which indicates that the real IRIX lpsched is
817 if (!stat("/var/spool/lp/FIFO", &statbuf
))
818 if (!S_ISFIFO(statbuf
.st_mode
))
819 unlink("/var/spool/lp/SCHEDLOCK");
823 * Free memory used by FD sets and return...
831 return (!stop_scheduler
);
836 * 'cupsdClosePipe()' - Close a pipe as necessary.
840 cupsdClosePipe(int *fds
) /* I - Pipe file descriptors (2) */
843 * Close file descriptors as needed...
861 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
864 int /* O - 0 on success, -1 on error */
865 cupsdOpenPipe(int *fds
) /* O - Pipe file descriptors (2) */
875 * Set the "close on exec" flag on each end of the pipe...
878 if (fcntl(fds
[0], F_SETFD
, fcntl(fds
[0], F_GETFD
) | FD_CLOEXEC
))
885 if (fcntl(fds
[1], F_SETFD
, fcntl(fds
[1], F_GETFD
) | FD_CLOEXEC
))
893 * Return 0 indicating success...
901 * 'cupsdCatchChildSignals()' - Catch SIGCHLD signals...
905 cupsdCatchChildSignals(void)
907 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
908 struct sigaction action
; /* Actions for POSIX signals */
909 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
912 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
913 sigset(SIGCHLD
, sigchld_handler
);
914 #elif defined(HAVE_SIGACTION)
915 memset(&action
, 0, sizeof(action
));
917 sigemptyset(&action
.sa_mask
);
918 sigaddset(&action
.sa_mask
, SIGTERM
);
919 sigaddset(&action
.sa_mask
, SIGCHLD
);
920 action
.sa_handler
= sigchld_handler
;
921 sigaction(SIGCHLD
, &action
, NULL
);
923 signal(SIGCLD
, sigchld_handler
); /* No, SIGCLD isn't a typo... */
924 #endif /* HAVE_SIGSET */
929 * 'cupsdClearString()' - Clear a string.
933 cupsdClearString(char **s
) /* O - String value */
944 * 'cupsdHoldSignals()' - Hold child and termination signals.
948 cupsdHoldSignals(void)
950 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
951 sigset_t newmask
; /* New POSIX signal mask */
952 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
962 #elif defined(HAVE_SIGACTION)
963 sigemptyset(&newmask
);
964 sigaddset(&newmask
, SIGTERM
);
965 sigaddset(&newmask
, SIGCHLD
);
966 sigprocmask(SIG_BLOCK
, &newmask
, &holdmask
);
967 #endif /* HAVE_SIGSET */
972 * 'cupsdIgnoreChildSignals()' - Ignore SIGCHLD signals...
974 * We don't really ignore them, we set the signal handler to SIG_DFL,
975 * since some OS's rely on signals for the wait4() function to work.
979 cupsdIgnoreChildSignals(void)
981 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
982 struct sigaction action
; /* Actions for POSIX signals */
983 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
986 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
987 sigset(SIGCHLD
, SIG_DFL
);
988 #elif defined(HAVE_SIGACTION)
989 memset(&action
, 0, sizeof(action
));
991 sigemptyset(&action
.sa_mask
);
992 sigaddset(&action
.sa_mask
, SIGCHLD
);
993 action
.sa_handler
= SIG_DFL
;
994 sigaction(SIGCHLD
, &action
, NULL
);
996 signal(SIGCLD
, SIG_DFL
); /* No, SIGCLD isn't a typo... */
997 #endif /* HAVE_SIGSET */
1002 * 'cupsdReleaseSignals()' - Release signals for delivery.
1006 cupsdReleaseSignals(void)
1015 #elif defined(HAVE_SIGACTION)
1016 sigprocmask(SIG_SETMASK
, &holdmask
, NULL
);
1017 #endif /* HAVE_SIGSET */
1022 * 'cupsdSetString()' - Set a string value.
1026 cupsdSetString(char **s
, /* O - New string */
1027 const char *v
) /* I - String value */
1043 * 'cupsdSetStringf()' - Set a formatted string value.
1047 cupsdSetStringf(char **s
, /* O - New string */
1048 const char *f
, /* I - Printf-style format string */
1049 ...) /* I - Additional args as needed */
1051 char v
[4096]; /* Formatting string value */
1052 va_list ap
; /* Argument pointer */
1053 char *olds
; /* Old string */
1064 vsnprintf(v
, sizeof(v
), f
, ap
);
1078 * 'parent_handler()' - Catch USR1/CHLD signals...
1082 parent_handler(int sig
) /* I - Signal */
1085 * Store the signal we got from the OS and return...
1088 parent_signal
= sig
;
1093 * 'process_children()' - Process all dead children...
1097 process_children(void)
1099 int status
; /* Exit status of child */
1100 int pid
; /* Process ID of child */
1101 cupsd_job_t
*job
; /* Current job */
1102 int i
; /* Looping var */
1105 cupsdLogMessage(L_DEBUG2
, "process_children()");
1108 * Reset the dead_children flag...
1114 * Collect the exit status of some children...
1118 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0)
1119 #elif defined(HAVE_WAIT3)
1120 while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0)
1122 if ((pid
= wait(&status
)) > 0)
1123 #endif /* HAVE_WAITPID */
1125 cupsdLogMessage(L_DEBUG2
, "process_children: pid = %d, status = %d\n", pid
, status
);
1128 * Ignore SIGTERM errors - that comes when a job is cancelled...
1131 if (status
== SIGTERM
)
1136 if (WIFEXITED(status
))
1137 cupsdLogMessage(L_ERROR
, "PID %d stopped with status %d!", pid
,
1138 WEXITSTATUS(status
));
1140 cupsdLogMessage(L_ERROR
, "PID %d crashed on signal %d!", pid
,
1143 if (LogLevel
< L_DEBUG
)
1144 cupsdLogMessage(L_INFO
, "Hint: Try setting the LogLevel to \"debug\" to find out more.");
1147 cupsdLogMessage(L_DEBUG2
, "PID %d exited with no errors.", pid
);
1150 * Delete certificates for CGI processes...
1154 cupsdDeleteCert(pid
);
1157 * Lookup the PID in the jobs list...
1160 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
1162 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
1163 if (job
->state
!= NULL
&&
1164 job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1166 for (i
= 0; job
->filters
[i
]; i
++)
1167 if (job
->filters
[i
] == pid
)
1170 if (job
->filters
[i
] || job
->backend
== pid
)
1173 * OK, this process has gone away; what's left?
1176 if (job
->filters
[i
])
1177 job
->filters
[i
] = -pid
;
1179 job
->backend
= -pid
;
1181 if (status
&& job
->status
>= 0)
1184 * An error occurred; save the exit status so we know to stop
1185 * the printer or cancel the job when all of the filters finish...
1187 * A negative status indicates that the backend failed and the
1188 * printer needs to be stopped.
1191 if (job
->filters
[i
])
1192 job
->status
= status
; /* Filter failed */
1194 job
->status
= -status
; /* Backend failed */
1198 * If this is not the last file in a job, see if all of the
1199 * filters are done, and if so move to the next file.
1202 if (job
->current_file
< job
->num_files
)
1204 for (i
= 0; job
->filters
[i
] < 0; i
++);
1206 if (!job
->filters
[i
])
1209 * Process the next file...
1212 cupsdFinishJob(job
);
1223 * 'sigchld_handler()' - Handle 'child' signals from old processes.
1227 sigchld_handler(int sig
) /* I - Signal number */
1232 * Flag that we have dead children...
1238 * Reset the signal handler as needed...
1241 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1242 signal(SIGCLD
, sigchld_handler
);
1243 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1248 * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
1252 sighup_handler(int sig
) /* I - Signal number */
1256 NeedReload
= RELOAD_ALL
;
1257 ReloadTime
= time(NULL
);
1259 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1260 signal(SIGHUP
, sighup_handler
);
1261 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1266 * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
1270 sigterm_handler(int sig
) /* I - Signal */
1272 (void)sig
; /* remove compiler warnings... */
1275 * Flag that we should stop and return...
1283 * 'select_timeout()' - Calculate the select timeout value.
1287 static long /* O - Number of seconds */
1288 select_timeout(int fds
) /* I - Number of ready descriptors select returned */
1290 int i
; /* Looping var */
1291 long timeout
; /* Timeout for select */
1292 time_t now
; /* Current time */
1293 cupsd_client_t
*con
; /* Client information */
1294 cupsd_printer_t
*p
; /* Printer information */
1295 cupsd_job_t
*job
; /* Job information */
1296 const char *why
; /* Debugging aid */
1300 * Check to see if any of the clients have pending data to be
1301 * processed; if so, the timeout should be 0...
1304 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
1305 if (con
->http
.used
> 0)
1309 * If select has been active in the last second (fds != 0) or we have
1310 * many resources in use then don't bother trying to optimize the
1311 * timeout, just make it 1 second.
1314 if (fds
|| NumClients
> 50)
1318 * Otherwise, check all of the possible events that we need to wake for...
1322 timeout
= now
+ 86400; /* 86400 == 1 day */
1326 * Check the activity and close old clients...
1329 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
1330 if ((con
->http
.activity
+ Timeout
) < timeout
)
1332 timeout
= con
->http
.activity
+ Timeout
;
1333 why
= "timeout a client connection";
1337 * Update the browse list as needed...
1340 if (Browsing
&& BrowseLocalProtocols
)
1343 if ((BrowseLocalProtocols
& BROWSE_SLP
) && (BrowseSLPRefresh
< timeout
))
1345 timeout
= BrowseSLPRefresh
;
1346 why
= "update SLP browsing";
1348 #endif /* HAVE_LIBSLP */
1350 if (BrowseLocalProtocols
& BROWSE_CUPS
)
1352 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1354 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1356 if (p
->type
& CUPS_PRINTER_REMOTE
)
1358 if ((p
->browse_time
+ BrowseTimeout
) < timeout
)
1360 timeout
= p
->browse_time
+ BrowseTimeout
;
1361 why
= "browse timeout a printer";
1364 else if (!(p
->type
& CUPS_PRINTER_IMPLICIT
))
1366 if (BrowseInterval
&& (p
->browse_time
+ BrowseInterval
) < timeout
)
1368 timeout
= p
->browse_time
+ BrowseInterval
;
1369 why
= "send browse update";
1377 * Check for any active jobs...
1380 if (timeout
> (now
+ 10) && ActiveJobs
)
1382 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
1384 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
1385 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
1388 why
= "process active jobs";
1393 #ifdef HAVE_MALLINFO
1395 * Log memory usage every minute...
1398 if (LogLevel
>= L_DEBUG
&& (mallinfo_time
+ 60) < timeout
)
1400 timeout
= mallinfo_time
+ 60;
1401 why
= "display memory usage";
1403 #endif /* HAVE_MALLINFO */
1406 * Update the root certificate when needed...
1409 if (!RunUser
&& RootCertDuration
&&
1410 (RootCertTime
+ RootCertDuration
) < timeout
)
1412 timeout
= RootCertTime
+ RootCertDuration
;
1413 why
= "update root certificate";
1417 * Adjust from absolute to relative time. If p->browse_time above
1418 * was 0 then we can end up with a negative value here, so check.
1419 * We add 1 second to the timeout since events occur after the
1420 * timeout expires, and limit the timeout to 86400 seconds (1 day)
1421 * to avoid select() timeout limits present on some operating
1425 timeout
= timeout
- now
+ 1;
1429 else if (timeout
> 86400)
1433 * Log and return the timeout value...
1436 cupsdLogMessage(L_DEBUG2
, "select_timeout: %ld seconds to %s", timeout
, why
);
1443 * 'usage()' - Show scheduler usage.
1449 fputs("Usage: cupsd [-c config-file] [-f] [-F]\n", stderr
);