1.1 --- a/fsaccess/op_run.c Wed Jan 24 21:12:41 2024 +0100
1.2 +++ b/fsaccess/op_run.c Wed Jan 24 21:17:37 2024 +0100
1.3 @@ -47,68 +47,131 @@
1.4
1.5 static file_t *readers[NUMBER_OF_JOBS] = {NULL};
1.6 static process_t *processes[NUMBER_OF_JOBS] = {NULL};
1.7 -static const char *programs[NUMBER_OF_JOBS] = {NULL};
1.8 +static char *programs[NUMBER_OF_JOBS] = {NULL};
1.9 static int next_job = 0;
1.10
1.11
1.12
1.13 +/* Show output from a program. */
1.14 +
1.15 +static void _show_output(file_t *reader)
1.16 +{
1.17 + char buffer[TO_TRANSFER];
1.18 + offset_t nread;
1.19 +
1.20 + while ((nread = client_read(reader, buffer, TO_TRANSFER)))
1.21 + fwrite(buffer, sizeof(char), nread, stdout);
1.22 +}
1.23 +
1.24 /* Wait for a program to finish, showing its output. */
1.25
1.26 static int _wait_program(file_t *reader, process_t *process)
1.27 {
1.28 - char buffer[TO_TRANSFER];
1.29 - notify_flags_t flags;
1.30 - notify_values_t values;
1.31 + notifier_t *notifier = client_notifier_local();
1.32 + notifiable_t *notifiable;
1.33 + int exitcode;
1.34 long err;
1.35
1.36 - /* Read until the pipe yields no more data. */
1.37 + /* Subscribe to reader and process notifications. */
1.38 +
1.39 + if (reader != NULL)
1.40 + {
1.41 + err = client_subscribe(reader, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier);
1.42 +
1.43 + if (err)
1.44 + {
1.45 + printf("Could not subscribe to pipe notifications: %s\n", l4sys_errtostr(err));
1.46 + client_notifier_close(notifier);
1.47 + return -1;
1.48 + }
1.49 + }
1.50 +
1.51 + err = notify_subscribe(process_notifiable(process), NOTIFY_TASK_ALL, notifier);
1.52 +
1.53 + if (err)
1.54 + {
1.55 + printf("Could not subscribe to process notifications: %s\n", l4sys_errtostr(err));
1.56 + client_unsubscribe(reader, notifier);
1.57 + client_notifier_close(notifier);
1.58 + return -1;
1.59 + }
1.60 +
1.61 + /* Read from and write to pipes until the program terminates. */
1.62
1.63 while (1)
1.64 {
1.65 - offset_t nread = client_read(reader, buffer, TO_TRANSFER);
1.66 + err = notify_wait_many(¬ifiable, notifier);
1.67 +
1.68 + if (err)
1.69 + {
1.70 + printf("Notification error: %s\n", l4sys_errtostr(err));
1.71 +
1.72 + if (reader != NULL)
1.73 + client_unsubscribe(reader, notifier);
1.74 +
1.75 + notify_unsubscribe(process_notifiable(process), notifier);
1.76 + client_notifier_close(notifier);
1.77 + return -1;
1.78 + }
1.79
1.80 - if (nread)
1.81 - fwrite(buffer, sizeof(char), nread, stdout);
1.82 - else
1.83 + /* Handle input from the reader. */
1.84 +
1.85 + if ((reader != NULL) && (file_notifications(reader) & (NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)))
1.86 + _show_output(reader);
1.87 +
1.88 + /* Handle process termination, obtaining the process state. */
1.89 +
1.90 + if (process_terminated(notifiable))
1.91 + {
1.92 + if (reader != NULL)
1.93 + _show_output(reader);
1.94 +
1.95 + printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n",
1.96 + notifiable->notifications, notifiable->values.sig, notifiable->values.val);
1.97 break;
1.98 + }
1.99 }
1.100
1.101 - /* Close the pipe and obtain the process state. */
1.102 + exitcode = notifiable->values.val;
1.103
1.104 - client_close(reader);
1.105 + if (reader != NULL)
1.106 + client_unsubscribe(reader, notifier);
1.107
1.108 - err = process_wait(process, &flags, &values);
1.109 + notify_unsubscribe(process_notifiable(process), notifier);
1.110
1.111 - printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", flags, values.sig, values.val);
1.112 + /* Close the process and pipe. */
1.113 +
1.114 + client_notifier_close(notifier);
1.115 + process_free(process);
1.116
1.117 - if (err)
1.118 - return -1;
1.119 + if (reader != NULL)
1.120 + client_close(reader);
1.121
1.122 - return values.val;
1.123 + return exitcode;
1.124 }
1.125
1.126 /* Run the given program. */
1.127
1.128 -int run_program(int argc, char *argv[])
1.129 +static int _run_program(int argc, char *argv[], file_t *input_reader)
1.130 {
1.131 process_t *process;
1.132 - file_t *reader, *writer;
1.133 + file_t *output_reader, *output_writer;
1.134 int last_job;
1.135 long err;
1.136
1.137 /* Create a pipe for process output. */
1.138
1.139 - err = client_pipe(&reader, &writer, 0);
1.140 + err = client_pipe(&output_reader, &output_writer, O_NONBLOCK);
1.141
1.142 if (err)
1.143 {
1.144 - printf("Could not obtain pipe: %s\n", l4sys_errtostr(err));
1.145 + printf("Could not obtain pipe for output: %s\n", l4sys_errtostr(err));
1.146 return -1;
1.147 }
1.148
1.149 /* Start the process. */
1.150
1.151 - err = process_spawn(argc, (const char **) argv, writer, &process);
1.152 + err = process_spawn(argc, (const char **) argv, input_reader, output_writer, &process);
1.153
1.154 if (err)
1.155 {
1.156 @@ -118,15 +181,15 @@
1.157
1.158 printf("Finished program initiation.\n");
1.159
1.160 - /* Release the writing end of the pipe. */
1.161 + /* Release the relinquished end of the pipe. */
1.162
1.163 - client_close(writer);
1.164 + client_close(output_writer);
1.165
1.166 /* Record the output stream. */
1.167
1.168 last_job = next_job;
1.169
1.170 - while (readers[next_job] != NULL)
1.171 + while (processes[next_job] != NULL)
1.172 {
1.173 next_job++;
1.174
1.175 @@ -136,16 +199,79 @@
1.176 /* Wait for the process to complete if no more job slots are available. */
1.177
1.178 if (next_job == last_job)
1.179 - return _wait_program(reader, process);
1.180 + return _wait_program(output_reader, process);
1.181 }
1.182
1.183 - readers[next_job] = reader;
1.184 + readers[next_job] = output_reader;
1.185 processes[next_job] = process;
1.186 programs[next_job] = strdup(argv[0]);
1.187
1.188 return 0;
1.189 }
1.190
1.191 +
1.192 +
1.193 +/* Run the given program, providing input from a file. */
1.194 +
1.195 +int file_to_program(int argc, char *argv[])
1.196 +{
1.197 + file_t *reader;
1.198 +
1.199 + /* Obtain a file reader and run the program with this as its input reader. */
1.200 +
1.201 + if (argc < 1)
1.202 + return -1;
1.203 +
1.204 + reader = client_open(argv[0], O_RDONLY);
1.205 +
1.206 + if (!client_opened(reader))
1.207 + {
1.208 + printf("Could not open file: %s\n", argv[0]);
1.209 + return -1;
1.210 + }
1.211 +
1.212 + return _run_program(argc - 1, &argv[1], reader);
1.213 +}
1.214 +
1.215 +/* Run the given program, connecting input from another program. */
1.216 +
1.217 +int pipe_to_program(int argc, char *argv[])
1.218 +{
1.219 + int job_number;
1.220 + int exitcode;
1.221 +
1.222 + /* Obtain the job number for the output writer and run the program with this
1.223 + as its input reader. */
1.224 +
1.225 + if (argc < 1)
1.226 + return -1;
1.227 +
1.228 + job_number = atoi(argv[0]);
1.229 +
1.230 + if (readers[job_number] == NULL)
1.231 + {
1.232 + printf("No output available for this job: %s\n", argv[0]);
1.233 + return -1;
1.234 + }
1.235 +
1.236 + exitcode = _run_program(argc - 1, &argv[1], readers[job_number]);
1.237 +
1.238 + /* Remove the job's reader to prevent direct access to it and to allow it to
1.239 + be closed by the receiving program. */
1.240 +
1.241 + client_close(readers[job_number]);
1.242 + readers[job_number] = NULL;
1.243 +
1.244 + return exitcode;
1.245 +}
1.246 +
1.247 +/* Run the given program. */
1.248 +
1.249 +int run_program(int argc, char *argv[])
1.250 +{
1.251 + return _run_program(argc, argv, NULL);
1.252 +}
1.253 +
1.254 /* Show initiated programs. */
1.255
1.256 int show_programs(int argc, char *argv[])
1.257 @@ -156,8 +282,9 @@
1.258
1.259 for (job_number = 0; job_number < NUMBER_OF_JOBS; job_number++)
1.260 {
1.261 - if (readers[job_number] != NULL)
1.262 - printf("[%d] %s\n", job_number, programs[job_number]);
1.263 + if (processes[job_number] != NULL)
1.264 + printf("[%d] %s%s\n", job_number, programs[job_number],
1.265 + readers[job_number] != NULL ? " [!]" : "");
1.266 }
1.267
1.268 return 0;
1.269 @@ -175,8 +302,11 @@
1.270
1.271 job_number = atoi(argv[0]);
1.272
1.273 - if (readers[job_number] == NULL)
1.274 + if (processes[job_number] == NULL)
1.275 + {
1.276 + printf("No such job: %s\n", argv[0]);
1.277 return -1;
1.278 + }
1.279
1.280 exitcode = _wait_program(readers[job_number], processes[job_number]);
1.281