diff --git a/build-aux/configure-lib.sh b/build-aux/configure-lib.sh index 0f9bc8f9..f1df1542 100644 --- a/build-aux/configure-lib.sh +++ b/build-aux/configure-lib.sh @@ -339,7 +339,9 @@ lib/stdio/feof.c lib/stdio/fgets.c lib/stdio/freopen.c lib/stdio/fscanf.c +lib/stdio/pclose.c lib/stdio/perror.c +lib/stdio/popen.c lib/stdio/rewind.c lib/stdio/vfscanf.c lib/stdlib/__exit.c @@ -385,8 +387,6 @@ lib/stub/gmtime.c lib/stub/log.c lib/stub/mktime.c lib/stub/modf.c -lib/stub/pclose.c -lib/stub/popen.c lib/stub/pow.c lib/stub/rand.c lib/stub/setbuf.c diff --git a/lib/stub/pclose.c b/lib/stdio/pclose.c similarity index 62% rename from lib/stub/pclose.c rename to lib/stdio/pclose.c index 14f15bdd..20d91206 100644 --- a/lib/stub/pclose.c +++ b/lib/stdio/pclose.c @@ -1,6 +1,6 @@ /* -*-comment-start: "//";comment-end:""-*- * GNU Mes --- Maxwell Equations of Software - * Copyright © 2018 Jan (janneke) Nieuwenhuizen + * Copyright © 2022 Jan (janneke) Nieuwenhuizen * * This file is part of GNU Mes. * @@ -20,14 +20,31 @@ #include #include +#include +#include +#include +#include +#include int -pclose (int x) +pclose (FILE *stream) { - static int stub = 0; - if (__mes_debug () && !stub) - eputs ("pclose stub\n"); - stub = 1; - errno = 0; - return 0; + int filedes = fileno (stream); + __ungetc_init (); + pid_t pid = __ungetc_buf[filedes]; + if (!pid) + { + errno = EINVAL; + return -1; + } + + if (fclose (stream)) + return -1; + + int status; + pid_t child_pid = waitpid (pid, &status, 0); + if (child_pid != pid) + return -1; + + return status; } diff --git a/lib/stdio/popen.c b/lib/stdio/popen.c new file mode 100644 index 00000000..71b43204 --- /dev/null +++ b/lib/stdio/popen.c @@ -0,0 +1,114 @@ +/* -*-comment-start: "//";comment-end:""-*- + * GNU Mes --- Maxwell Equations of Software + * Copyright © 2022 Jan (janneke) Nieuwenhuizen + * + * This file is part of GNU Mes. + * + * GNU Mes is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * GNU Mes is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Mes. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SHELL_FILE_NAME +#define SHELL_FILE_NAME "/bin/sh" +#endif +#ifndef SHELL_COMMAND_NAME +#define SHELL_COMMAND_NAME "sh" +#endif + +extern int *__ungetc_buf; + +FILE * +popen (char const *command, char const *mode) +{ + if (!command || !mode || (*mode != 'r' && *mode != 'w')) + { + errno = EINVAL; + return 0; + } + + int pipedes[2]; + if (pipe (pipedes) < 0) + return NULL; + + pid_t pid = fork (); + if (pid == -1) + { + close (pipedes[0]); + close (pipedes[1]); + return 0; + } + else if (pid == 0) + { + // child + int dup = (*mode == 'w' + ? dup2 (pipedes[STDIN], STDIN) + : dup2 (pipedes[STDOUT], STDOUT)) + if (dup < 0) + _exit (127); + + close (pipedes[STDIN]); + close (pipedes[STDOUT]); + + char const *argv[4]; + argv[0] = SHELL_COMMAND_NAME; + argv[1] = "-c"; + argv[2] = command; + argv[3] = 0; + execve (SHELL_FILE_NAME, (char *const *) argv, environ); + _exit (127); + } + + FILE *stream; + // parent + if (*mode == 'r') + { + close (pipedes[STDOUT]); + fcntl (pipedes[STDIN], F_SETFD, FD_CLOEXEC); + stream = fdopen (pipedes[STDIN], mode); + } + else + { + close (pipedes[STDIN]); + fcntl (pipedes[STDOUT], F_SETFD, FD_CLOEXEC); + stream = fdopen (pipedes[STDOUT], mode); + } + + if (!stream) + { + int save_errno = errno; + kill (pid, SIGKILL); + if (!stream) + close (pipedes[*mode == 'r' ? STDOUT : STDIN]); + else + fclose (stream); + waitpid (pid, (int *)0, 0); + errno = save_errno; + return 0; + } + + int filedes = fileno (stream); + // XXX misuse ungetc buffer for PID + // XXX TODO: make proper FILE struct + __ungetc_init (); + __ungetc_set (filedes, pidchild); + return stream; +} diff --git a/lib/stub/popen.c b/lib/stub/popen.c deleted file mode 100644 index 77fd5f95..00000000 --- a/lib/stub/popen.c +++ /dev/null @@ -1,33 +0,0 @@ -/* -*-comment-start: "//";comment-end:""-*- - * GNU Mes --- Maxwell Equations of Software - * Copyright © 2018 Jan (janneke) Nieuwenhuizen - * - * This file is part of GNU Mes. - * - * GNU Mes is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * GNU Mes is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Mes. If not, see . - */ - -#include -#include - -int -popen (int x) -{ - static int stub = 0; - if (__mes_debug () && !stub) - eputs ("popen stub\n"); - stub = 1; - errno = 0; - return 0; -}