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