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