/*
- * "$Id: main.c 4838 2005-11-14 18:34:27Z mike $"
+ * "$Id: main.c 5305 2006-03-18 03:05:12Z mike $"
*
* Scheduler main loop for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* property of Easy Software Products and are protected by Federal
* main() - Main entry for the CUPS scheduler.
* cupsdClosePipe() - Close a pipe as necessary.
* cupsdOpenPipe() - Create a pipe which is closed on exec.
- * cupsdCatchChildSignals() - Catch SIGCHLD signals...
* cupsdHoldSignals() - Hold child and termination signals.
- * cupsdIgnoreChildSignals() - Ignore SIGCHLD signals...
* cupsdReleaseSignals() - Release signals for delivery.
* cupsdSetString() - Set a string value.
* cupsdSetStringf() - Set a formatted string value.
+ * launchd_checkin() - Check-in with launchd and collect the
+ * listening fds.
+ * launchd_reload() - Tell launchd to reload the configuration
+ * file to pick up the new listening directives.
+ * launchd_sync_conf() - Re-write the launchd(8) config file
+ * org.cups.cupsd.plist based on cupsd.conf.
* parent_handler() - Catch USR1/CHLD signals...
* process_children() - Process all dead children...
* sigchld_handler() - Handle 'child' signals from old processes.
#include <syslog.h>
#include <grp.h>
+#ifdef HAVE_LAUNCH_H
+# include <launch.h>
+# include <libgen.h>
+#endif /* HAVE_LAUNCH_H */
+
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
# include <malloc.h>
#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
+#ifdef HAVE_NOTIFY_H
+# include <notify.h>
+#endif /* HAVE_NOTIFY_H */
/*
* Local functions...
*/
+#ifdef HAVE_LAUNCHD
+static void launchd_checkin(void);
+static void launchd_reload(void);
+static int launchd_sync_conf(void);
+#endif /* HAVE_LAUNCHD */
+
static void parent_handler(int sig);
static void process_children(void);
static void sigchld_handler(int sig);
static void sighup_handler(int sig);
static void sigterm_handler(int sig);
static long select_timeout(int fds);
-static void usage(void);
+static void usage(int status);
/*
*/
int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
+main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line arguments */
{
int i; /* Looping var */
char *opt; /* Option character */
int fg; /* Run in the foreground */
- int fds; /* Number of ready descriptors select returns */
+ int fds; /* Number of ready descriptors */
fd_set *input, /* Input set for select() */
*output; /* Output set for select() */
cupsd_client_t *con; /* Current client */
cupsd_job_t *job; /* Current job */
cupsd_listener_t *lis; /* Current listener */
time_t current_time, /* Current time */
- activity, /* Activity timer */
+ activity, /* Client activity timer */
browse_time, /* Next browse send time */
senddoc_time, /* Send-Document time */
expire_time; /* Subscription expire time */
-#ifdef HAVE_MALLINFO
time_t mallinfo_time; /* Malloc information time */
-#endif /* HAVE_MALLINFO */
+ size_t string_count, /* String count */
+ alloc_bytes, /* Allocated string bytes */
+ total_bytes; /* Total string bytes */
struct timeval timeout; /* select() timeout */
struct rlimit limit; /* Runtime limit */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
cups_file_t *fp; /* Fake lpsched lock file */
struct stat statbuf; /* Needed for checking lpsched FIFO */
#endif /* __sgi */
+#if HAVE_LAUNCHD
+ int launchd_idle_exit;
+ /* Idle exit on select timeout? */
+#endif /* HAVE_LAUNCHD */
/*
case 'c' : /* Configuration file */
i ++;
if (i >= argc)
- usage();
+ {
+ _cupsLangPuts(stderr, _("cupsd: Expected config filename "
+ "after \"-c\" option!\n"));
+ usage(1);
+ }
if (argv[i][0] == '/')
{
* Relative directory...
*/
- char current[1024]; /* Current directory */
+ char *current; /* Current directory */
+
+
+ /*
+ * Allocate a buffer for the current working directory to
+ * reduce run-time stack usage; this approximates the
+ * behavior of some implementations of getcwd() when they
+ * are passed a NULL pointer.
+ */
+ current = malloc(1024);
+ getcwd(current, 1024);
- getcwd(current, sizeof(current));
cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]);
+
+ free(current);
}
break;
fg = 1;
break;
- case 'F' : /* Run in foreground, but still disconnect from terminal... */
+ case 'F' : /* Run in foreground, but disconnect from terminal... */
fg = -1;
break;
+ case 'h' : /* Show usage/help */
+ usage(0);
+ break;
+
+ case 'l' : /* Started by launchd... */
+#ifdef HAVE_LAUNCHD
+ Launchd = 1;
+ fg = 1;
+#else
+ _cupsLangPuts(stderr, _("cupsd: launchd(8) support not compiled "
+ "in, running in normal mode.\n"));
+ fg = 0;
+#endif /* HAVE_LAUNCHD */
+ break;
+
default : /* Unknown option */
- fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n",
- *opt);
- usage();
+ _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
+ "aborting!\n"), *opt);
+ usage(1);
break;
}
else
{
- fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]);
- usage();
+ _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting!\n"),
+ argv[i]);
+ usage(1);
}
if (!ConfigurationFile)
}
else if (WIFEXITED(i))
{
- fprintf(stderr, "cupsd: Child exited with status %d!\n", WEXITSTATUS(i));
+ fprintf(stderr, "cupsd: Child exited with status %d!\n",
+ WEXITSTATUS(i));
return (2);
}
else
return (1);
}
+#if HAVE_LAUNCHD
+ if (Launchd)
+ {
+ /*
+ * If we were started by launchd make sure the cupsd plist file contains the
+ * same listeners as cupsd.conf; If it didn't then reload it before getting
+ * the list of listening file descriptors...
+ */
+
+ if (launchd_sync_conf())
+ {
+ launchd_reload();
+
+ /*
+ * Until rdar://3854821 is fixed we have to exit after the reload...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Exiting on launchd_reload");
+ exit(0);
+ }
+
+ launchd_checkin();
+ }
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Startup the server...
+ */
+
+ cupsdStartServer();
+
/*
* Catch hangup and child signals and ignore broken pipes...
*/
#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- if (RunAsUser)
- sigset(SIGHUP, sigterm_handler);
- else
- sigset(SIGHUP, sighup_handler);
-
+ sigset(SIGCHLD, sigchld_handler);
+ sigset(SIGHUP, sighup_handler);
sigset(SIGPIPE, SIG_IGN);
sigset(SIGTERM, sigterm_handler);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGHUP);
-
- if (RunAsUser)
- action.sa_handler = sigterm_handler;
- else
- action.sa_handler = sighup_handler;
+ sigaddset(&action.sa_mask, SIGTERM);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigchld_handler;
+ sigaction(SIGCHLD, &action, NULL);
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGHUP);
+ action.sa_handler = sighup_handler;
sigaction(SIGHUP, &action, NULL);
sigemptyset(&action.sa_mask);
action.sa_handler = sigterm_handler;
sigaction(SIGTERM, &action, NULL);
#else
- if (RunAsUser)
- signal(SIGHUP, sigterm_handler);
- else
- signal(SIGHUP, sighup_handler);
-
+ signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
+ signal(SIGHUP, sighup_handler);
signal(SIGPIPE, SIG_IGN);
signal(SIGTERM, sigterm_handler);
#endif /* HAVE_SIGSET */
kill(i, SIGUSR1);
}
+#ifdef __APPLE__
/*
- * If the administrator has configured the server to run as an unpriviledged
- * user, change to that user now...
- */
-
- if (RunAsUser)
- {
- setgid(Group);
- setgroups(1, &Group);
- setuid(User);
- }
-
- /*
- * Catch signals...
+ * Start power management framework...
*/
- cupsdCatchChildSignals();
+ cupsdStartSystemMonitor();
+#endif /* __APPLE__ */
/*
* Start any pending print jobs...
* Loop forever...
*/
-#ifdef HAVE_MALLINFO
mallinfo_time = 0;
-#endif /* HAVE_MALLINFO */
browse_time = time(NULL);
senddoc_time = time(NULL);
expire_time = time(NULL);
* Close any idle clients...
*/
- if (NumClients > 0)
+ if (cupsArrayCount(Clients) > 0)
{
- for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
if (con->http.state == HTTP_WAITING)
- {
cupsdCloseClient(con);
- con --;
- }
else
con->http.keep_alive = HTTP_KEEPALIVE_OFF;
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
job;
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
- if (job->state->values[0].integer == IPP_JOB_PROCESSING)
+ if (job->state_value == IPP_JOB_PROCESSING)
break;
/*
* if the reload timeout has elapsed...
*/
- if ((NumClients == 0 && (!job || NeedReload != RELOAD_ALL)) ||
+ if ((cupsArrayCount(Clients) == 0 &&
+ (!job || NeedReload != RELOAD_ALL)) ||
(time(NULL) - ReloadTime) >= ReloadTimeout)
{
+ /*
+ * Shutdown the server...
+ */
+
+ cupsdStopServer();
+
+ /*
+ * Read configuration...
+ */
+
if (!cupsdReadConfiguration())
{
syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
ConfigurationFile);
break;
}
+
+#if HAVE_LAUNCHD
+ if (Launchd)
+ {
+ if (launchd_sync_conf())
+ {
+ launchd_reload();
+
+ /*
+ * Until rdar://3854821 is fixed we have to exit after the reload...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Exiting on launchd_reload");
+ stop_scheduler = 1;
+ break;
+ }
+
+ launchd_checkin();
+ }
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Startup the server...
+ */
+
+ cupsdStartServer();
}
}
timeout.tv_sec = select_timeout(fds);
timeout.tv_usec = 0;
- if ((fds = select(MaxFDs, input, output, NULL, &timeout)) < 0)
+#if HAVE_LAUNCHD
+ /*
+ * If no other work is scheduled and we're being controlled by
+ * launchd(8) then timeout after 'LaunchdTimeout' seconds of
+ * inactivity...
+ */
+
+ if (timeout.tv_sec == 86400 && Launchd && LaunchdTimeout &&
+ (!Browsing || !(BrowseLocalProtocols & BROWSE_DNSSD) ||
+ cupsArrayCount(Printers) == 0))
+ {
+ timeout.tv_sec = LaunchdTimeout;
+ launchd_idle_exit = 1;
+ }
+ else
+ launchd_idle_exit = 0;
+#endif /* HAVE_LAUNCHD */
+
+ if (timeout.tv_sec < 86400) /* Only use timeout for < 1 day */
+ fds = select(MaxFDs, input, output, NULL, &timeout);
+ else
+ fds = select(MaxFDs, input, output, NULL, NULL);
+
+ if (fds < 0)
{
char s[16384], /* String buffer */
*sptr; /* Pointer into buffer */
cupsdLogMessage(CUPSD_LOG_EMERG, s);
- for (i = 0, con = Clients; i < NumClients; i ++, con ++)
+ for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
cupsdLogMessage(CUPSD_LOG_EMERG,
"Clients[%d] = %d, file = %d, state = %d",
i, con->http.fd, con->file, con->http.state);
- for (i = 0, lis = Listeners; i < NumListeners; i ++, lis ++)
+ for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);
cupsdLogMessage(CUPSD_LOG_EMERG, "BrowseSocket = %d", BrowseSocket);
+ cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);
+
+#ifdef __APPLE__
+ cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
+ SysEventPipes[0]);
+#endif /* __APPLE__ */
+
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
job;
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
current_time = time(NULL);
+#if HAVE_LAUNCHD
+ /*
+ * If no other work was scheduled and we're being controlled by launchd(8)
+ * then timeout after 'LaunchdTimeout' seconds of inactivity...
+ */
+
+ if (!fds && launchd_idle_exit)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer sharing is off and there are no jobs pending, "
+ "will restart on demand.");
+ stop_scheduler = 1;
+ break;
+ }
+#endif /* HAVE_LAUNCHD */
+
/*
* Check for status info from job filters...
*/
if (CGIPipes[0] >= 0 && FD_ISSET(CGIPipes[0], input))
cupsdUpdateCGI();
+ /*
+ * Handle system management events as needed...
+ */
+
+#ifdef __APPLE__
+ if (SysEventPipes[0] >= 0 && FD_ISSET(SysEventPipes[0], input))
+ cupsdUpdateSystemMonitor();
+#endif /* __APPLE__ */
+
/*
* Update notifier messages as needed...
*/
cupsdUpdateNotifierStatus();
/*
- * Expire subscriptions as needed...
+ * Expire subscriptions and unload completed jobs as needed...
*/
- if (cupsArrayCount(Subscriptions) > 0 && current_time > expire_time)
+ if (current_time > expire_time)
{
- cupsdExpireSubscriptions(NULL, NULL);
+ if (cupsArrayCount(Subscriptions) > 0)
+ cupsdExpireSubscriptions(NULL, NULL);
+
+ cupsdUnloadCompletedJobs();
expire_time = current_time;
}
* Update the browse list as needed...
*/
- if (Browsing && (BrowseLocalProtocols | BrowseRemoteProtocols))
+ if (Browsing && BrowseRemoteProtocols)
{
if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, input))
cupsdUpdateCUPSBrowse();
cupsdUpdatePolling();
#ifdef HAVE_LIBSLP
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
+ if ((BrowseRemoteProtocols & BROWSE_SLP) &&
BrowseSLPRefresh <= current_time)
cupsdUpdateSLPBrowse();
#endif /* HAVE_LIBSLP */
- if (current_time > browse_time)
- {
- cupsdSendBrowseList();
- browse_time = current_time;
- }
+#ifdef HAVE_LDAP
+ if ((BrowseRemoteProtocols & BROWSE_LDAP) &&
+ BrowseLDAPRefresh <= current_time)
+ cupsdUpdateLDAPBrowse();
+#endif /* HAVE_LDAP */
+ }
+
+ if (Browsing && BrowseLocalProtocols && current_time > browse_time)
+ {
+ cupsdSendBrowseList();
+ browse_time = current_time;
}
/*
* Check for new connections on the "listen" sockets...
*/
- for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
if (lis->fd >= 0 && FD_ISSET(lis->fd, input))
{
FD_CLR(lis->fd, input);
* Check for new data on the client sockets...
*/
- for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
{
/*
* Process the input buffer...
if (FD_ISSET(con->http.fd, input) || con->http.used)
{
+ int fd = con->file;
+
+
FD_CLR(con->http.fd, input);
if (!cupsdReadClient(con))
{
- if (con->pipe_pid)
- FD_CLR(con->file, input);
+ if (fd >= 0)
+ FD_CLR(fd, input);
- con --;
continue;
}
}
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"main: Removing fd %d from InputSet...", con->file);
+ FD_CLR(con->file, input);
FD_CLR(con->file, InputSet);
}
}
if (!con->pipe_pid || con->file_ready)
if (!cupsdWriteClient(con))
- {
- con --;
continue;
- }
}
/*
con->http.fd, Timeout);
cupsdCloseClient(con);
- con --;
continue;
}
}
senddoc_time = current_time;
}
-#ifdef HAVE_MALLINFO
/*
* Log memory usage every minute...
*/
- if ((current_time - mallinfo_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
+ if ((current_time - mallinfo_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG2)
{
+#ifdef HAVE_MALLINFO
struct mallinfo mem; /* Malloc information */
mem = mallinfo();
- cupsdLogMessage(CUPSD_LOG_DEBUG,
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
"mallinfo: arena = %d, used = %d, free = %d\n",
mem.arena, mem.usmblks + mem.uordblks,
mem.fsmblks + mem.fordblks);
+#endif /* HAVE_MALLINFO */
+
+ string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "stringpool: " CUPS_LLFMT " strings, "
+ CUPS_LLFMT " allocated, " CUPS_LLFMT " total bytes",
+ CUPS_LLCAST string_count, CUPS_LLCAST alloc_bytes,
+ CUPS_LLCAST total_bytes);
+
mallinfo_time = current_time;
}
-#endif /* HAVE_MALLINFO */
/*
* Update the root certificate once every 5 minutes...
cupsdDeleteCert(0);
cupsdAddCert(0, "root");
}
+
+ /*
+ * Handle OS-specific event notification for any events that have
+ * accumulated. Don't send these more than once a second...
+ */
+
+ if (LastEvent && (time(NULL) - LastEventTime) > 1)
+ {
+#ifdef HAVE_NOTIFY_POST
+ if (LastEvent & CUPSD_EVENT_PRINTER_CHANGED)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.printerListChange\")");
+ notify_post("com.apple.printerListChange");
+ }
+
+ if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.printerHistoryChange\")");
+ notify_post("com.apple.printerHistoryChange");
+ }
+
+ if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
+ CUPSD_EVENT_JOB_CONFIG_CHANGED |
+ CUPSD_EVENT_JOB_PROGRESS))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.jobChange\")");
+ notify_post("com.apple.jobChange");
+ }
+#endif /* HAVE_NOTIFY_POST */
+
+ /*
+ * Reset the accumulated events and notification time...
+ */
+
+ LastEventTime = time(NULL);
+ LastEvent = CUPSD_EVENT_NONE;
+ }
}
/*
cupsdStopServer();
- cupsdStopAllJobs();
+ cupsdFreeAllJobs();
+
+#ifdef __APPLE__
+ cupsdStopSystemMonitor();
+#endif /* __APPLE__ */
+
+#ifdef HAVE_LAUNCHD
+ /*
+ * Update the launchd config file as needed...
+ */
+
+ launchd_sync_conf();
+#endif /* HAVE_LAUNCHD */
#ifdef __sgi
/*
*/
if (pipe(fds))
+ {
+ fds[0] = -1;
+ fds[1] = -1;
+
return (-1);
+ }
/*
* Set the "close on exec" flag on each end of the pipe...
{
close(fds[0]);
close(fds[1]);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
return (-1);
}
{
close(fds[0]);
close(fds[1]);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
return (-1);
}
}
-/*
- * 'cupsdCatchChildSignals()' - Catch SIGCHLD signals...
- */
-
-void
-cupsdCatchChildSignals(void)
-{
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGCHLD, sigchld_handler);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
-
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGTERM);
- sigaddset(&action.sa_mask, SIGCHLD);
- action.sa_handler = sigchld_handler;
- sigaction(SIGCHLD, &action, NULL);
-#else
- signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
-#endif /* HAVE_SIGSET */
-}
-
-
/*
* 'cupsdClearString()' - Clear a string.
*/
}
-/*
- * 'cupsdIgnoreChildSignals()' - Ignore SIGCHLD signals...
- *
- * We don't really ignore them, we set the signal handler to SIG_DFL,
- * since some OS's rely on signals for the wait4() function to work.
- */
-
-void
-cupsdIgnoreChildSignals(void)
-{
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGCHLD, SIG_DFL);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
-
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGCHLD);
- action.sa_handler = SIG_DFL;
- sigaction(SIGCHLD, &action, NULL);
-#else
- signal(SIGCLD, SIG_DFL); /* No, SIGCLD isn't a typo... */
-#endif /* HAVE_SIGSET */
-}
-
-
/*
* 'cupsdReleaseSignals()' - Release signals for delivery.
*/
}
+#ifdef HAVE_LAUNCHD
+/*
+ * 'launchd_checkin()' - Check-in with launchd and collect the listening fds.
+ */
+
+static void
+launchd_checkin(void)
+{
+ int i, /* Looping var */
+ count, /* Numebr of listeners */
+ portnum; /* Port number */
+ launch_data_t ld_msg, /* Launch data message */
+ ld_resp, /* Launch data response */
+ ld_array, /* Launch data array */
+ ld_sockets, /* Launch data sockets dictionary */
+ ld_runatload, /* Run-at-load setting */
+ tmp; /* Launch data */
+ cupsd_listener_t *lis; /* Listeners array */
+ http_addr_t addr; /* Address variable */
+ socklen_t addrlen; /* Length of address */
+ bool runatload; /* Run-at-load setting value */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: pid=%d", (int)getpid());
+
+ /*
+ * Check-in with launchd...
+ */
+
+ ld_msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+ if ((ld_resp = launch_msg(ld_msg)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: launch_msg(\"" LAUNCH_KEY_CHECKIN
+ "\") IPC failure");
+ exit(EXIT_FAILURE);
+ }
+
+ if (launch_data_get_type(ld_resp) == LAUNCH_DATA_ERRNO)
+ {
+ errno = launch_data_get_errno(ld_resp);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_checkin: Check-in failed: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Get the "run-at-load" setting...
+ */
+
+ if ((ld_runatload =
+ launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_RUNATLOAD)) != NULL &&
+ launch_data_get_type(ld_runatload) == LAUNCH_DATA_BOOL)
+ runatload = launch_data_get_bool(ld_runatload);
+ else
+ {
+ errno = launch_data_get_errno(ld_resp);
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to find Run-at-load setting: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: Run-at-load=%s",
+ runatload ? "true" : "false");
+
+ /*
+ * Get the sockets dictionary...
+ */
+
+ if (!(ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: No sockets found to answer requests on!");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Get the array of listener sockets...
+ */
+
+ if (!(ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: No sockets found to answer requests on!");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Add listening fd(s) to the Listener array...
+ */
+
+ if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
+ {
+ /*
+ * Free the listeners array built from cupsd.conf...
+ */
+
+ cupsdDeleteAllListeners();
+
+ /*
+ * Create a new array of listeners from the launchd data...
+ */
+
+ Listeners = cupsArrayNew(NULL, NULL);
+ count = launch_data_array_get_count(ld_array);
+
+ for (i = 0; i < count; i ++)
+ {
+ /*
+ * Copy the current address and log it...
+ */
+
+ if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to allocate listener - %s.",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ cupsArrayAdd(Listeners, lis);
+
+ tmp = launch_data_array_get_index(ld_array, i);
+ lis->fd = launch_data_get_fd(tmp);
+ addrlen = sizeof(lis->address);
+
+ if (getsockname(lis->fd, (struct sockaddr *)&(lis->address), &addrlen))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to get local address - %s",
+ strerror(errno));
+ }
+
+# ifdef HAVE_SSL
+ portnum = 0;
+
+# ifdef AF_INET6
+ if (addr.addr.sa_family == AF_INET6)
+ portnum = ntohs(addr.ipv6.sin6_port);
+ else
+# endif /* AF_INET6 */
+ if (addr.addr.sa_family == AF_INET)
+ portnum = ntohs(addr.ipv4.sin_port);
+
+ if (portnum == 443)
+ lis->encryption = HTTP_ENCRYPT_ALWAYS;
+# endif /* HAVE_SSL */
+ }
+ }
+
+ /*
+ * Collect the browse socket (if there is one)...
+ */
+
+ if ((ld_array = launch_data_dict_lookup(ld_sockets, "BrowseSockets")))
+ {
+ if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
+ {
+ tmp = launch_data_array_get_index(ld_array, 0);
+
+ if (launch_data_get_type(tmp) == LAUNCH_DATA_FD)
+ {
+ if (BrowseSocket != -1)
+ close(BrowseSocket);
+
+ BrowseSocket = launch_data_get_fd(tmp);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "launchd_checkin: BrowseSocket not a fd!");
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "launchd_checkin: BrowseSockets is not an array!");
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: No BrowseSockets");
+
+ launch_data_free(ld_msg);
+ launch_data_free(ld_resp);
+}
+
+
+/*
+ * 'launchd_reload()' - Tell launchd to reload the configuration file to pick
+ * up the new listening directives.
+ */
+
+static void
+launchd_reload(void)
+{
+ int child_status; /* Exit status of child process */
+ pid_t child_pid, /* Child PID */
+ waitpid_status; /* Child process exit status */
+ char *argv[4]; /* Argument strings */
+
+
+ /*
+ * The current launchd doesn't support a reload option (rdar://3854821).
+ * Until this is fixed we need to reload the config file by execing launchctl
+ * twice (to unload then load). NOTE: This will cause us to exit on SIGTERM
+ * which will cancel all client & job activity.
+ *
+ * After this is fixed we'll be able to tell launchd to reload the file
+ * and pick up the new listening descriptors without disrupting current
+ * activity.
+ */
+
+ /*
+ * Unloading the current configuration will cause launchd to send us a SIGTERM;
+ * block it for now so we can get our work done...
+ */
+
+ cupsdHoldSignals();
+
+ /*
+ * Set up the unload arguments to launchctl...
+ */
+
+ argv[0] = "/bin/launchctl";
+ argv[1] = "unload";
+ argv[2] = LaunchdConf;
+ argv[3] = NULL;
+
+ if (cupsdStartProcess(argv[0], argv, NULL, -1, -1, -1, -1, 1, &child_pid) < 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_reload: Unable to execute %s - %s", argv[0],
+ strerror(errno));
+ else
+ {
+ do
+ {
+ waitpid_status = waitpid(child_pid, &child_status, 0);
+ }
+ while (waitpid_status == (pid_t)-1 && errno == EINTR);
+
+ if (WIFSIGNALED(child_status))
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_reload: %s pid %d crashed on signal %d!",
+ basename(argv[0]), child_pid, WTERMSIG(child_status));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_reload: %s pid %d stopped with status %d!",
+ basename(argv[0]), child_pid, WEXITSTATUS(child_status));
+
+ /*
+ * Do it again with the load command...
+ */
+
+ argv[1] = "load";
+
+ if (cupsdStartProcess(argv[0], argv, NULL, -1, -1, -1, -1, 1,
+ &child_pid) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_reload: Unable to fork for %s - %s", argv[0],
+ strerror(errno));
+ }
+ else
+ {
+ do
+ {
+ waitpid_status = waitpid(child_pid, &child_status, 0);
+ } while (waitpid_status == (pid_t)-1 && errno == EINTR);
+
+ if (WIFSIGNALED(child_status))
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_reload: %s pid %d crashed on signal %d!",
+ basename(argv[0]), child_pid, WTERMSIG(child_status));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_reload: %s pid %d stopped with status %d",
+ basename(argv[0]), child_pid,
+ WEXITSTATUS(child_status));
+ }
+ }
+
+ /*
+ * Leave signals blocked since exit() will be called momentarily anyways...
+ */
+}
+
+
+/*
+ * 'launchd_sync_conf()' - Re-write the launchd(8) config file
+ * org.cups.cupsd.plist based on cupsd.conf.
+ */
+
+static int /* O - 1 if the file was updated */
+launchd_sync_conf(void)
+{
+ int portnum; /* Port number */
+ CFMutableDictionaryRef cupsd_dict, /* org.cups.cupsd.plist dictionary */
+ sockets, /* Sockets dictionary */
+ listener; /* Listener dictionary */
+ CFDataRef resourceData; /* XML property list */
+ CFMutableArrayRef array; /* Array */
+ CFNumberRef socket_mode; /* Domain socket mode bits */
+ CFStringRef socket_path; /* Domain socket path */
+ CFTypeRef value; /* CF value */
+ CFURLRef fileURL; /* File URL */
+ SInt32 errorCode; /* Error code */
+ cupsd_listener_t *lis; /* Current listening socket */
+ struct servent *service; /* Services data base entry */
+ char temp[1024]; /* Temporary buffer for value */
+ struct stat cupsd_sb, /* File info for cupsd.conf */
+ launchd_sb; /* File info for org.cups.cupsd.plist */
+
+
+ /*
+ * If the launchd conf file modification time is newer than the cupsd.conf
+ * time then there's nothing to do...
+ */
+
+ if (!stat(ConfigurationFile, &cupsd_sb) &&
+ !stat(LaunchdConf, &launchd_sb) &&
+ launchd_sb.st_mtimespec.tv_sec >= cupsd_sb.st_mtimespec.tv_sec)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_sync_conf: Nothing to do, pid=%d.",
+ (int)getpid());
+ return (0);
+ }
+
+ /*
+ * Time to write a new 'org.cups.cupsd.plist' file.
+ * Create the new dictionary and populate it with values...
+ */
+
+ if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks)) != NULL)
+ {
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL),
+ CFSTR("org.cups.cupsd"));
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_ONDEMAND),
+ kCFBooleanTrue);
+
+ if ((Browsing && BrowseLocalProtocols && cupsArrayCount(Printers)) ||
+ cupsArrayCount(ActiveJobs))
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
+ kCFBooleanTrue);
+ else
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
+ kCFBooleanFalse);
+
+#ifdef LAUNCH_JOBKEY_SERVICEIPC
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SERVICEIPC),
+ kCFBooleanTrue);
+#endif /* LAUNCH_JOBKEY_SERVICEIPC */
+
+ if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 2,
+ &kCFTypeArrayCallBacks)) != NULL)
+ {
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS),
+ array);
+ CFArrayAppendValue(array, CFSTR("/usr/sbin/cupsd"));
+ CFArrayAppendValue(array, CFSTR("-l"));
+ CFRelease(array);
+ }
+
+ /*
+ * Add a sockets dictionary...
+ */
+
+ if ((sockets = (CFMutableDictionaryRef)CFDictionaryCreateMutable(
+ kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks)) != NULL)
+ {
+ CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SOCKETS), sockets);
+
+ /*
+ * Add a Listeners array to the sockets dictionary...
+ */
+
+ if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeArrayCallBacks)) != NULL)
+ {
+ CFDictionaryAddValue(sockets, CFSTR("Listeners"), array);
+
+ /*
+ * For each listener add a dictionary to the listeners array...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks)) != NULL)
+ {
+ CFArrayAppendValue(array, listener);
+
+# ifdef AF_LOCAL
+ if (lis->address.addr.sa_family == AF_LOCAL)
+ {
+ if ((socket_path = CFStringCreateWithCString(kCFAllocatorDefault,
+ lis->address.un.sun_path,
+ kCFStringEncodingUTF8)))
+ {
+ CFDictionaryAddValue(listener,
+ CFSTR(LAUNCH_JOBSOCKETKEY_PATHNAME),
+ socket_path);
+ CFRelease(socket_path);
+ }
+ portnum = 0140777; /* (S_IFSOCK|S_IRWXU|S_IRWXG|S_IRWXO) or *
+ * 49663d decimal */
+ if ((socket_mode = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberIntType, &portnum)))
+ {
+ CFDictionaryAddValue(listener, CFSTR("SockPathMode"),
+ socket_mode);
+ CFRelease(socket_mode);
+ }
+ }
+ else
+# endif /* AF_LOCAL */
+ {
+# ifdef AF_INET6
+ if (lis->address.addr.sa_family == AF_INET6)
+ {
+ CFDictionaryAddValue(listener,
+ CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
+ CFSTR("IPv6"));
+ portnum = lis->address.ipv6.sin6_port;
+ }
+ else
+# endif /* AF_INET6 */
+ {
+ CFDictionaryAddValue(listener,
+ CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
+ CFSTR("IPv4"));
+ portnum = lis->address.ipv4.sin_port;
+ }
+
+ if ((service = getservbyport(portnum, NULL)))
+ value = CFStringCreateWithCString(kCFAllocatorDefault,
+ service->s_name,
+ kCFStringEncodingUTF8);
+ else
+ value = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberIntType, &portnum);
+
+ if (value)
+ {
+ CFDictionaryAddValue(listener,
+ CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME),
+ value);
+ CFRelease(value);
+ }
+
+ httpAddrString(&lis->address, temp, sizeof(temp));
+ if ((value = CFStringCreateWithCString(kCFAllocatorDefault, temp,
+ kCFStringEncodingUTF8)))
+ {
+ CFDictionaryAddValue(listener,
+ CFSTR(LAUNCH_JOBSOCKETKEY_NODENAME),
+ value);
+ CFRelease(value);
+ }
+ }
+
+ CFRelease(listener);
+ }
+ }
+
+ CFRelease(array);
+ }
+
+ /*
+ * Add the BrowseSocket to the sockets dictionary...
+ */
+
+ if (Browsing && (BrowseRemoteProtocols & BROWSE_CUPS))
+ {
+ if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeArrayCallBacks)) != NULL)
+ {
+ CFDictionaryAddValue(sockets, CFSTR("BrowseSockets"), array);
+
+ if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks)) != NULL)
+ {
+ CFArrayAppendValue(array, listener);
+
+ CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
+ CFSTR("IPv4"));
+ CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_TYPE),
+ CFSTR("dgram"));
+
+ if ((service = getservbyport(BrowsePort, NULL)))
+ value = CFStringCreateWithCString(kCFAllocatorDefault,
+ service->s_name,
+ kCFStringEncodingUTF8);
+ else
+ value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
+ &BrowsePort);
+
+ CFDictionaryAddValue(listener,
+ CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME), value);
+ CFRelease(value);
+
+ CFRelease(listener);
+ }
+
+ CFRelease(array);
+ }
+ }
+
+ CFRelease(sockets);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_sync_conf: Updating \"%s\", pid=%d\n",
+ LaunchdConf, (int)getpid());
+
+ if ((fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ (const unsigned char *)LaunchdConf,
+ strlen(LaunchdConf), false)))
+ {
+ if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
+ cupsd_dict)))
+ {
+ if (!CFURLWriteDataAndPropertiesToResource(fileURL, resourceData,
+ NULL, &errorCode))
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "launchd_sync_conf: "
+ "CFURLWriteDataAndPropertiesToResource(\"%s\") "
+ "failed: %d\n",
+ LaunchdConf, (int)errorCode);
+ }
+
+ CFRelease(resourceData);
+ }
+
+ CFRelease(fileURL);
+ }
+
+ CFRelease(cupsd_dict);
+ }
+
+ /*
+ * Let the caller know we updated the file...
+ */
+
+ return (1);
+}
+#endif /* HAVE_LAUNCHD */
+
+
/*
* 'parent_handler()' - Catch USR1/CHLD signals...
*/
int pid; /* Process ID of child */
cupsd_job_t *job; /* Current job */
int i; /* Looping var */
+ char name[1024]; /* Process name */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");
if ((pid = wait(&status)) > 0)
#endif /* HAVE_WAITPID */
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "process_children: pid = %d, status = %d\n", pid, status);
-
/*
* Ignore SIGTERM errors - that comes when a job is cancelled...
*/
+ cupsdFinishProcess(pid, name, sizeof(name));
+
if (status == SIGTERM)
status = 0;
if (status)
{
if (WIFEXITED(status))
- cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d stopped with status %d!", pid,
- WEXITSTATUS(status));
+ cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) stopped with status %d!",
+ pid, name, WEXITSTATUS(status));
else
- cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d crashed on signal %d!", pid,
- WTERMSIG(status));
+ cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d!",
+ pid, name, WTERMSIG(status));
if (LogLevel < CUPSD_LOG_DEBUG)
cupsdLogMessage(CUPSD_LOG_INFO,
- "Hint: Try setting the LogLevel to \"debug\" to find out more.");
+ "Hint: Try setting the LogLevel to \"debug\" to find "
+ "out more.");
}
else
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "PID %d exited with no errors.", pid);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
+ pid, name);
/*
* Delete certificates for CGI processes...
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
job;
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
- if (job->state != NULL &&
- job->state->values[0].integer == IPP_JOB_PROCESSING)
+ if (job->state_value == IPP_JOB_PROCESSING)
{
for (i = 0; job->filters[i]; i ++)
if (job->filters[i] == pid)
job->status = status; /* Filter failed */
else
job->status = -status; /* Backend failed */
+
+ if (job->printer && !(job->printer->type & CUPS_PRINTER_FAX))
+ {
+ snprintf(job->printer->state_message,
+ sizeof(job->printer->state_message), "%s failed", name);
+ cupsdAddPrinterHistory(job->printer);
+ }
}
/*
*/
static long /* O - Number of seconds */
-select_timeout(int fds) /* I - Number of ready descriptors select returned */
+select_timeout(int fds) /* I - Number of descriptors returned */
{
- int i; /* Looping var */
long timeout; /* Timeout for select */
time_t now; /* Current time */
cupsd_client_t *con; /* Client information */
* processed; if so, the timeout should be 0...
*/
- for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
if (con->http.used > 0)
return (0);
* timeout, just make it 1 second.
*/
- if (fds || NumClients > 50)
+ if (fds || cupsArrayCount(Clients) > 50)
+ return (1);
+
+ /*
+ * If we had a recent event notification, timeout in 1 second...
+ */
+
+ if (LastEvent)
return (1);
/*
* Check the activity and close old clients...
*/
- for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
if ((con->http.activity + Timeout) < timeout)
{
timeout = con->http.activity + Timeout;
}
#endif /* HAVE_LIBSLP */
+#ifdef HAVE_LDAP
+ if ((BrowseLocalProtocols & BROWSE_LDAP) && (BrowseLDAPRefresh < timeout))
+ {
+ timeout = BrowseLDAPRefresh;
+ why = "update LDAP browsing";
+ }
+#endif /* HAVE_LDAP */
+
if (BrowseLocalProtocols & BROWSE_CUPS)
{
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
job;
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
- if (job->state->values[0].integer <= IPP_JOB_PROCESSING)
+ if (job->state_value <= IPP_JOB_PROCESSING)
{
timeout = now + 10;
why = "process active jobs";
}
#endif /* HAVE_MALLINFO */
- /*
- * Update the root certificate when needed...
- */
-
- if (!RunUser && RootCertDuration &&
- (RootCertTime + RootCertDuration) < timeout)
- {
- timeout = RootCertTime + RootCertDuration;
- why = "update root certificate";
- }
-
/*
* Expire subscriptions as needed...
*/
for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
sub;
sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
- if (!sub->job && sub->expire < timeout)
+ if (!sub->job && sub->expire && sub->expire < timeout)
{
timeout = sub->expire;
why = "expire subscription";
*/
static void
-usage(void)
+usage(int status) /* O - Exit status */
{
- fputs("Usage: cupsd [-c config-file] [-f] [-F]\n", stderr);
- exit(1);
+ _cupsLangPuts(status ? stderr : stdout,
+ _("Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+ "\n"
+ "-c config-file Load alternate configuration file\n"
+ "-f Run in the foreground\n"
+ "-F Run in the foreground but detach\n"
+ "-h Show this usage message\n"
+ "-l Run cupsd from launchd(8)\n"));
+ exit(status);
}
/*
- * End of "$Id: main.c 4838 2005-11-14 18:34:27Z mike $".
+ * End of "$Id: main.c 5305 2006-03-18 03:05:12Z mike $".
*/