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