Contents of /trunk/pcsc-lite/patches/pcsc-lite-1.7.4-systemd-socket-activation.patch
Parent Directory | Revision Log
Revision 1573 -
(show annotations)
(download)
Thu Nov 24 20:58:47 2011 UTC (12 years, 10 months ago) by niro
File size: 32205 byte(s)
Thu Nov 24 20:58:47 2011 UTC (12 years, 10 months ago) by niro
File size: 32205 byte(s)
systemd patches
1 | Add systemd socket-based activation support to pcscd as an alternative |
2 | to the existing autostart code which used forking from the user space |
3 | library. Systemd socket activation makes it possible to start pcscd on |
4 | demand by systemd when a request is sent on the IPC socket. |
5 | |
6 | The implementation uses the $LISTEN_FDS/$LISTEN_PID env var parsing code |
7 | from systemd's sd-daemon.[ch] copy library. |
8 | --- |
9 | PCSC/src/Makefile.am | 6 + |
10 | PCSC/src/pcscdaemon.c | 56 ++++-- |
11 | PCSC/src/sd-daemon.c | 520 +++++++++++++++++++++++++++++++++++++++++++ |
12 | PCSC/src/sd-daemon.h | 277 +++++++++++++++++++++++ |
13 | PCSC/src/winscard_msg.h | 1 + |
14 | PCSC/src/winscard_msg_srv.c | 25 ++ |
15 | 6 files changed, 870 insertions(+), 15 deletions(-) |
16 | create mode 100644 PCSC/src/sd-daemon.c |
17 | create mode 100644 PCSC/src/sd-daemon.h |
18 | |
19 | diff --git a/PCSC/src/Makefile.am b/PCSC/src/Makefile.am |
20 | index 2bd2f11..1b70466 100644 |
21 | --- a/PCSC/src/Makefile.am |
22 | +++ b/PCSC/src/Makefile.am |
23 | @@ -67,6 +67,8 @@ pcscd_SOURCES = \ |
24 | prothandler.h \ |
25 | readerfactory.c \ |
26 | readerfactory.h \ |
27 | + sd-daemon.c \ |
28 | + sd-daemon.h \ |
29 | simclist.c \ |
30 | simclist.h \ |
31 | strlcat.c \ |
32 | @@ -95,6 +97,10 @@ fix-rights: install-sbinPROGRAMS |
33 | chgrp pcscd $(DESTDIR)$(sbindir)/pcscd |
34 | chmod g+s $(DESTDIR)$(sbindir)/pcscd |
35 | |
36 | +update-systemd: |
37 | + curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c > sd-daemon.c |
38 | + curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h > sd-daemon.h |
39 | + |
40 | testpcsc_SOURCES = testpcsc.c |
41 | testpcsc_LDADD = libpcsclite.la |
42 | |
43 | diff --git a/PCSC/src/pcscdaemon.c b/PCSC/src/pcscdaemon.c |
44 | index 6abc328..609f981 100644 |
45 | --- a/PCSC/src/pcscdaemon.c |
46 | +++ b/PCSC/src/pcscdaemon.c |
47 | @@ -37,6 +37,7 @@ |
48 | #include "pcsclite.h" |
49 | #include "pcscd.h" |
50 | #include "debuglog.h" |
51 | +#include "sd-daemon.h" |
52 | #include "winscard_msg.h" |
53 | #include "winscard_svc.h" |
54 | #include "sys_generic.h" |
55 | @@ -54,6 +55,7 @@ |
56 | char AraKiri = FALSE; |
57 | static char Init = TRUE; |
58 | char AutoExit = FALSE; |
59 | +char SocketActivated = FALSE; |
60 | static int ExitValue = EXIT_FAILURE; |
61 | int HPForceReaderPolling = 0; |
62 | static int pipefd[] = {-1, -1}; |
63 | @@ -316,6 +318,20 @@ int main(int argc, char **argv) |
64 | } |
65 | |
66 | /* |
67 | + * Check if systemd passed us any file descriptors |
68 | + */ |
69 | + rv = sd_listen_fds(0); |
70 | + if (rv > 1) |
71 | + { |
72 | + Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received"); |
73 | + return EXIT_FAILURE; |
74 | + } |
75 | + else if (rv == 1) |
76 | + SocketActivated = TRUE; |
77 | + else |
78 | + SocketActivated = FALSE; |
79 | + |
80 | + /* |
81 | * test the presence of /var/run/pcscd/pcscd.comm |
82 | */ |
83 | |
84 | @@ -366,16 +382,19 @@ int main(int argc, char **argv) |
85 | return EXIT_FAILURE; |
86 | } |
87 | |
88 | - Log1(PCSC_LOG_CRITICAL, |
89 | - "file " PCSCLITE_CSOCK_NAME " already exists."); |
90 | - Log1(PCSC_LOG_CRITICAL, |
91 | - "Maybe another pcscd is running?"); |
92 | - Log1(PCSC_LOG_CRITICAL, |
93 | - "I can't read process pid from " PCSCLITE_RUN_PID); |
94 | - Log1(PCSC_LOG_CRITICAL, "Remove " PCSCLITE_CSOCK_NAME); |
95 | - Log1(PCSC_LOG_CRITICAL, |
96 | - "if pcscd is not running to clear this message."); |
97 | - return EXIT_FAILURE; |
98 | + if (!SocketActivated) |
99 | + { |
100 | + Log1(PCSC_LOG_CRITICAL, |
101 | + "file " PCSCLITE_CSOCK_NAME " already exists."); |
102 | + Log1(PCSC_LOG_CRITICAL, |
103 | + "Maybe another pcscd is running?"); |
104 | + Log1(PCSC_LOG_CRITICAL, |
105 | + "I can't read process pid from " PCSCLITE_RUN_PID); |
106 | + Log1(PCSC_LOG_CRITICAL, "Remove " PCSCLITE_CSOCK_NAME); |
107 | + Log1(PCSC_LOG_CRITICAL, |
108 | + "if pcscd is not running to clear this message."); |
109 | + return EXIT_FAILURE; |
110 | + } |
111 | } |
112 | } |
113 | else |
114 | @@ -568,7 +587,11 @@ int main(int argc, char **argv) |
115 | /* |
116 | * Initialize the comm structure |
117 | */ |
118 | - rv = InitializeSocket(); |
119 | + if (SocketActivated) |
120 | + rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0); |
121 | + else |
122 | + rv = InitializeSocket(); |
123 | + |
124 | if (rv) |
125 | { |
126 | Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); |
127 | @@ -652,10 +675,13 @@ static void clean_temp_files(void) |
128 | { |
129 | int rv; |
130 | |
131 | - rv = remove(PCSCLITE_CSOCK_NAME); |
132 | - if (rv != 0) |
133 | - Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s", |
134 | - strerror(errno)); |
135 | + if (!SocketActivated) |
136 | + { |
137 | + rv = remove(PCSCLITE_CSOCK_NAME); |
138 | + if (rv != 0) |
139 | + Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s", |
140 | + strerror(errno)); |
141 | + } |
142 | |
143 | rv = remove(PCSCLITE_RUN_PID); |
144 | if (rv != 0) |
145 | diff --git a/PCSC/src/sd-daemon.c b/PCSC/src/sd-daemon.c |
146 | new file mode 100644 |
147 | index 0000000..a2ec74c |
148 | --- /dev/null |
149 | +++ b/PCSC/src/sd-daemon.c |
150 | @@ -0,0 +1,520 @@ |
151 | +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
152 | + |
153 | +/*** |
154 | + Copyright 2010 Lennart Poettering |
155 | + |
156 | + Permission is hereby granted, free of charge, to any person |
157 | + obtaining a copy of this software and associated documentation files |
158 | + (the "Software"), to deal in the Software without restriction, |
159 | + including without limitation the rights to use, copy, modify, merge, |
160 | + publish, distribute, sublicense, and/or sell copies of the Software, |
161 | + and to permit persons to whom the Software is furnished to do so, |
162 | + subject to the following conditions: |
163 | + |
164 | + The above copyright notice and this permission notice shall be |
165 | + included in all copies or substantial portions of the Software. |
166 | + |
167 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
168 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
169 | + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
170 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
171 | + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
172 | + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
173 | + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
174 | + SOFTWARE. |
175 | +***/ |
176 | + |
177 | +#ifndef _GNU_SOURCE |
178 | +#define _GNU_SOURCE |
179 | +#endif |
180 | + |
181 | +#include <sys/types.h> |
182 | +#include <sys/stat.h> |
183 | +#include <sys/socket.h> |
184 | +#include <sys/un.h> |
185 | +#include <sys/fcntl.h> |
186 | +#include <netinet/in.h> |
187 | +#include <stdlib.h> |
188 | +#include <errno.h> |
189 | +#include <unistd.h> |
190 | +#include <string.h> |
191 | +#include <stdarg.h> |
192 | +#include <stdio.h> |
193 | +#include <stddef.h> |
194 | +#include <limits.h> |
195 | + |
196 | +#if defined(__linux__) |
197 | +#include <mqueue.h> |
198 | +#endif |
199 | + |
200 | +#include "sd-daemon.h" |
201 | + |
202 | +#if (__GNUC__ >= 4) && !defined(SD_EXPORT_SYMBOLS) |
203 | +#define _sd_hidden_ __attribute__ ((visibility("hidden"))) |
204 | +#else |
205 | +#define _sd_hidden_ |
206 | +#endif |
207 | + |
208 | +_sd_hidden_ int sd_listen_fds(int unset_environment) { |
209 | + |
210 | +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) |
211 | + return 0; |
212 | +#else |
213 | + int r, fd; |
214 | + const char *e; |
215 | + char *p = NULL; |
216 | + unsigned long l; |
217 | + |
218 | + if (!(e = getenv("LISTEN_PID"))) { |
219 | + r = 0; |
220 | + goto finish; |
221 | + } |
222 | + |
223 | + errno = 0; |
224 | + l = strtoul(e, &p, 10); |
225 | + |
226 | + if (errno != 0) { |
227 | + r = -errno; |
228 | + goto finish; |
229 | + } |
230 | + |
231 | + if (!p || *p || l <= 0) { |
232 | + r = -EINVAL; |
233 | + goto finish; |
234 | + } |
235 | + |
236 | + /* Is this for us? */ |
237 | + if (getpid() != (pid_t) l) { |
238 | + r = 0; |
239 | + goto finish; |
240 | + } |
241 | + |
242 | + if (!(e = getenv("LISTEN_FDS"))) { |
243 | + r = 0; |
244 | + goto finish; |
245 | + } |
246 | + |
247 | + errno = 0; |
248 | + l = strtoul(e, &p, 10); |
249 | + |
250 | + if (errno != 0) { |
251 | + r = -errno; |
252 | + goto finish; |
253 | + } |
254 | + |
255 | + if (!p || *p) { |
256 | + r = -EINVAL; |
257 | + goto finish; |
258 | + } |
259 | + |
260 | + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { |
261 | + int flags; |
262 | + |
263 | + if ((flags = fcntl(fd, F_GETFD)) < 0) { |
264 | + r = -errno; |
265 | + goto finish; |
266 | + } |
267 | + |
268 | + if (flags & FD_CLOEXEC) |
269 | + continue; |
270 | + |
271 | + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { |
272 | + r = -errno; |
273 | + goto finish; |
274 | + } |
275 | + } |
276 | + |
277 | + r = (int) l; |
278 | + |
279 | +finish: |
280 | + if (unset_environment) { |
281 | + unsetenv("LISTEN_PID"); |
282 | + unsetenv("LISTEN_FDS"); |
283 | + } |
284 | + |
285 | + return r; |
286 | +#endif |
287 | +} |
288 | + |
289 | +_sd_hidden_ int sd_is_fifo(int fd, const char *path) { |
290 | + struct stat st_fd; |
291 | + |
292 | + if (fd < 0) |
293 | + return -EINVAL; |
294 | + |
295 | + memset(&st_fd, 0, sizeof(st_fd)); |
296 | + if (fstat(fd, &st_fd) < 0) |
297 | + return -errno; |
298 | + |
299 | + if (!S_ISFIFO(st_fd.st_mode)) |
300 | + return 0; |
301 | + |
302 | + if (path) { |
303 | + struct stat st_path; |
304 | + |
305 | + memset(&st_path, 0, sizeof(st_path)); |
306 | + if (stat(path, &st_path) < 0) { |
307 | + |
308 | + if (errno == ENOENT || errno == ENOTDIR) |
309 | + return 0; |
310 | + |
311 | + return -errno; |
312 | + } |
313 | + |
314 | + return |
315 | + st_path.st_dev == st_fd.st_dev && |
316 | + st_path.st_ino == st_fd.st_ino; |
317 | + } |
318 | + |
319 | + return 1; |
320 | +} |
321 | + |
322 | +_sd_hidden_ int sd_is_special(int fd, const char *path) { |
323 | + struct stat st_fd; |
324 | + |
325 | + if (fd < 0) |
326 | + return -EINVAL; |
327 | + |
328 | + if (fstat(fd, &st_fd) < 0) |
329 | + return -errno; |
330 | + |
331 | + if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) |
332 | + return 0; |
333 | + |
334 | + if (path) { |
335 | + struct stat st_path; |
336 | + |
337 | + if (stat(path, &st_path) < 0) { |
338 | + |
339 | + if (errno == ENOENT || errno == ENOTDIR) |
340 | + return 0; |
341 | + |
342 | + return -errno; |
343 | + } |
344 | + |
345 | + if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) |
346 | + return |
347 | + st_path.st_dev == st_fd.st_dev && |
348 | + st_path.st_ino == st_fd.st_ino; |
349 | + else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) |
350 | + return st_path.st_rdev == st_fd.st_rdev; |
351 | + else |
352 | + return 0; |
353 | + } |
354 | + |
355 | + return 1; |
356 | +} |
357 | + |
358 | +static int sd_is_socket_internal(int fd, int type, int listening) { |
359 | + struct stat st_fd; |
360 | + |
361 | + if (fd < 0 || type < 0) |
362 | + return -EINVAL; |
363 | + |
364 | + if (fstat(fd, &st_fd) < 0) |
365 | + return -errno; |
366 | + |
367 | + if (!S_ISSOCK(st_fd.st_mode)) |
368 | + return 0; |
369 | + |
370 | + if (type != 0) { |
371 | + int other_type = 0; |
372 | + socklen_t l = sizeof(other_type); |
373 | + |
374 | + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) |
375 | + return -errno; |
376 | + |
377 | + if (l != sizeof(other_type)) |
378 | + return -EINVAL; |
379 | + |
380 | + if (other_type != type) |
381 | + return 0; |
382 | + } |
383 | + |
384 | + if (listening >= 0) { |
385 | + int accepting = 0; |
386 | + socklen_t l = sizeof(accepting); |
387 | + |
388 | + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) |
389 | + return -errno; |
390 | + |
391 | + if (l != sizeof(accepting)) |
392 | + return -EINVAL; |
393 | + |
394 | + if (!accepting != !listening) |
395 | + return 0; |
396 | + } |
397 | + |
398 | + return 1; |
399 | +} |
400 | + |
401 | +union sockaddr_union { |
402 | + struct sockaddr sa; |
403 | + struct sockaddr_in in4; |
404 | + struct sockaddr_in6 in6; |
405 | + struct sockaddr_un un; |
406 | + struct sockaddr_storage storage; |
407 | +}; |
408 | + |
409 | +_sd_hidden_ int sd_is_socket(int fd, int family, int type, int listening) { |
410 | + int r; |
411 | + |
412 | + if (family < 0) |
413 | + return -EINVAL; |
414 | + |
415 | + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) |
416 | + return r; |
417 | + |
418 | + if (family > 0) { |
419 | + union sockaddr_union sockaddr; |
420 | + socklen_t l; |
421 | + |
422 | + memset(&sockaddr, 0, sizeof(sockaddr)); |
423 | + l = sizeof(sockaddr); |
424 | + |
425 | + if (getsockname(fd, &sockaddr.sa, &l) < 0) |
426 | + return -errno; |
427 | + |
428 | + if (l < sizeof(sa_family_t)) |
429 | + return -EINVAL; |
430 | + |
431 | + return sockaddr.sa.sa_family == family; |
432 | + } |
433 | + |
434 | + return 1; |
435 | +} |
436 | + |
437 | +_sd_hidden_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { |
438 | + union sockaddr_union sockaddr; |
439 | + socklen_t l; |
440 | + int r; |
441 | + |
442 | + if (family != 0 && family != AF_INET && family != AF_INET6) |
443 | + return -EINVAL; |
444 | + |
445 | + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) |
446 | + return r; |
447 | + |
448 | + memset(&sockaddr, 0, sizeof(sockaddr)); |
449 | + l = sizeof(sockaddr); |
450 | + |
451 | + if (getsockname(fd, &sockaddr.sa, &l) < 0) |
452 | + return -errno; |
453 | + |
454 | + if (l < sizeof(sa_family_t)) |
455 | + return -EINVAL; |
456 | + |
457 | + if (sockaddr.sa.sa_family != AF_INET && |
458 | + sockaddr.sa.sa_family != AF_INET6) |
459 | + return 0; |
460 | + |
461 | + if (family > 0) |
462 | + if (sockaddr.sa.sa_family != family) |
463 | + return 0; |
464 | + |
465 | + if (port > 0) { |
466 | + if (sockaddr.sa.sa_family == AF_INET) { |
467 | + if (l < sizeof(struct sockaddr_in)) |
468 | + return -EINVAL; |
469 | + |
470 | + return htons(port) == sockaddr.in4.sin_port; |
471 | + } else { |
472 | + if (l < sizeof(struct sockaddr_in6)) |
473 | + return -EINVAL; |
474 | + |
475 | + return htons(port) == sockaddr.in6.sin6_port; |
476 | + } |
477 | + } |
478 | + |
479 | + return 1; |
480 | +} |
481 | + |
482 | +_sd_hidden_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { |
483 | + union sockaddr_union sockaddr; |
484 | + socklen_t l; |
485 | + int r; |
486 | + |
487 | + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) |
488 | + return r; |
489 | + |
490 | + memset(&sockaddr, 0, sizeof(sockaddr)); |
491 | + l = sizeof(sockaddr); |
492 | + |
493 | + if (getsockname(fd, &sockaddr.sa, &l) < 0) |
494 | + return -errno; |
495 | + |
496 | + if (l < sizeof(sa_family_t)) |
497 | + return -EINVAL; |
498 | + |
499 | + if (sockaddr.sa.sa_family != AF_UNIX) |
500 | + return 0; |
501 | + |
502 | + if (path) { |
503 | + if (length <= 0) |
504 | + length = strlen(path); |
505 | + |
506 | + if (length <= 0) |
507 | + /* Unnamed socket */ |
508 | + return l == offsetof(struct sockaddr_un, sun_path); |
509 | + |
510 | + if (path[0]) |
511 | + /* Normal path socket */ |
512 | + return |
513 | + (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && |
514 | + memcmp(path, sockaddr.un.sun_path, length+1) == 0; |
515 | + else |
516 | + /* Abstract namespace socket */ |
517 | + return |
518 | + (l == offsetof(struct sockaddr_un, sun_path) + length) && |
519 | + memcmp(path, sockaddr.un.sun_path, length) == 0; |
520 | + } |
521 | + |
522 | + return 1; |
523 | +} |
524 | + |
525 | +_sd_hidden_ int sd_is_mq(int fd, const char *path) { |
526 | +#if !defined(__linux__) |
527 | + return 0; |
528 | +#else |
529 | + struct mq_attr attr; |
530 | + |
531 | + if (fd < 0) |
532 | + return -EINVAL; |
533 | + |
534 | + if (mq_getattr(fd, &attr) < 0) |
535 | + return -errno; |
536 | + |
537 | + if (path) { |
538 | + char fpath[PATH_MAX]; |
539 | + struct stat a, b; |
540 | + |
541 | + if (path[0] != '/') |
542 | + return -EINVAL; |
543 | + |
544 | + if (fstat(fd, &a) < 0) |
545 | + return -errno; |
546 | + |
547 | + strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); |
548 | + fpath[sizeof(fpath)-1] = 0; |
549 | + |
550 | + if (stat(fpath, &b) < 0) |
551 | + return -errno; |
552 | + |
553 | + if (a.st_dev != b.st_dev || |
554 | + a.st_ino != b.st_ino) |
555 | + return 0; |
556 | + } |
557 | + |
558 | + return 1; |
559 | +#endif |
560 | +} |
561 | + |
562 | +_sd_hidden_ int sd_notify(int unset_environment, const char *state) { |
563 | +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) |
564 | + return 0; |
565 | +#else |
566 | + int fd = -1, r; |
567 | + struct msghdr msghdr; |
568 | + struct iovec iovec; |
569 | + union sockaddr_union sockaddr; |
570 | + const char *e; |
571 | + |
572 | + if (!state) { |
573 | + r = -EINVAL; |
574 | + goto finish; |
575 | + } |
576 | + |
577 | + if (!(e = getenv("NOTIFY_SOCKET"))) |
578 | + return 0; |
579 | + |
580 | + /* Must be an abstract socket, or an absolute path */ |
581 | + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { |
582 | + r = -EINVAL; |
583 | + goto finish; |
584 | + } |
585 | + |
586 | + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { |
587 | + r = -errno; |
588 | + goto finish; |
589 | + } |
590 | + |
591 | + memset(&sockaddr, 0, sizeof(sockaddr)); |
592 | + sockaddr.sa.sa_family = AF_UNIX; |
593 | + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); |
594 | + |
595 | + if (sockaddr.un.sun_path[0] == '@') |
596 | + sockaddr.un.sun_path[0] = 0; |
597 | + |
598 | + memset(&iovec, 0, sizeof(iovec)); |
599 | + iovec.iov_base = (char*) state; |
600 | + iovec.iov_len = strlen(state); |
601 | + |
602 | + memset(&msghdr, 0, sizeof(msghdr)); |
603 | + msghdr.msg_name = &sockaddr; |
604 | + msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); |
605 | + |
606 | + if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) |
607 | + msghdr.msg_namelen = sizeof(struct sockaddr_un); |
608 | + |
609 | + msghdr.msg_iov = &iovec; |
610 | + msghdr.msg_iovlen = 1; |
611 | + |
612 | + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { |
613 | + r = -errno; |
614 | + goto finish; |
615 | + } |
616 | + |
617 | + r = 1; |
618 | + |
619 | +finish: |
620 | + if (unset_environment) |
621 | + unsetenv("NOTIFY_SOCKET"); |
622 | + |
623 | + if (fd >= 0) |
624 | + close(fd); |
625 | + |
626 | + return r; |
627 | +#endif |
628 | +} |
629 | + |
630 | +_sd_hidden_ int sd_notifyf(int unset_environment, const char *format, ...) { |
631 | +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) |
632 | + return 0; |
633 | +#else |
634 | + va_list ap; |
635 | + char *p = NULL; |
636 | + int r; |
637 | + |
638 | + va_start(ap, format); |
639 | + r = vasprintf(&p, format, ap); |
640 | + va_end(ap); |
641 | + |
642 | + if (r < 0 || !p) |
643 | + return -ENOMEM; |
644 | + |
645 | + r = sd_notify(unset_environment, p); |
646 | + free(p); |
647 | + |
648 | + return r; |
649 | +#endif |
650 | +} |
651 | + |
652 | +_sd_hidden_ int sd_booted(void) { |
653 | +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) |
654 | + return 0; |
655 | +#else |
656 | + |
657 | + struct stat a, b; |
658 | + |
659 | + /* We simply test whether the systemd cgroup hierarchy is |
660 | + * mounted */ |
661 | + |
662 | + if (lstat("/sys/fs/cgroup", &a) < 0) |
663 | + return 0; |
664 | + |
665 | + if (lstat("/sys/fs/cgroup/systemd", &b) < 0) |
666 | + return 0; |
667 | + |
668 | + return a.st_dev != b.st_dev; |
669 | +#endif |
670 | +} |
671 | diff --git a/PCSC/src/sd-daemon.h b/PCSC/src/sd-daemon.h |
672 | new file mode 100644 |
673 | index 0000000..46dc7fd |
674 | --- /dev/null |
675 | +++ b/PCSC/src/sd-daemon.h |
676 | @@ -0,0 +1,277 @@ |
677 | +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
678 | + |
679 | +#ifndef foosddaemonhfoo |
680 | +#define foosddaemonhfoo |
681 | + |
682 | +/*** |
683 | + Copyright 2010 Lennart Poettering |
684 | + |
685 | + Permission is hereby granted, free of charge, to any person |
686 | + obtaining a copy of this software and associated documentation files |
687 | + (the "Software"), to deal in the Software without restriction, |
688 | + including without limitation the rights to use, copy, modify, merge, |
689 | + publish, distribute, sublicense, and/or sell copies of the Software, |
690 | + and to permit persons to whom the Software is furnished to do so, |
691 | + subject to the following conditions: |
692 | + |
693 | + The above copyright notice and this permission notice shall be |
694 | + included in all copies or substantial portions of the Software. |
695 | + |
696 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
697 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
698 | + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
699 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
700 | + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
701 | + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
702 | + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
703 | + SOFTWARE. |
704 | +***/ |
705 | + |
706 | +#include <sys/types.h> |
707 | +#include <inttypes.h> |
708 | + |
709 | +#ifdef __cplusplus |
710 | +extern "C" { |
711 | +#endif |
712 | + |
713 | +/* |
714 | + Reference implementation of a few systemd related interfaces for |
715 | + writing daemons. These interfaces are trivial to implement. To |
716 | + simplify porting we provide this reference implementation. |
717 | + Applications are welcome to reimplement the algorithms described |
718 | + here if they do not want to include these two source files. |
719 | + |
720 | + The following functionality is provided: |
721 | + |
722 | + - Support for logging with log levels on stderr |
723 | + - File descriptor passing for socket-based activation |
724 | + - Daemon startup and status notification |
725 | + - Detection of systemd boots |
726 | + |
727 | + You may compile this with -DDISABLE_SYSTEMD to disable systemd |
728 | + support. This makes all those calls NOPs that are directly related to |
729 | + systemd (i.e. only sd_is_xxx() will stay useful). |
730 | + |
731 | + Since this is drop-in code we don't want any of our symbols to be |
732 | + exported in any case. Hence we declare hidden visibility for all of |
733 | + them. |
734 | + |
735 | + You may find an up-to-date version of these source files online: |
736 | + |
737 | + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h |
738 | + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c |
739 | + |
740 | + This should compile on non-Linux systems, too, but with the |
741 | + exception of the sd_is_xxx() calls all functions will become NOPs. |
742 | + |
743 | + See sd-daemon(7) for more information. |
744 | +*/ |
745 | + |
746 | +#ifndef _sd_printf_attr_ |
747 | +#if __GNUC__ >= 4 |
748 | +#define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b))) |
749 | +#else |
750 | +#define _sd_printf_attr_(a,b) |
751 | +#endif |
752 | +#endif |
753 | + |
754 | +/* |
755 | + Log levels for usage on stderr: |
756 | + |
757 | + fprintf(stderr, SD_NOTICE "Hello World!\n"); |
758 | + |
759 | + This is similar to printk() usage in the kernel. |
760 | +*/ |
761 | +#define SD_EMERG "<0>" /* system is unusable */ |
762 | +#define SD_ALERT "<1>" /* action must be taken immediately */ |
763 | +#define SD_CRIT "<2>" /* critical conditions */ |
764 | +#define SD_ERR "<3>" /* error conditions */ |
765 | +#define SD_WARNING "<4>" /* warning conditions */ |
766 | +#define SD_NOTICE "<5>" /* normal but significant condition */ |
767 | +#define SD_INFO "<6>" /* informational */ |
768 | +#define SD_DEBUG "<7>" /* debug-level messages */ |
769 | + |
770 | +/* The first passed file descriptor is fd 3 */ |
771 | +#define SD_LISTEN_FDS_START 3 |
772 | + |
773 | +/* |
774 | + Returns how many file descriptors have been passed, or a negative |
775 | + errno code on failure. Optionally, removes the $LISTEN_FDS and |
776 | + $LISTEN_PID file descriptors from the environment (recommended, but |
777 | + problematic in threaded environments). If r is the return value of |
778 | + this function you'll find the file descriptors passed as fds |
779 | + SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative |
780 | + errno style error code on failure. This function call ensures that |
781 | + the FD_CLOEXEC flag is set for the passed file descriptors, to make |
782 | + sure they are not passed on to child processes. If FD_CLOEXEC shall |
783 | + not be set, the caller needs to unset it after this call for all file |
784 | + descriptors that are used. |
785 | + |
786 | + See sd_listen_fds(3) for more information. |
787 | +*/ |
788 | +int sd_listen_fds(int unset_environment); |
789 | + |
790 | +/* |
791 | + Helper call for identifying a passed file descriptor. Returns 1 if |
792 | + the file descriptor is a FIFO in the file system stored under the |
793 | + specified path, 0 otherwise. If path is NULL a path name check will |
794 | + not be done and the call only verifies if the file descriptor |
795 | + refers to a FIFO. Returns a negative errno style error code on |
796 | + failure. |
797 | + |
798 | + See sd_is_fifo(3) for more information. |
799 | +*/ |
800 | +int sd_is_fifo(int fd, const char *path); |
801 | + |
802 | +/* |
803 | + Helper call for identifying a passed file descriptor. Returns 1 if |
804 | + the file descriptor is a special character device on the file |
805 | + system stored under the specified path, 0 otherwise. |
806 | + If path is NULL a path name check will not be done and the call |
807 | + only verifies if the file descriptor refers to a special character. |
808 | + Returns a negative errno style error code on failure. |
809 | + |
810 | + See sd_is_special(3) for more information. |
811 | +*/ |
812 | +int sd_is_special(int fd, const char *path); |
813 | + |
814 | +/* |
815 | + Helper call for identifying a passed file descriptor. Returns 1 if |
816 | + the file descriptor is a socket of the specified family (AF_INET, |
817 | + ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If |
818 | + family is 0 a socket family check will not be done. If type is 0 a |
819 | + socket type check will not be done and the call only verifies if |
820 | + the file descriptor refers to a socket. If listening is > 0 it is |
821 | + verified that the socket is in listening mode. (i.e. listen() has |
822 | + been called) If listening is == 0 it is verified that the socket is |
823 | + not in listening mode. If listening is < 0 no listening mode check |
824 | + is done. Returns a negative errno style error code on failure. |
825 | + |
826 | + See sd_is_socket(3) for more information. |
827 | +*/ |
828 | +int sd_is_socket(int fd, int family, int type, int listening); |
829 | + |
830 | +/* |
831 | + Helper call for identifying a passed file descriptor. Returns 1 if |
832 | + the file descriptor is an Internet socket, of the specified family |
833 | + (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM, |
834 | + SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version |
835 | + check is not done. If type is 0 a socket type check will not be |
836 | + done. If port is 0 a socket port check will not be done. The |
837 | + listening flag is used the same way as in sd_is_socket(). Returns a |
838 | + negative errno style error code on failure. |
839 | + |
840 | + See sd_is_socket_inet(3) for more information. |
841 | +*/ |
842 | +int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port); |
843 | + |
844 | +/* |
845 | + Helper call for identifying a passed file descriptor. Returns 1 if |
846 | + the file descriptor is an AF_UNIX socket of the specified type |
847 | + (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0 |
848 | + a socket type check will not be done. If path is NULL a socket path |
849 | + check will not be done. For normal AF_UNIX sockets set length to |
850 | + 0. For abstract namespace sockets set length to the length of the |
851 | + socket name (including the initial 0 byte), and pass the full |
852 | + socket path in path (including the initial 0 byte). The listening |
853 | + flag is used the same way as in sd_is_socket(). Returns a negative |
854 | + errno style error code on failure. |
855 | + |
856 | + See sd_is_socket_unix(3) for more information. |
857 | +*/ |
858 | +int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length); |
859 | + |
860 | +/* |
861 | + Helper call for identifying a passed file descriptor. Returns 1 if |
862 | + the file descriptor is a POSIX Message Queue of the specified name, |
863 | + 0 otherwise. If path is NULL a message queue name check is not |
864 | + done. Returns a negative errno style error code on failure. |
865 | +*/ |
866 | +int sd_is_mq(int fd, const char *path); |
867 | + |
868 | +/* |
869 | + Informs systemd about changed daemon state. This takes a number of |
870 | + newline separated environment-style variable assignments in a |
871 | + string. The following variables are known: |
872 | + |
873 | + READY=1 Tells systemd that daemon startup is finished (only |
874 | + relevant for services of Type=notify). The passed |
875 | + argument is a boolean "1" or "0". Since there is |
876 | + little value in signaling non-readiness the only |
877 | + value daemons should send is "READY=1". |
878 | + |
879 | + STATUS=... Passes a single-line status string back to systemd |
880 | + that describes the daemon state. This is free-from |
881 | + and can be used for various purposes: general state |
882 | + feedback, fsck-like programs could pass completion |
883 | + percentages and failing programs could pass a human |
884 | + readable error message. Example: "STATUS=Completed |
885 | + 66% of file system check..." |
886 | + |
887 | + ERRNO=... If a daemon fails, the errno-style error code, |
888 | + formatted as string. Example: "ERRNO=2" for ENOENT. |
889 | + |
890 | + BUSERROR=... If a daemon fails, the D-Bus error-style error |
891 | + code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut" |
892 | + |
893 | + MAINPID=... The main pid of a daemon, in case systemd did not |
894 | + fork off the process itself. Example: "MAINPID=4711" |
895 | + |
896 | + Daemons can choose to send additional variables. However, it is |
897 | + recommended to prefix variable names not listed above with X_. |
898 | + |
899 | + Returns a negative errno-style error code on failure. Returns > 0 |
900 | + if systemd could be notified, 0 if it couldn't possibly because |
901 | + systemd is not running. |
902 | + |
903 | + Example: When a daemon finished starting up, it could issue this |
904 | + call to notify systemd about it: |
905 | + |
906 | + sd_notify(0, "READY=1"); |
907 | + |
908 | + See sd_notifyf() for more complete examples. |
909 | + |
910 | + See sd_notify(3) for more information. |
911 | +*/ |
912 | +int sd_notify(int unset_environment, const char *state); |
913 | + |
914 | +/* |
915 | + Similar to sd_notify() but takes a format string. |
916 | + |
917 | + Example 1: A daemon could send the following after initialization: |
918 | + |
919 | + sd_notifyf(0, "READY=1\n" |
920 | + "STATUS=Processing requests...\n" |
921 | + "MAINPID=%lu", |
922 | + (unsigned long) getpid()); |
923 | + |
924 | + Example 2: A daemon could send the following shortly before |
925 | + exiting, on failure: |
926 | + |
927 | + sd_notifyf(0, "STATUS=Failed to start up: %s\n" |
928 | + "ERRNO=%i", |
929 | + strerror(errno), |
930 | + errno); |
931 | + |
932 | + See sd_notifyf(3) for more information. |
933 | +*/ |
934 | +int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3); |
935 | + |
936 | +/* |
937 | + Returns > 0 if the system was booted with systemd. Returns < 0 on |
938 | + error. Returns 0 if the system was not booted with systemd. Note |
939 | + that all of the functions above handle non-systemd boots just |
940 | + fine. You should NOT protect them with a call to this function. Also |
941 | + note that this function checks whether the system, not the user |
942 | + session is controlled by systemd. However the functions above work |
943 | + for both user and system services. |
944 | + |
945 | + See sd_booted(3) for more information. |
946 | +*/ |
947 | +int sd_booted(void); |
948 | + |
949 | +#ifdef __cplusplus |
950 | +} |
951 | +#endif |
952 | + |
953 | +#endif |
954 | diff --git a/PCSC/src/winscard_msg.h b/PCSC/src/winscard_msg.h |
955 | index b2b6f90..b8c490c 100644 |
956 | --- a/PCSC/src/winscard_msg.h |
957 | +++ b/PCSC/src/winscard_msg.h |
958 | @@ -252,6 +252,7 @@ |
959 | |
960 | #ifdef PCSCD |
961 | int32_t InitializeSocket(void); |
962 | + int32_t ListenExistingSocket(int fd); |
963 | int32_t ProcessEventsServer(/*@out@*/ uint32_t *); |
964 | #else |
965 | char *getSocketName(void); |
966 | diff --git a/PCSC/src/winscard_msg_srv.c b/PCSC/src/winscard_msg_srv.c |
967 | index 19ea363..4bb5bdc 100644 |
968 | --- a/PCSC/src/winscard_msg_srv.c |
969 | +++ b/PCSC/src/winscard_msg_srv.c |
970 | @@ -39,6 +39,7 @@ |
971 | |
972 | #include "misc.h" |
973 | #include "pcscd.h" |
974 | +#include "sd-daemon.h" |
975 | #include "winscard.h" |
976 | #include "debuglog.h" |
977 | #include "winscard_msg.h" |
978 | @@ -138,6 +139,30 @@ INTERNAL int32_t InitializeSocket(void) |
979 | } |
980 | |
981 | /** |
982 | + * @brief Acquires a socket passed in from systemd. |
983 | + * |
984 | + * This is called by the server to start listening on an existing socket for |
985 | + * local IPC with the clients. |
986 | + * |
987 | + * @param fd The file descriptor to start listening on. |
988 | + * |
989 | + * @return Error code. |
990 | + * @retval 0 Success |
991 | + * @retval -1 Passed FD is not an UNIX socket. |
992 | + */ |
993 | +INTERNAL int32_t ListenExistingSocket(int fd) |
994 | +{ |
995 | + if (!sd_is_socket(fd, AF_UNIX, SOCK_STREAM, -1)) |
996 | + { |
997 | + Log1(PCSC_LOG_CRITICAL, "Passed FD is not an UNIX socket"); |
998 | + return -1; |
999 | + } |
1000 | + |
1001 | + commonSocket = fd; |
1002 | + return 0; |
1003 | +} |
1004 | + |
1005 | +/** |
1006 | * @brief Looks for messages sent by clients. |
1007 | * |
1008 | * This is called by the Server's function \c SVCServiceRunLoop(). |
1009 | -- |
1010 | 1.7.5.4 |