2 * uuidd.c --- UUID-generation daemon
4 * Copyright (C) 2007 Theodore Ts'o
7 * This file may be redistributed under the terms of the GNU Public
18 #include <sys/types.h>
20 #include <sys/socket.h>
28 extern int getopt(int argc, char * const argv[], const char *optstring);
39 #define CODE_ATTR(x) __attribute__(x)
44 static void usage(const char *progname)
46 fprintf(stderr, _("Usage: %s [-d] [-p pidfile] [-s socketpath] "
47 "[-T timeout]\n"), progname);
48 fprintf(stderr, _(" %s [-r|t] [-n num] [-s socketpath]\n"),
50 fprintf(stderr, _(" %s -k\n"), progname);
54 static void die(const char *msg)
60 static void create_daemon(void)
69 } else if (pid != 0) {
76 open("/dev/null", O_RDWR);
77 open("/dev/null", O_RDWR);
78 open("/dev/null", O_RDWR);
80 if (chdir("/")) {} /* Silence warn_unused_result warning */
83 if (setreuid(euid, euid) < 0)
87 static ssize_t read_all(int fd, char *buf, size_t count)
93 memset(buf, 0, count);
95 ret = read(fd, buf, count);
97 if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
111 static int write_all(int fd, char *buf, size_t count)
117 ret = write(fd, buf, count);
119 if ((errno == EAGAIN) || (errno == EINTR))
130 static const char *cleanup_pidfile, *cleanup_socket;
132 static void terminate_intr(int signo CODE_ATTR((unused)))
134 (void) unlink(cleanup_pidfile);
136 (void) unlink(cleanup_socket);
140 static int call_daemon(const char *socket_path, int op, char *buf,
141 int buflen, int *num, const char **err_context)
147 int32_t reply_len = 0;
148 struct sockaddr_un srv_addr;
150 if (((op == 4) || (op == 5)) && !num) {
152 *err_context = _("bad arguments");
157 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
159 *err_context = _("socket");
163 srv_addr.sun_family = AF_UNIX;
164 strncpy(srv_addr.sun_path, socket_path, sizeof(srv_addr.sun_path));
165 srv_addr.sun_path[sizeof(srv_addr.sun_path)-1] = '\0';
167 if (connect(s, (const struct sockaddr *) &srv_addr,
168 sizeof(struct sockaddr_un)) < 0) {
170 *err_context = _("connect");
176 if ((*num)*16 > buflen-4)
177 *num = (buflen-4) / 16;
181 if ((op == 4) || (op == 5)) {
182 memcpy(op_buf+1, num, sizeof(int));
183 op_len += sizeof(int);
186 ret = write_all(s, op_buf, op_len);
189 *err_context = _("write");
194 ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
197 *err_context = _("read count");
201 if (reply_len < 0 || reply_len > buflen) {
203 *err_context = _("bad response length");
207 ret = read_all(s, (char *) buf, reply_len);
209 if ((ret > 0) && (op == 4)) {
210 if (reply_len >= (int) (16+sizeof(int)))
211 memcpy(buf+16, num, sizeof(int));
215 if ((ret > 0) && (op == 5)) {
216 if (*num >= (int) sizeof(int))
217 memcpy(buf, num, sizeof(int));
227 static void server_loop(const char *socket_path, const char *pidfile_path,
228 int debug, int timeout, int quiet)
230 struct sockaddr_un my_addr, from_addr;
233 int32_t reply_len = 0;
236 char reply_buf[1024], *cp;
238 int i, s, ns, len, num;
241 fd_pidfile = open(pidfile_path, O_CREAT | O_RDWR, 0664);
242 if (fd_pidfile < 0) {
244 fprintf(stderr, "Failed to open/create %s: %s\n",
245 pidfile_path, strerror(errno));
248 cleanup_pidfile = pidfile_path;
250 signal(SIGALRM, terminate_intr);
253 fl.l_whence = SEEK_SET;
257 while (fcntl(fd_pidfile, F_SETLKW, &fl) < 0) {
258 if ((errno == EAGAIN) || (errno == EINTR))
261 fprintf(stderr, "Failed to lock %s: %s\n",
262 pidfile_path, strerror(errno));
265 ret = call_daemon(socket_path, 0, reply_buf, sizeof(reply_buf), 0, 0);
268 printf(_("uuidd daemon already running at pid %s\n"),
274 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
276 fprintf(stderr, _("Couldn't create unix stream "
277 "socket: %s"), strerror(errno));
282 * Make sure the socket isn't using fd numbers 0-2 to avoid it
283 * getting closed by create_daemon()
285 while (!debug && s <= 2) {
294 * Create the address we will be binding to.
296 my_addr.sun_family = AF_UNIX;
297 strncpy(my_addr.sun_path, socket_path, sizeof(my_addr.sun_path));
298 my_addr.sun_path[sizeof(my_addr.sun_path)-1] = '\0';
299 (void) unlink(socket_path);
300 save_umask = umask(0);
301 if (bind(s, (const struct sockaddr *) &my_addr,
302 sizeof(struct sockaddr_un)) < 0) {
305 _("Couldn't bind unix socket %s: %s\n"),
306 socket_path, strerror(errno));
309 (void) umask(save_umask);
311 if (listen(s, 5) < 0) {
313 fprintf(stderr, _("Couldn't listen on unix "
314 "socket %s: %s\n"), socket_path,
319 cleanup_socket = socket_path;
322 signal(SIGHUP, terminate_intr);
323 signal(SIGINT, terminate_intr);
324 signal(SIGTERM, terminate_intr);
325 signal(SIGALRM, terminate_intr);
326 signal(SIGPIPE, SIG_IGN);
328 sprintf(reply_buf, "%8d\n", getpid());
329 if (ftruncate(fd_pidfile, 0)) {} /* Silence warn_unused_result */
330 write_all(fd_pidfile, reply_buf, strlen(reply_buf));
332 close(fd_pidfile); /* Unlock the pid file */
335 fromlen = sizeof(from_addr);
338 ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
341 if ((errno == EAGAIN) || (errno == EINTR))
346 len = read(ns, &op, 1);
351 printf(_("Error reading from client, "
353 goto shutdown_socket;
355 if ((op == 4) || (op == 5)) {
356 if (read_all(ns, (char *) &num, sizeof(num)) != 4)
357 goto shutdown_socket;
359 printf(_("operation %d, incoming num = %d\n"),
362 printf("operation %d\n", op);
365 case UUIDD_OP_GETPID:
366 sprintf(reply_buf, "%d", getpid());
367 reply_len = strlen(reply_buf)+1;
369 case UUIDD_OP_GET_MAXOP:
370 sprintf(reply_buf, "%d", UUIDD_MAX_OP);
371 reply_len = strlen(reply_buf)+1;
373 case UUIDD_OP_TIME_UUID:
375 uuid__generate_time(uu, &num);
377 uuid_unparse(uu, str);
378 printf(_("Generated time UUID: %s\n"), str);
380 memcpy(reply_buf, uu, sizeof(uu));
381 reply_len = sizeof(uu);
383 case UUIDD_OP_RANDOM_UUID:
385 uuid__generate_random(uu, &num);
387 uuid_unparse(uu, str);
388 printf(_("Generated random UUID: %s\n"), str);
390 memcpy(reply_buf, uu, sizeof(uu));
391 reply_len = sizeof(uu);
393 case UUIDD_OP_BULK_TIME_UUID:
394 uuid__generate_time(uu, &num);
396 uuid_unparse(uu, str);
397 printf(_("Generated time UUID %s and %d "
398 "following\n"), str, num);
400 memcpy(reply_buf, uu, sizeof(uu));
401 reply_len = sizeof(uu);
402 memcpy(reply_buf+reply_len, &num, sizeof(num));
403 reply_len += sizeof(num);
405 case UUIDD_OP_BULK_RANDOM_UUID:
410 if (num*16 > (int) (sizeof(reply_buf)-sizeof(num)))
411 num = (sizeof(reply_buf)-sizeof(num)) / 16;
412 uuid__generate_random((unsigned char *) reply_buf +
415 printf(_("Generated %d UUID's:\n"), num);
416 for (i=0, cp=reply_buf+sizeof(num);
417 i < num; i++, cp+=16) {
418 uuid_unparse((unsigned char *)cp, str);
419 printf("\t%s\n", str);
422 reply_len = (num*16) + sizeof(num);
423 memcpy(reply_buf, &num, sizeof(num));
427 printf(_("Invalid operation %d\n"), op);
428 goto shutdown_socket;
430 write_all(ns, (char *) &reply_len, sizeof(reply_len));
431 write_all(ns, reply_buf, reply_len);
437 int main(int argc, char **argv)
439 const char *socket_path = UUIDD_SOCKET_PATH;
440 const char *pidfile_path = UUIDD_PIDFILE_PATH;
441 const char *err_context;
448 int debug = 0, do_type = 0, do_kill = 0, num = 0;
449 int timeout = 0, quiet = 0, drop_privs = 0;
451 setlocale(LC_ALL, "");
452 bindtextdomain(PACKAGE, LOCALEDIR);
455 while ((c = getopt (argc, argv, "dkn:qp:s:tT:r")) != EOF) {
466 num = strtol(optarg, &tmp, 0);
467 if ((num < 0) || *tmp) {
468 fprintf(stderr, _("Bad number: %s\n"), optarg);
472 pidfile_path = optarg;
479 socket_path = optarg;
483 do_type = UUIDD_OP_TIME_UUID;
487 timeout = strtol(optarg, &tmp, 0);
488 if ((timeout < 0) || *tmp) {
489 fprintf(stderr, _("Bad number: %s\n"), optarg);
494 do_type = UUIDD_OP_RANDOM_UUID;
502 if (uid && drop_privs) {
504 #ifdef HAVE_SETRESGID
505 if (setresgid(gid, gid, gid) < 0)
508 if (setregid(gid, gid) < 0)
512 #ifdef HAVE_SETRESUID
513 if (setresuid(uid, uid, uid) < 0)
516 if (setreuid(uid, uid) < 0)
520 if (num && do_type) {
521 ret = call_daemon(socket_path, do_type+2, buf,
522 sizeof(buf), &num, &err_context);
524 printf(_("Error calling uuidd daemon (%s): %s\n"),
525 err_context, strerror(errno));
528 if (do_type == UUIDD_OP_TIME_UUID) {
529 if (ret != sizeof(uu) + sizeof(num))
530 goto unexpected_size;
532 uuid_unparse((unsigned char *) buf, str);
534 printf(_("%s and subsequent %d UUID's\n"), str, num);
536 printf(_("List of UUID's:\n"));
538 if (ret != (int) (sizeof(num) + num*sizeof(uu)))
539 goto unexpected_size;
540 for (i=0; i < num; i++, cp+=16) {
541 uuid_unparse((unsigned char *) cp, str);
542 printf("\t%s\n", str);
548 ret = call_daemon(socket_path, do_type, (char *) &uu,
549 sizeof(uu), 0, &err_context);
551 printf(_("Error calling uuidd daemon (%s): %s\n"),
552 err_context, strerror(errno));
555 if (ret != sizeof(uu)) {
557 printf(_("Unexpected reply length from server %d\n"),
561 uuid_unparse(uu, str);
568 ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
569 if ((ret > 0) && ((do_kill = atoi((char *) buf)) > 0)) {
570 ret = kill(do_kill, SIGTERM);
574 _("Couldn't kill uuidd running "
575 "at pid %d: %s\n"), do_kill,
580 printf(_("Killed uuidd running at pid %d\n"),
586 server_loop(socket_path, pidfile_path, debug, timeout, quiet);