Index: main.c =================================================================== --- main.c (revision 6073) +++ main.c (working copy) @@ -32,9 +32,11 @@ * cupsdSetStringf() - Set a formatted string value. * launchd_checkin() - Check-in with launchd and collect the * listening fds. + * launchd_create_dict() - Create a dictionary representing the launchd + * config file org.cups.cupsd.plist. * 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 + * 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... @@ -76,6 +78,8 @@ #ifdef HAVE_LAUNCHD static void launchd_checkin(void); +static CFDictionaryRef + launchd_create_dict(void); static void launchd_reload(void); static int launchd_sync_conf(void); #endif /* HAVE_LAUNCHD */ @@ -101,7 +105,12 @@ static int dead_children = 0; /* Dead children? */ 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 */ + /* * 'main()' - Main entry for the CUPS scheduler. */ @@ -656,7 +665,7 @@ #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... */ @@ -761,7 +770,7 @@ #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... */ @@ -1082,6 +1091,12 @@ */ launchd_sync_conf(); + + if (launchd_conf_url) + CFRelease(launchd_conf_url); + + if (launchd_conf_dict) + CFRelease(launchd_conf_dict); #endif /* HAVE_LAUNCHD */ #ifdef __sgi @@ -1449,7 +1464,7 @@ { if (BrowseSocket != -1) close(BrowseSocket); - + BrowseSocket = launch_data_get_fd(tmp); } else @@ -1473,6 +1488,222 @@ /* + * '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 */ + 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); + + /* + * Run-at-load if there are active jobs, polling or shared printers + * to advertise... + */ + + runatload = (cupsArrayCount(ActiveJobs) || NumPolled || + (Browsing && BrowseLocalProtocols && + NumBrowsers && cupsArrayCount(Printers))) + ? true : false; + + CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD), + runatload ? kCFBooleanTrue : 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); + } + + return (cupsd_dict); +} + + +/* * 'launchd_reload()' - Tell launchd to reload the configuration file to pick * up the new listening directives. */ @@ -1573,272 +1804,103 @@ /* - * 'launchd_sync_conf()' - Re-write the launchd(8) config file + * '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) { - 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 */ + SInt32 errorCode; /* Error code */ + CFDataRef resourceData; /* XML property list */ + CFDictionaryRef cupsd_dict; /* New org.cups.cupsd.plist dict */ - /* - * If the launchd conf file modification time is newer than the cupsd.conf - * time then there's nothing to do... + * If needed reconstitute the existing org.cups.cupsd.plist... */ - if (!stat(ConfigurationFile, &cupsd_sb) && - !stat(LaunchdConf, &launchd_sb) && - launchd_sb.st_mtimespec.tv_sec >= cupsd_sb.st_mtimespec.tv_sec) + if (!launchd_conf_url && + !(launchd_conf_url = CFURLCreateFromFileSystemRepresentation( + kCFAllocatorDefault, + (const unsigned char *)LaunchdConf, + strlen(LaunchdConf), false))) { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "launchd_sync_conf: Nothing to do, pid=%d.", - (int)getpid()); - return (0); + cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: " + "Unable to create file URL for \"%s\"\n", LaunchdConf); + 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) + if (!launchd_conf_dict) { - CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL), - CFSTR("org.cups.cupsd")); - CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_ONDEMAND), - kCFBooleanTrue); + if (CFURLCreateDataAndPropertiesFromResource(NULL, launchd_conf_url, + &resourceData, NULL, NULL, &errorCode)) + { + launchd_conf_dict = CFPropertyListCreateFromXMLData(NULL, resourceData, + kCFPropertyListImmutable, NULL); + CFRelease(resourceData); + } - if ((Browsing && BrowseLocalProtocols && cupsArrayCount(Printers)) || - cupsArrayCount(ActiveJobs) || NumPolled) - 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) + if (!launchd_conf_dict) { - CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS), - array); - CFArrayAppendValue(array, CFSTR("/usr/sbin/cupsd")); - CFArrayAppendValue(array, CFSTR("-l")); - CFRelease(array); + cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: " + "Unable to create dictionary for \"%s\"\n", LaunchdConf); } + } - /* - * Add a sockets dictionary... - */ + /* + * Create a new org.cups.cupsd.plist dictionary... + */ - if ((sockets = (CFMutableDictionaryRef)CFDictionaryCreateMutable( - kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)) != NULL) - { - CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SOCKETS), sockets); + 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; + } - /* - * Add a Listeners array to the sockets dictionary... - */ + /* + * If the dictionaries are different write a new org.cups.cupsd.plist... + */ - if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks)) != NULL) + if (!CFEqual(cupsd_dict, launchd_conf_dict)) + { + if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault, + cupsd_dict))) + { + if (CFURLWriteDataAndPropertiesToResource(launchd_conf_url, resourceData, + NULL, &errorCode)) { - CFDictionaryAddValue(sockets, CFSTR("Listeners"), array); - /* - * For each listener add a dictionary to the listeners array... - */ + * The new cupsd dictionary becomes the on-disk launchd dictionary... + */ - 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); + if (launchd_conf_dict) + CFRelease(launchd_conf_dict); -# 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); + launchd_conf_dict = cupsd_dict; } - - /* - * Add the BrowseSocket to the sockets dictionary... - */ - - if (Browsing && (BrowseRemoteProtocols & BROWSE_CUPS)) + else { - if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks)) != NULL) - { - CFDictionaryAddValue(sockets, CFSTR("BrowseSockets"), array); + cupsdLogMessage(CUPSD_LOG_WARN, + "launchd_sync_conf: " + "CFURLWriteDataAndPropertiesToResource(\"%s\") " + "failed: %d\n", + LaunchdConf, (int)errorCode); - 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(cupsd_dict); } - - CFRelease(sockets); + + CFRelease(resourceData); } - cupsdLogMessage(CUPSD_LOG_DEBUG, - "launchd_sync_conf: Updating \"%s\", pid=%d\n", - LaunchdConf, (int)getpid()); + /* + * Let the caller know we updated the file... + */ - 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); + return 1; } - /* - * Let the caller know we updated the file... - */ - - return (1); + return 0; } #endif /* HAVE_LAUNCHD */