]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/uuidd.c
Merge branch 'PR/libsmartcols-cell-data' of github.com:karelzak/util-linux-work
[thirdparty/util-linux.git] / misc-utils / uuidd.c
CommitLineData
69045d3d
KZ
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 */
2049075a
SK
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
69045d3d 28#include <stdio.h>
69045d3d 29#include <stdlib.h>
69045d3d
KZ
30#include <unistd.h>
31#include <inttypes.h>
32#include <errno.h>
ea091bed 33#include <err.h>
69045d3d
KZ
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>
69045d3d 41#include <getopt.h>
25d66b4e
SK
42#include <sys/signalfd.h>
43#include <poll.h>
69045d3d
KZ
44
45#include "uuid.h"
46#include "uuidd.h"
e12c9866 47#include "all-io.h"
f6f3dc78 48#include "c.h"
c05a80ca 49#include "closestream.h"
bcb693de 50#include "strutils.h"
e4faf648 51#include "optutils.h"
25d66b4e
SK
52#include "monotonic.h"
53#include "timer.h"
bbe289c4 54
ebff016a
KZ
55#ifdef HAVE_LIBSYSTEMD
56# include <systemd/sd-daemon.h>
bbe289c4
PU
57#endif
58
69045d3d
KZ
59#include "nls.h"
60
3c560686 61/* Protocol segment lengths */
b4911618
SK
62typedef uint8_t uuidd_prot_op_t; /* client operation field */
63typedef int32_t uuidd_prot_num_t; /* number of requested uuids */
64
65enum {
66 /* client - server buffer size */
67 UUIDD_PROT_BUFSZ = ((sizeof(uuidd_prot_num_t)) + (sizeof(uuid_t) * 63))
68};
a8f13198 69
881a0f6b
PU
70/* server loop control structure */
71struct uuidd_cxt_t {
25d66b4e
SK
72 const char *cleanup_pidfile;
73 const char *cleanup_socket;
d8bb8a03 74 uint32_t timeout;
3cfba7d3
MT
75 uint32_t cont_clock_offset;
76
881a0f6b
PU
77 unsigned int debug: 1,
78 quiet: 1,
79 no_fork: 1,
80 no_sock: 1;
81};
82
b03ffec1 83struct uuidd_options_t {
b4911618
SK
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;
b03ffec1
SK
91};
92
86be6a32 93static void __attribute__((__noreturn__)) usage(void)
69045d3d 94{
86be6a32 95 FILE *out = stdout;
db433bf7 96 fputs(USAGE_HEADER, out);
61b64276 97 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
451dbcfa
BS
98 fputs(USAGE_SEPARATOR, out);
99 fputs(_("A daemon for generating UUIDs.\n"), out);
db433bf7 100 fputs(USAGE_OPTIONS, out);
61b64276
SK
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);
3cfba7d3
MT
111 fputs(_(" -C, --cont-clock[=<NUM>[hd]]\n"), out);
112 fputs(_(" activate continuous clock handling\n"), out);
61b64276
SK
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);
bad4c729
MY
116 fprintf(out, USAGE_HELP_OPTIONS(25));
117 fprintf(out, USAGE_MAN_TAIL("uuidd(8)"));
86be6a32 118 exit(EXIT_SUCCESS);
69045d3d
KZ
119}
120
69045d3d
KZ
121static void create_daemon(void)
122{
69045d3d
KZ
123 uid_t euid;
124
f7c297b8 125 if (daemon(0, 0))
ea091bed 126 err(EXIT_FAILURE, "daemon");
69045d3d 127
69045d3d
KZ
128 euid = geteuid();
129 if (setreuid(euid, euid) < 0)
ea091bed 130 err(EXIT_FAILURE, "setreuid");
69045d3d
KZ
131}
132
b4911618
SK
133static 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)
69045d3d 135{
b4911618
SK
136 char op_buf[sizeof(op) + sizeof(*num)];
137 size_t op_len;
69045d3d
KZ
138 int s;
139 ssize_t ret;
140 int32_t reply_len = 0;
141 struct sockaddr_un srv_addr;
142
78314078
PU
143 if (((op == UUIDD_OP_BULK_TIME_UUID) ||
144 (op == UUIDD_OP_BULK_RANDOM_UUID)) && !num) {
69045d3d
KZ
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;
eb10dbc1
RM
158 assert(strlen(socket_path) < sizeof(srv_addr.sun_path));
159 xstrncpy(srv_addr.sun_path, socket_path, sizeof(srv_addr.sun_path));
69045d3d
KZ
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
78314078 169 if (op == UUIDD_OP_BULK_RANDOM_UUID) {
b4911618
SK
170 if ((buflen - sizeof(*num)) < (size_t)((*num) * sizeof(uuid_t)))
171 *num = (buflen - sizeof(*num)) / sizeof(uuid_t);
69045d3d
KZ
172 }
173 op_buf[0] = op;
b4911618 174 op_len = sizeof(op);
78314078
PU
175 if ((op == UUIDD_OP_BULK_TIME_UUID) ||
176 (op == UUIDD_OP_BULK_RANDOM_UUID)) {
b4911618
SK
177 memcpy(op_buf + sizeof(op), num, sizeof(*num));
178 op_len += sizeof(*num);
69045d3d
KZ
179 }
180
181 ret = write_all(s, op_buf, op_len);
38674931 182 if (ret < 0) {
69045d3d
KZ
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 }
c3bfedc3 196 if (reply_len < 0 || (size_t) reply_len > buflen) {
69045d3d
KZ
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
78314078 204 if ((ret > 0) && (op == UUIDD_OP_BULK_TIME_UUID)) {
b4911618
SK
205 if ((sizeof(uuid_t) + sizeof(*num)) <= (size_t) reply_len)
206 memcpy(buf + sizeof(uuid_t), num, sizeof(*num));
69045d3d
KZ
207 else
208 *num = -1;
209 }
78314078 210 if ((ret > 0) && (op == UUIDD_OP_BULK_RANDOM_UUID)) {
b4911618
SK
211 if (sizeof(*num) <= (size_t) reply_len)
212 memcpy(buf, num, sizeof(*num));
69045d3d
KZ
213 else
214 *num = -1;
215 }
216
217 close(s);
218
219 return ret;
220}
221
c4536355
PU
222/*
223 * Exclusively create and open a pid file with path @pidfile_path
224 *
c4536355
PU
225 * Return file descriptor of the created pid_file.
226 */
b85df4b7 227static int create_pidfile(struct uuidd_cxt_t *cxt, const char *pidfile_path)
69045d3d 228{
c4536355
PU
229 int fd_pidfile;
230 struct flock fl;
69045d3d
KZ
231
232 fd_pidfile = open(pidfile_path, O_CREAT | O_RDWR, 0664);
233 if (fd_pidfile < 0) {
b85df4b7 234 if (!cxt->quiet)
bcb693de 235 warn(_("cannot open %s"), pidfile_path);
41dc5bc0 236 exit(EXIT_FAILURE);
69045d3d 237 }
b85df4b7 238 cxt->cleanup_pidfile = pidfile_path;
c4536355 239
69045d3d
KZ
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;
b85df4b7 248 if (!cxt->quiet)
bcb693de 249 warn(_("cannot lock %s"), pidfile_path);
41dc5bc0 250 exit(EXIT_FAILURE);
69045d3d 251 }
c4536355
PU
252
253 return fd_pidfile;
254}
255
75a94e8b
PU
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
3fd1f771 260 * of the socket is >2, so that it won't be later closed
75a94e8b
PU
261 * during create_daemon().
262 *
263 * Return file descriptor corresponding to created socket.
264 */
25d66b4e
SK
265static int create_socket(struct uuidd_cxt_t *uuidd_cxt,
266 const char *socket_path, int will_fork)
c4536355 267{
75a94e8b 268 struct sockaddr_un my_addr;
c4536355 269 mode_t save_umask;
b85df4b7 270 int s;
69045d3d
KZ
271
272 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
25d66b4e 273 if (!uuidd_cxt->quiet)
bcb693de 274 warn(_("couldn't create unix stream socket"));
41dc5bc0 275 exit(EXIT_FAILURE);
69045d3d
KZ
276 }
277
fdb3e93c
TT
278 /*
279 * Make sure the socket isn't using fd numbers 0-2 to avoid it
280 * getting closed by create_daemon()
281 */
75a94e8b 282 while (will_fork && s <= 2) {
fdb3e93c 283 s = dup(s);
2d169242 284 if (s < 0)
ea091bed 285 err(EXIT_FAILURE, "dup");
fdb3e93c
TT
286 }
287
69045d3d
KZ
288 /*
289 * Create the address we will be binding to.
290 */
291 my_addr.sun_family = AF_UNIX;
eb10dbc1
RM
292 assert(strlen(socket_path) < sizeof(my_addr.sun_path));
293 xstrncpy(my_addr.sun_path, socket_path, sizeof(my_addr.sun_path));
f7c297b8 294 unlink(socket_path);
69045d3d
KZ
295 save_umask = umask(0);
296 if (bind(s, (const struct sockaddr *) &my_addr,
297 sizeof(struct sockaddr_un)) < 0) {
25d66b4e 298 if (!uuidd_cxt->quiet)
bcb693de 299 warn(_("couldn't bind unix socket %s"), socket_path);
41dc5bc0 300 exit(EXIT_FAILURE);
69045d3d 301 }
f7c297b8 302 umask(save_umask);
25d66b4e 303 uuidd_cxt->cleanup_socket = socket_path;
69045d3d 304
75a94e8b
PU
305 return s;
306}
307
25d66b4e
SK
308static 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
317static 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
334static void timeout_handler(int sig __attribute__((__unused__)),
335 siginfo_t * info,
336 void *context __attribute__((__unused__)))
337{
6df5acf9 338#ifdef HAVE_TIMER_CREATE
25d66b4e 339 if (info->si_code == SI_TIMER)
6df5acf9 340#endif
25d66b4e
SK
341 errx(EXIT_FAILURE, _("timed out"));
342}
343
75a94e8b 344static void server_loop(const char *socket_path, const char *pidfile_path,
25d66b4e 345 struct uuidd_cxt_t *uuidd_cxt)
75a94e8b
PU
346{
347 struct sockaddr_un from_addr;
348 socklen_t fromlen;
349 int32_t reply_len = 0;
350 uuid_t uu;
b4911618
SK
351 char reply_buf[UUIDD_PROT_BUFSZ], *cp;
352 uuidd_prot_op_t op;
353 char str[UUID_STR_LEN];
4813a521 354 int i, ns, len;
b4911618 355 uuidd_prot_num_t num; /* intentionally uninitialized */
bbe289c4 356 int s = 0;
75a94e8b
PU
357 int fd_pidfile = -1;
358 int ret;
3d6250e9 359 struct pollfd pfd[2];
25d66b4e
SK
360 sigset_t sigmask;
361 int sigfd;
362 enum {
363 POLLFD_SIGNAL = 0,
364 POLLFD_SOCKET
365 };
75a94e8b 366
ebff016a 367#ifdef HAVE_LIBSYSTEMD
881a0f6b 368 if (!uuidd_cxt->no_sock) /* no_sock implies no_fork and no_pid */
bbe289c4
PU
369#endif
370 {
6df5acf9 371 struct ul_timer timer;
25d66b4e 372 struct itimerval timeout;
75a94e8b 373
25d66b4e
SK
374 memset(&timeout, 0, sizeof timeout);
375 timeout.it_value.tv_sec = 30;
6df5acf9 376 if (setup_timer(&timer, &timeout, &timeout_handler))
9e708d01 377 err(EXIT_FAILURE, _("cannot set up timer"));
bbe289c4 378 if (pidfile_path)
b85df4b7 379 fd_pidfile = create_pidfile(uuidd_cxt, pidfile_path);
bbe289c4
PU
380 ret = call_daemon(socket_path, UUIDD_OP_GETPID, reply_buf,
381 sizeof(reply_buf), 0, NULL);
6df5acf9 382 cancel_timer(&timer);
bbe289c4 383 if (ret > 0) {
881a0f6b 384 if (!uuidd_cxt->quiet)
0012e33c 385 warnx(_("uuidd daemon is already running at pid %s"),
25d66b4e 386 reply_buf);
bbe289c4
PU
387 exit(EXIT_FAILURE);
388 }
bbe289c4 389
25d66b4e
SK
390 s = create_socket(uuidd_cxt, socket_path,
391 (!uuidd_cxt->debug || !uuidd_cxt->no_fork));
bbe289c4 392 if (listen(s, SOMAXCONN) < 0) {
881a0f6b 393 if (!uuidd_cxt->quiet)
bcb693de 394 warn(_("couldn't listen on unix socket %s"), socket_path);
bbe289c4
PU
395 exit(EXIT_FAILURE);
396 }
397
881a0f6b 398 if (!uuidd_cxt->debug && !uuidd_cxt->no_fork)
bbe289c4
PU
399 create_daemon();
400
401 if (pidfile_path) {
948cac89 402 snprintf(reply_buf, sizeof(reply_buf), "%8d\n", getpid());
caac2064
SK
403 if (ftruncate(fd_pidfile, 0))
404 err(EXIT_FAILURE, _("could not truncate file: %s"), pidfile_path);
bbe289c4 405 write_all(fd_pidfile, reply_buf, strlen(reply_buf));
74ce680a
SK
406 if (fd_pidfile > 1 && close_fd(fd_pidfile) != 0)
407 err(EXIT_FAILURE, _("write failed: %s"), pidfile_path);
bbe289c4 408 }
75a94e8b 409
69045d3d
KZ
410 }
411
ebff016a 412#ifdef HAVE_LIBSYSTEMD
881a0f6b 413 if (uuidd_cxt->no_sock) {
fd346daf 414 const int r = sd_listen_fds(0);
fa8945db 415
fd346daf
SK
416 if (r < 0) {
417 errno = r * -1;
fa8945db 418 err(EXIT_FAILURE, _("sd_listen_fds() failed"));
fd346daf 419 } else if (r == 0)
fa8945db
SK
420 errx(EXIT_FAILURE,
421 _("no file descriptors received, check systemctl status uuidd.socket"));
fd346daf 422 else if (1 < r)
fa8945db
SK
423 errx(EXIT_FAILURE,
424 _("too many file descriptors received, check uuidd.socket"));
bbe289c4 425 s = SD_LISTEN_FDS_START + 0;
f7c297b8 426 }
bbe289c4 427#endif
69045d3d 428
25d66b4e
SK
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
3cfba7d3
MT
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
69045d3d 454 while (1) {
4b09b1c2
KZ
455 ret = poll(pfd, ARRAY_SIZE(pfd),
456 uuidd_cxt->timeout ?
457 (int) uuidd_cxt->timeout * 1000 : -1);
25d66b4e
SK
458 if (ret < 0) {
459 if (errno == EAGAIN)
460 continue;
461 warn(_("poll failed"));
ef6ac596 462 all_done(uuidd_cxt, EXIT_FAILURE);
25d66b4e 463 }
9e930041 464 if (ret == 0) { /* true when poll() times out */
3d6250e9 465 if (uuidd_cxt->debug)
f187035d 466 fprintf(stderr, _("timeout [%d sec]\n"), uuidd_cxt->timeout);
25d66b4e 467 all_done(uuidd_cxt, EXIT_SUCCESS);
3d6250e9 468 }
25d66b4e
SK
469 if (pfd[POLLFD_SIGNAL].revents != 0)
470 handle_signal(uuidd_cxt, sigfd);
471 if (pfd[POLLFD_SOCKET].revents == 0)
472 continue;
69045d3d 473 fromlen = sizeof(from_addr);
69045d3d 474 ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
69045d3d
KZ
475 if (ns < 0) {
476 if ((errno == EAGAIN) || (errno == EINTR))
477 continue;
042f62df 478 err(EXIT_FAILURE, "accept");
69045d3d 479 }
b4911618
SK
480 len = read(ns, &op, sizeof(op));
481 if (len != sizeof(op)) {
69045d3d 482 if (len < 0)
bcb693de 483 warn(_("read failed"));
69045d3d 484 else
0012e33c 485 warnx(_("error reading from client, len = %d"),
bcb693de 486 len);
69045d3d
KZ
487 goto shutdown_socket;
488 }
78314078
PU
489 if ((op == UUIDD_OP_BULK_TIME_UUID) ||
490 (op == UUIDD_OP_BULK_RANDOM_UUID)) {
b4911618 491 if (read_all(ns, (char *) &num, sizeof(num)) != sizeof(num))
69045d3d 492 goto shutdown_socket;
881a0f6b 493 if (uuidd_cxt->debug)
18c68d70 494 fprintf(stderr, _("operation %d, incoming num = %d\n"),
69045d3d 495 op, num);
881a0f6b 496 } else if (uuidd_cxt->debug)
18c68d70 497 fprintf(stderr, _("operation %d\n"), op);
69045d3d 498
f7c297b8 499 switch (op) {
69045d3d 500 case UUIDD_OP_GETPID:
948cac89 501 snprintf(reply_buf, sizeof(reply_buf), "%d", getpid());
f7c297b8 502 reply_len = strlen(reply_buf) + 1;
69045d3d
KZ
503 break;
504 case UUIDD_OP_GET_MAXOP:
948cac89 505 snprintf(reply_buf, sizeof(reply_buf), "%d", UUIDD_MAX_OP);
f7c297b8 506 reply_len = strlen(reply_buf) + 1;
69045d3d
KZ
507 break;
508 case UUIDD_OP_TIME_UUID:
509 num = 1;
3cfba7d3
MT
510 ret = __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
511 if (ret < 0 && !uuidd_cxt->quiet)
f27876f9 512 warnx(_("failed to open/lock clock counter"));
881a0f6b 513 if (uuidd_cxt->debug) {
69045d3d 514 uuid_unparse(uu, str);
18c68d70 515 fprintf(stderr, _("Generated time UUID: %s\n"), str);
69045d3d
KZ
516 }
517 memcpy(reply_buf, uu, sizeof(uu));
518 reply_len = sizeof(uu);
519 break;
520 case UUIDD_OP_RANDOM_UUID:
521 num = 1;
b408a291 522 __uuid_generate_random(uu, &num);
881a0f6b 523 if (uuidd_cxt->debug) {
69045d3d 524 uuid_unparse(uu, str);
18c68d70 525 fprintf(stderr, _("Generated random UUID: %s\n"), str);
69045d3d
KZ
526 }
527 memcpy(reply_buf, uu, sizeof(uu));
528 reply_len = sizeof(uu);
529 break;
530 case UUIDD_OP_BULK_TIME_UUID:
3cfba7d3
MT
531 ret = __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset);
532 if (ret < 0 && !uuidd_cxt->quiet)
f27876f9 533 warnx(_("failed to open/lock clock counter"));
881a0f6b 534 if (uuidd_cxt->debug) {
69045d3d 535 uuid_unparse(uu, str);
18c68d70
PU
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),
0149cd84 540 str, num - 1);
69045d3d
KZ
541 }
542 memcpy(reply_buf, uu, sizeof(uu));
543 reply_len = sizeof(uu);
f7c297b8 544 memcpy(reply_buf + reply_len, &num, sizeof(num));
69045d3d
KZ
545 reply_len += sizeof(num);
546 break;
547 case UUIDD_OP_BULK_RANDOM_UUID:
548 if (num < 0)
549 num = 1;
b4911618
SK
550 if ((sizeof(reply_buf) - sizeof(num)) < (size_t) (sizeof(uu) * num))
551 num = (sizeof(reply_buf) - sizeof(num)) / sizeof(uu);
70b989c2 552 __uuid_generate_random((unsigned char *) reply_buf +
c544aa2c 553 sizeof(num), &num);
b4911618 554 reply_len = sizeof(num) + (sizeof(uu) * num);
ea941692 555 memcpy(reply_buf, &num, sizeof(num));
881a0f6b 556 if (uuidd_cxt->debug) {
18c68d70
PU
557 fprintf(stderr, P_("Generated %d UUID:\n",
558 "Generated %d UUIDs:\n", num), num);
b4911618 559 cp = reply_buf + sizeof(num);
ea941692 560 for (i = 0; i < num; i++) {
69045d3d 561 uuid_unparse((unsigned char *)cp, str);
18c68d70 562 fprintf(stderr, "\t%s\n", str);
b4911618 563 cp += sizeof(uu);
69045d3d
KZ
564 }
565 }
69045d3d
KZ
566 break;
567 default:
881a0f6b 568 if (uuidd_cxt->debug)
18c68d70 569 fprintf(stderr, _("Invalid operation %d\n"), op);
69045d3d
KZ
570 goto shutdown_socket;
571 }
b4911618 572 write_all(ns, (char *) &reply_len, sizeof(num));
69045d3d
KZ
573 write_all(ns, reply_buf, reply_len);
574 shutdown_socket:
575 close(ns);
576 }
577}
578
2fb35353
SK
579static void __attribute__ ((__noreturn__)) unexpected_size(int size)
580{
581 errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size);
582}
583
3cfba7d3
MT
584static 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
084efcee
SK
605static void parse_options(int argc, char **argv, struct uuidd_cxt_t *uuidd_cxt,
606 struct uuidd_options_t *uuidd_opts)
69045d3d 607{
084efcee 608 const struct option longopts[] = {
f0ef0b58
SK
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'},
0abfbd9c 616 {"no-pid", no_argument, NULL, 'P'},
e1cf3ebe 617 {"no-fork", no_argument, NULL, 'F'},
bbe289c4 618 {"socket-activation", no_argument, NULL, 'S'},
3cfba7d3 619 {"cont-clock", optional_argument, NULL, 'C'},
f0ef0b58
SK
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 };
084efcee 626 const ul_excl_t excl[] = {
e4faf648
SK
627 { 'P', 'p' },
628 { 'd', 'q' },
629 { 'r', 't' },
630 { 0 }
631 };
632 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
084efcee 633 int c;
f0ef0b58 634
3cfba7d3 635 while ((c = getopt_long(argc, argv, "p:s:T:krtn:PFSC::dqVh", longopts, NULL)) != -1) {
e4faf648 636 err_exclusive_options(c, longopts, excl, excl_st);
69045d3d 637 switch (c) {
3cfba7d3
MT
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;
69045d3d 644 case 'd':
084efcee 645 uuidd_cxt->debug = 1;
69045d3d
KZ
646 break;
647 case 'k':
084efcee 648 uuidd_opts->do_kill = 1;
69045d3d
KZ
649 break;
650 case 'n':
b4911618 651 uuidd_opts->num = (uuidd_prot_num_t) strtou16_or_err(optarg,
bcb693de 652 _("failed to parse --uuids"));
b747e886 653 break;
69045d3d 654 case 'p':
084efcee 655 uuidd_opts->pidfile_path = optarg;
0abfbd9c
PU
656 break;
657 case 'P':
084efcee 658 uuidd_opts->no_pid = 1;
69045d3d 659 break;
e1cf3ebe 660 case 'F':
084efcee 661 uuidd_cxt->no_fork = 1;
e1cf3ebe 662 break;
bbe289c4 663 case 'S':
ebff016a 664#ifdef HAVE_LIBSYSTEMD
084efcee
SK
665 uuidd_cxt->no_sock = 1;
666 uuidd_cxt->no_fork = 1;
667 uuidd_opts->no_pid = 1;
bbe289c4 668#else
bcb693de 669 errx(EXIT_FAILURE, _("uuidd has been built without "
0012e33c 670 "support for socket activation"));
bbe289c4
PU
671#endif
672 break;
69045d3d 673 case 'q':
084efcee 674 uuidd_cxt->quiet = 1;
69045d3d 675 break;
3c062294 676 case 'r':
084efcee 677 uuidd_opts->do_type = UUIDD_OP_RANDOM_UUID;
3c062294 678 break;
69045d3d 679 case 's':
084efcee
SK
680 uuidd_opts->socket_path = optarg;
681 uuidd_opts->s_flag = 1;
69045d3d
KZ
682 break;
683 case 't':
084efcee 684 uuidd_opts->do_type = UUIDD_OP_TIME_UUID;
69045d3d
KZ
685 break;
686 case 'T':
084efcee 687 uuidd_cxt->timeout = strtou32_or_err(optarg,
bcb693de 688 _("failed to parse --timeout"));
69045d3d 689 break;
2c308875 690
f0ef0b58 691 case 'V':
2c308875 692 print_version(EXIT_SUCCESS);
f0ef0b58 693 case 'h':
86be6a32 694 usage();
69045d3d 695 default:
677ec86c 696 errtryhelp(EXIT_FAILURE);
69045d3d
KZ
697 }
698 }
77a54655
SK
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 }
084efcee
SK
710}
711
712int main(int argc, char **argv)
713{
714 const char *err_context = NULL;
715 char *cp;
716 int ret;
717
3cfba7d3 718 struct uuidd_cxt_t uuidd_cxt = { .timeout = 0, .cont_clock_offset = 0 };
084efcee
SK
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);
0abfbd9c 727
c4a66fa9 728 if (strlen(uuidd_opts.socket_path) >= sizeof_member(struct sockaddr_un, sun_path))
b03ffec1 729 errx(EXIT_FAILURE, _("socket name too long: %s"), uuidd_opts.socket_path);
eb10dbc1 730
b03ffec1
SK
731 if (!uuidd_opts.no_pid && !uuidd_opts.pidfile_path)
732 uuidd_opts.pidfile_path = UUIDD_PIDFILE_PATH;
0abfbd9c 733
bbe289c4 734 /* custom socket path and socket-activation make no sense */
b03ffec1 735 if (uuidd_opts.s_flag && uuidd_cxt.no_sock && !uuidd_cxt.quiet)
bcb693de 736 warnx(_("Both --socket-activation and --socket specified. "
0012e33c 737 "Ignoring --socket."));
0abfbd9c 738
b03ffec1 739 if (uuidd_opts.num && uuidd_opts.do_type) {
b4911618 740 char buf[UUIDD_PROT_BUFSZ];
b03ffec1
SK
741 char str[UUID_STR_LEN];
742
77a54655 743 ret = call_daemon(uuidd_opts.socket_path, uuidd_opts.do_type, buf,
b03ffec1
SK
744 sizeof(buf), &uuidd_opts.num, &err_context);
745
bcb693de
KZ
746 if (ret < 0)
747 err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
57a24292 748 err_context ? : _("unexpected error"));
bcb693de 749
77a54655 750 if (uuidd_opts.do_type == UUIDD_OP_BULK_TIME_UUID) {
b03ffec1 751 if (ret != sizeof(uuid_t) + sizeof(uuidd_opts.num))
2fb35353 752 unexpected_size(ret);
69045d3d
KZ
753
754 uuid_unparse((unsigned char *) buf, str);
755
0149cd84 756 printf(P_("%s and %d subsequent UUID\n",
b03ffec1
SK
757 "%s and %d subsequent UUIDs\n", uuidd_opts.num - 1),
758 str, uuidd_opts.num - 1);
69045d3d 759 } else {
b03ffec1
SK
760 int i;
761
333ec749 762 printf(_("List of UUIDs:\n"));
b4911618 763 cp = buf + sizeof(uuidd_opts.num);
b03ffec1 764 if (ret != (int) (sizeof(uuidd_opts.num) + uuidd_opts.num * sizeof(uuid_t)))
2fb35353 765 unexpected_size(ret);
b4911618 766 for (i = 0; i < uuidd_opts.num; i++, cp += sizeof(uuid_t)) {
69045d3d
KZ
767 uuid_unparse((unsigned char *) cp, str);
768 printf("\t%s\n", str);
769 }
770 }
41dc5bc0 771 return EXIT_SUCCESS;
69045d3d 772 }
b03ffec1
SK
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,
69045d3d 779 sizeof(uu), 0, &err_context);
b03ffec1 780
bcb693de
KZ
781 if (ret < 0)
782 err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
57a24292 783 err_context ? : _("unexpected error"));
2fb35353
SK
784 if (ret != sizeof(uu))
785 unexpected_size(ret);
786
69045d3d
KZ
787 uuid_unparse(uu, str);
788
789 printf("%s\n", str);
41dc5bc0 790 return EXIT_SUCCESS;
69045d3d
KZ
791 }
792
b03ffec1
SK
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);
c14e0f62
SK
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);
69045d3d 802 if (ret < 0) {
4b1cf29d 803 if (!uuidd_cxt.quiet)
bcb693de 804 warn(_("couldn't kill uuidd running "
c14e0f62 805 "at pid %d"), pid);
41dc5bc0 806 return EXIT_FAILURE;
69045d3d 807 }
4b1cf29d 808 if (!uuidd_cxt.quiet)
c14e0f62 809 printf(_("Killed uuidd running at pid %d.\n"), pid);
69045d3d 810 }
41dc5bc0 811 return EXIT_SUCCESS;
69045d3d
KZ
812 }
813
b03ffec1 814 server_loop(uuidd_opts.socket_path, uuidd_opts.pidfile_path, &uuidd_cxt);
41dc5bc0 815 return EXIT_SUCCESS;
69045d3d 816}