Krolyxon
Commit ad95012

Branches

Refs →

nsxivad95012

Add reuseable abstraction over fork/exec/dup2 (#211)

Author
N-R-K
Date
2022-02-20 15:54 +0000
Committer
GitHub · 2022-02-20 15:54 +0000
Parent
3cf4fc5
Commit
ad95012be993664e062e7724155c54a482a51315

+113 −45

3 files changed

  1. M main.c +24 −45
  2. M nsxiv.h +13 −0
  3. M util.c +76 −0
M main.c View
@@ -240,29 +240,22 @@ void close_info(void)
240240
241241 void open_info(void)
242242 {
243− int pfd[2];
243+ spawn_t pfd;
244244 char w[12], h[12];
245+ char *argv[5];
245246
246247 if (info.f.err || info.fd >= 0 || win.bar.h == 0)
247248 return;
248249 win.bar.l.buf[0] = '\0';
249− if (pipe(pfd) < 0)
250− return;
251− if ((info.pid = fork()) == 0) {
252− close(pfd[0]);
253− dup2(pfd[1], 1);
254− snprintf(w, sizeof(w), "%d", img.w);
255− snprintf(h, sizeof(h), "%d", img.h);
256− execl(info.f.cmd, info.f.cmd, files[fileidx].name, w, h, NULL);
257− error(EXIT_FAILURE, errno, "exec: %s", info.f.cmd);
258− }
259− close(pfd[1]);
260− if (info.pid < 0) {
261− close(pfd[0]);
262− } else {
263− fcntl(pfd[0], F_SETFL, O_NONBLOCK);
264− info.fd = pfd[0];
250+ snprintf(w, sizeof(w), "%d", img.w);
251+ snprintf(h, sizeof(h), "%d", img.h);
252+ construct_argv(argv, ARRLEN(argv), info.f.cmd, files[fileidx].name, w, h, NULL);
253+ pfd = spawn(info.f.cmd, argv, X_READ);
254+ if (pfd.readfd >= 0) {
255+ fcntl(pfd.readfd, F_SETFL, O_NONBLOCK);
256+ info.fd = pfd.readfd;
265257 info.i = info.lastsep = 0;
258+ info.pid = pfd.pid;
266259 }
267260 }
268261
@@ -510,15 +503,16 @@ void handle_key_handler(bool init)
510503
511504 static bool run_key_handler(const char *key, unsigned int mask)
512505 {
513− pid_t pid;
514506 FILE *pfs;
515507 bool marked = mode == MODE_THUMB && markcnt > 0;
516508 bool changed = false;
517− int f, i, pfd[2];
509+ int f, i;
518510 int fcnt = marked ? markcnt : 1;
519511 char kstr[32];
520512 struct stat *oldst, st;
521513 XEvent dump;
514+ char *argv[3];
515+ spawn_t pfd;
522516
523517 if (keyhandler.f.err) {
524518 if (!keyhandler.warned) {
@@ -530,41 +524,27 @@ static bool run_key_handler(const char *key, unsigned int mask)
530524 if (key == NULL)
531525 return false;
532526
533− if (pipe(pfd) < 0) {
534− error(0, errno, "pipe");
535− return false;
536− }
537− if ((pfs = fdopen(pfd[1], "w")) == NULL) {
538− error(0, errno, "open pipe");
539− close(pfd[0]), close(pfd[1]);
540− return false;
541− }
542− oldst = emalloc(fcnt * sizeof(*oldst));
543−
544527 close_info();
545528 strncpy(win.bar.l.buf, "Running key handler...", win.bar.l.size);
546529 win_draw(&win);
547530 win_set_cursor(&win, CURSOR_WATCH);
531+ setenv("NSXIV_USING_NULL", options->using_null ? "1" : "0", 1);
548532
549533 snprintf(kstr, sizeof(kstr), "%s%s%s%s",
550534 mask & ControlMask ? "C-" : "",
551535 mask & Mod1Mask ? "M-" : "",
552536 mask & ShiftMask ? "S-" : "", key);
553− setenv("NSXIV_USING_NULL", options->using_null ? "1" : "0", 1);
554−
555− if ((pid = fork()) == 0) {
556− close(pfd[1]);
557− dup2(pfd[0], 0);
558− execl(keyhandler.f.cmd, keyhandler.f.cmd, kstr, NULL);
559− error(EXIT_FAILURE, errno, "exec: %s", keyhandler.f.cmd);
560− }
561− close(pfd[0]);
562− if (pid < 0) {
563− error(0, errno, "fork");
564− fclose(pfs);
565− goto end;
537+ construct_argv(argv, ARRLEN(argv), keyhandler.f.cmd, kstr, NULL);
538+ pfd = spawn(keyhandler.f.cmd, argv, X_WRITE);
539+ if (pfd.writefd < 0)
540+ return false;
541+ if ((pfs = fdopen(pfd.writefd, "w")) == NULL) {
542+ close(pfd.writefd);
543+ error(0, errno, "open pipe");
544+ return false;
566545 }
567546
547+ oldst = emalloc(fcnt * sizeof(*oldst));
568548 for (f = i = 0; f < fcnt; i++) {
569549 if ((marked && (files[i].flags & FF_MARK)) || (!marked && i == fileidx)) {
570550 stat(files[i].path, &oldst[f]);
@@ -573,7 +553,7 @@ static bool run_key_handler(const char *key, unsigned int mask)
573553 }
574554 }
575555 fclose(pfs);
576− while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
556+ while (waitpid(pfd.pid, NULL, 0) == -1 && errno == EINTR);
577557
578558 for (f = i = 0; f < fcnt; i++) {
579559 if ((marked && (files[i].flags & FF_MARK)) || (!marked && i == fileidx)) {
@@ -592,7 +572,6 @@ static bool run_key_handler(const char *key, unsigned int mask)
592572 /* drop user input events that occurred while running the key handler */
593573 while (XCheckIfEvent(win.env.dpy, &dump, is_input_ev, NULL));
594574
595−end:
596575 if (mode == MODE_IMAGE) {
597576 if (changed) {
598577 img_close(&img, true);
M nsxiv.h View
@@ -342,6 +342,17 @@ typedef struct {
342342 int stlen;
343343 } r_dir_t;
344344
345+typedef struct {
346+ int readfd;
347+ int writefd;
348+ pid_t pid;
349+} spawn_t;
350+
351+enum {
352+ X_READ = (1 << 0),
353+ X_WRITE = (1 << 1)
354+};
355+
345356 extern const char *progname;
346357
347358 void* emalloc(size_t);
@@ -353,6 +364,8 @@ int r_opendir(r_dir_t*, const char*, bool);
353364 int r_closedir(r_dir_t*);
354365 char* r_readdir(r_dir_t*, bool);
355366 int r_mkdir(char*);
367+void construct_argv(char**, unsigned int, ...);
368+spawn_t spawn(const char*, char *const [], unsigned int);
356369
357370
358371 /* window.c */
M util.c View
@@ -211,3 +211,79 @@ int r_mkdir(char *path)
211211 }
212212 return 0;
213213 }
214+
215+void construct_argv(char **argv, unsigned int len, ...)
216+{
217+ unsigned int i;
218+ va_list args;
219+
220+ va_start(args, len);
221+ for (i = 0; i < len; ++i)
222+ argv[i] = va_arg(args, char *);
223+ va_end(args);
224+ if (argv[len-1] != NULL)
225+ error(EXIT_FAILURE, 0, "argv not NULL terminated");
226+}
227+
228+spawn_t spawn(const char *cmd, char *const argv[], unsigned int flags)
229+{
230+ pid_t pid;
231+ spawn_t status = { -1, -1, -1 };
232+ int pfd_read[2] = { -1, -1 };
233+ int pfd_write[2] = { -1, -1 };
234+ const bool r = flags & X_READ;
235+ const bool w = flags & X_WRITE;
236+
237+ if (cmd == NULL || argv == NULL || flags == 0)
238+ return status;
239+
240+ if (r && pipe(pfd_read) < 0) {
241+ error(0, errno, "pipe: %s", cmd);
242+ return status;
243+ }
244+
245+ if (w && pipe(pfd_write) < 0) {
246+ if (r) {
247+ close(pfd_read[0]);
248+ close(pfd_read[1]);
249+ }
250+ error(0, errno, "pipe: %s", cmd);
251+ return status;
252+ }
253+
254+ if ((pid = fork()) == 0) {
255+ bool err = (r && dup2(pfd_read[1], 1) < 0) || (w && dup2(pfd_write[0], 0) < 0);
256+ if (r) {
257+ close(pfd_read[0]);
258+ close(pfd_read[1]);
259+ }
260+ if (w) {
261+ close(pfd_write[0]);
262+ close(pfd_write[1]);
263+ }
264+
265+ if (err)
266+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
267+ execv(cmd, argv);
268+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
269+ }
270+
271+ if (r)
272+ close(pfd_read[1]);
273+ if (w)
274+ close(pfd_write[0]);
275+
276+ if (pid < 0) {
277+ if (r)
278+ close(pfd_read[0]);
279+ if (w)
280+ close(pfd_write[1]);
281+ error(0, errno, "fork: %s", cmd);
282+ return status;
283+ }
284+
285+ status.pid = pid;
286+ status.readfd = pfd_read[0];
287+ status.writefd = pfd_write[1];
288+ return status;
289+}