Annotation of /trunk/pcsc-lite/patches/pcsc-lite-1.7.4-systemd-socket-activation.patch
Parent Directory | Revision Log
Revision 1574 -
(hide 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 | niro | 1574 | 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 | niro | 1573 | |
6 | niro | 1574 | 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 | niro | 1573 | |
11 | niro | 1574 | 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 | niro | 1573 | + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h |
743 | + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c | ||
744 | niro | 1574 | + |
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 | niro | 1573 | -- |
1015 | 1.7.5.4 | ||
1016 | niro | 1574 |