Skip to content

Refactoring of POSIX process logic #208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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