]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/uuidd.c
autotools: add missing dist_noinst_DATA
[thirdparty/util-linux.git] / misc-utils / uuidd.c
1 /*
2 * uuidd.c --- UUID-generation daemon
3 *
4 * Copyright (C) 2007 Theodore Ts'o
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12 /*
13 * The uuidd protocol.
14 *
15 * Client:
16 * | operation type (1 byte) | number of uuids (if bulk request, 4 bytes) |
17 *
18 * Server:
19 * | reply length (4 bytes) | uuid reply (16 bytes) |
20 * or
21 * | reply length (4 bytes) | uuid reply (16 bytes) multiply by number when random bulk request |
22 * or
23 * | reply length (4 bytes) | uuid reply (16 bytes) | number (4 bytes) time bulk |
24 * or
25 * | reply length (4 bytes) | pid or maxop number string length in ascii (up to 7 bytes) |
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <inttypes.h>
32 #include <errno.h>
33 #include <err.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <string.h>
41 #include <getopt.h>
42 #include <sys/signalfd.h>
43 #include <poll.h>
44
45 #include "uuid.h"
46 #include "uuidd.h"
47 #include "all-io.h"
48 #include "c.h"
49 #include "closestream.h"
50 #include "strutils.h"
51 #include "optutils.h"
52 #include "monotonic.h"
53 #include "timer.h"
54
55 #ifdef HAVE_LIBSYSTEMD
56 # include <systemd/sd-daemon.h>
57 #endif
58
59 #include "nls.h"
60
61 /* Protocol segment lengths */
62 typedef uint8_t uuidd_prot_op_t; /* client operation field */
63 typedef int32_t uuidd_prot_num_t; /* number of requested uuids */
64
65 enum {
66 /* client - server buffer size */
67 UUIDD_PROT_BUFSZ = ((sizeof(uuidd_prot_num_t)) + (sizeof(uuid_t) * 63))
68 };
69
70 /* server loop control structure */
71 struct uuidd_cxt_t {
72 const char *cleanup_pidfile;
73 const char *cleanup_socket;
74 uint32_t timeout;
75 uint32_t cont_clock_offset;
76
77 unsigned int debug: 1,
78 quiet: 1,
79 no_fork: 1,
80 no_sock: 1;
81 };
82
83 struct uuidd_options_t {
84 const char *pidfile_path;
85 const char *socket_path;
86 uuidd_prot_num_t num;
87 uuidd_prot_op_t do_type;
88 unsigned int do_kill:1,
89 no_pid:1,
90 s_flag:1;
91 };
92
93 static void __attribute__((__noreturn__)) usage(void)
94 {
95 FILE *out = stdout;
96 fputs(USAGE_HEADER, out);
97 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
98 fputs(USAGE_SEPARATOR, out);
99 fputs(_("A daemon for generating UUIDs.\n"), out);
100 fputs(USAGE_OPTIONS, out);
101 fputs(_(" -p, --pid <path> path to pid file\n"), out);
102 fputs(_(" -s, --socket <path> path to socket\n"), out);
103 fputs(_(" -T, --timeout <sec> specify inactivity timeout\n"), out);
104 fputs(_(" -k, --kill kill running daemon\n"), out);
105 fputs(_(" -r, --random test random-based generation\n"), out);
106 fputs(_(" -t, --time test time-based generation\n"), out);
107 fputs(_(" -n, --uuids <num> request number of uuids\n"), out);
108 fputs(_(" -P, --no-pid do not create pid file\n"), out);
109 fputs(_(" -F, --no-fork do not daemonize using double-fork\n"), out);
110 fputs(_(" -S, --socket-activation do not create listening socket\n"), out);
111 fputs(_(" -C, --cont-clock[=<NUM>[hd]]\n"), out);
112 fputs(_(" activate continuous clock handling\n"), out);
113 fputs(_(" -d, --debug run in debugging mode\n"), out);
114 fputs(_(" -q, --quiet turn on quiet mode\n"), out);
115 fputs(USAGE_SEPARATOR, out);
116 fprintf(out, USAGE_HELP_OPTIONS(25));
117 fprintf(out, USAGE_MAN_TAIL("uuidd(8)"));
118 exit(EXIT_SUCCESS);
119 }
120
121 static void create_daemon(void)
122 {
123 uid_t euid;
124
125 if (daemon(0, 0))
126 err(EXIT_FAILURE, "daemon");
127
128 euid = geteuid();
129 if (setreuid(euid, euid) < 0)
130 err(EXIT_FAILURE, "setreuid");
131 }
132
133 static int call_daemon(const char *socket_path, uuidd_prot_op_t op, char *buf,
134 size_t buflen, uuidd_prot_num_t *num, const char **err_context)
135 {
136 char op_buf[sizeof(op) + sizeof(*num)];
137 size_t op_len;
138 int s;
139 ssize_t ret;
140 int32_t reply_len = 0;
141 struct sockaddr_un srv_addr;
142
143 if (((op == UUIDD_OP_BULK_TIME_UUID) ||
144 (op == UUIDD_OP_BULK_RANDOM_UUID)) && !num) {
145 if (err_context)
146 *err_context = _("bad arguments");
147 errno = EINVAL;
148 return -1;
149 }
150
151 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
152 if (err_context)
153 *err_context = _("socket");
154 return -1;
155 }
156
157 srv_addr.sun_family = AF_UNIX;
158 assert(strlen(socket_path) < sizeof(srv_addr.sun_path));
159 xstrncpy(srv_addr.sun_path, socket_path, sizeof(srv_addr.sun_path));
160
161 if (connect(s, (const struct sockaddr *) &srv_addr,
162 sizeof(struct sockaddr_un)) < 0) {
163 if (err_context)
164 *err_context = _("connect");
165 close(s);
166 return -1;
167 }
168
169 if (op == UUIDD_OP_BULK_RANDOM_UUID) {
170 if ((buflen - sizeof(*num)) < (size_t)((*num) * sizeof(uuid_t)))
171 *num = (buflen - sizeof(*num)) / sizeof(uuid_t);
172 }
173 op_buf[0] = op;
174 op_len = sizeof(op);
175 if ((op == UUIDD_OP_BULK_TIME_UUID) ||
176 (op == UUIDD_OP_BULK_RANDOM_UUID)) {
177 memcpy(op_buf + sizeof(op), num, sizeof(*num));
178 op_len += sizeof(*num);
179 }
180
181 ret = write_all(s, op_buf, op_len);
182 if (ret < 0) {
183 if (err_context)
184 *err_context = _("write");
185 close(s);
186 return -1;
187 }
188
189 ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
190 if (ret < 0) {
191 if (err_context)
192 *err_context = _("read count");
193 close(s);
194 return -1;
195 }
196 if (reply_len < 0 || (size_t) reply_len > buflen) {
197 if (err_context)
198 *err_context = _("bad response length");
199 close(s);
200 return -1;
201 }
202 ret = read_all(s, (char *) buf, reply_len);
203
204 if ((ret > 0) && (op == UUIDD_OP_BULK_TIME_UUID)) {
205 if ((sizeof(uuid_t) + sizeof(*num)) <= (size_t) reply_len)
206 memcpy(buf + sizeof(uuid_t), num, sizeof(*num));
207 else
208 *num = -1;
209 }
210 if ((ret > 0) && (op == UUIDD_OP_BULK_RANDOM_UUID)) {
211 if (sizeof(*num) <= (size_t) reply_len)
212 memcpy(buf, num, sizeof(*num));
213 else
214 *num = -1;
215 }
216
217 close(s);
218
219 return ret;
220 }
221
222 /*
223 * Exclusively create and open a pid file with path @pidfile_path
224 *
225 * Return file descriptor of the created pid_file.
226 */
227 static int create_pidfile(struct uuidd_cxt_t *cxt, const char *pidfile_path)
228 {
229 int fd_pidfile;
230 struct flock fl;
231
232 fd_pidfile = open(pidfile_path, O_CREAT | O_RDWR, 0664);
233 if (fd_pidfile < 0) {
234 if (!cxt->quiet)
235 warn(_("cannot open %s"), pidfile_path);
236 exit(EXIT_FAILURE);
237 }
238 cxt->cleanup_pidfile = pidfile_path;
239
240 fl.l_type = F_WRLCK;
241 fl.l_whence = SEEK_SET;
242 fl.l_start = 0;
243 fl.l_len = 0;
244 fl.l_pid = 0;
245 while (fcntl(fd_pidfile, F_SETLKW, &fl) < 0) {
246 if ((errno == EAGAIN) || (errno == EINTR))
247 continue;
248 if (!cxt->quiet)
249 warn(_("cannot lock %s"), pidfile_path);
250 exit(EXIT_FAILURE);
251 }
252
253 return fd_pidfile;
254 }
255
256 /*
257 * Create AF_UNIX, SOCK_STREAM socket and bind to @socket_path
258 *
259 * If @will_fork is true, then make sure the descriptor
260 * of the socket is >2, so that it won't be later closed
261 * during create_daemon().
262 *
263 * Return file descriptor corresponding to created socket.
264 */
265 static int create_socket(struct uuidd_cxt_t *uuidd_cxt,
266 const char *socket_path, int will_fork)
267 {
268 struct sockaddr_un my_addr;
269 mode_t save_umask;
270 int s;
271
272 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
273 if (!uuidd_cxt->quiet)
274 warn(_("couldn't create unix stream socket"));
275 exit(EXIT_FAILURE);
276 }
277
278 /*
279 * Make sure the socket isn't using fd numbers 0-2 to avoid it
280 * getting closed by create_daemon()
281 */
282 while (will_fork && s <= 2) {
283 s = dup(s);
284 if (s < 0)
285 err(EXIT_FAILURE, "dup");
286 }
287
288 /*
289 * Create the address we will be binding to.
290 */
291 my_addr.sun_family = AF_UNIX;
292 assert(strlen(socket_path) < sizeof(my_addr.sun_path));
293 xstrncpy(my_addr.sun_path, socket_path, sizeof(my_addr.sun_path));
294 unlink(socket_path);
295 save_umask = umask(0);
296 if (bind(s, (const struct sockaddr *) &my_addr,
297 sizeof(struct sockaddr_un)) < 0) {
298 if (!uuidd_cxt->quiet)
299 warn(_("couldn't bind unix socket %s"), socket_path);
300 exit(EXIT_FAILURE);
301 }
302 umask(save_umask);
303 uuidd_cxt->cleanup_socket = socket_path;
304
305 return s;
306 }
307
308 static void __attribute__((__noreturn__)) all_done(const struct uuidd_cxt_t *uuidd_cxt, int ret)
309 {
310 if (uuidd_cxt->cleanup_pidfile)
311 unlink(uuidd_cxt->cleanup_pidfile);
312 if (uuidd_cxt->cleanup_socket)
313 unlink(uuidd_cxt->cleanup_socket);
314 exit(ret);
315 }
316
317 static void handle_signal(const struct uuidd_cxt_t *uuidd_cxt, int fd)
318 {
319 struct signalfd_siginfo info;
320 ssize_t bytes;
321
322 bytes = read(fd, &info, sizeof(info));
323 if (bytes != sizeof(info)) {
324 if (errno == EAGAIN)
325 return;
326 warn(_("receiving signal failed"));
327 info.ssi_signo = 0;
328 }
329 if (info.ssi_signo == SIGPIPE)
330 return; /* ignored */
331 all_done(uuidd_cxt, EXIT_SUCCESS);
332 }
333
334 static void timeout_handler(int sig __attribute__((__unused__)),
335 siginfo_t * info,
336 void *context __attribute__((__unused__)))
337 {
338 #ifdef HAVE_TIMER_CREATE
339 if (info->si_code == SI_TIMER)
340 #endif
341 errx(EXIT_FAILURE, _("timed out"));
342 }
343
344 static void server_loop(const char *socket_path, const char *pidfile_path,
345 struct uuidd_cxt_t *uuidd_cxt)
346 {
347 struct sockaddr_un from_addr;
348 socklen_t fromlen;
349 int32_t reply_len = 0;
350 uuid_t uu;
351 char reply_buf[UUIDD_PROT_BUFSZ], *cp;
352 uuidd_prot_op_t op;
353 char str[UUID_STR_LEN];
354 int i, ns, len;
355 uuidd_prot_num_t num; /* intentionally uninitialized */
356 int s = 0;
357 int fd_pidfile = -1;
358 int ret;
359 struct pollfd pfd[2];
360 sigset_t sigmask;
361 int sigfd;
362 enum {
363 POLLFD_SIGNAL = 0,
364 POLLFD_SOCKET
365 };
366
367 #ifdef HAVE_LIBSYSTEMD
368 if (!uuidd_cxt->no_sock) /* no_sock implies no_fork and no_pid */
369 #endif
370 {
371 struct ul_timer timer;
372 struct itimerval timeout;
373
374 memset(&timeout, 0, sizeof timeout);
375 timeout.it_value.tv_sec = 30;
376 if (setup_timer(&timer, &timeout, &timeout_handler))
377 err(EXIT_FAILURE, _("cannot set up timer"));
378 if (pidfile_path)
379 fd_pidfile = create_pidfile(uuidd_cxt, pidfile_path);
380 ret = call_daemon(socket_path, UUIDD_OP_GETPID, reply_buf,
381 sizeof(reply_buf), 0, NULL);
382 cancel_timer(&timer);
383 if (ret > 0) {
384 if (!uuidd_cxt->quiet)
385 warnx(_("uuidd daemon is already running at pid %s"),
386 reply_buf);
387 exit(EXIT_FAILURE);
388 }
389
390 s = create_socket(uuidd_cxt, socket_path,
391 (!uuidd_cxt->debug || !uuidd_cxt->no_fork));
392 if (listen(s, SOMAXCONN) < 0) {
393 if (!uuidd_cxt->quiet)
394 warn(_("couldn't listen on unix socket %s"), socket_path);
395 exit(EXIT_FAILURE);
396 }
397
398 if (!uuidd_cxt->debug && !uuidd_cxt->no_fork)
399 create_daemon();
400
401 if (pidfile_path) {
402 snprintf(reply_buf, sizeof(reply_buf), "%8d\n", getpid());
403 if (ftruncate(fd_pidfile, 0))
404 err(EXIT_FAILURE, _("could not truncate file: %s"), pidfile_path);
405 write_all(fd_pidfile, reply_buf, strlen(reply_buf));
406 if (fd_pidfile > 1 && close_fd(fd_pidfile) != 0)
407 err(EXIT_FAILURE, _("write failed: %s"), pidfile_path);
408 }
409
410 }
411
412 #ifdef HAVE_LIBSYSTEMD
413 if (uuidd_cxt->no_sock) {
414 const int r = sd_listen_fds(0);
415
416 if (r < 0) {
417 errno = r * -1;
418 err(EXIT_FAILURE, _("sd_listen_fds() failed"));
419 } else if (r == 0)
420 errx(EXIT_FAILURE,
421 _("no file descriptors received, check systemctl status uuidd.socket"));
422 else if (1 < r)
423 errx(EXIT_FAILURE,
424 _("too many file descriptors received, check uuidd.socket"));
425 s = SD_LISTEN_FDS_START + 0;
426 }
427 #endif
428
429 sigemptyset(&sigmask);
430 sigaddset(&sigmask, SIGHUP);
431 sigaddset(&sigmask, SIGINT);
432 sigaddset(&sigmask, SIGTERM);
433 sigaddset(&sigmask, SIGALRM);
434 sigaddset(&sigmask, SIGPIPE);
435 /* Block signals so that they aren't handled according to their
436 * default dispositions */
437 sigprocmask(SIG_BLOCK, &sigmask, NULL);
438 if ((sigfd = signalfd(-1, &sigmask, 0)) < 0)
439 err(EXIT_FAILURE, _("cannot set signal handler"));
440
441 pfd[POLLFD_SIGNAL].fd = sigfd;
442 pfd[POLLFD_SOCKET].fd = s;
443 pfd[POLLFD_SIGNAL].events = pfd[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP;
444
445 num = 1;
446 if (uuidd_cxt->cont_clock_offset) {
447 /* trigger initialization */
448 (void) __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
449 if (uuidd_cxt->debug)
450 fprintf(stderr, _("max_clock_offset = %u sec\n"),
451 uuidd_cxt->cont_clock_offset);
452 }
453
454 while (1) {
455 ret = poll(pfd, ARRAY_SIZE(pfd),
456 uuidd_cxt->timeout ?
457 (int) uuidd_cxt->timeout * 1000 : -1);
458 if (ret < 0) {
459 if (errno == EAGAIN)
460 continue;
461 warn(_("poll failed"));
462 all_done(uuidd_cxt, EXIT_FAILURE);
463 }
464 if (ret == 0) { /* true when poll() times out */
465 if (uuidd_cxt->debug)
466 fprintf(stderr, _("timeout [%d sec]\n"), uuidd_cxt->timeout);
467 all_done(uuidd_cxt, EXIT_SUCCESS);
468 }
469 if (pfd[POLLFD_SIGNAL].revents != 0)
470 handle_signal(uuidd_cxt, sigfd);
471 if (pfd[POLLFD_SOCKET].revents == 0)
472 continue;
473 fromlen = sizeof(from_addr);
474 ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
475 if (ns < 0) {
476 if ((errno == EAGAIN) || (errno == EINTR))
477 continue;
478 err(EXIT_FAILURE, "accept");
479 }
480 len = read(ns, &op, sizeof(op));
481 if (len != sizeof(op)) {
482 if (len < 0)
483 warn(_("read failed"));
484 else
485 warnx(_("error reading from client, len = %d"),
486 len);
487 goto shutdown_socket;
488 }
489 if ((op == UUIDD_OP_BULK_TIME_UUID) ||
490 (op == UUIDD_OP_BULK_RANDOM_UUID)) {
491 if (read_all(ns, (char *) &num, sizeof(num)) != sizeof(num))
492 goto shutdown_socket;
493 if (uuidd_cxt->debug)
494 fprintf(stderr, _("operation %d, incoming num = %d\n"),
495 op, num);
496 } else if (uuidd_cxt->debug)
497 fprintf(stderr, _("operation %d\n"), op);
498
499 switch (op) {
500 case UUIDD_OP_GETPID:
501 snprintf(reply_buf, sizeof(reply_buf), "%d", getpid());
502 reply_len = strlen(reply_buf) + 1;
503 break;
504 case UUIDD_OP_GET_MAXOP:
505 snprintf(reply_buf, sizeof(reply_buf), "%d", UUIDD_MAX_OP);
506 reply_len = strlen(reply_buf) + 1;
507 break;
508 case UUIDD_OP_TIME_UUID:
509 num = 1;
510 ret = __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
511 if (ret < 0 && !uuidd_cxt->quiet)
512 warnx(_("failed to open/lock clock counter"));
513 if (uuidd_cxt->debug) {
514 uuid_unparse(uu, str);
515 fprintf(stderr, _("Generated time UUID: %s\n"), str);
516 }
517 memcpy(reply_buf, uu, sizeof(uu));
518 reply_len = sizeof(uu);
519 break;
520 case UUIDD_OP_RANDOM_UUID:
521 num = 1;
522 __uuid_generate_random(uu, &num);
523 if (uuidd_cxt->debug) {
524 uuid_unparse(uu, str);
525 fprintf(stderr, _("Generated random UUID: %s\n"), str);
526 }
527 memcpy(reply_buf, uu, sizeof(uu));
528 reply_len = sizeof(uu);
529 break;
530 case UUIDD_OP_BULK_TIME_UUID:
531 ret = __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
532 if (ret < 0 && !uuidd_cxt->quiet)
533 warnx(_("failed to open/lock clock counter"));
534 if (uuidd_cxt->debug) {
535 uuid_unparse(uu, str);
536 fprintf(stderr, P_("Generated time UUID %s "
537 "and %d following\n",
538 "Generated time UUID %s "
539 "and %d following\n", num - 1),
540 str, num - 1);
541 }
542 memcpy(reply_buf, uu, sizeof(uu));
543 reply_len = sizeof(uu);
544 memcpy(reply_buf + reply_len, &num, sizeof(num));
545 reply_len += sizeof(num);
546 break;
547 case UUIDD_OP_BULK_RANDOM_UUID:
548 if (num < 0)
549 num = 1;
550 if ((sizeof(reply_buf) - sizeof(num)) < (size_t) (sizeof(uu) * num))
551 num = (sizeof(reply_buf) - sizeof(num)) / sizeof(uu);
552 __uuid_generate_random((unsigned char *) reply_buf +
553 sizeof(num), &num);
554 reply_len = sizeof(num) + (sizeof(uu) * num);
555 memcpy(reply_buf, &num, sizeof(num));
556 if (uuidd_cxt->debug) {
557 fprintf(stderr, P_("Generated %d UUID:\n",
558 "Generated %d UUIDs:\n", num), num);
559 cp = reply_buf + sizeof(num);
560 for (i = 0; i < num; i++) {
561 uuid_unparse((unsigned char *)cp, str);
562 fprintf(stderr, "\t%s\n", str);
563 cp += sizeof(uu);
564 }
565 }
566 break;
567 default:
568 if (uuidd_cxt->debug)
569 fprintf(stderr, _("Invalid operation %d\n"), op);
570 goto shutdown_socket;
571 }
572 write_all(ns, (char *) &reply_len, sizeof(num));
573 write_all(ns, reply_buf, reply_len);
574 shutdown_socket:
575 close(ns);
576 }
577 }
578
579 static void __attribute__ ((__noreturn__)) unexpected_size(int size)
580 {
581 errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size);
582 }
583
584 static uint32_t parse_cont_clock(char *arg)
585 {
586 uint32_t min_val = 60,
587 max_val = (3600 * 24 * 365),
588 factor = 1;
589 char *p = &arg[strlen(arg)-1];
590
591 if ('h' == *p) {
592 *p = '\0';
593 factor = 3600;
594 min_val = 1;
595 }
596 if ('d' == *p) {
597 *p = '\0';
598 factor = 24 * 3600;
599 min_val = 1;
600 }
601 return factor * str2num_or_err(optarg, 10, _("failed to parse --cont-clock/-C"),
602 min_val, max_val / factor);
603 }
604
605 static void parse_options(int argc, char **argv, struct uuidd_cxt_t *uuidd_cxt,
606 struct uuidd_options_t *uuidd_opts)
607 {
608 const struct option longopts[] = {
609 {"pid", required_argument, NULL, 'p'},
610 {"socket", required_argument, NULL, 's'},
611 {"timeout", required_argument, NULL, 'T'},
612 {"kill", no_argument, NULL, 'k'},
613 {"random", no_argument, NULL, 'r'},
614 {"time", no_argument, NULL, 't'},
615 {"uuids", required_argument, NULL, 'n'},
616 {"no-pid", no_argument, NULL, 'P'},
617 {"no-fork", no_argument, NULL, 'F'},
618 {"socket-activation", no_argument, NULL, 'S'},
619 {"cont-clock", optional_argument, NULL, 'C'},
620 {"debug", no_argument, NULL, 'd'},
621 {"quiet", no_argument, NULL, 'q'},
622 {"version", no_argument, NULL, 'V'},
623 {"help", no_argument, NULL, 'h'},
624 {NULL, 0, NULL, 0}
625 };
626 const ul_excl_t excl[] = {
627 { 'P', 'p' },
628 { 'd', 'q' },
629 { 'r', 't' },
630 { 0 }
631 };
632 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
633 int c;
634
635 while ((c = getopt_long(argc, argv, "p:s:T:krtn:PFSC::dqVh", longopts, NULL)) != -1) {
636 err_exclusive_options(c, longopts, excl, excl_st);
637 switch (c) {
638 case 'C':
639 if (optarg != NULL)
640 uuidd_cxt->cont_clock_offset = parse_cont_clock(optarg);
641 else
642 uuidd_cxt->cont_clock_offset = 7200; /* default 2h */
643 break;
644 case 'd':
645 uuidd_cxt->debug = 1;
646 break;
647 case 'k':
648 uuidd_opts->do_kill = 1;
649 break;
650 case 'n':
651 uuidd_opts->num = (uuidd_prot_num_t) strtou16_or_err(optarg,
652 _("failed to parse --uuids"));
653 break;
654 case 'p':
655 uuidd_opts->pidfile_path = optarg;
656 break;
657 case 'P':
658 uuidd_opts->no_pid = 1;
659 break;
660 case 'F':
661 uuidd_cxt->no_fork = 1;
662 break;
663 case 'S':
664 #ifdef HAVE_LIBSYSTEMD
665 uuidd_cxt->no_sock = 1;
666 uuidd_cxt->no_fork = 1;
667 uuidd_opts->no_pid = 1;
668 #else
669 errx(EXIT_FAILURE, _("uuidd has been built without "
670 "support for socket activation"));
671 #endif
672 break;
673 case 'q':
674 uuidd_cxt->quiet = 1;
675 break;
676 case 'r':
677 uuidd_opts->do_type = UUIDD_OP_RANDOM_UUID;
678 break;
679 case 's':
680 uuidd_opts->socket_path = optarg;
681 uuidd_opts->s_flag = 1;
682 break;
683 case 't':
684 uuidd_opts->do_type = UUIDD_OP_TIME_UUID;
685 break;
686 case 'T':
687 uuidd_cxt->timeout = strtou32_or_err(optarg,
688 _("failed to parse --timeout"));
689 break;
690
691 case 'V':
692 print_version(EXIT_SUCCESS);
693 case 'h':
694 usage();
695 default:
696 errtryhelp(EXIT_FAILURE);
697 }
698 }
699
700 if (0 < uuidd_opts->num) {
701 switch (uuidd_opts->do_type) {
702 case UUIDD_OP_RANDOM_UUID:
703 uuidd_opts->do_type = UUIDD_OP_BULK_RANDOM_UUID;
704 break;
705 case UUIDD_OP_TIME_UUID:
706 uuidd_opts->do_type = UUIDD_OP_BULK_TIME_UUID;
707 break;
708 }
709 }
710 }
711
712 int main(int argc, char **argv)
713 {
714 const char *err_context = NULL;
715 char *cp;
716 int ret;
717
718 struct uuidd_cxt_t uuidd_cxt = { .timeout = 0, .cont_clock_offset = 0 };
719 struct uuidd_options_t uuidd_opts = { .socket_path = UUIDD_SOCKET_PATH };
720
721 setlocale(LC_ALL, "");
722 bindtextdomain(PACKAGE, LOCALEDIR);
723 textdomain(PACKAGE);
724 close_stdout_atexit();
725
726 parse_options(argc, argv, &uuidd_cxt, &uuidd_opts);
727
728 if (strlen(uuidd_opts.socket_path) >= sizeof_member(struct sockaddr_un, sun_path))
729 errx(EXIT_FAILURE, _("socket name too long: %s"), uuidd_opts.socket_path);
730
731 if (!uuidd_opts.no_pid && !uuidd_opts.pidfile_path)
732 uuidd_opts.pidfile_path = UUIDD_PIDFILE_PATH;
733
734 /* custom socket path and socket-activation make no sense */
735 if (uuidd_opts.s_flag && uuidd_cxt.no_sock && !uuidd_cxt.quiet)
736 warnx(_("Both --socket-activation and --socket specified. "
737 "Ignoring --socket."));
738
739 if (uuidd_opts.num && uuidd_opts.do_type) {
740 char buf[UUIDD_PROT_BUFSZ];
741 char str[UUID_STR_LEN];
742
743 ret = call_daemon(uuidd_opts.socket_path, uuidd_opts.do_type, buf,
744 sizeof(buf), &uuidd_opts.num, &err_context);
745
746 if (ret < 0)
747 err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
748 err_context ? : _("unexpected error"));
749
750 if (uuidd_opts.do_type == UUIDD_OP_BULK_TIME_UUID) {
751 if (ret != sizeof(uuid_t) + sizeof(uuidd_opts.num))
752 unexpected_size(ret);
753
754 uuid_unparse((unsigned char *) buf, str);
755
756 printf(P_("%s and %d subsequent UUID\n",
757 "%s and %d subsequent UUIDs\n", uuidd_opts.num - 1),
758 str, uuidd_opts.num - 1);
759 } else {
760 int i;
761
762 printf(_("List of UUIDs:\n"));
763 cp = buf + sizeof(uuidd_opts.num);
764 if (ret != (int) (sizeof(uuidd_opts.num) + uuidd_opts.num * sizeof(uuid_t)))
765 unexpected_size(ret);
766 for (i = 0; i < uuidd_opts.num; i++, cp += sizeof(uuid_t)) {
767 uuid_unparse((unsigned char *) cp, str);
768 printf("\t%s\n", str);
769 }
770 }
771 return EXIT_SUCCESS;
772 }
773
774 if (uuidd_opts.do_type) {
775 uuid_t uu;
776 char str[UUID_STR_LEN];
777
778 ret = call_daemon(uuidd_opts.socket_path, uuidd_opts.do_type, (char *) &uu,
779 sizeof(uu), 0, &err_context);
780
781 if (ret < 0)
782 err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
783 err_context ? : _("unexpected error"));
784 if (ret != sizeof(uu))
785 unexpected_size(ret);
786
787 uuid_unparse(uu, str);
788
789 printf("%s\n", str);
790 return EXIT_SUCCESS;
791 }
792
793 if (uuidd_opts.do_kill) {
794 char buf[16];
795
796 ret = call_daemon(uuidd_opts.socket_path, UUIDD_OP_GETPID, buf, sizeof(buf), 0, NULL);
797 if (0 < ret) {
798 pid_t pid;
799
800 pid = (pid_t)strtou32_or_err(buf, _("failed to parse pid"));
801 ret = kill(pid, SIGTERM);
802 if (ret < 0) {
803 if (!uuidd_cxt.quiet)
804 warn(_("couldn't kill uuidd running "
805 "at pid %d"), pid);
806 return EXIT_FAILURE;
807 }
808 if (!uuidd_cxt.quiet)
809 printf(_("Killed uuidd running at pid %d.\n"), pid);
810 }
811 return EXIT_SUCCESS;
812 }
813
814 server_loop(uuidd_opts.socket_path, uuidd_opts.pidfile_path, &uuidd_cxt);
815 return EXIT_SUCCESS;
816 }