LCOV - code coverage report
Current view: top level - lib/process - process_unix.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 200 248 80.6 %
Date: 2021-11-24 03:28:48 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2003, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file process_unix.c
       8             :  * \brief Module for working with Unix processes.
       9             :  **/
      10             : 
      11             : #define PROCESS_UNIX_PRIVATE
      12             : #include "lib/intmath/cmp.h"
      13             : #include "lib/buf/buffers.h"
      14             : #include "lib/net/buffers_net.h"
      15             : #include "lib/container/smartlist.h"
      16             : #include "lib/evloop/compat_libevent.h"
      17             : #include "lib/log/log.h"
      18             : #include "lib/log/util_bug.h"
      19             : #include "lib/process/process.h"
      20             : #include "lib/process/process_unix.h"
      21             : #include "lib/process/waitpid.h"
      22             : #include "lib/process/env.h"
      23             : 
      24             : #include <stdio.h>
      25             : 
      26             : #ifdef HAVE_STRING_H
      27             : #include <string.h>
      28             : #endif
      29             : 
      30             : #ifdef HAVE_ERRNO_H
      31             : #include <errno.h>
      32             : #endif
      33             : 
      34             : #ifdef HAVE_UNISTD_H
      35             : #include <unistd.h>
      36             : #endif
      37             : 
      38             : #ifdef HAVE_FCNTL_H
      39             : #include <fcntl.h>
      40             : #endif
      41             : 
      42             : #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
      43             : #include <sys/prctl.h>
      44             : #endif
      45             : 
      46             : #if HAVE_SIGNAL_H
      47             : #include <signal.h>
      48             : #endif
      49             : 
      50             : #ifndef _WIN32
      51             : 
      52             : /** Maximum number of file descriptors, if we cannot get it via sysconf() */
      53             : #define DEFAULT_MAX_FD 256
      54             : 
      55             : /** Internal state for Unix handles. */
      56             : struct process_unix_handle_t {
      57             :   /** Unix File Descriptor. */
      58             :   int fd;
      59             : 
      60             :   /** Have we reached end of file? */
      61             :   bool reached_eof;
      62             : 
      63             :   /** Event structure for libevent. */
      64             :   struct event *event;
      65             : 
      66             :   /** Are we writing? */
      67             :   bool is_writing;
      68             : };
      69             : 
      70             : /** Internal state for our Unix process. */
      71             : struct process_unix_t {
      72             :   /** Standard in handle. */
      73             :   process_unix_handle_t stdin_handle;
      74             : 
      75             :   /** Standard out handle. */
      76             :   process_unix_handle_t stdout_handle;
      77             : 
      78             :   /** Standard error handle. */
      79             :   process_unix_handle_t stderr_handle;
      80             : 
      81             :   /** The process identifier of our process. */
      82             :   pid_t pid;
      83             : 
      84             :   /** Waitpid Callback structure. */
      85             :   waitpid_callback_t *waitpid;
      86             : };
      87             : 
      88             : /** Returns a newly allocated <b>process_unix_t</b>. */
      89             : process_unix_t *
      90          32 : process_unix_new(void)
      91             : {
      92          32 :   process_unix_t *unix_process;
      93          32 :   unix_process = tor_malloc_zero(sizeof(process_unix_t));
      94             : 
      95          32 :   unix_process->stdin_handle.fd = -1;
      96          32 :   unix_process->stderr_handle.fd = -1;
      97          32 :   unix_process->stdout_handle.fd = -1;
      98             : 
      99          32 :   return unix_process;
     100             : }
     101             : 
     102             : /** Deallocates the given <b>unix_process</b>. */
     103             : void
     104          29 : process_unix_free_(process_unix_t *unix_process)
     105             : {
     106          29 :   if (! unix_process)
     107             :     return;
     108             : 
     109             :   /* Clean up our waitpid callback. */
     110          29 :   clear_waitpid_callback(unix_process->waitpid);
     111             : 
     112             :   /* FIXME(ahf): Refactor waitpid code? */
     113          29 :   unix_process->waitpid = NULL;
     114             : 
     115             :   /* Close all our file descriptors. */
     116          29 :   process_unix_close_file_descriptors(unix_process);
     117             : 
     118          29 :   tor_event_free(unix_process->stdout_handle.event);
     119          29 :   tor_event_free(unix_process->stderr_handle.event);
     120          29 :   tor_event_free(unix_process->stdin_handle.event);
     121             : 
     122          29 :   tor_free(unix_process);
     123             : }
     124             : 
     125             : /** Executes the given process as a child process of Tor.  This function is
     126             :  * responsible for setting up the child process and run it. This includes
     127             :  * setting up pipes for interprocess communication, initialize the waitpid
     128             :  * callbacks, and finally run fork() followed by execve(). Returns
     129             :  * <b>PROCESS_STATUS_RUNNING</b> upon success. */
     130             : process_status_t
     131           3 : process_unix_exec(process_t *process)
     132             : {
     133           3 :   static int max_fd = -1;
     134             : 
     135           3 :   process_unix_t *unix_process;
     136           3 :   pid_t pid;
     137           3 :   int stdin_pipe[2];
     138           3 :   int stdout_pipe[2];
     139           3 :   int stderr_pipe[2];
     140           3 :   int retval, fd;
     141             : 
     142           3 :   unix_process = process_get_unix_process(process);
     143             : 
     144             :   /* Create standard in pipe. */
     145           3 :   retval = pipe(stdin_pipe);
     146             : 
     147           3 :   if (-1 == retval) {
     148           0 :     log_warn(LD_PROCESS,
     149             :              "Unable to create pipe for stdin "
     150             :              "communication with process: %s",
     151             :              strerror(errno));
     152             : 
     153           0 :     return PROCESS_STATUS_ERROR;
     154             :   }
     155             : 
     156             :   /* Create standard out pipe. */
     157           3 :   retval = pipe(stdout_pipe);
     158             : 
     159           3 :   if (-1 == retval) {
     160           0 :     log_warn(LD_PROCESS,
     161             :              "Unable to create pipe for stdout "
     162             :              "communication with process: %s",
     163             :              strerror(errno));
     164             : 
     165             :     /** Cleanup standard in pipe. */
     166           0 :     close(stdin_pipe[0]);
     167           0 :     close(stdin_pipe[1]);
     168             : 
     169           0 :     return PROCESS_STATUS_ERROR;
     170             :   }
     171             : 
     172             :   /* Create standard error pipe. */
     173           3 :   retval = pipe(stderr_pipe);
     174             : 
     175           3 :   if (-1 == retval) {
     176           0 :     log_warn(LD_PROCESS,
     177             :              "Unable to create pipe for stderr "
     178             :              "communication with process: %s",
     179             :              strerror(errno));
     180             : 
     181             :     /** Cleanup standard in pipe. */
     182           0 :     close(stdin_pipe[0]);
     183           0 :     close(stdin_pipe[1]);
     184             : 
     185             :     /** Cleanup standard out pipe. */
     186           0 :     close(stdout_pipe[0]);
     187           0 :     close(stdout_pipe[1]);
     188             : 
     189           0 :     return PROCESS_STATUS_ERROR;
     190             :   }
     191             : 
     192             : #ifdef _SC_OPEN_MAX
     193           3 :   if (-1 == max_fd) {
     194           1 :     max_fd = (int)sysconf(_SC_OPEN_MAX);
     195             : 
     196           1 :     if (max_fd == -1) {
     197           0 :       max_fd = DEFAULT_MAX_FD;
     198           0 :       log_warn(LD_PROCESS,
     199             :                "Cannot find maximum file descriptor, assuming: %d", max_fd);
     200             :     }
     201             :   }
     202             : #else /* !defined(_SC_OPEN_MAX) */
     203             :   max_fd = DEFAULT_MAX_FD;
     204             : #endif /* defined(_SC_OPEN_MAX) */
     205             : 
     206           3 :   pid = fork();
     207             : 
     208           5 :   if (0 == pid) {
     209             :     /* This code is running in the child process context. */
     210             : 
     211             : #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
     212             :     /* Attempt to have the kernel issue a SIGTERM if the parent
     213             :      * goes away. Certain attributes of the binary being execve()ed
     214             :      * will clear this during the execve() call, but it's better
     215             :      * than nothing.
     216             :      */
     217           2 :     prctl(PR_SET_PDEATHSIG, SIGTERM);
     218             : #endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */
     219             : 
     220             :     /* Link process stdout to the write end of the pipe. */
     221           2 :     retval = dup2(stdout_pipe[1], STDOUT_FILENO);
     222           2 :     if (-1 == retval)
     223           0 :       goto error;
     224             : 
     225             :     /* Link process stderr to the write end of the pipe. */
     226           2 :     retval = dup2(stderr_pipe[1], STDERR_FILENO);
     227           2 :     if (-1 == retval)
     228           0 :       goto error;
     229             : 
     230             :     /* Link process stdin to the read end of the pipe */
     231           2 :     retval = dup2(stdin_pipe[0], STDIN_FILENO);
     232           2 :     if (-1 == retval)
     233           0 :       goto error;
     234             : 
     235             :     /* Close our pipes now after they have been dup2()'ed. */
     236           2 :     close(stderr_pipe[0]);
     237           2 :     close(stderr_pipe[1]);
     238           2 :     close(stdout_pipe[0]);
     239           2 :     close(stdout_pipe[1]);
     240           2 :     close(stdin_pipe[0]);
     241           2 :     close(stdin_pipe[1]);
     242             : 
     243             :     /* Close all other fds, including the read end of the pipe.  XXX: We should
     244             :      * now be doing enough FD_CLOEXEC setting to make this needless.
     245             :      */
     246        2046 :     for (fd = STDERR_FILENO + 1; fd < max_fd; fd++)
     247        2042 :       close(fd);
     248             : 
     249             :     /* Create the argv value for our new process. */
     250           2 :     char **argv = process_get_argv(process);
     251             : 
     252             :     /* Create the env value for our new process. */
     253           2 :     process_environment_t *env = process_get_environment(process);
     254             : 
     255             :     /* Call the requested program. */
     256           2 :     execve(argv[0], argv, env->unixoid_environment_block);
     257             : 
     258             :     /* If we made it here it is because execve failed :-( */
     259           2 :     tor_free(argv);
     260           2 :     process_environment_free(env);
     261             : 
     262           0 :  error:
     263           0 :     fprintf(stderr, "Error from child process: %s", strerror(errno));
     264           0 :     _exit(1);
     265             :   }
     266             : 
     267             :   /* We are in the parent process. */
     268           3 :   if (-1 == pid) {
     269           0 :     log_warn(LD_PROCESS,
     270             :              "Failed to create child process: %s", strerror(errno));
     271             : 
     272             :     /** Cleanup standard in pipe. */
     273           0 :     close(stdin_pipe[0]);
     274           0 :     close(stdin_pipe[1]);
     275             : 
     276             :     /** Cleanup standard out pipe. */
     277           0 :     close(stdout_pipe[0]);
     278           0 :     close(stdout_pipe[1]);
     279             : 
     280             :     /** Cleanup standard error pipe. */
     281           0 :     close(stderr_pipe[0]);
     282           0 :     close(stderr_pipe[1]);
     283             : 
     284           0 :     return PROCESS_STATUS_ERROR;
     285             :   }
     286             : 
     287             :   /* Register our PID. */
     288           3 :   unix_process->pid = pid;
     289             : 
     290             :   /* Setup waitpid callbacks. */
     291           3 :   unix_process->waitpid = set_waitpid_callback(pid,
     292             :                                                process_unix_waitpid_callback,
     293             :                                                process);
     294             : 
     295             :   /* Handle standard out. */
     296           3 :   unix_process->stdout_handle.fd = stdout_pipe[0];
     297           3 :   retval = close(stdout_pipe[1]);
     298             : 
     299           3 :   if (-1 == retval) {
     300           0 :     log_warn(LD_PROCESS, "Failed to close write end of standard out pipe: %s",
     301             :              strerror(errno));
     302             :   }
     303             : 
     304             :   /* Handle standard error. */
     305           3 :   unix_process->stderr_handle.fd = stderr_pipe[0];
     306           3 :   retval = close(stderr_pipe[1]);
     307             : 
     308           3 :   if (-1 == retval) {
     309           0 :     log_warn(LD_PROCESS,
     310             :              "Failed to close write end of standard error pipe: %s",
     311             :              strerror(errno));
     312             :   }
     313             : 
     314             :   /* Handle standard in. */
     315           3 :   unix_process->stdin_handle.fd = stdin_pipe[1];
     316           3 :   retval = close(stdin_pipe[0]);
     317             : 
     318           3 :   if (-1 == retval) {
     319           0 :     log_warn(LD_PROCESS, "Failed to close read end of standard in pipe: %s",
     320             :              strerror(errno));
     321             :   }
     322             : 
     323             :   /* Setup our handles. */
     324           3 :   process_unix_setup_handle(process,
     325             :                             &unix_process->stdout_handle,
     326             :                             EV_READ|EV_PERSIST,
     327             :                             stdout_read_callback);
     328             : 
     329           3 :   process_unix_setup_handle(process,
     330             :                             &unix_process->stderr_handle,
     331             :                             EV_READ|EV_PERSIST,
     332             :                             stderr_read_callback);
     333             : 
     334           3 :   process_unix_setup_handle(process,
     335             :                             &unix_process->stdin_handle,
     336             :                             EV_WRITE|EV_PERSIST,
     337             :                             stdin_write_callback);
     338             : 
     339             :   /* Start reading from standard out and standard error. */
     340           3 :   process_unix_start_reading(&unix_process->stdout_handle);
     341           3 :   process_unix_start_reading(&unix_process->stderr_handle);
     342             : 
     343           3 :   return PROCESS_STATUS_RUNNING;
     344             : }
     345             : 
     346             : /** Terminate the given process. Returns true on success, otherwise false. */
     347             : bool
     348           1 : process_unix_terminate(process_t *process)
     349             : {
     350           1 :   tor_assert(process);
     351             : 
     352           1 :   process_unix_t *unix_process = process_get_unix_process(process);
     353             : 
     354             :   /* All running processes should have a waitpid. */
     355           1 :   if (BUG(unix_process->waitpid == NULL))
     356           0 :     return false;
     357             : 
     358           1 :   bool success = true;
     359             : 
     360             :   /* Send a SIGTERM to our child process. */
     361           1 :   int ret;
     362             : 
     363           1 :   ret = kill(unix_process->pid, SIGTERM);
     364             : 
     365           1 :   if (ret == -1) {
     366           0 :     log_warn(LD_PROCESS, "Unable to terminate process: %s",
     367             :              strerror(errno));
     368           0 :     success = false;
     369             :   }
     370             : 
     371             :   /* Close all our FD's. */
     372           1 :   if (! process_unix_close_file_descriptors(unix_process))
     373           0 :     success = false;
     374             : 
     375             :   return success;
     376             : }
     377             : 
     378             : /** Returns the unique process identifier for the given <b>process</b>. */
     379             : process_pid_t
     380           1 : process_unix_get_pid(process_t *process)
     381             : {
     382           1 :   tor_assert(process);
     383             : 
     384           1 :   process_unix_t *unix_process = process_get_unix_process(process);
     385           1 :   return (process_pid_t)unix_process->pid;
     386             : }
     387             : 
     388             : /** Write the given <b>buffer</b> as input to the given <b>process</b>'s
     389             :  * standard input. Returns the number of bytes written. */
     390             : int
     391           5 : process_unix_write(process_t *process, buf_t *buffer)
     392             : {
     393           5 :   tor_assert(process);
     394           5 :   tor_assert(buffer);
     395             : 
     396           5 :   process_unix_t *unix_process = process_get_unix_process(process);
     397             : 
     398           5 :   size_t buffer_flush_len = buf_datalen(buffer);
     399           5 :   const size_t max_to_write = MIN(PROCESS_MAX_WRITE, buffer_flush_len);
     400             : 
     401             :   /* If we have data to write (when buffer_flush_len > 0) and we are not
     402             :    * currently getting file descriptor events from the kernel, we tell the
     403             :    * kernel to start notifying us about when we can write to our file
     404             :    * descriptor and return. */
     405           5 :   if (buffer_flush_len > 0 && ! unix_process->stdin_handle.is_writing) {
     406           1 :     process_unix_start_writing(&unix_process->stdin_handle);
     407           1 :     return 0;
     408             :   }
     409             : 
     410             :   /* We don't have any data to write, but the kernel is currently notifying us
     411             :    * about whether we are able to write or not. Tell the kernel to stop
     412             :    * notifying us until we have data to write. */
     413           4 :   if (buffer_flush_len == 0 && unix_process->stdin_handle.is_writing) {
     414           1 :     process_unix_stop_writing(&unix_process->stdin_handle);
     415           1 :     return 0;
     416             :   }
     417             : 
     418             :   /* We have data to write and the kernel have told us to write it. */
     419           3 :   return buf_flush_to_pipe(buffer,
     420           3 :                            process_get_unix_process(process)->stdin_handle.fd,
     421             :                            max_to_write);
     422             : }
     423             : 
     424             : /** Read data from the given process's standard output and put it into
     425             :  * <b>buffer</b>. Returns the number of bytes read. */
     426             : int
     427           5 : process_unix_read_stdout(process_t *process, buf_t *buffer)
     428             : {
     429           5 :   tor_assert(process);
     430           5 :   tor_assert(buffer);
     431             : 
     432           5 :   process_unix_t *unix_process = process_get_unix_process(process);
     433             : 
     434           5 :   return process_unix_read_handle(process,
     435             :                                   &unix_process->stdout_handle,
     436             :                                   buffer);
     437             : }
     438             : 
     439             : /** Read data from the given process's standard error and put it into
     440             :  * <b>buffer</b>. Returns the number of bytes read. */
     441             : int
     442           5 : process_unix_read_stderr(process_t *process, buf_t *buffer)
     443             : {
     444           5 :   tor_assert(process);
     445           5 :   tor_assert(buffer);
     446             : 
     447           5 :   process_unix_t *unix_process = process_get_unix_process(process);
     448             : 
     449           5 :   return process_unix_read_handle(process,
     450             :                                   &unix_process->stderr_handle,
     451             :                                   buffer);
     452             : }
     453             : 
     454             : /** This function is called whenever libevent thinks we have data that could be
     455             :  * read from the child process's standard output. We notify the Process
     456             :  * subsystem, which is then responsible for calling back to us for doing the
     457             :  * actual reading of the data. */
     458             : STATIC void
     459           5 : stdout_read_callback(evutil_socket_t fd, short event, void *data)
     460             : {
     461           5 :   (void)fd;
     462           5 :   (void)event;
     463             : 
     464           5 :   process_t *process = data;
     465           5 :   tor_assert(process);
     466             : 
     467           5 :   process_notify_event_stdout(process);
     468           5 : }
     469             : 
     470             : /** This function is called whenever libevent thinks we have data that could be
     471             :  * read from the child process's standard error. We notify the Process
     472             :  * subsystem, which is then responsible for calling back to us for doing the
     473             :  * actual reading of the data. */
     474             : STATIC void
     475           5 : stderr_read_callback(evutil_socket_t fd, short event, void *data)
     476             : {
     477           5 :   (void)fd;
     478           5 :   (void)event;
     479             : 
     480           5 :   process_t *process = data;
     481           5 :   tor_assert(process);
     482             : 
     483           5 :   process_notify_event_stderr(process);
     484           5 : }
     485             : 
     486             : /** This function is called whenever libevent thinks we have data that could be
     487             :  * written the child process's standard input. We notify the Process subsystem,
     488             :  * which is then responsible for calling back to us for doing the actual write
     489             :  * of the data. */
     490             : STATIC void
     491           1 : stdin_write_callback(evutil_socket_t fd, short event, void *data)
     492             : {
     493           1 :   (void)fd;
     494           1 :   (void)event;
     495             : 
     496           1 :   process_t *process = data;
     497           1 :   tor_assert(process);
     498             : 
     499           1 :   process_notify_event_stdin(process);
     500           1 : }
     501             : 
     502             : /** This function tells libevent that we are interested in receiving read
     503             :  * events from the given <b>handle</b>. */
     504             : STATIC void
     505           6 : process_unix_start_reading(process_unix_handle_t *handle)
     506             : {
     507           6 :   tor_assert(handle);
     508             : 
     509           6 :   if (event_add(handle->event, NULL))
     510           0 :     log_warn(LD_PROCESS,
     511             :              "Unable to add libevent event for handle.");
     512           6 : }
     513             : 
     514             : /** This function tells libevent that we are no longer interested in receiving
     515             :  * read events from the given <b>handle</b>. */
     516             : STATIC void
     517          60 : process_unix_stop_reading(process_unix_handle_t *handle)
     518             : {
     519          60 :   tor_assert(handle);
     520             : 
     521          60 :   if (handle->event == NULL)
     522             :     return;
     523             : 
     524           8 :   if (event_del(handle->event))
     525           0 :     log_warn(LD_PROCESS,
     526             :              "Unable to delete libevent event for handle.");
     527             : }
     528             : 
     529             : /** This function tells libevent that we are interested in receiving write
     530             :  * events from the given <b>handle</b>. */
     531             : STATIC void
     532           1 : process_unix_start_writing(process_unix_handle_t *handle)
     533             : {
     534           1 :   tor_assert(handle);
     535             : 
     536           1 :   if (event_add(handle->event, NULL))
     537           0 :     log_warn(LD_PROCESS,
     538             :              "Unable to add libevent event for handle.");
     539             : 
     540           1 :   handle->is_writing = true;
     541           1 : }
     542             : 
     543             : /** This function tells libevent that we are no longer interested in receiving
     544             :  * write events from the given <b>handle</b>. */
     545             : STATIC void
     546           1 : process_unix_stop_writing(process_unix_handle_t *handle)
     547             : {
     548           1 :   tor_assert(handle);
     549             : 
     550           1 :   if (handle->event == NULL)
     551             :     return;
     552             : 
     553           1 :   if (event_del(handle->event))
     554           0 :     log_warn(LD_PROCESS,
     555             :              "Unable to delete libevent event for handle.");
     556             : 
     557           1 :   handle->is_writing = false;
     558             : }
     559             : 
     560             : /** This function is called when the waitpid system have detected that our
     561             :  * process have terminated. We disable the waitpid system and notify the
     562             :  * Process subsystem that we have terminated. */
     563             : STATIC void
     564           3 : process_unix_waitpid_callback(int status, void *data)
     565             : {
     566           3 :   tor_assert(data);
     567             : 
     568           3 :   process_t *process = data;
     569           3 :   process_unix_t *unix_process = process_get_unix_process(process);
     570             : 
     571             :   /* Remove our waitpid callback. */
     572           3 :   clear_waitpid_callback(unix_process->waitpid);
     573           3 :   unix_process->waitpid = NULL;
     574             : 
     575             :   /* Notify our process. */
     576           3 :   process_notify_event_exit(process, status);
     577             : 
     578             :   /* Make sure you don't modify the process after we have called
     579             :    * process_notify_event_exit() on it, to allow users to process_free() it in
     580             :    * the exit callback. */
     581           3 : }
     582             : 
     583             : /** This function sets the file descriptor in the <b>handle</b> as non-blocking
     584             :  * and configures the libevent event structure based on the given <b>flags</b>
     585             :  * to ensure that <b>callback</b> is called whenever we have events on the
     586             :  * given <b>handle</b>. */
     587             : STATIC void
     588           9 : process_unix_setup_handle(process_t *process,
     589             :                           process_unix_handle_t *handle,
     590             :                           short flags,
     591             :                           event_callback_fn callback)
     592             : {
     593           9 :   tor_assert(process);
     594           9 :   tor_assert(handle);
     595           9 :   tor_assert(callback);
     596             : 
     597             :   /* Put our file descriptor into non-blocking mode. */
     598           9 :   if (fcntl(handle->fd, F_SETFL, O_NONBLOCK) < 0) {
     599           0 :     log_warn(LD_PROCESS, "Unable mark Unix handle as non-blocking: %s",
     600             :              strerror(errno));
     601             :   }
     602             : 
     603             :   /* Setup libevent event. */
     604           9 :   handle->event = tor_event_new(tor_libevent_get_base(),
     605             :                                 handle->fd,
     606             :                                 flags,
     607             :                                 callback,
     608             :                                 process);
     609           9 : }
     610             : 
     611             : /** This function reads data from the given <b>handle</b> and puts it into
     612             :  * <b>buffer</b>. Returns the number of bytes read this way. */
     613             : STATIC int
     614          10 : process_unix_read_handle(process_t *process,
     615             :                          process_unix_handle_t *handle,
     616             :                          buf_t *buffer)
     617             : {
     618          10 :   tor_assert(process);
     619          10 :   tor_assert(handle);
     620          10 :   tor_assert(buffer);
     621             : 
     622          10 :   int ret = 0;
     623          10 :   int eof = 0;
     624          10 :   int error = 0;
     625             : 
     626          10 :   ret = buf_read_from_pipe(buffer,
     627             :                            handle->fd,
     628             :                            PROCESS_MAX_READ,
     629             :                            &eof,
     630             :                            &error);
     631             : 
     632          10 :   if (error)
     633           0 :     log_warn(LD_PROCESS,
     634             :              "Unable to read data: %s", strerror(error));
     635             : 
     636          10 :   if (eof) {
     637           4 :     handle->reached_eof = true;
     638           4 :     process_unix_stop_reading(handle);
     639             :   }
     640             : 
     641          10 :   return ret;
     642             : }
     643             : 
     644             : /** Close the standard in, out, and error handles of the given
     645             :  * <b>unix_process</b>. */
     646             : STATIC bool
     647          30 : process_unix_close_file_descriptors(process_unix_t *unix_process)
     648             : {
     649          30 :   tor_assert(unix_process);
     650             : 
     651          30 :   int ret;
     652          30 :   bool success = true;
     653             : 
     654             :   /* Stop reading and writing before we close() our
     655             :    * file descriptors. */
     656          30 :   if (! unix_process->stdout_handle.reached_eof)
     657          28 :     process_unix_stop_reading(&unix_process->stdout_handle);
     658             : 
     659          30 :   if (! unix_process->stderr_handle.reached_eof)
     660          28 :     process_unix_stop_reading(&unix_process->stderr_handle);
     661             : 
     662          30 :   if (unix_process->stdin_handle.is_writing)
     663           0 :     process_unix_stop_writing(&unix_process->stdin_handle);
     664             : 
     665          30 :   if (unix_process->stdin_handle.fd != -1) {
     666           3 :     ret = close(unix_process->stdin_handle.fd);
     667           3 :     if (ret == -1) {
     668           0 :       log_warn(LD_PROCESS, "Unable to close standard in");
     669           0 :       success = false;
     670             :     }
     671             : 
     672           3 :     unix_process->stdin_handle.fd = -1;
     673             :   }
     674             : 
     675          30 :   if (unix_process->stdout_handle.fd != -1) {
     676           3 :     ret = close(unix_process->stdout_handle.fd);
     677           3 :     if (ret == -1) {
     678           0 :       log_warn(LD_PROCESS, "Unable to close standard out");
     679           0 :       success = false;
     680             :     }
     681             : 
     682           3 :     unix_process->stdout_handle.fd = -1;
     683             :   }
     684             : 
     685          30 :   if (unix_process->stderr_handle.fd != -1) {
     686           3 :     ret = close(unix_process->stderr_handle.fd);
     687           3 :     if (ret == -1) {
     688           0 :       log_warn(LD_PROCESS, "Unable to close standard error");
     689           0 :       success = false;
     690             :     }
     691             : 
     692           3 :     unix_process->stderr_handle.fd = -1;
     693             :   }
     694             : 
     695          30 :   return success;
     696             : }
     697             : 
     698             : #endif /* !defined(_WIN32) */

Generated by: LCOV version 1.14