Merge remote-tracking branch 'sami/uuidd-work'

* sami/uuidd-work:
  uuidd: fix misleading indentation
  uuidd: make timeout to take effect when debug is not defined
  uuidd: remove unnecessary bulk request size limit
  uuidd: add uuidd specific data types that are used in protocol
  uuidd: reorder bulk time and random generation code
  uuidd: document uuidd protocol
  uuidd: override operation type when performing bulk request
  uuidd: move option parsing to separate function
  uuidd: add command-line option values struct
  uuidd: use pid_t type when referring to process id
This commit is contained in:
Karel Zak 2020-11-24 13:12:22 +01:00
commit 665d79e793
1 changed files with 154 additions and 97 deletions

View File

@ -8,6 +8,23 @@
* License. * License.
* %End-Header% * %End-Header%
*/ */
/*
* The uuidd protocol.
*
* Client:
* | operation type (1 byte) | number of uuids (if bulk request, 4 bytes) |
*
* Server:
* | reply length (4 bytes) | uuid reply (16 bytes) |
* or
* | reply length (4 bytes) | uuid reply (16 bytes) multiply by number when random bulk request |
* or
* | reply length (4 bytes) | uuid reply (16 bytes) | number (4 bytes) time bulk |
* or
* | reply length (4 bytes) | pid or maxop number string length in ascii (up to 7 bytes) |
*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -41,8 +58,14 @@
#include "nls.h" #include "nls.h"
/* length of binary representation of UUID */ /* Protocol segment lenghts */
#define UUID_LEN (sizeof(uuid_t)) typedef uint8_t uuidd_prot_op_t; /* client operation field */
typedef int32_t uuidd_prot_num_t; /* number of requested uuids */
enum {
/* client - server buffer size */
UUIDD_PROT_BUFSZ = ((sizeof(uuidd_prot_num_t)) + (sizeof(uuid_t) * 63))
};
/* server loop control structure */ /* server loop control structure */
struct uuidd_cxt_t { struct uuidd_cxt_t {
@ -55,6 +78,16 @@ struct uuidd_cxt_t {
no_sock: 1; no_sock: 1;
}; };
struct uuidd_options_t {
const char *pidfile_path;
const char *socket_path;
uuidd_prot_num_t num;
uuidd_prot_op_t do_type;
unsigned int do_kill:1,
no_pid:1,
s_flag:1;
};
static void __attribute__((__noreturn__)) usage(void) static void __attribute__((__noreturn__)) usage(void)
{ {
FILE *out = stdout; FILE *out = stdout;
@ -93,11 +126,11 @@ static void create_daemon(void)
err(EXIT_FAILURE, "setreuid"); err(EXIT_FAILURE, "setreuid");
} }
static int call_daemon(const char *socket_path, int op, char *buf, static int call_daemon(const char *socket_path, uuidd_prot_op_t op, char *buf,
size_t buflen, int *num, const char **err_context) size_t buflen, uuidd_prot_num_t *num, const char **err_context)
{ {
char op_buf[8]; char op_buf[sizeof(op) + sizeof(*num)];
int op_len; size_t op_len;
int s; int s;
ssize_t ret; ssize_t ret;
int32_t reply_len = 0; int32_t reply_len = 0;
@ -130,15 +163,15 @@ static int call_daemon(const char *socket_path, int op, char *buf,
} }
if (op == UUIDD_OP_BULK_RANDOM_UUID) { if (op == UUIDD_OP_BULK_RANDOM_UUID) {
if ((*num) * UUID_LEN > buflen - 4) if ((buflen - sizeof(*num)) < (size_t)((*num) * sizeof(uuid_t)))
*num = (buflen - 4) / UUID_LEN; *num = (buflen - sizeof(*num)) / sizeof(uuid_t);
} }
op_buf[0] = op; op_buf[0] = op;
op_len = 1; op_len = sizeof(op);
if ((op == UUIDD_OP_BULK_TIME_UUID) || if ((op == UUIDD_OP_BULK_TIME_UUID) ||
(op == UUIDD_OP_BULK_RANDOM_UUID)) { (op == UUIDD_OP_BULK_RANDOM_UUID)) {
memcpy(op_buf + 1, num, sizeof(int)); memcpy(op_buf + sizeof(op), num, sizeof(*num));
op_len += sizeof(int); op_len += sizeof(*num);
} }
ret = write_all(s, op_buf, op_len); ret = write_all(s, op_buf, op_len);
@ -165,14 +198,14 @@ static int call_daemon(const char *socket_path, int op, char *buf,
ret = read_all(s, (char *) buf, reply_len); ret = read_all(s, (char *) buf, reply_len);
if ((ret > 0) && (op == UUIDD_OP_BULK_TIME_UUID)) { if ((ret > 0) && (op == UUIDD_OP_BULK_TIME_UUID)) {
if (reply_len >= (int) (UUID_LEN + sizeof(int))) if ((sizeof(uuid_t) + sizeof(*num)) <= (size_t) reply_len)
memcpy(buf + UUID_LEN, num, sizeof(int)); memcpy(buf + sizeof(uuid_t), num, sizeof(*num));
else else
*num = -1; *num = -1;
} }
if ((ret > 0) && (op == UUIDD_OP_BULK_RANDOM_UUID)) { if ((ret > 0) && (op == UUIDD_OP_BULK_RANDOM_UUID)) {
if (reply_len >= (int) sizeof(int)) if (sizeof(*num) <= (size_t) reply_len)
memcpy(buf, num, sizeof(int)); memcpy(buf, num, sizeof(*num));
else else
*num = -1; *num = -1;
} }
@ -311,10 +344,11 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
socklen_t fromlen; socklen_t fromlen;
int32_t reply_len = 0; int32_t reply_len = 0;
uuid_t uu; uuid_t uu;
char reply_buf[1024], *cp; char reply_buf[UUIDD_PROT_BUFSZ], *cp;
char op, str[UUID_STR_LEN]; uuidd_prot_op_t op;
char str[UUID_STR_LEN];
int i, ns, len; int i, ns, len;
int num; /* intentionally uninitialized */ uuidd_prot_num_t num; /* intentionally uninitialized */
int s = 0; int s = 0;
int fd_pidfile = -1; int fd_pidfile = -1;
int ret; int ret;
@ -412,11 +446,11 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
if (errno == EAGAIN) if (errno == EAGAIN)
continue; continue;
warn(_("poll failed")); warn(_("poll failed"));
all_done(uuidd_cxt, EXIT_FAILURE); all_done(uuidd_cxt, EXIT_FAILURE);
} }
if (ret == 0) { /* true when poll() times out */ if (ret == 0) { /* true when poll() times out */
if (uuidd_cxt->debug) if (uuidd_cxt->debug)
fprintf(stderr, _("timeout [%d sec]\n"), uuidd_cxt->timeout), fprintf(stderr, _("timeout [%d sec]\n"), uuidd_cxt->timeout);
all_done(uuidd_cxt, EXIT_SUCCESS); all_done(uuidd_cxt, EXIT_SUCCESS);
} }
if (pfd[POLLFD_SIGNAL].revents != 0) if (pfd[POLLFD_SIGNAL].revents != 0)
@ -430,8 +464,8 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
continue; continue;
err(EXIT_FAILURE, "accept"); err(EXIT_FAILURE, "accept");
} }
len = read(ns, &op, 1); len = read(ns, &op, sizeof(op));
if (len != 1) { if (len != sizeof(op)) {
if (len < 0) if (len < 0)
warn(_("read failed")); warn(_("read failed"));
else else
@ -441,7 +475,7 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
} }
if ((op == UUIDD_OP_BULK_TIME_UUID) || if ((op == UUIDD_OP_BULK_TIME_UUID) ||
(op == UUIDD_OP_BULK_RANDOM_UUID)) { (op == UUIDD_OP_BULK_RANDOM_UUID)) {
if (read_all(ns, (char *) &num, sizeof(num)) != 4) if (read_all(ns, (char *) &num, sizeof(num)) != sizeof(num))
goto shutdown_socket; goto shutdown_socket;
if (uuidd_cxt->debug) if (uuidd_cxt->debug)
fprintf(stderr, _("operation %d, incoming num = %d\n"), fprintf(stderr, _("operation %d, incoming num = %d\n"),
@ -496,31 +530,29 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
case UUIDD_OP_BULK_RANDOM_UUID: case UUIDD_OP_BULK_RANDOM_UUID:
if (num < 0) if (num < 0)
num = 1; num = 1;
if (num > 1000) if ((sizeof(reply_buf) - sizeof(num)) < (size_t) (sizeof(uu) * num))
num = 1000; num = (sizeof(reply_buf) - sizeof(num)) / sizeof(uu);
if (num * UUID_LEN > (int) (sizeof(reply_buf) - sizeof(num)))
num = (sizeof(reply_buf) - sizeof(num)) / UUID_LEN;
__uuid_generate_random((unsigned char *) reply_buf + __uuid_generate_random((unsigned char *) reply_buf +
sizeof(num), &num); sizeof(num), &num);
reply_len = sizeof(num) + (sizeof(uu) * num);
memcpy(reply_buf, &num, sizeof(num));
if (uuidd_cxt->debug) { if (uuidd_cxt->debug) {
fprintf(stderr, P_("Generated %d UUID:\n", fprintf(stderr, P_("Generated %d UUID:\n",
"Generated %d UUIDs:\n", num), num); "Generated %d UUIDs:\n", num), num);
for (i = 0, cp = reply_buf + sizeof(num); cp = reply_buf + sizeof(num);
i < num; for (i = 0; i < num; i++) {
i++, cp += UUID_LEN) {
uuid_unparse((unsigned char *)cp, str); uuid_unparse((unsigned char *)cp, str);
fprintf(stderr, "\t%s\n", str); fprintf(stderr, "\t%s\n", str);
cp += sizeof(uu);
} }
} }
reply_len = (num * UUID_LEN) + sizeof(num);
memcpy(reply_buf, &num, sizeof(num));
break; break;
default: default:
if (uuidd_cxt->debug) if (uuidd_cxt->debug)
fprintf(stderr, _("Invalid operation %d\n"), op); fprintf(stderr, _("Invalid operation %d\n"), op);
goto shutdown_socket; goto shutdown_socket;
} }
write_all(ns, (char *) &reply_len, sizeof(reply_len)); write_all(ns, (char *) &reply_len, sizeof(num));
write_all(ns, reply_buf, reply_len); write_all(ns, reply_buf, reply_len);
shutdown_socket: shutdown_socket:
close(ns); close(ns);
@ -532,22 +564,10 @@ static void __attribute__ ((__noreturn__)) unexpected_size(int size)
errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size); errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size);
} }
int main(int argc, char **argv) static void parse_options(int argc, char **argv, struct uuidd_cxt_t *uuidd_cxt,
struct uuidd_options_t *uuidd_opts)
{ {
const char *socket_path = UUIDD_SOCKET_PATH; const struct option longopts[] = {
const char *pidfile_path = NULL;
const char *err_context = NULL;
char buf[1024], *cp;
char str[UUID_STR_LEN];
uuid_t uu;
int i, c, ret;
int do_type = 0, do_kill = 0, num = 0;
int no_pid = 0;
int s_flag = 0;
struct uuidd_cxt_t uuidd_cxt = { .timeout = 0 };
static const struct option longopts[] = {
{"pid", required_argument, NULL, 'p'}, {"pid", required_argument, NULL, 'p'},
{"socket", required_argument, NULL, 's'}, {"socket", required_argument, NULL, 's'},
{"timeout", required_argument, NULL, 'T'}, {"timeout", required_argument, NULL, 'T'},
@ -564,68 +584,62 @@ int main(int argc, char **argv)
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
static const ul_excl_t excl[] = { const ul_excl_t excl[] = {
{ 'P', 'p' }, { 'P', 'p' },
{ 'd', 'q' }, { 'd', 'q' },
{ 'r', 't' }, { 'r', 't' },
{ 0 } { 0 }
}; };
int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
int c;
setlocale(LC_ALL, ""); while ((c = getopt_long(argc, argv, "p:s:T:krtn:PFSdqVh", longopts, NULL)) != -1) {
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
close_stdout_atexit();
while ((c =
getopt_long(argc, argv, "p:s:T:krtn:PFSdqVh", longopts,
NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st); err_exclusive_options(c, longopts, excl, excl_st);
switch (c) { switch (c) {
case 'd': case 'd':
uuidd_cxt.debug = 1; uuidd_cxt->debug = 1;
break; break;
case 'k': case 'k':
do_kill++; uuidd_opts->do_kill = 1;
break; break;
case 'n': case 'n':
num = strtou32_or_err(optarg, uuidd_opts->num = (uuidd_prot_num_t) strtou16_or_err(optarg,
_("failed to parse --uuids")); _("failed to parse --uuids"));
break; break;
case 'p': case 'p':
pidfile_path = optarg; uuidd_opts->pidfile_path = optarg;
break; break;
case 'P': case 'P':
no_pid = 1; uuidd_opts->no_pid = 1;
break; break;
case 'F': case 'F':
uuidd_cxt.no_fork = 1; uuidd_cxt->no_fork = 1;
break; break;
case 'S': case 'S':
#ifdef HAVE_LIBSYSTEMD #ifdef HAVE_LIBSYSTEMD
uuidd_cxt.no_sock = 1; uuidd_cxt->no_sock = 1;
uuidd_cxt.no_fork = 1; uuidd_cxt->no_fork = 1;
no_pid = 1; uuidd_opts->no_pid = 1;
#else #else
errx(EXIT_FAILURE, _("uuidd has been built without " errx(EXIT_FAILURE, _("uuidd has been built without "
"support for socket activation")); "support for socket activation"));
#endif #endif
break; break;
case 'q': case 'q':
uuidd_cxt.quiet = 1; uuidd_cxt->quiet = 1;
break; break;
case 'r': case 'r':
do_type = UUIDD_OP_RANDOM_UUID; uuidd_opts->do_type = UUIDD_OP_RANDOM_UUID;
break; break;
case 's': case 's':
socket_path = optarg; uuidd_opts->socket_path = optarg;
s_flag = 1; uuidd_opts->s_flag = 1;
break; break;
case 't': case 't':
do_type = UUIDD_OP_TIME_UUID; uuidd_opts->do_type = UUIDD_OP_TIME_UUID;
break; break;
case 'T': case 'T':
uuidd_cxt.timeout = strtou32_or_err(optarg, uuidd_cxt->timeout = strtou32_or_err(optarg,
_("failed to parse --timeout")); _("failed to parse --timeout"));
break; break;
@ -638,48 +652,87 @@ int main(int argc, char **argv)
} }
} }
if (strlen(socket_path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) if (0 < uuidd_opts->num) {
errx(EXIT_FAILURE, _("socket name too long: %s"), socket_path); switch (uuidd_opts->do_type) {
case UUIDD_OP_RANDOM_UUID:
uuidd_opts->do_type = UUIDD_OP_BULK_RANDOM_UUID;
break;
case UUIDD_OP_TIME_UUID:
uuidd_opts->do_type = UUIDD_OP_BULK_TIME_UUID;
break;
}
}
}
if (!no_pid && !pidfile_path) int main(int argc, char **argv)
pidfile_path = UUIDD_PIDFILE_PATH; {
const char *err_context = NULL;
char *cp;
int ret;
struct uuidd_cxt_t uuidd_cxt = { .timeout = 0 };
struct uuidd_options_t uuidd_opts = { .socket_path = UUIDD_SOCKET_PATH };
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
close_stdout_atexit();
parse_options(argc, argv, &uuidd_cxt, &uuidd_opts);
if (strlen(uuidd_opts.socket_path) >= sizeof(((struct sockaddr_un *)0)->sun_path))
errx(EXIT_FAILURE, _("socket name too long: %s"), uuidd_opts.socket_path);
if (!uuidd_opts.no_pid && !uuidd_opts.pidfile_path)
uuidd_opts.pidfile_path = UUIDD_PIDFILE_PATH;
/* custom socket path and socket-activation make no sense */ /* custom socket path and socket-activation make no sense */
if (s_flag && uuidd_cxt.no_sock && !uuidd_cxt.quiet) if (uuidd_opts.s_flag && uuidd_cxt.no_sock && !uuidd_cxt.quiet)
warnx(_("Both --socket-activation and --socket specified. " warnx(_("Both --socket-activation and --socket specified. "
"Ignoring --socket.")); "Ignoring --socket."));
if (num && do_type) { if (uuidd_opts.num && uuidd_opts.do_type) {
ret = call_daemon(socket_path, do_type + 2, buf, char buf[UUIDD_PROT_BUFSZ];
sizeof(buf), &num, &err_context); char str[UUID_STR_LEN];
ret = call_daemon(uuidd_opts.socket_path, uuidd_opts.do_type, buf,
sizeof(buf), &uuidd_opts.num, &err_context);
if (ret < 0) if (ret < 0)
err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"), err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
err_context ? : _("unexpected error")); err_context ? : _("unexpected error"));
if (do_type == UUIDD_OP_TIME_UUID) { if (uuidd_opts.do_type == UUIDD_OP_BULK_TIME_UUID) {
if (ret != sizeof(uu) + sizeof(num)) if (ret != sizeof(uuid_t) + sizeof(uuidd_opts.num))
unexpected_size(ret); unexpected_size(ret);
uuid_unparse((unsigned char *) buf, str); uuid_unparse((unsigned char *) buf, str);
printf(P_("%s and %d subsequent UUID\n", printf(P_("%s and %d subsequent UUID\n",
"%s and %d subsequent UUIDs\n", num - 1), "%s and %d subsequent UUIDs\n", uuidd_opts.num - 1),
str, num - 1); str, uuidd_opts.num - 1);
} else { } else {
int i;
printf(_("List of UUIDs:\n")); printf(_("List of UUIDs:\n"));
cp = buf + 4; cp = buf + sizeof(uuidd_opts.num);
if (ret != (int) (sizeof(num) + num * sizeof(uu))) if (ret != (int) (sizeof(uuidd_opts.num) + uuidd_opts.num * sizeof(uuid_t)))
unexpected_size(ret); unexpected_size(ret);
for (i = 0; i < num; i++, cp += UUID_LEN) { for (i = 0; i < uuidd_opts.num; i++, cp += sizeof(uuid_t)) {
uuid_unparse((unsigned char *) cp, str); uuid_unparse((unsigned char *) cp, str);
printf("\t%s\n", str); printf("\t%s\n", str);
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (do_type) {
ret = call_daemon(socket_path, do_type, (char *) &uu, if (uuidd_opts.do_type) {
uuid_t uu;
char str[UUID_STR_LEN];
ret = call_daemon(uuidd_opts.socket_path, uuidd_opts.do_type, (char *) &uu,
sizeof(uu), 0, &err_context); sizeof(uu), 0, &err_context);
if (ret < 0) if (ret < 0)
err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"), err(EXIT_FAILURE, _("error calling uuidd daemon (%s)"),
err_context ? : _("unexpected error")); err_context ? : _("unexpected error"));
@ -692,23 +745,27 @@ int main(int argc, char **argv)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (do_kill) { if (uuidd_opts.do_kill) {
ret = call_daemon(socket_path, UUIDD_OP_GETPID, buf, sizeof(buf), 0, NULL); char buf[16];
if ((ret > 0) && ((do_kill = atoi((char *) buf)) > 0)) {
ret = kill(do_kill, SIGTERM); ret = call_daemon(uuidd_opts.socket_path, UUIDD_OP_GETPID, buf, sizeof(buf), 0, NULL);
if (0 < ret) {
pid_t pid;
pid = (pid_t)strtou32_or_err(buf, _("failed to parse pid"));
ret = kill(pid, SIGTERM);
if (ret < 0) { if (ret < 0) {
if (!uuidd_cxt.quiet) if (!uuidd_cxt.quiet)
warn(_("couldn't kill uuidd running " warn(_("couldn't kill uuidd running "
"at pid %d"), do_kill); "at pid %d"), pid);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!uuidd_cxt.quiet) if (!uuidd_cxt.quiet)
printf(_("Killed uuidd running at pid %d.\n"), printf(_("Killed uuidd running at pid %d.\n"), pid);
do_kill);
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
server_loop(socket_path, pidfile_path, &uuidd_cxt); server_loop(uuidd_opts.socket_path, uuidd_opts.pidfile_path, &uuidd_cxt);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }