Skip to content

Commit

Permalink
Merge pull request #208 from bgamari/wip/refactor
Browse files Browse the repository at this point in the history
Refactoring of POSIX process logic
  • Loading branch information
snoyberg authored Jul 12, 2021
2 parents 7010ac3 + c7e5b06 commit 9410f77
Show file tree
Hide file tree
Showing 15 changed files with 857 additions and 414 deletions.
15 changes: 8 additions & 7 deletions System/Process/Posix.hs
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,20 @@ createProcess_Internal fun
when mb_delegate_ctlc
startDelegateControlC

let flags = (if mb_close_fds then RUN_PROCESS_IN_CLOSE_FDS else 0)
.|.(if mb_create_group then RUN_PROCESS_IN_NEW_GROUP else 0)
.|.(if mb_detach_console then RUN_PROCESS_DETACHED else 0)
.|.(if mb_create_new_console then RUN_PROCESS_NEW_CONSOLE else 0)
.|.(if mb_new_session then RUN_PROCESS_NEW_SESSION else 0)
.|.(if mb_delegate_ctlc then RESET_INT_QUIT_HANDLERS else 0)

-- See the comment on runInteractiveProcess_lock
proc_handle <- withMVar runInteractiveProcess_lock $ \_ ->
c_runInteractiveProcess pargs pWorkDir pEnv
fdin fdout fderr
pfdStdInput pfdStdOutput pfdStdError
pChildGroup pChildUser
(if mb_delegate_ctlc then 1 else 0)
((if mb_close_fds then RUN_PROCESS_IN_CLOSE_FDS else 0)
.|.(if mb_create_group then RUN_PROCESS_IN_NEW_GROUP else 0)
.|.(if mb_detach_console then RUN_PROCESS_DETACHED else 0)
.|.(if mb_create_new_console then RUN_PROCESS_NEW_CONSOLE else 0)
.|.(if mb_new_session then RUN_PROCESS_NEW_SESSION else 0))
flags
pFailedDoing

when (proc_handle == -1) $ do
Expand Down Expand Up @@ -273,7 +275,6 @@ foreign import ccall unsafe "runInteractiveProcess"
-> Ptr FD
-> Ptr CGid
-> Ptr CUid
-> CInt -- reset child's SIGINT & SIGQUIT handlers
-> CInt -- flags
-> Ptr CString
-> IO PHANDLE
Expand Down
52 changes: 52 additions & 0 deletions cbits/posix/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include "runProcess.h"

enum std_handle_behavior {
// Close the handle
STD_HANDLE_CLOSE,
// dup2 the specified fd to standard handle
STD_HANDLE_USE_FD,
// dup2 the appropriate end of the given pipe to the standard handle and
// close the other end.
STD_HANDLE_USE_PIPE
};

struct std_handle {
enum std_handle_behavior behavior;
union {
int use_fd;
struct {
int parent_end, child_end;
} use_pipe;
};
};

int get_max_fd(void);

// defined in find_executable.c
#if !defined(HAVE_execvpe)
char *find_executable(char *filename);
#endif

// defined in fork_exec.c
ProcHandle
do_spawn_fork (char *const args[],
char *workingDirectory, char **environment,
struct std_handle *stdInHdl,
struct std_handle *stdOutHdl,
struct std_handle *stdErrHdl,
gid_t *childGroup, uid_t *childUser,
int flags,
char **failed_doing);

// defined in posix_spawn.c
ProcHandle
do_spawn_posix (char *const args[],
char *workingDirectory, char **environment,
struct std_handle *stdInHdl,
struct std_handle *stdOutHdl,
struct std_handle *stdErrHdl,
gid_t *childGroup, uid_t *childUser,
int flags,
char **failed_doing);
79 changes: 79 additions & 0 deletions cbits/posix/find_executable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* ----------------------------------------------------------------------------
* search path search logic
* (c) Ben Gamari 2021
*/

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

#include "common.h"

// the below is only necessary when we don't have execvpe.
#if !defined(HAVE_execvpe)

/* Return true if the given file exists and is an executable. */
static bool is_executable(const char *path) {
return access(path, X_OK) == 0;
}

/* Find an executable with the given filename in the given search path. The
* result must be freed by the caller. Returns NULL if a matching file is not
* found.
*/
static char *find_in_search_path(char *search_path, const char *filename) {
const int filename_len = strlen(filename);
char *tokbuf;
char *path = strtok_r(search_path, ":", &tokbuf);
while (path != NULL) {
const int tmp_len = filename_len + 1 + strlen(path) + 1;
char *tmp = malloc(tmp_len);
snprintf(tmp, tmp_len, "%s/%s", path, filename);
if (is_executable(tmp)) {
return tmp;
} else {
free(tmp);
}

path = strtok_r(NULL, ":", &tokbuf);
}
return NULL;
}

/* Identify the executable search path. The result must be freed by the caller. */
static char *get_executable_search_path(void) {
char *search_path;

search_path = getenv("PATH");
if (search_path) {
search_path = strdup(search_path);
return search_path;
}

#if defined(HAVE_CONFSTR)
int len = confstr(_CS_PATH, NULL, 0);
search_path = malloc(len + 1)
if (search_path != NULL) {
search_path[0] = ':';
(void) confstr (_CS_PATH, search_path + 1, len);
return search_path;
}
#endif

return strdup(":");
}

/* Find the given executable in the executable search path. */
char *find_executable(char *filename) {
/* If it's an absolute or relative path name, it's easy. */
if (strchr(filename, '/') && is_executable(filename)) {
return filename;
}

char *search_path = get_executable_search_path();
return find_in_search_path(search_path, filename);
}

#endif
Loading

0 comments on commit 9410f77

Please sign in to comment.