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