/*
- * "$Id: main.c 6365 2007-03-19 20:56:57Z mike $"
+ * "$Id: main.c 6914 2007-09-05 21:05:04Z mike $"
*
* Scheduler main loop for the Common UNIX Printing System (CUPS).
*
+ * 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:
*
* launchd_checkin() - Check-in with launchd and collect the
* listening fds.
* launchd_checkout() - Check-out with launchd.
- * launchd_create_dict() - Create a dictionary representing the launchd
- * config file org.cups.cupsd.plist.
- * launchd_sync_conf() - Re-write the launchd 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 <sys/resource.h>
#include <syslog.h>
#include <grp.h>
+#include <cups/dir.h>
#ifdef HAVE_LAUNCH_H
# include <launch.h>
#ifdef HAVE_LAUNCHD
static void launchd_checkin(void);
static void launchd_checkout(void);
-static CFDictionaryRef launchd_create_dict(void);
-static int launchd_sync_conf(void);
#endif /* HAVE_LAUNCHD */
static void parent_handler(int sig);
static void process_children(void);
static int stop_scheduler = 0;
/* Should the scheduler stop? */
-#ifdef HAVE_LAUNCHD
-static CFURLRef launchd_conf_url = NULL;
- /* org.cups.cupsd.plist url */
-static CFDictionaryRef launchd_conf_dict = NULL;
- /* org.cups.cupsd.plist dict */
-#endif /* HAVE_LAUNCHD */
-
#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
static const char *PSQLibPath = "/usr/lib/libPrintServiceQuota.dylib";
static const char *PSQLibFuncName = "PSQUpdateQuota";
#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 ++)
fg = 1;
break;
+ case 't' : /* Test the cupsd.conf file... */
+ TestConfigFile = 1;
+ fg = 1;
+ break;
+
default : /* Unknown option */
_cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
"aborting!\n"), *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 */
}
if (!cupsdReadConfiguration())
{
- syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
- ConfigurationFile);
+ 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 HAVE_LAUNCHD
- if (Launchd)
+ if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
{
/*
- * If we were started by launchd, make sure the cupsd plist file contains
- * the same listeners as cupsd.conf.
+ * Clean out the temporary directory...
*/
- launchd_sync_conf();
+ cups_dir_t *dir; /* Temporary directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char tempfile[1024]; /* Temporary filename */
+
+
+ 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)
+ {
/*
- * Then get the file descriptors from launchd...
+ * If we were started by launchd get the listen sockets file descriptors...
*/
launchd_checkin();
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))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context");
+#endif /* HAVE_GSSAPI */
+
/*
* Startup the server...
*/
#if HAVE_LAUNCHD
if (Launchd)
{
- launchd_sync_conf();
+ /*
+ * If we were started by launchd get the listen sockets file descriptors...
+ */
+
launchd_checkin();
}
#endif /* HAVE_LAUNCHD */
*/
if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
+ !cupsArrayCount(ActiveJobs) &&
(!Browsing ||
(!BrowseRemoteProtocols &&
(!NumBrowsers || !BrowseLocalProtocols ||
}
#endif /* HAVE_LAUNCHD */
+ /*
+ * Resume listening for new connections as needed...
+ */
+
+ if (ListeningPaused && ListeningPaused <= current_time &&
+ cupsArrayCount(Clients) < MaxClients)
+ cupsdResumeListening();
+
/*
* Expire subscriptions and unload completed jobs as needed...
*/
"Scheduler shutting down due to program error.");
/*
- * Close all network clients and stop all jobs...
+ * Close all network clients...
*/
cupsdStopServer();
+#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_LAUNCHD
+#ifdef HAVE_GSSAPI
/*
- * Update the launchd config file as needed...
+ * Free the scheduler's Kerberos context...
*/
- if (Launchd)
- {
- launchd_checkout();
- launchd_sync_conf();
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
- if (launchd_conf_url)
- CFRelease(launchd_conf_url);
+ if (krb5_init_context != NULL)
+# endif /* __APPLE__ */
+ krb5_free_context(KerberosContext);
+#endif /* HAVE_GSSAPI */
- if (launchd_conf_dict)
- CFRelease(launchd_conf_dict);
+#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_LAUNCHD */
+#endif /* HAVE_DLFCN_H */
+#endif /* __APPLE__ */
#ifdef __sgi
/*
}
}
- /*
- * 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);
}
unlink(CUPS_KEEPALIVE);
}
}
-
-
-/*
- * 'launchd_create_dict()' - Create a dictionary representing the launchd
- * config file org.cups.cupsd.plist.
- */
-
-static CFDictionaryRef /* O - CFDictionary */
-launchd_create_dict(void)
-{
- int portnum; /* Port number */
- bool runatload; /* Run at load? */
- CFMutableDictionaryRef cupsd_dict, /* org.cups.cupsd.plist dictionary */
- keepalive, /* KeepAlive dictionary */
- pathstate, /* PathState dictionary */
- sockets, /* Sockets dictionary */
- listener; /* Listener dictionary */
- CFMutableArrayRef array; /* Array */
- CFNumberRef socket_mode; /* Domain socket mode bits */
- CFStringRef socket_path; /* Domain socket path */
- CFTypeRef value; /* CF values */
- cupsd_listener_t *lis; /* Current listening socket */
- struct servent *service; /* Services data base entry */
- char temp[1024]; /* Temporary buffer for value */
-
-
- if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks)) == NULL)
- return (NULL);
-
- CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL),
- CFSTR("org.cups.cupsd"));
- CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_ONDEMAND),
- kCFBooleanTrue);
-
- /*
- * Use run-at-load and/or KeepAlive if there are active jobs, polling or
- * shared printers to advertise...
- */
-
- if ((keepalive = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks)) != NULL)
- {
- if ((pathstate = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks)) != NULL)
- {
- CFDictionaryAddValue(pathstate, CFSTR(CUPS_KEEPALIVE), kCFBooleanTrue);
- CFDictionaryAddValue(keepalive, CFSTR(LAUNCH_JOBKEY_PATHSTATE),
- pathstate);
- }
-
- CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_KEEPALIVE),
- keepalive);
- }
-
- runatload = (cupsArrayCount(ActiveJobs) || NumPolled ||
- (Browsing && BrowseLocalProtocols &&
- NumBrowsers && cupsArrayCount(Printers))) ? true : false;
-
- CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
- runatload ? kCFBooleanTrue : kCFBooleanFalse);
- CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SERVICEIPC),
- kCFBooleanTrue);
-
- 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);
- }
-
- return (cupsd_dict);
-}
-
-
-/*
- * 'launchd_sync_conf()' - Rewrite the launchd config file
- * org.cups.cupsd.plist based on cupsd.conf.
- */
-
-static int /* O - 1 if the file was updated */
-launchd_sync_conf(void)
-{
- SInt32 errorCode; /* Error code */
- CFDataRef resourceData; /* XML property list */
- CFDictionaryRef cupsd_dict; /* New org.cups.cupsd.plist dict */
-
-
- /*
- * If needed reconstitute the existing org.cups.cupsd.plist...
- */
-
- if (!launchd_conf_url &&
- !(launchd_conf_url = CFURLCreateFromFileSystemRepresentation(
- kCFAllocatorDefault,
- (const unsigned char *)LaunchdConf,
- strlen(LaunchdConf), false)))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
- "Unable to create file URL for \"%s\"\n", LaunchdConf);
- return (0);
- }
-
- if (!launchd_conf_dict)
- {
- if (CFURLCreateDataAndPropertiesFromResource(NULL, launchd_conf_url,
- &resourceData, NULL, NULL, &errorCode))
- {
- launchd_conf_dict = CFPropertyListCreateFromXMLData(NULL, resourceData,
- kCFPropertyListImmutable, NULL);
- CFRelease(resourceData);
- }
-
- if (!launchd_conf_dict)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
- "Unable to create dictionary for \"%s\"\n", LaunchdConf);
- }
- }
-
- /*
- * Create a new org.cups.cupsd.plist dictionary...
- */
-
- if ((cupsd_dict = launchd_create_dict()) == NULL)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
- "Unable to create file URL for \"%s\"\n", LaunchdConf);
- return (0);
- }
-
- /*
- * If the dictionaries are different write a new org.cups.cupsd.plist...
- */
-
- if (!CFEqual(cupsd_dict, launchd_conf_dict))
- {
- if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
- cupsd_dict)))
- {
- if (CFURLWriteDataAndPropertiesToResource(launchd_conf_url, resourceData,
- NULL, &errorCode))
- {
- /*
- * The new cupsd dictionary becomes the on-disk launchd dictionary...
- */
-
- if (launchd_conf_dict)
- CFRelease(launchd_conf_dict);
-
- launchd_conf_dict = cupsd_dict;
- }
- else
- {
- cupsdLogMessage(CUPSD_LOG_WARN,
- "launchd_sync_conf: "
- "CFURLWriteDataAndPropertiesToResource(\"%s\") "
- "failed: %d\n",
- LaunchdConf, (int)errorCode);
-
- CFRelease(cupsd_dict);
- }
-
- CFRelease(resourceData);
- }
-
- /*
- * Let the caller know we updated the file...
- */
-
- return (1);
- }
-
- return (0);
-}
#endif /* HAVE_LAUNCHD */
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...
*/
/*
- * End of "$Id: main.c 6365 2007-03-19 20:56:57Z mike $".
+ * End of "$Id: main.c 6914 2007-09-05 21:05:04Z mike $".
*/