1 /* 2 * Run programs residing in the filesystem. 3 * 4 * Copyright (C) 2022, 2023, 2024 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/sys/err.h> 23 24 #include <fsclient/client.h> 25 #include <fsclient/process.h> 26 #include <systypes/fcntl.h> 27 #include <systypes/format.h> 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "ops.h" 34 35 36 37 /* Transfer size for communication. */ 38 39 static const offset_t TO_TRANSFER = 1024; 40 41 42 43 /* Initiated programs (jobs). 44 NOTE: Arbitrary limit. */ 45 46 #define NUMBER_OF_JOBS 32 47 48 static file_t *readers[NUMBER_OF_JOBS] = {NULL}; 49 static process_t *processes[NUMBER_OF_JOBS] = {NULL}; 50 static const char *programs[NUMBER_OF_JOBS] = {NULL}; 51 static int next_job = 0; 52 53 54 55 /* Wait for a program to finish, showing its output. */ 56 57 static int _wait_program(file_t *reader, process_t *process) 58 { 59 char buffer[TO_TRANSFER]; 60 notify_flags_t flags; 61 notify_values_t values; 62 long err; 63 64 /* Read until the pipe yields no more data. */ 65 66 while (1) 67 { 68 offset_t nread = client_read(reader, buffer, TO_TRANSFER); 69 70 if (nread) 71 fwrite(buffer, sizeof(char), nread, stdout); 72 else 73 break; 74 } 75 76 /* Close the pipe and obtain the process state. */ 77 78 client_close(reader); 79 80 err = process_wait(process, &flags, &values); 81 82 printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", flags, values.sig, values.val); 83 84 if (err) 85 return -1; 86 87 return values.val; 88 } 89 90 /* Run the given program. */ 91 92 int run_program(int argc, char *argv[]) 93 { 94 process_t *process; 95 file_t *reader, *writer; 96 int last_job; 97 long err; 98 99 /* Create a pipe for process output. */ 100 101 err = client_pipe(&reader, &writer, 0); 102 103 if (err) 104 { 105 printf("Could not obtain pipe: %s\n", l4sys_errtostr(err)); 106 return -1; 107 } 108 109 /* Start the process. */ 110 111 err = process_spawn(argc, (const char **) argv, writer, &process); 112 113 if (err) 114 { 115 printf("Could not start process: %s\n", l4sys_errtostr(err)); 116 return -1; 117 } 118 119 printf("Finished program initiation.\n"); 120 121 /* Release the writing end of the pipe. */ 122 123 client_close(writer); 124 125 /* Record the output stream. */ 126 127 last_job = next_job; 128 129 while (readers[next_job] != NULL) 130 { 131 next_job++; 132 133 if (next_job >= NUMBER_OF_JOBS) 134 next_job = 0; 135 136 /* Wait for the process to complete if no more job slots are available. */ 137 138 if (next_job == last_job) 139 return _wait_program(reader, process); 140 } 141 142 readers[next_job] = reader; 143 processes[next_job] = process; 144 programs[next_job] = strdup(argv[0]); 145 146 return 0; 147 } 148 149 /* Show initiated programs. */ 150 151 int show_programs(int argc, char *argv[]) 152 { 153 (void) argc; (void) argv; 154 155 int job_number; 156 157 for (job_number = 0; job_number < NUMBER_OF_JOBS; job_number++) 158 { 159 if (readers[job_number] != NULL) 160 printf("[%d] %s\n", job_number, programs[job_number]); 161 } 162 163 return 0; 164 } 165 166 /* Wait for the indicated program to finish, showing its output. */ 167 168 int wait_program(int argc, char *argv[]) 169 { 170 int job_number; 171 int exitcode; 172 173 if (argc < 1) 174 return -1; 175 176 job_number = atoi(argv[0]); 177 178 if (readers[job_number] == NULL) 179 return -1; 180 181 exitcode = _wait_program(readers[job_number], processes[job_number]); 182 183 readers[job_number] = NULL; 184 processes[job_number] = NULL; 185 186 free(programs[job_number]); 187 programs[job_number] = NULL; 188 189 return exitcode; 190 } 191 192 /* vim: tabstop=2 expandtab shiftwidth=2 193 */