Magellan Linux

Annotation of /trunk/cups/patches/cups-1.4.7-systemd-socket.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1422 - (hide annotations) (download)
Mon Jul 18 12:24:57 2011 UTC (12 years, 10 months ago) by niro
File size: 35856 byte(s)
-added fedoras systemd socket patch
1 niro 1422 From 1db0a48375836c7e93ac30649007c2391be8b3b2 Mon Sep 17 00:00:00 2001
2     From: Lennart Poettering <lennart@poettering.net>
3     Date: Mon, 4 Jul 2011 01:37:01 +0200
4     Subject: [PATCH] systemd: add systemd socket activation and unit files
5    
6     On newer Linux machines systemd supports launchd-style socket
7     activation. This patch adds support for this mechanism and also adds
8     systemd unit files as appropriate to hook this up with systemd.
9    
10     This includes an MIT-licensed drop-in file that implements the most
11     basic interfaces needed to get the file descriptors from systemd. Most
12     of the systemd and Linux-specific code compiles to NOPs on other
13     systems.
14    
15     Three triggers to start CUPS are defined: a) if new printer hardware is
16     plugged in, b) when a client accesses the CUPS socket and c) when a
17     spool file resides in /var/spool/cups.
18     ---
19     Makedefs.in | 2 +
20     config-scripts/cups-systemd.m4 | 25 ++
21     configure.in | 4 +
22     data/Makefile | 9 +
23     data/cups.path.in | 8 +
24     data/cups.service.in | 9 +
25     data/cups.socket.in | 9 +
26     scheduler/Makefile | 9 +
27     scheduler/main.c | 107 ++++++++
28     scheduler/sd-daemon.c | 520 ++++++++++++++++++++++++++++++++++++++++
29     scheduler/sd-daemon.h | 277 +++++++++++++++++++++
30     11 files changed, 979 insertions(+), 0 deletions(-)
31     create mode 100644 config-scripts/cups-systemd.m4
32     create mode 100644 data/cups.path.in
33     create mode 100644 data/cups.service.in
34     create mode 100644 data/cups.socket.in
35     create mode 100644 scheduler/sd-daemon.c
36     create mode 100644 scheduler/sd-daemon.h
37    
38     diff --git a/Makedefs.in b/Makedefs.in
39     index 654eea4..02c43b6 100644
40     --- a/Makedefs.in
41     +++ b/Makedefs.in
42     @@ -143,6 +143,7 @@ CXXFLAGS = @CPPFLAGS@ @CXXFLAGS@
43     CXXLIBS = @CXXLIBS@
44     DBUS_NOTIFIER = @DBUS_NOTIFIER@
45     DBUS_NOTIFIERLIBS = @DBUS_NOTIFIERLIBS@
46     +SYSTEMD_UNITS = @SYSTEMD_UNITS@
47     DNSSD_BACKEND = @DNSSD_BACKEND@
48     DSOFLAGS = -L../cups @DSOFLAGS@
49     DSOLIBS = @DSOLIBS@ $(COMMONLIBS)
50     @@ -267,6 +268,7 @@ PAMFILE = @PAMFILE@
51    
52     DEFAULT_LAUNCHD_CONF = @DEFAULT_LAUNCHD_CONF@
53     DBUSDIR = @DBUSDIR@
54     +SYSTEMDUNITDIR = $(BUILDROOT)@systemdsystemunitdir@
55    
56    
57     #
58     diff --git a/config-scripts/cups-systemd.m4 b/config-scripts/cups-systemd.m4
59     new file mode 100644
60     index 0000000..fead8a9
61     --- /dev/null
62     +++ b/config-scripts/cups-systemd.m4
63     @@ -0,0 +1,25 @@
64     +dnl
65     +dnl "$Id$"
66     +dnl
67     +dnl systemd stuff for CUPS.
68     +
69     +dnl Find whether systemd is available
70     +
71     +AC_ARG_WITH([systemdsystemunitdir],
72     + AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
73     + [], [with_systemdsystemunitdir=$($PKGCONFIG --variable=systemdsystemunitdir systemd)])
74     +if test "x$with_systemdsystemunitdir" != xno; then
75     + AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
76     +fi
77     +
78     +if test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ; then
79     + SYSTEMD_UNITS="cups.service cups.socket cups.path"
80     +else
81     + SYSTEMD_UNITS=""
82     +fi
83     +
84     +AC_SUBST(SYSTEMD_UNITS)
85     +
86     +dnl
87     +dnl "$Id$"
88     +dnl
89     diff --git a/configure.in b/configure.in
90     index 560f4f8..b0c19a9 100644
91     --- a/configure.in
92     +++ b/configure.in
93     @@ -37,6 +37,7 @@ sinclude(config-scripts/cups-pam.m4)
94     sinclude(config-scripts/cups-largefile.m4)
95     sinclude(config-scripts/cups-dnssd.m4)
96     sinclude(config-scripts/cups-launchd.m4)
97     +sinclude(config-scripts/cups-systemd.m4)
98     sinclude(config-scripts/cups-defaults.m4)
99     sinclude(config-scripts/cups-pdf.m4)
100     sinclude(config-scripts/cups-scripting.m4)
101     @@ -71,6 +72,9 @@ AC_OUTPUT(Makedefs
102     conf/snmp.conf
103     cups-config
104     data/testprint
105     + data/cups.service
106     + data/cups.socket
107     + data/cups.path
108     desktop/cups.desktop
109     doc/help/ref-cupsd-conf.html
110     doc/help/standard.html
111     diff --git a/data/Makefile b/data/Makefile
112     index b9de21a..cccab85 100644
113     --- a/data/Makefile
114     +++ b/data/Makefile
115     @@ -112,6 +112,12 @@ install-data:
116     $(INSTALL_DATA) $$file $(DATADIR)/ppdc; \
117     done
118     $(INSTALL_DIR) -m 755 $(DATADIR)/profiles
119     + if test "x$(SYSTEMD_UNITS)" != "x" ; then \
120     + $(INSTALL_DIR) -m 755 $(SYSTEMDUNITDIR); \
121     + for file in $(SYSTEMD_UNITS); do \
122     + $(INSTALL_DATA) $$file $(SYSTEMDUNITDIR); \
123     + done; \
124     + fi
125    
126    
127     #
128     @@ -159,6 +165,9 @@ uninstall:
129     -$(RMDIR) $(DATADIR)/charsets
130     -$(RMDIR) $(DATADIR)/banners
131     -$(RMDIR) $(DATADIR)
132     + for file in $(SYSTEMD_UNITS); do \
133     + $(RM) $(SYSTEMDUNITDIR)/$$file; \
134     + done
135    
136    
137     #
138     diff --git a/data/cups.path.in b/data/cups.path.in
139     new file mode 100644
140     index 0000000..c99e39b
141     --- /dev/null
142     +++ b/data/cups.path.in
143     @@ -0,0 +1,8 @@
144     +[Unit]
145     +Description=CUPS Printer Service Spool
146     +
147     +[Path]
148     +DirectoryNotEmpty=@CUPS_REQUESTS@
149     +
150     +[Install]
151     +WantedBy=multi-user.target
152     diff --git a/data/cups.service.in b/data/cups.service.in
153     new file mode 100644
154     index 0000000..007d0e6
155     --- /dev/null
156     +++ b/data/cups.service.in
157     @@ -0,0 +1,9 @@
158     +[Unit]
159     +Description=CUPS Printing Service
160     +
161     +[Service]
162     +ExecStart=@sbindir@/cupsd -f
163     +
164     +[Install]
165     +Also=cups.socket cups.path
166     +WantedBy=printer.target
167     diff --git a/data/cups.socket.in b/data/cups.socket.in
168     new file mode 100644
169     index 0000000..b940096
170     --- /dev/null
171     +++ b/data/cups.socket.in
172     @@ -0,0 +1,9 @@
173     +[Unit]
174     +Description=CUPS Printing Service Sockets
175     +
176     +[Socket]
177     +ListenStream=@CUPS_DEFAULT_DOMAINSOCKET@
178     +ListenStream=631
179     +
180     +[Install]
181     +WantedBy=sockets.target
182     diff --git a/scheduler/Makefile b/scheduler/Makefile
183     index 3c7da8e..05152a6 100644
184     --- a/scheduler/Makefile
185     +++ b/scheduler/Makefile
186     @@ -39,6 +39,7 @@ CUPSDOBJS = \
187     server.o \
188     statbuf.o \
189     subscriptions.o \
190     + sd-daemon.o \
191     sysman.o
192     LIBOBJS = \
193     filter.o \
194     @@ -568,6 +569,14 @@ sloc:
195    
196    
197     #
198     +# Update sd-daemon.[ch] drop-in file from upstream git
199     +#
200     +
201     +update-systemd:
202     + curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c > sd-daemon.c
203     + curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h > sd-daemon.h
204     +
205     +#
206     # Dependencies...
207     #
208    
209     diff --git a/scheduler/main.c b/scheduler/main.c
210     index baaa3a1..5a4b8e1 100644
211     --- a/scheduler/main.c
212     +++ b/scheduler/main.c
213     @@ -26,6 +26,8 @@
214     * launchd_checkin() - Check-in with launchd and collect the listening
215     * fds.
216     * launchd_checkout() - Update the launchd KeepAlive file as needed.
217     + * systemd_checkin() - Check-in with systemd and collect the
218     + * listening fds.
219     * parent_handler() - Catch USR1/CHLD signals...
220     * process_children() - Process all dead children...
221     * select_timeout() - Calculate the select timeout value.
222     @@ -62,6 +64,8 @@
223     # endif /* !LAUNCH_JOBKEY_SERVICEIPC */
224     #endif /* HAVE_LAUNCH_H */
225    
226     +#include "sd-daemon.h"
227     +
228     #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
229     # include <malloc.h>
230     #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
231     @@ -78,6 +82,7 @@
232     static void launchd_checkin(void);
233     static void launchd_checkout(void);
234     #endif /* HAVE_LAUNCHD */
235     +static void systemd_checkin(void);
236     static void parent_handler(int sig);
237     static void process_children(void);
238     static void sigchld_handler(int sig);
239     @@ -520,6 +525,11 @@ main(int argc, /* I - Number of command-line args */
240     #endif /* HAVE_LAUNCHD */
241    
242     /*
243     + * If we were started by systemd get the listen sockets file descriptors...
244     + */
245     + systemd_checkin();
246     +
247     + /*
248     * Startup the server...
249     */
250    
251     @@ -731,6 +741,12 @@ main(int argc, /* I - Number of command-line args */
252     #endif /* HAVE_LAUNCHD */
253    
254     /*
255     + * If we were started by systemd get the listen sockets file descriptors...
256     + */
257     +
258     + systemd_checkin();
259     +
260     + /*
261     * Startup the server...
262     */
263    
264     @@ -1535,6 +1551,97 @@ launchd_checkout(void)
265     }
266     #endif /* HAVE_LAUNCHD */
267    
268     +static void
269     +systemd_checkin(void)
270     +{
271     + int n, fd;
272     +
273     + n = sd_listen_fds(1);
274     + if (n < 0)
275     + {
276     + cupsdLogMessage(CUPSD_LOG_ERROR,
277     + "systemd_checkin: Failed to acquire sockets from systemd - %s",
278     + strerror(-n));
279     + exit(EXIT_FAILURE);
280     + return;
281     + }
282     +
283     + if (n == 0)
284     + return;
285     +
286     + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
287     + {
288     + http_addr_t addr;
289     + socklen_t addrlen;
290     + int r;
291     + cupsd_listener_t *lis;
292     + char s[256];
293     +
294     + r = sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1);
295     + if (r < 0) {
296     + cupsdLogMessage(CUPSD_LOG_ERROR,
297     + "systemd_checkin: Unable to verify socket type - %s",
298     + strerror(-r));
299     + continue;
300     + }
301     +
302     + if (!r) {
303     + cupsdLogMessage(CUPSD_LOG_ERROR,
304     + "systemd_checkin: Socket not of the right type");
305     + continue;
306     + }
307     +
308     + if (getsockname(fd, (struct sockaddr*) &addr, &addrlen))
309     + {
310     + cupsdLogMessage(CUPSD_LOG_ERROR,
311     + "systemd_checkin: Unable to get local address - %s",
312     + strerror(errno));
313     + continue;
314     + }
315     +
316     + /*
317     + * Try to match the systemd socket address to one of the listeners...
318     + */
319     +
320     + for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
321     + lis;
322     + lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
323     + if (httpAddrEqual(&lis->address, &addr))
324     + break;
325     +
326     + if (lis)
327     + {
328     + cupsdLogMessage(CUPSD_LOG_DEBUG,
329     + "systemd_checkin: Matched existing listener %s with fd %d...",
330     + httpAddrString(&(lis->address), s, sizeof(s)), fd);
331     + }
332     + else
333     + {
334     + cupsdLogMessage(CUPSD_LOG_DEBUG,
335     + "systemd_checkin: Adding new listener %s with fd %d...",
336     + httpAddrString(&addr, s, sizeof(s)), fd);
337     +
338     + if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
339     + {
340     + cupsdLogMessage(CUPSD_LOG_ERROR,
341     + "systemd_checkin: Unable to allocate listener - "
342     + "%s.", strerror(errno));
343     + exit(EXIT_FAILURE);
344     + }
345     +
346     + cupsArrayAdd(Listeners, lis);
347     +
348     + memcpy(&lis->address, &addr, sizeof(lis->address));
349     + }
350     +
351     + lis->fd = fd;
352     +
353     +# ifdef HAVE_SSL
354     + if (_httpAddrPort(&(lis->address)) == 443)
355     + lis->encryption = HTTP_ENCRYPT_ALWAYS;
356     +# endif /* HAVE_SSL */
357     + }
358     +}
359    
360     /*
361     * 'parent_handler()' - Catch USR1/CHLD signals...
362     diff --git a/scheduler/sd-daemon.c b/scheduler/sd-daemon.c
363     new file mode 100644
364     index 0000000..a2ec74c
365     --- /dev/null
366     +++ b/scheduler/sd-daemon.c
367     @@ -0,0 +1,520 @@
368     +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
369     +
370     +/***
371     + Copyright 2010 Lennart Poettering
372     +
373     + Permission is hereby granted, free of charge, to any person
374     + obtaining a copy of this software and associated documentation files
375     + (the "Software"), to deal in the Software without restriction,
376     + including without limitation the rights to use, copy, modify, merge,
377     + publish, distribute, sublicense, and/or sell copies of the Software,
378     + and to permit persons to whom the Software is furnished to do so,
379     + subject to the following conditions:
380     +
381     + The above copyright notice and this permission notice shall be
382     + included in all copies or substantial portions of the Software.
383     +
384     + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
385     + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
386     + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
387     + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
388     + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
389     + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
390     + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
391     + SOFTWARE.
392     +***/
393     +
394     +#ifndef _GNU_SOURCE
395     +#define _GNU_SOURCE
396     +#endif
397     +
398     +#include <sys/types.h>
399     +#include <sys/stat.h>
400     +#include <sys/socket.h>
401     +#include <sys/un.h>
402     +#include <sys/fcntl.h>
403     +#include <netinet/in.h>
404     +#include <stdlib.h>
405     +#include <errno.h>
406     +#include <unistd.h>
407     +#include <string.h>
408     +#include <stdarg.h>
409     +#include <stdio.h>
410     +#include <stddef.h>
411     +#include <limits.h>
412     +
413     +#if defined(__linux__)
414     +#include <mqueue.h>
415     +#endif
416     +
417     +#include "sd-daemon.h"
418     +
419     +#if (__GNUC__ >= 4) && !defined(SD_EXPORT_SYMBOLS)
420     +#define _sd_hidden_ __attribute__ ((visibility("hidden")))
421     +#else
422     +#define _sd_hidden_
423     +#endif
424     +
425     +_sd_hidden_ int sd_listen_fds(int unset_environment) {
426     +
427     +#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
428     + return 0;
429     +#else
430     + int r, fd;
431     + const char *e;
432     + char *p = NULL;
433     + unsigned long l;
434     +
435     + if (!(e = getenv("LISTEN_PID"))) {
436     + r = 0;
437     + goto finish;
438     + }
439     +
440     + errno = 0;
441     + l = strtoul(e, &p, 10);
442     +
443     + if (errno != 0) {
444     + r = -errno;
445     + goto finish;
446     + }
447     +
448     + if (!p || *p || l <= 0) {
449     + r = -EINVAL;
450     + goto finish;
451     + }
452     +
453     + /* Is this for us? */
454     + if (getpid() != (pid_t) l) {
455     + r = 0;
456     + goto finish;
457     + }
458     +
459     + if (!(e = getenv("LISTEN_FDS"))) {
460     + r = 0;
461     + goto finish;
462     + }
463     +
464     + errno = 0;
465     + l = strtoul(e, &p, 10);
466     +
467     + if (errno != 0) {
468     + r = -errno;
469     + goto finish;
470     + }
471     +
472     + if (!p || *p) {
473     + r = -EINVAL;
474     + goto finish;
475     + }
476     +
477     + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
478     + int flags;
479     +
480     + if ((flags = fcntl(fd, F_GETFD)) < 0) {
481     + r = -errno;
482     + goto finish;
483     + }
484     +
485     + if (flags & FD_CLOEXEC)
486     + continue;
487     +
488     + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
489     + r = -errno;
490     + goto finish;
491     + }
492     + }
493     +
494     + r = (int) l;
495     +
496     +finish:
497     + if (unset_environment) {
498     + unsetenv("LISTEN_PID");
499     + unsetenv("LISTEN_FDS");
500     + }
501     +
502     + return r;
503     +#endif
504     +}
505     +
506     +_sd_hidden_ int sd_is_fifo(int fd, const char *path) {
507     + struct stat st_fd;
508     +
509     + if (fd < 0)
510     + return -EINVAL;
511     +
512     + memset(&st_fd, 0, sizeof(st_fd));
513     + if (fstat(fd, &st_fd) < 0)
514     + return -errno;
515     +
516     + if (!S_ISFIFO(st_fd.st_mode))
517     + return 0;
518     +
519     + if (path) {
520     + struct stat st_path;
521     +
522     + memset(&st_path, 0, sizeof(st_path));
523     + if (stat(path, &st_path) < 0) {
524     +
525     + if (errno == ENOENT || errno == ENOTDIR)
526     + return 0;
527     +
528     + return -errno;
529     + }
530     +
531     + return
532     + st_path.st_dev == st_fd.st_dev &&
533     + st_path.st_ino == st_fd.st_ino;
534     + }
535     +
536     + return 1;
537     +}
538     +
539     +_sd_hidden_ int sd_is_special(int fd, const char *path) {
540     + struct stat st_fd;
541     +
542     + if (fd < 0)
543     + return -EINVAL;
544     +
545     + if (fstat(fd, &st_fd) < 0)
546     + return -errno;
547     +
548     + if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
549     + return 0;
550     +
551     + if (path) {
552     + struct stat st_path;
553     +
554     + if (stat(path, &st_path) < 0) {
555     +
556     + if (errno == ENOENT || errno == ENOTDIR)
557     + return 0;
558     +
559     + return -errno;
560     + }
561     +
562     + if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
563     + return
564     + st_path.st_dev == st_fd.st_dev &&
565     + st_path.st_ino == st_fd.st_ino;
566     + else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
567     + return st_path.st_rdev == st_fd.st_rdev;
568     + else
569     + return 0;
570     + }
571     +
572     + return 1;
573     +}
574     +
575     +static int sd_is_socket_internal(int fd, int type, int listening) {
576     + struct stat st_fd;
577     +
578     + if (fd < 0 || type < 0)
579     + return -EINVAL;
580     +
581     + if (fstat(fd, &st_fd) < 0)
582     + return -errno;
583     +
584     + if (!S_ISSOCK(st_fd.st_mode))
585     + return 0;
586     +
587     + if (type != 0) {
588     + int other_type = 0;
589     + socklen_t l = sizeof(other_type);
590     +
591     + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
592     + return -errno;
593     +
594     + if (l != sizeof(other_type))
595     + return -EINVAL;
596     +
597     + if (other_type != type)
598     + return 0;
599     + }
600     +
601     + if (listening >= 0) {
602     + int accepting = 0;
603     + socklen_t l = sizeof(accepting);
604     +
605     + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
606     + return -errno;
607     +
608     + if (l != sizeof(accepting))
609     + return -EINVAL;
610     +
611     + if (!accepting != !listening)
612     + return 0;
613     + }
614     +
615     + return 1;
616     +}
617     +
618     +union sockaddr_union {
619     + struct sockaddr sa;
620     + struct sockaddr_in in4;
621     + struct sockaddr_in6 in6;
622     + struct sockaddr_un un;
623     + struct sockaddr_storage storage;
624     +};
625     +
626     +_sd_hidden_ int sd_is_socket(int fd, int family, int type, int listening) {
627     + int r;
628     +
629     + if (family < 0)
630     + return -EINVAL;
631     +
632     + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
633     + return r;
634     +
635     + if (family > 0) {
636     + union sockaddr_union sockaddr;
637     + socklen_t l;
638     +
639     + memset(&sockaddr, 0, sizeof(sockaddr));
640     + l = sizeof(sockaddr);
641     +
642     + if (getsockname(fd, &sockaddr.sa, &l) < 0)
643     + return -errno;
644     +
645     + if (l < sizeof(sa_family_t))
646     + return -EINVAL;
647     +
648     + return sockaddr.sa.sa_family == family;
649     + }
650     +
651     + return 1;
652     +}
653     +
654     +_sd_hidden_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
655     + union sockaddr_union sockaddr;
656     + socklen_t l;
657     + int r;
658     +
659     + if (family != 0 && family != AF_INET && family != AF_INET6)
660     + return -EINVAL;
661     +
662     + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
663     + return r;
664     +
665     + memset(&sockaddr, 0, sizeof(sockaddr));
666     + l = sizeof(sockaddr);
667     +
668     + if (getsockname(fd, &sockaddr.sa, &l) < 0)
669     + return -errno;
670     +
671     + if (l < sizeof(sa_family_t))
672     + return -EINVAL;
673     +
674     + if (sockaddr.sa.sa_family != AF_INET &&
675     + sockaddr.sa.sa_family != AF_INET6)
676     + return 0;
677     +
678     + if (family > 0)
679     + if (sockaddr.sa.sa_family != family)
680     + return 0;
681     +
682     + if (port > 0) {
683     + if (sockaddr.sa.sa_family == AF_INET) {
684     + if (l < sizeof(struct sockaddr_in))
685     + return -EINVAL;
686     +
687     + return htons(port) == sockaddr.in4.sin_port;
688     + } else {
689     + if (l < sizeof(struct sockaddr_in6))
690     + return -EINVAL;
691     +
692     + return htons(port) == sockaddr.in6.sin6_port;
693     + }
694     + }
695     +
696     + return 1;
697     +}
698     +
699     +_sd_hidden_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
700     + union sockaddr_union sockaddr;
701     + socklen_t l;
702     + int r;
703     +
704     + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
705     + return r;
706     +
707     + memset(&sockaddr, 0, sizeof(sockaddr));
708     + l = sizeof(sockaddr);
709     +
710     + if (getsockname(fd, &sockaddr.sa, &l) < 0)
711     + return -errno;
712     +
713     + if (l < sizeof(sa_family_t))
714     + return -EINVAL;
715     +
716     + if (sockaddr.sa.sa_family != AF_UNIX)
717     + return 0;
718     +
719     + if (path) {
720     + if (length <= 0)
721     + length = strlen(path);
722     +
723     + if (length <= 0)
724     + /* Unnamed socket */
725     + return l == offsetof(struct sockaddr_un, sun_path);
726     +
727     + if (path[0])
728     + /* Normal path socket */
729     + return
730     + (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
731     + memcmp(path, sockaddr.un.sun_path, length+1) == 0;
732     + else
733     + /* Abstract namespace socket */
734     + return
735     + (l == offsetof(struct sockaddr_un, sun_path) + length) &&
736     + memcmp(path, sockaddr.un.sun_path, length) == 0;
737     + }
738     +
739     + return 1;
740     +}
741     +
742     +_sd_hidden_ int sd_is_mq(int fd, const char *path) {
743     +#if !defined(__linux__)
744     + return 0;
745     +#else
746     + struct mq_attr attr;
747     +
748     + if (fd < 0)
749     + return -EINVAL;
750     +
751     + if (mq_getattr(fd, &attr) < 0)
752     + return -errno;
753     +
754     + if (path) {
755     + char fpath[PATH_MAX];
756     + struct stat a, b;
757     +
758     + if (path[0] != '/')
759     + return -EINVAL;
760     +
761     + if (fstat(fd, &a) < 0)
762     + return -errno;
763     +
764     + strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
765     + fpath[sizeof(fpath)-1] = 0;
766     +
767     + if (stat(fpath, &b) < 0)
768     + return -errno;
769     +
770     + if (a.st_dev != b.st_dev ||
771     + a.st_ino != b.st_ino)
772     + return 0;
773     + }
774     +
775     + return 1;
776     +#endif
777     +}
778     +
779     +_sd_hidden_ int sd_notify(int unset_environment, const char *state) {
780     +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
781     + return 0;
782     +#else
783     + int fd = -1, r;
784     + struct msghdr msghdr;
785     + struct iovec iovec;
786     + union sockaddr_union sockaddr;
787     + const char *e;
788     +
789     + if (!state) {
790     + r = -EINVAL;
791     + goto finish;
792     + }
793     +
794     + if (!(e = getenv("NOTIFY_SOCKET")))
795     + return 0;
796     +
797     + /* Must be an abstract socket, or an absolute path */
798     + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
799     + r = -EINVAL;
800     + goto finish;
801     + }
802     +
803     + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
804     + r = -errno;
805     + goto finish;
806     + }
807     +
808     + memset(&sockaddr, 0, sizeof(sockaddr));
809     + sockaddr.sa.sa_family = AF_UNIX;
810     + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
811     +
812     + if (sockaddr.un.sun_path[0] == '@')
813     + sockaddr.un.sun_path[0] = 0;
814     +
815     + memset(&iovec, 0, sizeof(iovec));
816     + iovec.iov_base = (char*) state;
817     + iovec.iov_len = strlen(state);
818     +
819     + memset(&msghdr, 0, sizeof(msghdr));
820     + msghdr.msg_name = &sockaddr;
821     + msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
822     +
823     + if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
824     + msghdr.msg_namelen = sizeof(struct sockaddr_un);
825     +
826     + msghdr.msg_iov = &iovec;
827     + msghdr.msg_iovlen = 1;
828     +
829     + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
830     + r = -errno;
831     + goto finish;
832     + }
833     +
834     + r = 1;
835     +
836     +finish:
837     + if (unset_environment)
838     + unsetenv("NOTIFY_SOCKET");
839     +
840     + if (fd >= 0)
841     + close(fd);
842     +
843     + return r;
844     +#endif
845     +}
846     +
847     +_sd_hidden_ int sd_notifyf(int unset_environment, const char *format, ...) {
848     +#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
849     + return 0;
850     +#else
851     + va_list ap;
852     + char *p = NULL;
853     + int r;
854     +
855     + va_start(ap, format);
856     + r = vasprintf(&p, format, ap);
857     + va_end(ap);
858     +
859     + if (r < 0 || !p)
860     + return -ENOMEM;
861     +
862     + r = sd_notify(unset_environment, p);
863     + free(p);
864     +
865     + return r;
866     +#endif
867     +}
868     +
869     +_sd_hidden_ int sd_booted(void) {
870     +#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
871     + return 0;
872     +#else
873     +
874     + struct stat a, b;
875     +
876     + /* We simply test whether the systemd cgroup hierarchy is
877     + * mounted */
878     +
879     + if (lstat("/sys/fs/cgroup", &a) < 0)
880     + return 0;
881     +
882     + if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
883     + return 0;
884     +
885     + return a.st_dev != b.st_dev;
886     +#endif
887     +}
888     diff --git a/scheduler/sd-daemon.h b/scheduler/sd-daemon.h
889     new file mode 100644
890     index 0000000..46dc7fd
891     --- /dev/null
892     +++ b/scheduler/sd-daemon.h
893     @@ -0,0 +1,277 @@
894     +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
895     +
896     +#ifndef foosddaemonhfoo
897     +#define foosddaemonhfoo
898     +
899     +/***
900     + Copyright 2010 Lennart Poettering
901     +
902     + Permission is hereby granted, free of charge, to any person
903     + obtaining a copy of this software and associated documentation files
904     + (the "Software"), to deal in the Software without restriction,
905     + including without limitation the rights to use, copy, modify, merge,
906     + publish, distribute, sublicense, and/or sell copies of the Software,
907     + and to permit persons to whom the Software is furnished to do so,
908     + subject to the following conditions:
909     +
910     + The above copyright notice and this permission notice shall be
911     + included in all copies or substantial portions of the Software.
912     +
913     + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
914     + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
915     + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
916     + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
917     + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
918     + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
919     + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
920     + SOFTWARE.
921     +***/
922     +
923     +#include <sys/types.h>
924     +#include <inttypes.h>
925     +
926     +#ifdef __cplusplus
927     +extern "C" {
928     +#endif
929     +
930     +/*
931     + Reference implementation of a few systemd related interfaces for
932     + writing daemons. These interfaces are trivial to implement. To
933     + simplify porting we provide this reference implementation.
934     + Applications are welcome to reimplement the algorithms described
935     + here if they do not want to include these two source files.
936     +
937     + The following functionality is provided:
938     +
939     + - Support for logging with log levels on stderr
940     + - File descriptor passing for socket-based activation
941     + - Daemon startup and status notification
942     + - Detection of systemd boots
943     +
944     + You may compile this with -DDISABLE_SYSTEMD to disable systemd
945     + support. This makes all those calls NOPs that are directly related to
946     + systemd (i.e. only sd_is_xxx() will stay useful).
947     +
948     + Since this is drop-in code we don't want any of our symbols to be
949     + exported in any case. Hence we declare hidden visibility for all of
950     + them.
951     +
952     + You may find an up-to-date version of these source files online:
953     +
954     + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h
955     + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c
956     +
957     + This should compile on non-Linux systems, too, but with the
958     + exception of the sd_is_xxx() calls all functions will become NOPs.
959     +
960     + See sd-daemon(7) for more information.
961     +*/
962     +
963     +#ifndef _sd_printf_attr_
964     +#if __GNUC__ >= 4
965     +#define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
966     +#else
967     +#define _sd_printf_attr_(a,b)
968     +#endif
969     +#endif
970     +
971     +/*
972     + Log levels for usage on stderr:
973     +
974     + fprintf(stderr, SD_NOTICE "Hello World!\n");
975     +
976     + This is similar to printk() usage in the kernel.
977     +*/
978     +#define SD_EMERG "<0>" /* system is unusable */
979     +#define SD_ALERT "<1>" /* action must be taken immediately */
980     +#define SD_CRIT "<2>" /* critical conditions */
981     +#define SD_ERR "<3>" /* error conditions */
982     +#define SD_WARNING "<4>" /* warning conditions */
983     +#define SD_NOTICE "<5>" /* normal but significant condition */
984     +#define SD_INFO "<6>" /* informational */
985     +#define SD_DEBUG "<7>" /* debug-level messages */
986     +
987     +/* The first passed file descriptor is fd 3 */
988     +#define SD_LISTEN_FDS_START 3
989     +
990     +/*
991     + Returns how many file descriptors have been passed, or a negative
992     + errno code on failure. Optionally, removes the $LISTEN_FDS and
993     + $LISTEN_PID file descriptors from the environment (recommended, but
994     + problematic in threaded environments). If r is the return value of
995     + this function you'll find the file descriptors passed as fds
996     + SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative
997     + errno style error code on failure. This function call ensures that
998     + the FD_CLOEXEC flag is set for the passed file descriptors, to make
999     + sure they are not passed on to child processes. If FD_CLOEXEC shall
1000     + not be set, the caller needs to unset it after this call for all file
1001     + descriptors that are used.
1002     +
1003     + See sd_listen_fds(3) for more information.
1004     +*/
1005     +int sd_listen_fds(int unset_environment);
1006     +
1007     +/*
1008     + Helper call for identifying a passed file descriptor. Returns 1 if
1009     + the file descriptor is a FIFO in the file system stored under the
1010     + specified path, 0 otherwise. If path is NULL a path name check will
1011     + not be done and the call only verifies if the file descriptor
1012     + refers to a FIFO. Returns a negative errno style error code on
1013     + failure.
1014     +
1015     + See sd_is_fifo(3) for more information.
1016     +*/
1017     +int sd_is_fifo(int fd, const char *path);
1018     +
1019     +/*
1020     + Helper call for identifying a passed file descriptor. Returns 1 if
1021     + the file descriptor is a special character device on the file
1022     + system stored under the specified path, 0 otherwise.
1023     + If path is NULL a path name check will not be done and the call
1024     + only verifies if the file descriptor refers to a special character.
1025     + Returns a negative errno style error code on failure.
1026     +
1027     + See sd_is_special(3) for more information.
1028     +*/
1029     +int sd_is_special(int fd, const char *path);
1030     +
1031     +/*
1032     + Helper call for identifying a passed file descriptor. Returns 1 if
1033     + the file descriptor is a socket of the specified family (AF_INET,
1034     + ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If
1035     + family is 0 a socket family check will not be done. If type is 0 a
1036     + socket type check will not be done and the call only verifies if
1037     + the file descriptor refers to a socket. If listening is > 0 it is
1038     + verified that the socket is in listening mode. (i.e. listen() has
1039     + been called) If listening is == 0 it is verified that the socket is
1040     + not in listening mode. If listening is < 0 no listening mode check
1041     + is done. Returns a negative errno style error code on failure.
1042     +
1043     + See sd_is_socket(3) for more information.
1044     +*/
1045     +int sd_is_socket(int fd, int family, int type, int listening);
1046     +
1047     +/*
1048     + Helper call for identifying a passed file descriptor. Returns 1 if
1049     + the file descriptor is an Internet socket, of the specified family
1050     + (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM,
1051     + SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version
1052     + check is not done. If type is 0 a socket type check will not be
1053     + done. If port is 0 a socket port check will not be done. The
1054     + listening flag is used the same way as in sd_is_socket(). Returns a
1055     + negative errno style error code on failure.
1056     +
1057     + See sd_is_socket_inet(3) for more information.
1058     +*/
1059     +int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port);
1060     +
1061     +/*
1062     + Helper call for identifying a passed file descriptor. Returns 1 if
1063     + the file descriptor is an AF_UNIX socket of the specified type
1064     + (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0
1065     + a socket type check will not be done. If path is NULL a socket path
1066     + check will not be done. For normal AF_UNIX sockets set length to
1067     + 0. For abstract namespace sockets set length to the length of the
1068     + socket name (including the initial 0 byte), and pass the full
1069     + socket path in path (including the initial 0 byte). The listening
1070     + flag is used the same way as in sd_is_socket(). Returns a negative
1071     + errno style error code on failure.
1072     +
1073     + See sd_is_socket_unix(3) for more information.
1074     +*/
1075     +int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length);
1076     +
1077     +/*
1078     + Helper call for identifying a passed file descriptor. Returns 1 if
1079     + the file descriptor is a POSIX Message Queue of the specified name,
1080     + 0 otherwise. If path is NULL a message queue name check is not
1081     + done. Returns a negative errno style error code on failure.
1082     +*/
1083     +int sd_is_mq(int fd, const char *path);
1084     +
1085     +/*
1086     + Informs systemd about changed daemon state. This takes a number of
1087     + newline separated environment-style variable assignments in a
1088     + string. The following variables are known:
1089     +
1090     + READY=1 Tells systemd that daemon startup is finished (only
1091     + relevant for services of Type=notify). The passed
1092     + argument is a boolean "1" or "0". Since there is
1093     + little value in signaling non-readiness the only
1094     + value daemons should send is "READY=1".
1095     +
1096     + STATUS=... Passes a single-line status string back to systemd
1097     + that describes the daemon state. This is free-from
1098     + and can be used for various purposes: general state
1099     + feedback, fsck-like programs could pass completion
1100     + percentages and failing programs could pass a human
1101     + readable error message. Example: "STATUS=Completed
1102     + 66% of file system check..."
1103     +
1104     + ERRNO=... If a daemon fails, the errno-style error code,
1105     + formatted as string. Example: "ERRNO=2" for ENOENT.
1106     +
1107     + BUSERROR=... If a daemon fails, the D-Bus error-style error
1108     + code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut"
1109     +
1110     + MAINPID=... The main pid of a daemon, in case systemd did not
1111     + fork off the process itself. Example: "MAINPID=4711"
1112     +
1113     + Daemons can choose to send additional variables. However, it is
1114     + recommended to prefix variable names not listed above with X_.
1115     +
1116     + Returns a negative errno-style error code on failure. Returns > 0
1117     + if systemd could be notified, 0 if it couldn't possibly because
1118     + systemd is not running.
1119     +
1120     + Example: When a daemon finished starting up, it could issue this
1121     + call to notify systemd about it:
1122     +
1123     + sd_notify(0, "READY=1");
1124     +
1125     + See sd_notifyf() for more complete examples.
1126     +
1127     + See sd_notify(3) for more information.
1128     +*/
1129     +int sd_notify(int unset_environment, const char *state);
1130     +
1131     +/*
1132     + Similar to sd_notify() but takes a format string.
1133     +
1134     + Example 1: A daemon could send the following after initialization:
1135     +
1136     + sd_notifyf(0, "READY=1\n"
1137     + "STATUS=Processing requests...\n"
1138     + "MAINPID=%lu",
1139     + (unsigned long) getpid());
1140     +
1141     + Example 2: A daemon could send the following shortly before
1142     + exiting, on failure:
1143     +
1144     + sd_notifyf(0, "STATUS=Failed to start up: %s\n"
1145     + "ERRNO=%i",
1146     + strerror(errno),
1147     + errno);
1148     +
1149     + See sd_notifyf(3) for more information.
1150     +*/
1151     +int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3);
1152     +
1153     +/*
1154     + Returns > 0 if the system was booted with systemd. Returns < 0 on
1155     + error. Returns 0 if the system was not booted with systemd. Note
1156     + that all of the functions above handle non-systemd boots just
1157     + fine. You should NOT protect them with a call to this function. Also
1158     + note that this function checks whether the system, not the user
1159     + session is controlled by systemd. However the functions above work
1160     + for both user and system services.
1161     +
1162     + See sd_booted(3) for more information.
1163     +*/
1164     +int sd_booted(void);
1165     +
1166     +#ifdef __cplusplus
1167     +}
1168     +#endif
1169     +
1170     +#endif
1171     --
1172     1.7.6
1173