]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/uuidd.c
namei: provide more usable error message on lstat() error
[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{
301 if (info->si_code == SI_TIMER)
302 errx(EXIT_FAILURE, _("timed out"));
303}
304
75a94e8b 305static void server_loop(const char *socket_path, const char *pidfile_path,
25d66b4e 306 struct uuidd_cxt_t *uuidd_cxt)
75a94e8b
PU
307{
308 struct sockaddr_un from_addr;
309 socklen_t fromlen;
310 int32_t reply_len = 0;
311 uuid_t uu;
312 char reply_buf[1024], *cp;
313 char op, str[UUID_STR_LEN];
bbe289c4
PU
314 int i, ns, len, num;
315 int s = 0;
75a94e8b
PU
316 int fd_pidfile = -1;
317 int ret;
3d6250e9 318 struct pollfd pfd[2];
25d66b4e
SK
319 sigset_t sigmask;
320 int sigfd;
321 enum {
322 POLLFD_SIGNAL = 0,
323 POLLFD_SOCKET
324 };
75a94e8b 325
ebff016a 326#ifdef HAVE_LIBSYSTEMD
881a0f6b 327 if (!uuidd_cxt->no_sock) /* no_sock implies no_fork and no_pid */
bbe289c4
PU
328#endif
329 {
25d66b4e
SK
330 static timer_t t_id;
331 struct itimerval timeout;
75a94e8b 332
25d66b4e
SK
333 memset(&timeout, 0, sizeof timeout);
334 timeout.it_value.tv_sec = 30;
335 if (setup_timer(&t_id, &timeout, &timeout_handler))
9e708d01 336 err(EXIT_FAILURE, _("cannot set up timer"));
bbe289c4 337 if (pidfile_path)
b85df4b7 338 fd_pidfile = create_pidfile(uuidd_cxt, pidfile_path);
bbe289c4
PU
339 ret = call_daemon(socket_path, UUIDD_OP_GETPID, reply_buf,
340 sizeof(reply_buf), 0, NULL);
25d66b4e 341 cancel_timer(&t_id);
bbe289c4 342 if (ret > 0) {
881a0f6b 343 if (!uuidd_cxt->quiet)
0012e33c 344 warnx(_("uuidd daemon is already running at pid %s"),
25d66b4e 345 reply_buf);
bbe289c4
PU
346 exit(EXIT_FAILURE);
347 }
bbe289c4 348
25d66b4e
SK
349 s = create_socket(uuidd_cxt, socket_path,
350 (!uuidd_cxt->debug || !uuidd_cxt->no_fork));
bbe289c4 351 if (listen(s, SOMAXCONN) < 0) {
881a0f6b 352 if (!uuidd_cxt->quiet)
bcb693de 353 warn(_("couldn't listen on unix socket %s"), socket_path);
bbe289c4
PU
354 exit(EXIT_FAILURE);
355 }
356
881a0f6b 357 if (!uuidd_cxt->debug && !uuidd_cxt->no_fork)
bbe289c4
PU
358 create_daemon();
359
360 if (pidfile_path) {
361 sprintf(reply_buf, "%8d\n", getpid());
caac2064
SK
362 if (ftruncate(fd_pidfile, 0))
363 err(EXIT_FAILURE, _("could not truncate file: %s"), pidfile_path);
bbe289c4 364 write_all(fd_pidfile, reply_buf, strlen(reply_buf));
74ce680a
SK
365 if (fd_pidfile > 1 && close_fd(fd_pidfile) != 0)
366 err(EXIT_FAILURE, _("write failed: %s"), pidfile_path);
bbe289c4 367 }
75a94e8b 368
69045d3d
KZ
369 }
370
ebff016a 371#ifdef HAVE_LIBSYSTEMD
881a0f6b 372 if (uuidd_cxt->no_sock) {
fd346daf 373 const int r = sd_listen_fds(0);
fa8945db 374
fd346daf
SK
375 if (r < 0) {
376 errno = r * -1;
fa8945db 377 err(EXIT_FAILURE, _("sd_listen_fds() failed"));
fd346daf 378 } else if (r == 0)
fa8945db
SK
379 errx(EXIT_FAILURE,
380 _("no file descriptors received, check systemctl status uuidd.socket"));
fd346daf 381 else if (1 < r)
fa8945db
SK
382 errx(EXIT_FAILURE,
383 _("too many file descriptors received, check uuidd.socket"));
bbe289c4 384 s = SD_LISTEN_FDS_START + 0;
f7c297b8 385 }
bbe289c4 386#endif
69045d3d 387
25d66b4e
SK
388 sigemptyset(&sigmask);
389 sigaddset(&sigmask, SIGHUP);
390 sigaddset(&sigmask, SIGINT);
391 sigaddset(&sigmask, SIGTERM);
392 sigaddset(&sigmask, SIGALRM);
393 sigaddset(&sigmask, SIGPIPE);
394 /* Block signals so that they aren't handled according to their
395 * default dispositions */
396 sigprocmask(SIG_BLOCK, &sigmask, NULL);
397 if ((sigfd = signalfd(-1, &sigmask, 0)) < 0)
398 err(EXIT_FAILURE, _("cannot set signal handler"));
399
400 pfd[POLLFD_SIGNAL].fd = sigfd;
401 pfd[POLLFD_SOCKET].fd = s;
402 pfd[POLLFD_SIGNAL].events = pfd[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP;
403
69045d3d 404 while (1) {
4b09b1c2
KZ
405 ret = poll(pfd, ARRAY_SIZE(pfd),
406 uuidd_cxt->timeout ?
407 (int) uuidd_cxt->timeout * 1000 : -1);
25d66b4e
SK
408 if (ret < 0) {
409 if (errno == EAGAIN)
410 continue;
411 warn(_("poll failed"));
412 all_done(uuidd_cxt, EXIT_FAILURE);
413 }
9e930041 414 if (ret == 0) { /* true when poll() times out */
3d6250e9
KZ
415 if (uuidd_cxt->debug)
416 fprintf(stderr, _("timeout [%d sec]\n"), uuidd_cxt->timeout),
25d66b4e 417 all_done(uuidd_cxt, EXIT_SUCCESS);
3d6250e9 418 }
25d66b4e
SK
419 if (pfd[POLLFD_SIGNAL].revents != 0)
420 handle_signal(uuidd_cxt, sigfd);
421 if (pfd[POLLFD_SOCKET].revents == 0)
422 continue;
69045d3d 423 fromlen = sizeof(from_addr);
69045d3d 424 ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
69045d3d
KZ
425 if (ns < 0) {
426 if ((errno == EAGAIN) || (errno == EINTR))
427 continue;
2d169242 428 else
ea091bed 429 err(EXIT_FAILURE, "accept");
69045d3d
KZ
430 }
431 len = read(ns, &op, 1);
432 if (len != 1) {
433 if (len < 0)
bcb693de 434 warn(_("read failed"));
69045d3d 435 else
0012e33c 436 warnx(_("error reading from client, len = %d"),
bcb693de 437 len);
69045d3d
KZ
438 goto shutdown_socket;
439 }
78314078
PU
440 if ((op == UUIDD_OP_BULK_TIME_UUID) ||
441 (op == UUIDD_OP_BULK_RANDOM_UUID)) {
69045d3d
KZ
442 if (read_all(ns, (char *) &num, sizeof(num)) != 4)
443 goto shutdown_socket;
881a0f6b 444 if (uuidd_cxt->debug)
18c68d70 445 fprintf(stderr, _("operation %d, incoming num = %d\n"),
69045d3d 446 op, num);
881a0f6b 447 } else if (uuidd_cxt->debug)
18c68d70 448 fprintf(stderr, _("operation %d\n"), op);
69045d3d 449
f7c297b8 450 switch (op) {
69045d3d
KZ
451 case UUIDD_OP_GETPID:
452 sprintf(reply_buf, "%d", getpid());
f7c297b8 453 reply_len = strlen(reply_buf) + 1;
69045d3d
KZ
454 break;
455 case UUIDD_OP_GET_MAXOP:
456 sprintf(reply_buf, "%d", UUIDD_MAX_OP);
f7c297b8 457 reply_len = strlen(reply_buf) + 1;
69045d3d
KZ
458 break;
459 case UUIDD_OP_TIME_UUID:
460 num = 1;
70b989c2 461 __uuid_generate_time(uu, &num);
881a0f6b 462 if (uuidd_cxt->debug) {
69045d3d 463 uuid_unparse(uu, str);
18c68d70 464 fprintf(stderr, _("Generated time UUID: %s\n"), str);
69045d3d
KZ
465 }
466 memcpy(reply_buf, uu, sizeof(uu));
467 reply_len = sizeof(uu);
468 break;
469 case UUIDD_OP_RANDOM_UUID:
470 num = 1;
c544aa2c 471 __uuid_generate_random(uu, &num);
881a0f6b 472 if (uuidd_cxt->debug) {
69045d3d 473 uuid_unparse(uu, str);
18c68d70 474 fprintf(stderr, _("Generated random UUID: %s\n"), str);
69045d3d
KZ
475 }
476 memcpy(reply_buf, uu, sizeof(uu));
477 reply_len = sizeof(uu);
478 break;
479 case UUIDD_OP_BULK_TIME_UUID:
70b989c2 480 __uuid_generate_time(uu, &num);
881a0f6b 481 if (uuidd_cxt->debug) {
69045d3d 482 uuid_unparse(uu, str);
18c68d70
PU
483 fprintf(stderr, P_("Generated time UUID %s "
484 "and %d following\n",
485 "Generated time UUID %s "
486 "and %d following\n", num - 1),
0149cd84 487 str, num - 1);
69045d3d
KZ
488 }
489 memcpy(reply_buf, uu, sizeof(uu));
490 reply_len = sizeof(uu);
f7c297b8 491 memcpy(reply_buf + reply_len, &num, sizeof(num));
69045d3d
KZ
492 reply_len += sizeof(num);
493 break;
494 case UUIDD_OP_BULK_RANDOM_UUID:
495 if (num < 0)
496 num = 1;
497 if (num > 1000)
498 num = 1000;
f7c297b8
SK
499 if (num * UUID_LEN > (int) (sizeof(reply_buf) - sizeof(num)))
500 num = (sizeof(reply_buf) - sizeof(num)) / UUID_LEN;
70b989c2 501 __uuid_generate_random((unsigned char *) reply_buf +
c544aa2c 502 sizeof(num), &num);
881a0f6b 503 if (uuidd_cxt->debug) {
18c68d70
PU
504 fprintf(stderr, P_("Generated %d UUID:\n",
505 "Generated %d UUIDs:\n", num), num);
f7c297b8
SK
506 for (i = 0, cp = reply_buf + sizeof(num);
507 i < num;
508 i++, cp += UUID_LEN) {
69045d3d 509 uuid_unparse((unsigned char *)cp, str);
18c68d70 510 fprintf(stderr, "\t%s\n", str);
69045d3d
KZ
511 }
512 }
a8f13198 513 reply_len = (num * UUID_LEN) + sizeof(num);
69045d3d
KZ
514 memcpy(reply_buf, &num, sizeof(num));
515 break;
516 default:
881a0f6b 517 if (uuidd_cxt->debug)
18c68d70 518 fprintf(stderr, _("Invalid operation %d\n"), op);
69045d3d
KZ
519 goto shutdown_socket;
520 }
521 write_all(ns, (char *) &reply_len, sizeof(reply_len));
522 write_all(ns, reply_buf, reply_len);
523 shutdown_socket:
524 close(ns);
525 }
526}
527
2fb35353
SK
528static void __attribute__ ((__noreturn__)) unexpected_size(int size)
529{
530 errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size);
531}
532
69045d3d
KZ
533int main(int argc, char **argv)
534{
535 const char *socket_path = UUIDD_SOCKET_PATH;
0abfbd9c 536 const char *pidfile_path = NULL;
57a24292 537 const char *err_context = NULL;
69045d3d 538 char buf[1024], *cp;
bcb693de 539 char str[UUID_STR_LEN];
69045d3d 540 uuid_t uu;
69045d3d 541 int i, c, ret;
4b1cf29d
KZ
542 int do_type = 0, do_kill = 0, num = 0;
543 int no_pid = 0;
544 int s_flag = 0;
545
546 struct uuidd_cxt_t uuidd_cxt = { .timeout = 0 };
69045d3d 547
f0ef0b58
SK
548 static const struct option longopts[] = {
549 {"pid", required_argument, NULL, 'p'},
550 {"socket", required_argument, NULL, 's'},
551 {"timeout", required_argument, NULL, 'T'},
552 {"kill", no_argument, NULL, 'k'},
553 {"random", no_argument, NULL, 'r'},
554 {"time", no_argument, NULL, 't'},
555 {"uuids", required_argument, NULL, 'n'},
0abfbd9c 556 {"no-pid", no_argument, NULL, 'P'},
e1cf3ebe 557 {"no-fork", no_argument, NULL, 'F'},
bbe289c4 558 {"socket-activation", no_argument, NULL, 'S'},
f0ef0b58
SK
559 {"debug", no_argument, NULL, 'd'},
560 {"quiet", no_argument, NULL, 'q'},
561 {"version", no_argument, NULL, 'V'},
562 {"help", no_argument, NULL, 'h'},
563 {NULL, 0, NULL, 0}
564 };
e4faf648
SK
565 static const ul_excl_t excl[] = {
566 { 'P', 'p' },
567 { 'd', 'q' },
568 { 'r', 't' },
569 { 0 }
570 };
571 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
f0ef0b58 572
69045d3d
KZ
573 setlocale(LC_ALL, "");
574 bindtextdomain(PACKAGE, LOCALEDIR);
575 textdomain(PACKAGE);
c05a80ca 576 atexit(close_stdout);
69045d3d 577
f0ef0b58 578 while ((c =
bbe289c4 579 getopt_long(argc, argv, "p:s:T:krtn:PFSdqVh", longopts,
f0ef0b58 580 NULL)) != -1) {
e4faf648 581 err_exclusive_options(c, longopts, excl, excl_st);
69045d3d
KZ
582 switch (c) {
583 case 'd':
4b1cf29d 584 uuidd_cxt.debug = 1;
69045d3d
KZ
585 break;
586 case 'k':
587 do_kill++;
69045d3d
KZ
588 break;
589 case 'n':
bcb693de
KZ
590 num = strtou32_or_err(optarg,
591 _("failed to parse --uuids"));
b747e886 592 break;
69045d3d 593 case 'p':
b7a245e2 594 pidfile_path = optarg;
0abfbd9c
PU
595 break;
596 case 'P':
597 no_pid = 1;
69045d3d 598 break;
e1cf3ebe 599 case 'F':
4b1cf29d 600 uuidd_cxt.no_fork = 1;
e1cf3ebe 601 break;
bbe289c4 602 case 'S':
ebff016a 603#ifdef HAVE_LIBSYSTEMD
4b1cf29d
KZ
604 uuidd_cxt.no_sock = 1;
605 uuidd_cxt.no_fork = 1;
bbe289c4
PU
606 no_pid = 1;
607#else
bcb693de 608 errx(EXIT_FAILURE, _("uuidd has been built without "
0012e33c 609 "support for socket activation"));
bbe289c4
PU
610#endif
611 break;
69045d3d 612 case 'q':
4b1cf29d 613 uuidd_cxt.quiet = 1;
69045d3d 614 break;
3c062294
BS
615 case 'r':
616 do_type = UUIDD_OP_RANDOM_UUID;
3c062294 617 break;
69045d3d
KZ
618 case 's':
619 socket_path = optarg;
bbe289c4 620 s_flag = 1;
69045d3d
KZ
621 break;
622 case 't':
623 do_type = UUIDD_OP_TIME_UUID;
69045d3d
KZ
624 break;
625 case 'T':
bcb693de
KZ
626 uuidd_cxt.timeout = strtou32_or_err(optarg,
627 _("failed to parse --timeout"));
69045d3d 628 break;
f0ef0b58 629 case 'V':
e421313d 630 printf(UTIL_LINUX_VERSION);
f0ef0b58
SK
631 return EXIT_SUCCESS;
632 case 'h':
86be6a32 633 usage();
69045d3d 634 default:
677ec86c 635 errtryhelp(EXIT_FAILURE);
69045d3d
KZ
636 }
637 }
0abfbd9c 638
2446d048 639 if (strlen(socket_path) >= sizeof(((struct sockaddr_un *)0)->sun_path))
eb10dbc1 640 errx(EXIT_FAILURE, _("socket name too long: %s"), socket_path);
eb10dbc1 641
b7a245e2 642 if (!no_pid && !pidfile_path)
0abfbd9c 643 pidfile_path = UUIDD_PIDFILE_PATH;
0abfbd9c 644
bbe289c4 645 /* custom socket path and socket-activation make no sense */
4b1cf29d 646 if (s_flag && uuidd_cxt.no_sock && !uuidd_cxt.quiet)
bcb693de 647 warnx(_("Both --socket-activation and --socket specified. "
0012e33c 648 "Ignoring --socket."));
0abfbd9c 649
69045d3d 650 if (num && do_type) {
f7c297b8 651 ret = call_daemon(socket_path, do_type + 2, buf,
69045d3d 652 sizeof(buf), &num, &err_context);
bcb693de
KZ
653 if (ret < 0)
654 err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
57a24292 655 err_context ? : _("unexpected error"));
bcb693de 656
69045d3d
KZ
657 if (do_type == UUIDD_OP_TIME_UUID) {
658 if (ret != sizeof(uu) + sizeof(num))
2fb35353 659 unexpected_size(ret);
69045d3d
KZ
660
661 uuid_unparse((unsigned char *) buf, str);
662
0149cd84
BS
663 printf(P_("%s and %d subsequent UUID\n",
664 "%s and %d subsequent UUIDs\n", num - 1),
665 str, num - 1);
69045d3d 666 } else {
333ec749 667 printf(_("List of UUIDs:\n"));
69045d3d 668 cp = buf + 4;
f7c297b8 669 if (ret != (int) (sizeof(num) + num * sizeof(uu)))
2fb35353 670 unexpected_size(ret);
f7c297b8 671 for (i = 0; i < num; i++, cp += UUID_LEN) {
69045d3d
KZ
672 uuid_unparse((unsigned char *) cp, str);
673 printf("\t%s\n", str);
674 }
675 }
41dc5bc0 676 return EXIT_SUCCESS;
69045d3d
KZ
677 }
678 if (do_type) {
679 ret = call_daemon(socket_path, do_type, (char *) &uu,
680 sizeof(uu), 0, &err_context);
bcb693de
KZ
681 if (ret < 0)
682 err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
57a24292 683 err_context ? : _("unexpected error"));
2fb35353
SK
684 if (ret != sizeof(uu))
685 unexpected_size(ret);
686
69045d3d
KZ
687 uuid_unparse(uu, str);
688
689 printf("%s\n", str);
41dc5bc0 690 return EXIT_SUCCESS;
69045d3d
KZ
691 }
692
693 if (do_kill) {
2e9b39ef 694 ret = call_daemon(socket_path, UUIDD_OP_GETPID, buf, sizeof(buf), 0, NULL);
69045d3d
KZ
695 if ((ret > 0) && ((do_kill = atoi((char *) buf)) > 0)) {
696 ret = kill(do_kill, SIGTERM);
697 if (ret < 0) {
4b1cf29d 698 if (!uuidd_cxt.quiet)
bcb693de
KZ
699 warn(_("couldn't kill uuidd running "
700 "at pid %d"), do_kill);
41dc5bc0 701 return EXIT_FAILURE;
69045d3d 702 }
4b1cf29d 703 if (!uuidd_cxt.quiet)
0012e33c 704 printf(_("Killed uuidd running at pid %d.\n"),
69045d3d
KZ
705 do_kill);
706 }
41dc5bc0 707 return EXIT_SUCCESS;
69045d3d
KZ
708 }
709
881a0f6b 710 server_loop(socket_path, pidfile_path, &uuidd_cxt);
41dc5bc0 711 return EXIT_SUCCESS;
69045d3d 712}