From dd4665bfbd4d5255d3671a7a41afb5afdf179576 Mon Sep 17 00:00:00 2001 From: FRIGN Date: Thu, 18 Sep 2014 22:27:51 +0200 Subject: Change global in-fifos from O_RDWR to O_RDONLY O_RDWR is a dirty hack to get around the issue of infinite EOFs while reading an in-FIFO. Instead, stop breaking POSIX and set the FIFOs to O_RDONLY. In case a read returns EOF (r == 0), we reopen the fd. Same will be applied to the friend-fifos (especially file_in), helping us get rid of strange timeouts and heuristics and rather solve the problem the POSIX-way. The only downside to this is that we are blind for writes to the in-FIFOs between catching read == 0 and close(), but this is not an issue. To make reopening as easy as possible, I added a dirfd to all slots. While at it, I changed the initial setup and removed the chdir() in favor of the POSIX-2008-compliant *at-functions. This lets us do stuff without having to use snprintf to build paths and is more bulletproof even in case the directory is renamed. --- ratox.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 15 deletions(-) (limited to 'ratox.c') diff --git a/ratox.c b/ratox.c index 76c8b39..3c18649 100644 --- a/ratox.c +++ b/ratox.c @@ -49,6 +49,7 @@ struct slot { const char *name; void (*cb)(void *); int outtype; + int dirfd; int fd[NR_GFILES]; }; @@ -76,7 +77,7 @@ static struct slot gslots[] = { }; static struct file gfiles[] = { - { .type = FIFO, .name = "in", .flags = O_RDWR | O_NONBLOCK, }, + { .type = FIFO, .name = "in", .flags = O_RDONLY | O_NONBLOCK, }, { .type = OUT_F, .name = "out", .flags = O_WRONLY | O_TRUNC | O_CREAT }, { .type = OUT_F, .name = "err", .flags = O_WRONLY | O_TRUNC | O_CREAT }, }; @@ -549,19 +550,25 @@ localinit(void) perror("mkdir"); exit(EXIT_FAILURE); } - r = chdir(gslots[i].name); + d = opendir(gslots[i].name); + if (!d) { + perror("opendir"); + exit(EXIT_FAILURE); + } + r = dirfd(d); if (r < 0) { - perror("chdir"); + perror("dirfd"); exit(EXIT_FAILURE); } + gslots[i].dirfd = r; for (m = 0; m < LEN(gfiles); m++) { if (gfiles[m].type == FIFO) { - r = mkfifo(gfiles[m].name, 0644); + r = mkfifoat(gslots[i].dirfd, gfiles[m].name, 0644); if (r < 0 && errno != EEXIST) { perror("mkfifo"); exit(EXIT_FAILURE); } - r = open(gfiles[m].name, gfiles[m].flags, 0644); + r = openat(gslots[i].dirfd, gfiles[m].name, gfiles[m].flags, 0644); if (r < 0) { perror("open"); exit(EXIT_FAILURE); @@ -569,33 +576,27 @@ localinit(void) gslots[i].fd[m] = r; } else if (gfiles[m].type == OUT_F) { if (gslots[i].outtype == STATIC) { - r = open(gfiles[m].name, gfiles[m].flags, 0644); + r = openat(gslots[i].dirfd, gfiles[m].name, gfiles[m].flags, 0644); if (r < 0) { perror("open"); exit(EXIT_FAILURE); } gslots[i].fd[m] = r; } else if (gslots[i].outtype == FOLDER) { - r = mkdir(gfiles[m].name, 0777); + r = mkdirat(gslots[i].dirfd, gfiles[m].name, 0777); if (r < 0 && errno != EEXIST) { perror("mkdir"); exit(EXIT_FAILURE); } - d = opendir(gfiles[m].name); - if (!d) { - perror("opendir"); - exit(EXIT_FAILURE); - } - r = dirfd(d); + r = openat(gslots[i].dirfd, gfiles[m].name, O_RDONLY | O_DIRECTORY); if (r < 0) { - perror("dirfd"); + perror("openat"); exit(EXIT_FAILURE); } gslots[i].fd[m] = r; } } } - chdir(".."); } /* Dump current name */ @@ -789,6 +790,16 @@ setname(void *data) again: r = read(gslots[NAME].fd[IN], name, sizeof(name) - 1); + if (r == 0) { + close(gslots[NAME].fd[IN]); + r = openat(gslots[NAME].dirfd, gfiles[IN].name, gfiles[IN].flags, 0644); + if (r < 0) { + perror("openat"); + exit(EXIT_FAILURE); + } + gslots[NAME].fd[IN] = r; + return; + } if (r < 0) { if (errno == EINTR) goto again; @@ -815,6 +826,16 @@ setstatus(void *data) again: r = read(gslots[STATUS].fd[IN], status, sizeof(status) - 1); + if (r == 0) { + close(gslots[STATUS].fd[IN]); + r = openat(gslots[STATUS].dirfd, gfiles[IN].name, gfiles[IN].flags, 0644); + if (r < 0) { + perror("openat"); + exit(EXIT_FAILURE); + } + gslots[STATUS].fd[IN] = r; + return; + } if (r < 0) { if (errno == EINTR) goto again; @@ -843,6 +864,16 @@ sendfriendreq(void *data) again: r = read(gslots[REQUEST].fd[IN], buf, sizeof(buf) - 1); + if (r == 0) { + close(gslots[REQUEST].fd[IN]); + r = openat(gslots[REQUEST].dirfd, gfiles[IN].name, gfiles[IN].flags, 0644); + if (r < 0) { + perror("openat"); + exit(EXIT_FAILURE); + } + gslots[REQUEST].fd[IN] = r; + return; + } if (r < 0) { if (errno == EINTR) goto again; -- cgit v1.2.3