/*
- * "$Id: main.c 177 2006-06-21 00:20:03Z jlovell $"
+ * "$Id: main.c 6564 2007-06-18 23:40:38Z mike $"
*
* Scheduler main loop for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * 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
* 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.
+ * 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.
#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 <notify.h>
#endif /* HAVE_NOTIFY_H */
+#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
+# include <dlfcn.h>
+#endif /* __APPLE__ && HAVE_DLFCN_H */
+
/*
* Local functions...
*/
#ifdef HAVE_LAUNCHD
-static void launchd_checkin(void);
-static void launchd_reload(void);
-static int launchd_sync_conf(void);
+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);
+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 */
/*
char *opt; /* Option character */
int fg; /* Run in the foreground */
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 */
activity, /* Client activity timer */
browse_time, /* Next browse send time */
senddoc_time, /* Send-Document time */
- expire_time; /* Subscription expire time */
- time_t mallinfo_time; /* Malloc information time */
+ 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 */
- struct timeval timeout; /* select() timeout */
+ long timeout; /* Timeout for cupsdDoSelect() */
struct rlimit limit; /* Runtime limit */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
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 ++)
getrlimit(RLIMIT_NOFILE, &limit);
- for (i = 0; i < limit.rlim_cur; i ++)
+ for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
close(i);
#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);
- /*
- * Allocate memory for the input and output sets...
- */
-
- SetSize = (MaxFDs + 31) / 8 + 4;
- if (SetSize < sizeof(fd_set))
- SetSize = sizeof(fd_set);
-
- InputSet = (fd_set *)calloc(1, SetSize);
- OutputSet = (fd_set *)calloc(1, SetSize);
- input = (fd_set *)calloc(1, SetSize);
- output = (fd_set *)calloc(1, SetSize);
-
- if (InputSet == NULL || OutputSet == NULL || input == NULL || output == NULL)
- {
- syslog(LOG_LPR, "Unable to allocate memory for select() sets - exiting!");
- return (1);
- }
+ cupsdStartSelect();
/*
* Read configuration...
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 we were started by launchd get the listen sockets 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 */
+#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
+ /*
+ * Load Print Service quota enforcement library (X Server only)
+ */
+
+ PSQLibRef = dlopen(PSQLibPath, RTLD_LAZY);
+
+ if (PSQLibRef)
+ PSQUpdateQuotaProc = dlsym(PSQLibRef, PSQLibFuncName);
+#endif /* __APPLE__ && HAVE_DLFCN_H */
+
/*
* Startup the server...
*/
#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;
- }
+ /*
+ * If we were started by launchd get the listen sockets file descriptors...
+ */
launchd_checkin();
}
}
/*
- * 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.tv_sec = select_timeout(fds);
- timeout.tv_usec = 0;
+ timeout = select_timeout(fds);
#if HAVE_LAUNCHD
/*
* If no other work is scheduled and we're being controlled by
- * launchd(8) then timeout after 'LaunchdTimeout' seconds of
+ * launchd then timeout after 'LaunchdTimeout' seconds of
* inactivity...
*/
- if (timeout.tv_sec == 86400 && Launchd && LaunchdTimeout &&
- (!Browsing || !(BrowseLocalProtocols & BROWSE_DNSSD) ||
- cupsArrayCount(Printers) == 0))
+ if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
+ (!Browsing ||
+ (!BrowseRemoteProtocols &&
+ (!NumBrowsers || !BrowseLocalProtocols ||
+ cupsArrayCount(Printers) == 0))))
{
- timeout.tv_sec = LaunchdTimeout;
+ timeout = 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)
+ 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", 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", s);
-
for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
con;
i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
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;
}
#if HAVE_LAUNCHD
/*
- * If no other work was scheduled and we're being controlled by launchd(8)
+ * If no other work was scheduled and we're being controlled by launchd
* then timeout after 'LaunchdTimeout' seconds of inactivity...
*/
}
#endif /* HAVE_LAUNCHD */
- /*
- * Check for status info from job filters...
- */
-
- 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);
- }
-
- /*
- * Update CGI messages as needed...
- */
-
- 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...
- */
-
- if (NotifierPipes[0] >= 0 && FD_ISSET(NotifierPipes[0], input))
- cupsdUpdateNotifierStatus();
-
/*
* Expire subscriptions and unload completed jobs as needed...
*/
* 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 ((BrowseRemoteProtocols & BROWSE_SLP) &&
BrowseSLPRefresh <= current_time)
}
/*
- * Check for new connections on the "listen" sockets...
+ * Update the root certificate once every 5 minutes if we have client
+ * connections...
*/
- 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);
- cupsdAcceptClient(lis);
- }
+ if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
+ !RunUser && cupsArrayCount(Clients))
+ {
+ /*
+ * Update the root certificate...
+ */
+
+ cupsdDeleteCert(0);
+ cupsdAddCert(0, "root");
+ }
/*
* Check for new data on the client sockets...
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 (fd >= 0)
- FD_CLR(fd, input);
-
- continue;
- }
- }
-
- /*
- * 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))
- continue;
+ cupsdReadClient(con);
+ continue;
}
/*
mallinfo_time = current_time;
}
- /*
- * Update the root certificate once every 5 minutes if we have client
- * connections...
- */
-
- if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
- !RunUser && cupsArrayCount(Clients))
- {
- /*
- * Update the root certificate...
- */
-
- 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...
#ifdef HAVE_LAUNCHD
/*
- * Update the launchd config file as needed...
+ * Update the launchd KeepAlive file as needed...
*/
- launchd_sync_conf();
+ if (Launchd)
+ launchd_checkout();
#endif /* HAVE_LAUNCHD */
+#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
/*
* Remove the fake IRIX lpsched lock file, but only if the existing
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);
}
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());
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);
+ count = launch_data_array_get_count(ld_array);
for (i = 0; i < count; i ++)
{
/*
- * Copy the current address and log it...
+ * Get the launchd file descriptor and address...
*/
- if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+ 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 allocate listener - %s.",
- strerror(errno));
- exit(EXIT_FAILURE);
+ "launchd_checkin: Unable to get local address - %s",
+ strerror(errno));
+ continue;
}
- cupsArrayAdd(Listeners, lis);
+ /*
+ * Try to match the launchd socket address to one of the listeners...
+ */
- tmp = launch_data_array_get_index(ld_array, i);
- lis->fd = launch_data_get_fd(tmp);
- addrlen = sizeof(lis->address);
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (httpAddrEqual(&lis->address, &addr))
+ break;
- if (getsockname(lis->fd, (struct sockaddr *)&(lis->address), &addrlen))
+ /*
+ * Add a new listener If there's no match...
+ */
+
+ if (lis)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "launchd_checkin: Unable to get local address - %s",
- strerror(errno));
+ 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 (addr.addr.sa_family == AF_INET6)
- portnum = ntohs(addr.ipv6.sin6_port);
+ if (lis->address.addr.sa_family == AF_INET6)
+ portnum = ntohs(lis->address.ipv6.sin6_port);
else
# endif /* AF_INET6 */
- if (addr.addr.sa_family == AF_INET)
- portnum = ntohs(addr.ipv4.sin_port);
+ if (lis->address.addr.sa_family == AF_INET)
+ portnum = ntohs(lis->address.ipv4.sin_port);
if (portnum == 443)
lis->encryption = HTTP_ENCRYPT_ALWAYS;
}
}
- /*
- * 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)
- {
- if ((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 an empty array!");
- }
- 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.
+ * 'launchd_checkout()' - Update the launchd KeepAlive file as needed.
*/
static void
-launchd_reload(void)
+launchd_checkout(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.
- */
+ int fd; /* File descriptor */
- /*
- * 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...
+ * Create or remove the launchd KeepAlive file based on whether
+ * there are active jobs, polling, browsing for remote printers or
+ * shared printers to advertise...
*/
- 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)
+ if ((cupsArrayCount(ActiveJobs) || NumPolled ||
+ (Browsing &&
+ (BrowseRemoteProtocols ||
+ (BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers))))))
{
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...
- */
+ "Creating launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
- if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks)) != NULL)
+ if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
+ close(fd);
+ }
+ else
{
- 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);
- }
+ "Removing launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
- CFRelease(cupsd_dict);
+ unlink(CUPS_KEEPALIVE);
}
-
- /*
- * Let the caller know we updated the file...
- */
-
- return (1);
}
#endif /* HAVE_LAUNCHD */
#endif /* HAVE_WAITPID */
{
/*
- * 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));
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 || cupsArrayCount(Clients) > 50)
+ if (fds > 0 || cupsArrayCount(Clients) > 50)
return (1);
/*
}
#endif /* HAVE_LDAP */
- if (BrowseLocalProtocols & BROWSE_CUPS)
+ 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)
{
* 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);
}
/*
- * End of "$Id: main.c 177 2006-06-21 00:20:03Z jlovell $".
+ * End of "$Id: main.c 6564 2007-06-18 23:40:38Z mike $".
*/