Description: CUPS Upstart socket activation: Important to note: - Run by default in foreground (-f), not Foreground (-F). With -F CUPS closes all inherited file descriptors, which is not needed under upstart since it does that on our behalf, furthermore closing passed socket activation descriptors prevents us from using socket activation. - Force foreground (-f) mode if environment suggests that we are Upstart socket activated (similar to "-l" flag for launchd). - Initialize addrlen to sizeof(addr) to make getsockname() work. - Correct environment variable name used to check event type - Get UPSTART_FDS simply with atoi() - Perform explicit return code checking from getsockname function call Author: Till Kamppeter , Dimitri John Ledkov Bug: https://bugs.launchpad.net/ubuntu/+source/cups/+bug/1276713 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -71,6 +71,7 @@ #ifdef HAVE_SYSTEMD static int systemd_checkin(void); #endif /* HAVE_SYSTEMD */ +static void upstart_checkin(void); static void parent_handler(int sig); static void process_children(void); static void sigchld_handler(int sig); @@ -342,6 +343,14 @@ usage(1); } + /* force non-disconnecting foreground mode upon upstart socket + * activation, as otherwise all fd's are closed before we get to use + * them */ + if (getenv("UPSTART_FDS")) + { + fg = 1; + } + if (!ConfigurationFile) cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf"); @@ -602,6 +611,11 @@ #endif /* HAVE_SYSTEMD */ /* + * If we were started by Upstart get the listen sockets file descriptors... + */ + upstart_checkin(); + + /* * Startup the server... */ @@ -800,6 +814,13 @@ #endif /* HAVE_SYSTEMD */ /* + * If we were started by Upstart get the listen sockets file + * descriptors... + */ + + upstart_checkin(); + + /* * Startup the server... */ @@ -1681,6 +1702,94 @@ } #endif /* HAVE_SYSTEMD */ +static void +upstart_checkin(void) +{ + /* + * Example socket event environment: + * + * UPSTART_INSTANCE= + * PORT=34568 + * PROTO=inet + * UPSTART_JOB=foo5 + * UPSTART_FDS=43 + * UPSTART_EVENTS=socket + * ADDR=127.0.0.1 + * + */ + int fd = 0; + const char *e; + http_addr_t addr; + socklen_t addrlen = sizeof(addr); + cupsd_listener_t *lis; + char s[256]; + + if (!(e = getenv("UPSTART_EVENTS"))) + return; + + if (strcasecmp(e, "socket")) + return; + + if (!(e = getenv("UPSTART_FDS"))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "upstart_checkin: We got started via Upstart socket event but no environment variable UPSTART_FDS is not set"); + return; + } + + fd = atoi(e); + + if (getsockname(fd, (struct sockaddr*) &addr, &addrlen) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "upstart_checkin: Unable to get local address - %s", + strerror(errno)); + return; + } + + /* + * Try to match the systemd 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; + + if (lis) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "upstart_checkin: Matched existing listener %s with fd %d...", + httpAddrString(&(lis->address), s, sizeof(s)), fd); + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "upstart_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, + "upstart_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 + if (_httpAddrPort(&(lis->address)) == 443) + lis->encryption = HTTP_ENCRYPT_ALWAYS; +# endif /* HAVE_SSL */ +} + /* * 'parent_handler()' - Catch USR1/CHLD signals... */