feat: unique directory for pipelines
Also, start using fork/chdir/exec idiom instead of posix_spawn, because as we all know: posix_spawn is stupid as a system call: https://lwn.net/Articles/360556/
This commit is contained in:
		| @@ -29,6 +29,7 @@ typedef struct { | |||||||
|     bool use_colors; |     bool use_colors; | ||||||
|     optional_str log_file; |     optional_str log_file; | ||||||
|     optional_str pipeline_log_dir; |     optional_str pipeline_log_dir; | ||||||
|  |     optional_str pipeline_cwd; | ||||||
|     optional_strlist environment_vars; |     optional_strlist environment_vars; | ||||||
| } cli_options; | } cli_options; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
|  |  | ||||||
| void executor(void* pipeline_event); | void executor(void* pipeline_event); | ||||||
| void set_logdir(const char* logdir); | void set_logdir(const char* logdir); | ||||||
|  | void set_working_directory(const char* cwd); | ||||||
| void set_shared_environment(const strlist_node* root); | void set_shared_environment(const strlist_node* root); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								src/cli.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/cli.c
									
									
									
									
									
								
							| @@ -51,6 +51,10 @@ cli_options new_options() { | |||||||
|     result.pipeline_log_dir.has_value = pipeline_log_dir != NULL; |     result.pipeline_log_dir.has_value = pipeline_log_dir != NULL; | ||||||
|     result.pipeline_log_dir.value = pipeline_log_dir; |     result.pipeline_log_dir.value = pipeline_log_dir; | ||||||
|  |  | ||||||
|  |     char* pipeline_cwd = getenv("SCI_PIPELINE_CWD"); | ||||||
|  |     result.pipeline_cwd.has_value = pipeline_cwd != NULL; | ||||||
|  |     result.pipeline_cwd.value = pipeline_cwd; | ||||||
|  |  | ||||||
|     char* environment_vars = getenv("SCI_PIPELINE_ENV_VARS"); |     char* environment_vars = getenv("SCI_PIPELINE_ENV_VARS"); | ||||||
|     if(environment_vars == NULL) { |     if(environment_vars == NULL) { | ||||||
|         result.environment_vars.has_value = false; |         result.environment_vars.has_value = false; | ||||||
| @@ -78,17 +82,18 @@ void destroy_options(cli_options v) { | |||||||
| } | } | ||||||
|  |  | ||||||
| //                                                         <max | //                                                         <max | ||||||
| const char* optstring = "f:L:w:v:Cl:e:hV"; | const char* optstring = "f:L:P:w:v:Cl:e:hV"; | ||||||
| const char* help_msg =  | const char* help_msg =  | ||||||
|     "%s %s\n" |     "%s %s\n" | ||||||
|     "Usage: [-f file] [-L dir] [-w count] [-v level] \n" |     "Usage: [-f file] [-L dir] [-P dir] [-w count]\n\n" | ||||||
|     "       [-C] [-l file] [-e ENV] [-h] [-V]\n" |     "       [-v level] [-C] [-l file] [-e ENV] [-h] [-V]\n" | ||||||
|     "\n" |     "\n" | ||||||
|     SCI_DESCRIPTION "\n" |     SCI_DESCRIPTION "\n" | ||||||
|     "\n" |     "\n" | ||||||
|     "OPTIONS:\n" |     "OPTIONS:\n" | ||||||
|     "  -f file     Set sci config file\n" |     "  -f file     Set sci config file\n" | ||||||
|     "  -L dir      Set pipeline log output directory\n" |     "  -L dir      Set pipeline log output directory\n" | ||||||
|  |     "  -P dir      Set pipeline working directory prefix\n" | ||||||
|     "  -w count    Set the amount of worker threads\n" |     "  -w count    Set the amount of worker threads\n" | ||||||
|     "  -v level    Set verbosity level [0-4]\n" |     "  -v level    Set verbosity level [0-4]\n" | ||||||
|     "  -C          Force color output, ignoring $NO_COLOR\n" |     "  -C          Force color output, ignoring $NO_COLOR\n" | ||||||
| @@ -119,6 +124,10 @@ cli_options parse(int argc, char** argv) { | |||||||
|                 options.pipeline_log_dir.value = strdup(optarg); |                 options.pipeline_log_dir.value = strdup(optarg); | ||||||
|                 options.pipeline_log_dir.has_value = true; |                 options.pipeline_log_dir.has_value = true; | ||||||
|                 break; |                 break; | ||||||
|  |             case 'P': | ||||||
|  |                 options.pipeline_cwd.value = strdup(optarg); | ||||||
|  |                 options.pipeline_cwd.has_value = true; | ||||||
|  |                 break; | ||||||
|             case 'v': |             case 'v': | ||||||
|                 options.verbosity = atoi(optarg); |                 options.verbosity = atoi(optarg); | ||||||
|                 break; |                 break; | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
| #include <uuid/uuid.h> | #include <uuid/uuid.h> | ||||||
|  |  | ||||||
| const char* log_dir = "."; | const char* log_dir = "."; | ||||||
|  | const char* cwd = "/tmp"; | ||||||
| const strlist_node* shared_environment = NULL; | const strlist_node* shared_environment = NULL; | ||||||
|  |  | ||||||
| void set_shared_environment(const strlist_node* root) { | void set_shared_environment(const strlist_node* root) { | ||||||
| @@ -28,6 +29,13 @@ void set_logdir(const char* logdir) { | |||||||
|         mkdir(log_dir, 0700); |         mkdir(log_dir, 0700); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void set_working_directory(const char* _cwd) { | ||||||
|  |     cwd = _cwd; | ||||||
|  |     struct stat st = {0}; | ||||||
|  |     if(stat(cwd, &st) == -1) | ||||||
|  |         mkdir(cwd, 0700); | ||||||
|  | } | ||||||
|  |  | ||||||
| char* create_pipeline_id() { | char* create_pipeline_id() { | ||||||
|     uuid_t uuid; |     uuid_t uuid; | ||||||
|     uuid_generate(uuid); |     uuid_generate(uuid); | ||||||
| @@ -98,10 +106,6 @@ void executor(void* data) { | |||||||
|  |  | ||||||
|     // spawn the process |     // spawn the process | ||||||
|     pid_t pid; |     pid_t pid; | ||||||
|     posix_spawn_file_actions_t actions; |  | ||||||
|     posix_spawn_file_actions_init(&actions); |  | ||||||
|     posix_spawn_file_actions_adddup2(&actions, fd.value, STDOUT_FILENO); |  | ||||||
|     posix_spawn_file_actions_adddup2(&actions, fd.value, STDERR_FILENO); |  | ||||||
|     const pipeline_event* const e = data; |     const pipeline_event* const e = data; | ||||||
|     char** envp = create_environment(e, pipeline_id); |     char** envp = create_environment(e, pipeline_id); | ||||||
|     int argc; |     int argc; | ||||||
| @@ -112,16 +116,34 @@ void executor(void* data) { | |||||||
|     char arg0[PATH_MAX]; |     char arg0[PATH_MAX]; | ||||||
|     if(which(argv[0], arg0, PATH_MAX) == -1) |     if(which(argv[0], arg0, PATH_MAX) == -1) | ||||||
|         goto end; |         goto end; | ||||||
|     if(posix_spawnp(&pid, arg0, &actions, NULL, argv, envp) != 0) { |  | ||||||
|         perror("posix_spawn"); |     // fork / cwd / exec idiom | ||||||
|  |     pid = fork(); | ||||||
|  |     if(pid < 0) { | ||||||
|  |         perror("fork"); | ||||||
|         goto end; // I know. The raptors have picked up the scent. I'll just have to mask it with more stinky code. |         goto end; // I know. The raptors have picked up the scent. I'll just have to mask it with more stinky code. | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if(pid == 0) { | ||||||
|  |         // child process | ||||||
|  |         dup2(fd.value, STDOUT_FILENO); | ||||||
|  |         dup2(fd.value, STDERR_FILENO); | ||||||
|  |         char* pipeline_cwd = join3(cwd, "/", pipeline_id); | ||||||
|  |         struct stat st = {0}; | ||||||
|  |         if(stat(pipeline_cwd, &st) == -1) | ||||||
|  |             mkdir(pipeline_cwd, 0700); | ||||||
|  |         chdir(pipeline_cwd); | ||||||
|  |         free(pipeline_cwd); | ||||||
|  |         execvpe(arg0, argv, envp); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     log_info("{%s} (%s) spawned", pipeline_id, e->name); |     log_info("{%s} (%s) spawned", pipeline_id, e->name); | ||||||
|  |  | ||||||
|     // Wait for process to complete |     // Wait for process to complete | ||||||
|     int status; |     int status; | ||||||
|     waitpid(pid, &status, 0); |     waitpid(pid, &status, 0); | ||||||
|     log_info("{%s} (%s) exited with status %d", pipeline_id, e->name, status); |     log_info("{%s} (%s) [pid=%d] exited with status %d", pipeline_id, e->name, pid, status); | ||||||
|     char buf[32]; |     char buf[32]; | ||||||
|     sprintf(buf, "exited with status %d", status); |     sprintf(buf, "exited with status %d", status); | ||||||
|     if(write(fd.value, buf, strnlen(buf, 32)) == -1) |     if(write(fd.value, buf, strnlen(buf, 32)) == -1) | ||||||
|   | |||||||
| @@ -101,6 +101,8 @@ int main(int argc, char** argv) { | |||||||
|  |  | ||||||
|     if(args.pipeline_log_dir.has_value) |     if(args.pipeline_log_dir.has_value) | ||||||
|         set_logdir(args.pipeline_log_dir.value); |         set_logdir(args.pipeline_log_dir.value); | ||||||
|  |     if(args.pipeline_cwd.has_value) | ||||||
|  |         set_working_directory(args.pipeline_cwd.value); | ||||||
|  |  | ||||||
|     struct stat st = {0}; |     struct stat st = {0}; | ||||||
|     if(stat("/tmp/sci", &st) == -1) |     if(stat("/tmp/sci", &st) == -1) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user