Annotation of /trunk/pcsc-lite/patches/pcsc-lite-1.7.4-systemd-socket-activation.patch
Parent Directory | Revision Log
Revision 1573 -
(hide annotations)
(download)
Thu Nov 24 20:58:47 2011 UTC (12 years, 6 months ago) by niro
File size: 32205 byte(s)
Thu Nov 24 20:58:47 2011 UTC (12 years, 6 months ago) by niro
File size: 32205 byte(s)
systemd patches
1 | niro | 1573 | 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 |