/*
- * "$Id: main.c 4997 2006-01-26 21:43:54Z mike $"
+ * "$Id: main.c 6914 2007-09-05 21:05:04Z mike $"
*
* Scheduler main loop for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2007 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
- * copyright law. Distribution and use rights are outlined in the file
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
* "LICENSE" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
* 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_checkout() - Check-out with launchd.
* parent_handler() - Catch USR1/CHLD signals...
* process_children() - Process all dead children...
* sigchld_handler() - Handle 'child' signals from old processes.
#include <sys/resource.h>
#include <syslog.h>
#include <grp.h>
+#include <cups/dir.h>
+
+#ifdef HAVE_LAUNCH_H
+# include <launch.h>
+# include <libgen.h>
+# define CUPS_KEEPALIVE CUPS_CACHEDIR "/org.cups.cupsd"
+ /* Name of the launchd KeepAlive file */
+# ifndef LAUNCH_JOBKEY_KEEPALIVE
+# define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
+# endif /* !LAUNCH_JOBKEY_KEEPALIVE */
+# ifndef LAUNCH_JOBKEY_PATHSTATE
+# define LAUNCH_JOBKEY_PATHSTATE "PathState"
+# endif /* !LAUNCH_JOBKEY_PATHSTATE */
+# ifndef LAUNCH_JOBKEY_SERVICEIPC
+# define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC"
+# endif /* !LAUNCH_JOBKEY_SERVICEIPC */
+#endif /* HAVE_LAUNCH_H */
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
# include <malloc.h>
# include <notify.h>
#endif /* HAVE_NOTIFY_H */
+#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
+# include <dlfcn.h>
+#endif /* __APPLE__ && HAVE_DLFCN_H */
+
/*
* Local functions...
*/
-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);
+#ifdef HAVE_LAUNCHD
+static void launchd_checkin(void);
+static void launchd_checkout(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(int status);
/*
* Local globals...
*/
-static int parent_signal = 0; /* Set to signal number from child */
-static int holdcount = 0; /* Number of times "hold" was called */
+static int parent_signal = 0;
+ /* Set to signal number from child */
+static int holdcount = 0; /* Number of times "hold" was called */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
-static sigset_t holdmask; /* Old POSIX signal mask */
+static sigset_t holdmask; /* Old POSIX signal mask */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-static int dead_children = 0; /* Dead children? */
-static int stop_scheduler = 0; /* Should the scheduler stop? */
+static int dead_children = 0;
+ /* Dead children? */
+static int stop_scheduler = 0;
+ /* Should the scheduler stop? */
+
+#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
+static const char *PSQLibPath = "/usr/lib/libPrintServiceQuota.dylib";
+static const char *PSQLibFuncName = "PSQUpdateQuota";
+static void *PSQLibRef; /* libPrintServiceQuota.dylib */
+#endif /* HAVE_DLFCN_H */
/*
*/
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 */
- fd_set *input, /* Input set for select() */
- *output; /* Output set for select() */
+ int fds; /* Number of ready descriptors */
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 */
- struct timeval timeout; /* select() timeout */
+ expire_time, /* Subscription expire time */
+ mallinfo_time; /* Malloc information time */
+ size_t string_count, /* String count */
+ alloc_bytes, /* Allocated string bytes */
+ total_bytes; /* Total string bytes */
+ long timeout; /* Timeout for cupsdDoSelect() */
struct rlimit limit; /* Runtime limit */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
cups_file_t *fp; /* Fake lpsched lock file */
struct stat statbuf; /* Needed for checking lpsched FIFO */
#endif /* __sgi */
+#ifdef __APPLE__
+ int run_as_child = 0;
+ /* Needed for Mac OS X fork/exec */
+#else
+ time_t netif_time = 0; /* Time since last network update */
+#endif /* __APPLE__ */
+#if HAVE_LAUNCHD
+ int launchd_idle_exit;
+ /* Idle exit on select timeout? */
+#endif /* HAVE_LAUNCHD */
+#ifdef HAVE_GETEUID
+ /*
+ * Check for setuid invocation, which we do not support!
+ */
+
+ if (getuid() != geteuid())
+ {
+ fputs("cupsd: Cannot run as a setuid program!\n", stderr);
+ return (1);
+ }
+#endif /* HAVE_GETEUID */
+
/*
* Check for command-line arguments...
*/
fg = 0;
+#ifdef HAVE_LAUNCHD
+ if (getenv("CUPSD_LAUNCHD"))
+ {
+ Launchd = 1;
+ fg = 1;
+ }
+#endif /* HAVE_LAUNCHD */
+
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-')
for (opt = argv[i] + 1; *opt != '\0'; opt ++)
switch (*opt)
{
+#ifdef __APPLE__
+ case 'C' : /* Run as child with config file */
+ run_as_child = 1;
+ fg = -1;
+#endif /* __APPLE__ */
+
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;
+
+ case 'p' : /* Stop immediately for profiling */
+ puts("Warning: -p option is for internal testing use only!");
+ stop_scheduler = 1;
+ fg = 1;
+ break;
+
+ case 't' : /* Test the cupsd.conf file... */
+ TestConfigFile = 1;
+ fg = 1;
+ 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 (3);
}
}
+
+#ifdef __APPLE__
+ /*
+ * Since CoreFoundation has an overly-agressive check for whether a
+ * process has forked but not exec'd (whether CF has been called or
+ * not...), we now have to exec ourselves with the "-f" option to
+ * eliminate their bogus warning messages.
+ */
+
+ execlp(argv[0], argv[0], "-C", ConfigurationFile, (char *)0);
+ exit(errno);
+#endif /* __APPLE__ */
}
if (fg < 1)
getrlimit(RLIMIT_NOFILE, &limit);
- for (i = 0; i < limit.rlim_cur; i ++)
+ for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
close(i);
+
+ /*
+ * Redirect stdin/out/err to /dev/null...
+ */
+
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_WRONLY);
+ open("/dev/null", O_WRONLY);
#endif /* DEBUG */
}
getrlimit(RLIMIT_NOFILE, &limit);
- if (limit.rlim_max > CUPS_MAX_FDS)
- MaxFDs = CUPS_MAX_FDS;
+#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
+ if (limit.rlim_max > FD_SETSIZE)
+ MaxFDs = FD_SETSIZE;
+ else
+#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
+#ifdef RLIM_INFINITY
+ if (limit.rlim_max == RLIM_INFINITY)
+ MaxFDs = 16384;
else
+#endif /* RLIM_INFINITY */
MaxFDs = limit.rlim_max;
limit.rlim_cur = MaxFDs;
setrlimit(RLIMIT_NOFILE, &limit);
+ cupsdStartSelect();
+
/*
- * Allocate memory for the input and output sets...
+ * Read configuration...
*/
- SetSize = (MaxFDs + 31) / 8 + 4;
- if (SetSize < sizeof(fd_set))
- SetSize = sizeof(fd_set);
+ if (!cupsdReadConfiguration())
+ {
+ if (TestConfigFile)
+ printf("%s contains errors\n", ConfigurationFile);
+ else
+ syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
+ ConfigurationFile);
+ return (1);
+ }
+ else if (TestConfigFile)
+ {
+ printf("%s is OK\n", ConfigurationFile);
+ return (0);
+ }
+
+ if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
+ {
+ /*
+ * Clean out the temporary directory...
+ */
- InputSet = (fd_set *)calloc(1, SetSize);
- OutputSet = (fd_set *)calloc(1, SetSize);
- input = (fd_set *)calloc(1, SetSize);
- output = (fd_set *)calloc(1, SetSize);
+ cups_dir_t *dir; /* Temporary directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char tempfile[1024]; /* Temporary filename */
- if (InputSet == NULL || OutputSet == NULL || input == NULL || output == NULL)
+
+ if ((dir = cupsDirOpen(TempDir)) != NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Cleaning out old temporary files in \"%s\"...", TempDir);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->filename);
+
+ if (cupsdRemoveFile(tempfile))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to remove temporary file \"%s\" - %s",
+ tempfile, strerror(errno));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed temporary file \"%s\"...",
+ tempfile);
+ }
+
+ cupsDirClose(dir);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open temporary directory \"%s\" - %s",
+ TempDir, strerror(errno));
+ }
+
+#if HAVE_LAUNCHD
+ if (Launchd)
{
- syslog(LOG_LPR, "Unable to allocate memory for select() sets - exiting!");
- return (1);
+ /*
+ * If we were started by launchd get the listen sockets file descriptors...
+ */
+
+ launchd_checkin();
}
+#endif /* HAVE_LAUNCHD */
+#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
/*
- * Read configuration...
+ * Load Print Service quota enforcement library (X Server only)
*/
- if (!cupsdReadConfiguration())
+ PSQLibRef = dlopen(PSQLibPath, RTLD_LAZY);
+
+ if (PSQLibRef)
+ PSQUpdateQuotaProc = dlsym(PSQLibRef, PSQLibFuncName);
+#endif /* __APPLE__ && HAVE_DLFCN_H */
+
+#ifdef HAVE_GSSAPI
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (krb5_init_context != NULL)
+# endif /* __APPLE__ */
+
+ /*
+ * Setup a Kerberos context for the scheduler to use...
+ */
+
+ if (krb5_init_context(&KerberosContext))
{
- syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
- ConfigurationFile);
- return (1);
+ KerberosContext = NULL;
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context");
}
+#endif /* HAVE_GSSAPI */
+
+ /*
+ * 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 */
* we are up and running...
*/
+#ifdef __APPLE__
+ if (!fg || run_as_child)
+#else
if (!fg)
+#endif /* __APPLE__ */
{
/*
* Send a signal to the parent process, but only if the parent is
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 we were started by launchd get the listen sockets file descriptors...
+ */
+
+ launchd_checkin();
+ }
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Startup the server...
+ */
+
+ cupsdStartServer();
}
}
/*
- * Check for available input or ready output. If select() returns
- * 0 or -1, something bad happened and we should exit immediately.
+ * Check for available input or ready output. If cupsdDoSelect()
+ * returns 0 or -1, something bad happened and we should exit
+ * immediately.
*
* Note that we at least have one listening socket open at all
* times.
*/
- memcpy(input, InputSet, SetSize);
- memcpy(output, OutputSet, SetSize);
+ timeout = select_timeout(fds);
- timeout.tv_sec = select_timeout(fds);
- timeout.tv_usec = 0;
+#if HAVE_LAUNCHD
+ /*
+ * If no other work is scheduled and we're being controlled by
+ * launchd then timeout after 'LaunchdTimeout' seconds of
+ * inactivity...
+ */
- if (timeout.tv_sec < 86400) /* Only use timeout for < 1 day */
- fds = select(MaxFDs, input, output, NULL, &timeout);
+ if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
+ !cupsArrayCount(ActiveJobs) &&
+ (!Browsing ||
+ (!BrowseRemoteProtocols &&
+ (!NumBrowsers || !BrowseLocalProtocols ||
+ cupsArrayCount(Printers) == 0))))
+ {
+ timeout = LaunchdTimeout;
+ launchd_idle_exit = 1;
+ }
else
- fds = select(MaxFDs, input, output, NULL, NULL);
+ launchd_idle_exit = 0;
+#endif /* HAVE_LAUNCHD */
- if (fds < 0)
+ if ((fds = cupsdDoSelect(timeout)) < 0)
{
- char s[16384], /* String buffer */
- *sptr; /* Pointer into buffer */
- int slen; /* Length of string buffer */
-
-
/*
* Got an error from select!
*/
- if (errno == EINTR) /* Just interrupted by a signal */
+#ifdef HAVE_DNSSD
+ cupsd_printer_t *p; /* Current printer */
+#endif /* HAVE_DNSSD */
+
+
+ if (errno == EINTR) /* Just interrupted by a signal */
continue;
/*
* Log all sorts of debug info to help track down the problem.
*/
- cupsdLogMessage(CUPSD_LOG_EMERG, "select() failed - %s!",
+ cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
strerror(errno));
- strcpy(s, "InputSet =");
- slen = 10;
- sptr = s + 10;
-
- for (i = 0; i < MaxFDs; i ++)
- if (FD_ISSET(i, InputSet))
- {
- snprintf(sptr, sizeof(s) - slen, " %d", i);
- slen += strlen(sptr);
- sptr += strlen(sptr);
- }
-
- cupsdLogMessage(CUPSD_LOG_EMERG, s);
-
- strcpy(s, "OutputSet =");
- slen = 11;
- sptr = s + 11;
-
- for (i = 0; i < MaxFDs; i ++)
- if (FD_ISSET(i, OutputSet))
- {
- snprintf(sptr, sizeof(s) - slen, " %d", i);
- slen += strlen(sptr);
- sptr += strlen(sptr);
- }
-
- 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))
job->status_buffer ? job->status_buffer->fd : -1,
job->print_pipes[0], job->print_pipes[1],
job->back_pipes[0], job->back_pipes[1]);
+
+#ifdef HAVE_DNSSD
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] %d", p->name,
+ p->dnssd_ipp_fd);
+#endif /* HAVE_DNSSD */
+
break;
}
current_time = time(NULL);
+#ifndef __APPLE__
/*
- * Check for status info from job filters...
+ * Update the network interfaces once a minute...
*/
- for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
- job;
- job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
- if (job->status_buffer && FD_ISSET(job->status_buffer->fd, input))
- {
- /*
- * Clear the input bit to avoid updating the next job
- * using the same status pipe file descriptor...
- */
-
- FD_CLR(job->status_buffer->fd, input);
-
- /*
- * Read any status messages from the filters...
- */
-
- cupsdUpdateJob(job);
- }
+ if ((current_time - netif_time) >= 60)
+ {
+ netif_time = current_time;
+ NetIFUpdate = 1;
+ }
+#endif /* !__APPLE__ */
+#if HAVE_LAUNCHD
/*
- * Update CGI messages as needed...
+ * If no other work was scheduled and we're being controlled by launchd
+ * then timeout after 'LaunchdTimeout' seconds of inactivity...
*/
- if (CGIPipes[0] >= 0 && FD_ISSET(CGIPipes[0], input))
- cupsdUpdateCGI();
+ 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 */
/*
- * Update notifier messages as needed...
+ * Resume listening for new connections as needed...
*/
- if (NotifierPipes[0] >= 0 && FD_ISSET(NotifierPipes[0], input))
- cupsdUpdateNotifierStatus();
+ if (ListeningPaused && ListeningPaused <= current_time &&
+ cupsArrayCount(Clients) < MaxClients)
+ cupsdResumeListening();
/*
- * 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 && BrowseRemoteProtocols)
+ if (Browsing)
{
- if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, input))
- cupsdUpdateCUPSBrowse();
-
- if (PollPipe >= 0 && FD_ISSET(PollPipe, input))
- cupsdUpdatePolling();
-
#ifdef HAVE_LIBSLP
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
+ if ((BrowseRemoteProtocols & BROWSE_SLP) &&
BrowseSLPRefresh <= current_time)
cupsdUpdateSLPBrowse();
#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if ((BrowseRemoteProtocols & BROWSE_LDAP) &&
+ BrowseLDAPRefresh <= current_time)
+ cupsdUpdateLDAPBrowse();
+#endif /* HAVE_LDAP */
}
if (Browsing && BrowseLocalProtocols && current_time > browse_time)
}
/*
- * Check for new connections on the "listen" sockets...
+ * Update the root certificate once every 5 minutes if we have client
+ * connections...
*/
- for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
- if (lis->fd >= 0 && FD_ISSET(lis->fd, input))
- {
- FD_CLR(lis->fd, input);
- cupsdAcceptClient(lis);
- }
-
- /*
- * Check for new data on the client sockets...
- */
-
- for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
+ !RunUser && cupsArrayCount(Clients))
{
/*
- * Process the input buffer...
+ * Update the root certificate...
*/
- if (FD_ISSET(con->http.fd, input) || con->http.used)
- {
- FD_CLR(con->http.fd, input);
-
- if (!cupsdReadClient(con))
- {
- if (con->pipe_pid)
- FD_CLR(con->file, input);
+ cupsdDeleteCert(0);
+ cupsdAddCert(0, "root");
+ }
- con --;
- continue;
- }
- }
+ /*
+ * Check for new data on the client sockets...
+ */
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ {
/*
- * Write data as needed...
+ * Process pending data in the input buffer...
*/
- if (con->pipe_pid && FD_ISSET(con->file, input))
- {
- /*
- * Keep track of pending input from the file/pipe separately
- * so that we don't needlessly spin on select() when the web
- * client is not ready to receive data...
- */
-
- FD_CLR(con->file, input);
- con->file_ready = 1;
-
-#ifdef DEBUG
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "main: Data ready file %d!",
- con->file);
-#endif /* DEBUG */
-
- if (!FD_ISSET(con->http.fd, output))
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "main: Removing fd %d from InputSet...", con->file);
- FD_CLR(con->file, input);
- FD_CLR(con->file, InputSet);
- }
- }
-
- if (FD_ISSET(con->http.fd, output))
+ if (con->http.used)
{
- FD_CLR(con->http.fd, output);
-
- if (!con->pipe_pid || con->file_ready)
- if (!cupsdWriteClient(con))
- {
- con --;
- continue;
- }
+ cupsdReadClient(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);
- mallinfo_time = current_time;
- }
#endif /* HAVE_MALLINFO */
- /*
- * Update the root certificate once every 5 minutes...
- */
-
- if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
- !RunUser)
- {
- /*
- * Update the root certificate...
- */
+ 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);
- cupsdDeleteCert(0);
- cupsdAddCert(0, "root");
+ mallinfo_time = current_time;
}
/*
* accumulated. Don't send these more than once a second...
*/
- if (LastEvent && (time(NULL) - LastEventTime) > 1)
+ if (LastEvent)
{
#ifdef HAVE_NOTIFY_POST
- if (LastEvent & CUPSD_EVENT_PRINTER_CHANGED)
+ if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
+ CUPSD_EVENT_PRINTER_DELETED |
+ CUPSD_EVENT_PRINTER_MODIFIED))
{
- cupsdLogMessage(CUPSD_LOG_DEBUG,
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
"notify_post(\"com.apple.printerListChange\")");
notify_post("com.apple.printerListChange");
}
if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG,
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
"notify_post(\"com.apple.printerHistoryChange\")");
notify_post("com.apple.printerHistoryChange");
}
CUPSD_EVENT_JOB_CONFIG_CHANGED |
CUPSD_EVENT_JOB_PROGRESS))
{
- cupsdLogMessage(CUPSD_LOG_DEBUG,
+ 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...
+ * Reset the accumulated events...
*/
- LastEventTime = time(NULL);
LastEvent = CUPSD_EVENT_NONE;
}
}
"Scheduler shutting down due to program error.");
/*
- * Close all network clients and stop all jobs...
+ * Close all network clients...
*/
cupsdStopServer();
- cupsdStopAllJobs();
+#ifdef HAVE_LAUNCHD
+ /*
+ * Update the launchd KeepAlive file as needed...
+ */
+
+ if (Launchd)
+ launchd_checkout();
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Stop all jobs...
+ */
+
+ cupsdFreeAllJobs();
+
+#ifdef __APPLE__
+ /*
+ * Stop monitoring system event monitoring...
+ */
+
+ cupsdStopSystemMonitor();
+#endif /* __APPLE__ */
+
+#ifdef HAVE_GSSAPI
+ /*
+ * Free the scheduler's Kerberos context...
+ */
+
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (krb5_init_context != NULL)
+# endif /* __APPLE__ */
+ if (KerberosContext)
+ krb5_free_context(KerberosContext);
+#endif /* HAVE_GSSAPI */
+
+#ifdef __APPLE__
+#ifdef HAVE_DLFCN_H
+ /*
+ * Unload Print Service quota enforcement library (X Server only)
+ */
+
+ PSQUpdateQuotaProc = NULL;
+ if (PSQLibRef)
+ {
+ dlclose(PSQLibRef);
+ PSQLibRef = NULL;
+ }
+#endif /* HAVE_DLFCN_H */
+#endif /* __APPLE__ */
#ifdef __sgi
/*
unlink("/var/spool/lp/SCHEDLOCK");
#endif /* __sgi */
- /*
- * Free memory used by FD sets and return...
- */
-
- free(InputSet);
- free(OutputSet);
- free(input);
- free(output);
+ cupsdStopSelect();
return (!stop_scheduler);
}
*/
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.
*/
{
if (s && *s)
{
- free(*s);
+ _cupsStrFree(*s);
*s = NULL;
}
}
}
-/*
- * '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.
*/
return;
if (*s)
- free(*s);
+ _cupsStrFree(*s);
if (v)
- *s = strdup(v);
+ *s = _cupsStrAlloc(v);
else
*s = NULL;
}
vsnprintf(v, sizeof(v), f, ap);
va_end(ap);
- *s = strdup(v);
+ *s = _cupsStrAlloc(v);
}
else
*s = NULL;
if (olds)
- free(olds);
+ _cupsStrFree(olds);
+}
+
+
+#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 */
+ tmp; /* Launch data */
+ cupsd_listener_t *lis; /* Listeners array */
+ http_addr_t addr; /* Address variable */
+ socklen_t addrlen; /* Length of address */
+ int fd; /* File descriptor */
+ char s[256]; /* String addresss */
+
+
+ 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 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)
+ {
+ count = launch_data_array_get_count(ld_array);
+
+ for (i = 0; i < count; i ++)
+ {
+ /*
+ * Get the launchd file descriptor and address...
+ */
+
+ tmp = launch_data_array_get_index(ld_array, i);
+ fd = launch_data_get_fd(tmp);
+ addrlen = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to get local address - %s",
+ strerror(errno));
+ continue;
+ }
+
+ /*
+ * Try to match the launchd socket address to one of the listeners...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (httpAddrEqual(&lis->address, &addr))
+ break;
+
+ /*
+ * Add a new listener If there's no match...
+ */
+
+ if (lis)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_checkin: Matched existing listener %s with fd %d...",
+ httpAddrString(&(lis->address), s, sizeof(s)), fd);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_checkin: Adding new listener %s with fd %d...",
+ httpAddrString(&addr, s, sizeof(s)), fd);
+
+ 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);
+
+ memcpy(&lis->address, &addr, sizeof(lis->address));
+ }
+
+ lis->fd = fd;
+
+# ifdef HAVE_SSL
+ portnum = 0;
+
+# ifdef AF_INET6
+ if (lis->address.addr.sa_family == AF_INET6)
+ portnum = ntohs(lis->address.ipv6.sin6_port);
+ else
+# endif /* AF_INET6 */
+ if (lis->address.addr.sa_family == AF_INET)
+ portnum = ntohs(lis->address.ipv4.sin_port);
+
+ if (portnum == 443)
+ lis->encryption = HTTP_ENCRYPT_ALWAYS;
+# endif /* HAVE_SSL */
+ }
+ }
+
+ launch_data_free(ld_msg);
+ launch_data_free(ld_resp);
}
+/*
+ * 'launchd_checkout()' - Update the launchd KeepAlive file as needed.
+ */
+
+static void
+launchd_checkout(void)
+{
+ int fd; /* File descriptor */
+
+
+ /*
+ * Create or remove the launchd KeepAlive file based on whether
+ * there are active jobs, polling, browsing for remote printers or
+ * shared printers to advertise...
+ */
+
+ if ((cupsArrayCount(ActiveJobs) || NumPolled ||
+ (Browsing &&
+ (BrowseRemoteProtocols ||
+ (BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers))))))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Creating launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+
+ if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
+ close(fd);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Removing launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+
+ unlink(CUPS_KEEPALIVE);
+ }
+}
+#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...
+ * Ignore SIGTERM errors - that comes when a job is canceled...
*/
+ 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);
/*
- * If select has been active in the last second (fds != 0) or we have
+ * If select has been active in the last second (fds > 0) or we have
* many resources in use then don't bother trying to optimize the
* timeout, just make it 1 second.
*/
- if (fds || NumClients > 50)
- return (1);
-
- /*
- * If we had a recent event notification, timeout in 1 second...
- */
-
- if (LastEvent)
+ if (fds > 0 || cupsArrayCount(Clients) > 50)
return (1);
/*
timeout = now + 86400; /* 86400 == 1 day */
why = "do nothing";
+ /*
+ * Check whether we are accepting new connections...
+ */
+
+ if (ListeningPaused > 0 && cupsArrayCount(Clients) < MaxClients &&
+ ListeningPaused < timeout)
+ {
+ if (ListeningPaused <= now)
+ timeout = now;
+ else
+ timeout = ListeningPaused;
+
+ why = "resume listening";
+ }
+
/*
* 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 */
- if (BrowseLocalProtocols & BROWSE_CUPS)
+#ifdef HAVE_LDAP
+ if ((BrowseLocalProtocols & BROWSE_LDAP) && (BrowseLDAPRefresh < timeout))
+ {
+ timeout = BrowseLDAPRefresh;
+ why = "update LDAP browsing";
+ }
+#endif /* HAVE_LDAP */
+
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && NumBrowsers)
{
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
why = "browse timeout a printer";
}
}
- else if (!(p->type & CUPS_PRINTER_IMPLICIT))
+ else if (p->shared && !(p->type & CUPS_PRINTER_IMPLICIT))
{
if (BrowseInterval && (p->browse_time + BrowseInterval) < timeout)
{
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";
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";
* Log and return the timeout value...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: %ld seconds to %s",
- timeout, why);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout(%d): %ld seconds to %s",
+ fds, timeout, why);
return (timeout);
}
*/
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 4997 2006-01-26 21:43:54Z mike $".
+ * End of "$Id: main.c 6914 2007-09-05 21:05:04Z mike $".
*/