PatchworkOS  3984a1d
A non-POSIX operating system.
Loading...
Searching...
No Matches
pipeline.c
Go to the documentation of this file.
1#include "pipeline.h"
2#include "builtin.h"
3
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/argsplit.h>
10#include <sys/io.h>
11#include <sys/proc.h>
12
14{
16 const char** tokens = argsplit(cmdline, UINT64_MAX, &tokenAmount);
17 if (tokens == NULL)
18 {
19 return ERR;
20 }
21
22 if (tokenAmount == 0)
23 {
24 pipeline->cmds = NULL;
25 pipeline->capacity = tokenAmount;
26 pipeline->amount = 0;
27 free(tokens);
28 return 0;
29 }
30
31 pipeline->cmds = malloc(sizeof(cmd_t) * tokenAmount);
32 if (pipeline->cmds == NULL)
33 {
34 free(tokens);
35 return ERR;
36 }
37
38 pipeline->capacity = tokenAmount;
39 pipeline->amount = 0;
40 pipeline->status[0] = '\0';
41
42 for (uint64_t i = 0; i < tokenAmount; i++)
43 {
44 cmd_t* cmd = &pipeline->cmds[i];
45 cmd->argv = NULL;
46 cmd->argc = 0;
47 cmd->stdin = stdin;
48 cmd->stdout = stdout;
49 cmd->stderr = stderr;
50 cmd->shouldCloseStdin = false;
51 cmd->shouldCloseStdout = false;
52 cmd->shouldCloseStderr = false;
53 cmd->pid = ERR;
54 }
55
58 const char** currentArgv = malloc(sizeof(char*) * (tokenAmount + 1));
59 if (currentArgv == NULL)
60 {
61 free(pipeline->cmds);
62 free(tokens);
63 return ERR;
64 }
65
66 for (uint64_t i = 0; i < tokenAmount; i++)
67 {
68 if (strcmp(tokens[i], "|") == 0)
69 {
70 if (currentArg == 0)
71 {
72 printf("shell: empty command in pipeline\n");
73 if (pipeline->cmds[currentCmd].shouldCloseStdin)
74 {
75 close(pipeline->cmds[currentCmd].stdin);
76 pipeline->cmds[currentCmd].shouldCloseStdin = false;
77 }
79 }
80
82
83 cmd_t* cmd = &pipeline->cmds[currentCmd];
85 cmd->argc = currentArg;
86
87 fd_t pipe[2];
88 if (open2("/dev/pipe/new", pipe) == ERR)
89 {
90 printf("shell: unable to open pipe (%s)\n", strerror(errno));
92 }
93
94 cmd->stdout = pipe[PIPE_WRITE];
95 cmd->shouldCloseStdout = true;
96
97 currentCmd++;
98 currentArg = 0;
99 currentArgv = malloc(sizeof(char*) * (tokenAmount + 1));
100 if (currentArgv == NULL)
101 {
102 printf("shell: out of memory\n");
104 }
105
106 cmd_t* nextCmd = &pipeline->cmds[currentCmd];
108 nextCmd->shouldCloseStdin = true;
109 }
110 else if (strcmp(tokens[i], "<") == 0)
111 {
112 if (i + 1 >= tokenAmount)
113 {
114 printf("shell: missing filename after <\n");
116 }
117
118 fd_t fd = open(tokens[i + 1]);
119 if (fd == ERR)
120 {
121 printf("shell: unable to open %s (%s)\n", tokens[i + 1], strerror(errno));
123 }
124
125 cmd_t* cmd = &pipeline->cmds[currentCmd];
126 if (cmd->shouldCloseStdin)
127 {
128 close(cmd->stdin);
129 }
130 cmd->stdin = fd;
131 cmd->shouldCloseStdin = true;
132
133 i++; // Skip file
134 }
135 else if (strcmp(tokens[i], ">") == 0)
136 {
137 if (i + 1 >= tokenAmount)
138 {
139 printf("shell: missing filename after >\n");
141 }
142
143 fd_t fd = open(tokens[i + 1]);
144 if (fd == ERR)
145 {
146 printf("shell: unable to open %s (%s)\n", tokens[i + 1], strerror(errno));
148 }
149
150 cmd_t* cmd = &pipeline->cmds[currentCmd];
151 if (cmd->shouldCloseStdout)
152 {
153 close(cmd->stdout);
154 }
155 cmd->stdout = fd;
156 cmd->shouldCloseStdout = true;
157
158 i++; // Skip file
159 }
160 else if (strcmp(tokens[i], "2>") == 0)
161 {
162 if (i + 1 >= tokenAmount)
163 {
164 printf("shell: missing filename after 2>\n");
166 }
167
168 fd_t fd = open(tokens[i + 1]);
169 if (fd == ERR)
170 {
171 printf("shell: unable to open %s (%s)\n", tokens[i + 1], strerror(errno));
173 }
174
175 cmd_t* cmd = &pipeline->cmds[currentCmd];
176 if (cmd->shouldCloseStderr)
177 {
178 close(cmd->stderr);
179 }
180 cmd->stderr = fd;
181 cmd->shouldCloseStderr = true;
182
183 i++; // Skip file
184 }
185 else
186 {
189 {
190 printf("shell: out of memory\n");
192 }
193 currentArg++;
194 }
195 }
196
197 if (currentArg > 0)
198 {
200 pipeline->cmds[currentCmd].argv = currentArgv;
201 pipeline->cmds[currentCmd].argc = currentArg;
202 currentCmd++;
203 }
204 else
205 {
207 if (pipeline->amount > 0 && currentCmd > 0)
208 {
209 printf("shell: pipeline ends with empty command\n");
211 if (emptyCmd->shouldCloseStdin)
212 {
213 close(emptyCmd->stdin);
214 emptyCmd->shouldCloseStdin = false;
215 }
217 }
218 }
219
220 pipeline->amount = currentCmd;
221 free(tokens);
222 return 0;
223
225 if (currentArgv != NULL)
226 {
227 for (uint64_t k = 0; k < currentArg; k++)
228 {
229 free((void*)currentArgv[k]);
230 }
231 }
233
235 for (uint64_t j = 0; j < tokenAmount; j++)
236 {
237 if (pipeline->cmds[j].shouldCloseStdin)
238 {
239 close(pipeline->cmds[j].stdin);
240 }
241 if (pipeline->cmds[j].shouldCloseStdout)
242 {
243 close(pipeline->cmds[j].stdout);
244 }
245 if (pipeline->cmds[j].shouldCloseStderr)
246 {
247 close(pipeline->cmds[j].stderr);
248 }
249
250 if (pipeline->cmds[j].argv != NULL)
251 {
252 for (uint64_t k = 0; pipeline->cmds[j].argv[k] != NULL; k++)
253 {
254 free((void*)pipeline->cmds[j].argv[k]);
255 }
256 free(pipeline->cmds[j].argv);
257 }
258 }
259 free(pipeline->cmds);
260 free(tokens);
261 return ERR;
262}
263
265{
266 for (uint64_t j = 0; j < pipeline->amount; j++)
267 {
268 if (pipeline->cmds[j].shouldCloseStdin)
269 {
270 close(pipeline->cmds[j].stdin);
271 }
272 if (pipeline->cmds[j].shouldCloseStdout)
273 {
274 close(pipeline->cmds[j].stdout);
275 }
276 if (pipeline->cmds[j].shouldCloseStderr)
277 {
278 close(pipeline->cmds[j].stderr);
279 }
280
281 if (pipeline->cmds[j].argv != NULL)
282 {
283 for (uint64_t k = 0; pipeline->cmds[j].argv[k] != NULL; k++)
284 {
285 free((void*)pipeline->cmds[j].argv[k]);
286 }
287 free(pipeline->cmds[j].argv);
288 }
289 }
290 if (pipeline->cmds != NULL)
291 {
292 free(pipeline->cmds);
293 }
294}
295
297{
298 pid_t result = ERR;
299
301 if (originalStdin == ERR)
302 {
303 return ERR;
304 }
306 if (originalStdout == ERR)
307 {
309 return ERR;
310 }
312 if (originalStderr == ERR)
313 {
316 return ERR;
317 }
318
319 if (dup2(cmd->stdin, STDIN_FILENO) == ERR || dup2(cmd->stdout, STDOUT_FILENO) == ERR ||
320 dup2(cmd->stderr, STDERR_FILENO) == ERR)
321 {
325 return ERR;
326 }
327
328 const char** argv = cmd->argv;
329 uint64_t argc = cmd->argc;
330 if (builtin_exists(argv[0]))
331 {
332 if (builtin_execute(cmd->argc, cmd->argv) == ERR)
333 {
334 result = ERR;
335 }
336 else
337 {
338 result = 0;
339 }
340 }
341 else if (strchr(argv[0], '/') != NULL)
342 {
343 stat_t info;
344 if (stat(argv[0], &info) != ERR && info.type != INODE_DIR)
345 {
346 result = spawn(argv, SPAWN_STDIO_FDS);
347 }
348 else
349 {
350 printf("shell: %s not found\n", argv[0]);
351 result = ERR;
352 }
353 }
354 else
355 {
356 bool isFound = false;
357 char* pathEnv = sreadfile("/proc/self/env/PATH");
358 if (pathEnv == NULL)
359 {
360 pathEnv = strdup("/bin:/usr/bin");
361 }
362
363 if (pathEnv != NULL)
364 {
365 char* token = strtok(pathEnv, ":");
366 while (token != NULL)
367 {
368 char path[MAX_PATH];
369 if (snprintf(path, MAX_PATH, "%s/%s", token, argv[0]) < MAX_PATH)
370 {
371 stat_t info;
372 if (stat(path, &info) != ERR && info.type != INODE_DIR)
373 {
374 const char* newArgv[argc + 1];
375 newArgv[0] = path;
376 for (uint64_t k = 1; k < argc; k++)
377 {
378 newArgv[k] = argv[k];
379 }
380 newArgv[argc] = NULL;
381 result = spawn(newArgv, SPAWN_STDIO_FDS);
382 isFound = true;
383 break;
384 }
385 }
386 token = strtok(NULL, ":");
387 }
388 free(pathEnv);
389 }
390
391 if (!isFound)
392 {
393 fprintf(stderr, "shell: %s not found\n", argv[0]);
394 result = ERR;
395 }
396 }
397
400 {
401 result = ERR;
402 }
403
407
408 if (cmd->shouldCloseStdin)
409 {
410 close(cmd->stdin);
411 cmd->shouldCloseStdin = false;
412 }
413 if (cmd->shouldCloseStdout)
414 {
415 close(cmd->stdout);
416 cmd->shouldCloseStdout = false;
417 }
418 if (cmd->shouldCloseStderr)
419 {
420 close(cmd->stderr);
421 cmd->shouldCloseStderr = false;
422 }
423
424 return result;
425}
426
428{
429 for (uint64_t i = 0; i < pipeline->amount; i++)
430 {
431 pipeline->cmds[i].pid = pipeline_execute_cmd(&pipeline->cmds[i]);
432 }
433}
434
436{
437 for (uint64_t i = 0; i < pipeline->amount; i++)
438 {
439 cmd_t* cmd = &pipeline->cmds[i];
440
441 if (cmd->pid == ERR)
442 {
443 strcpy(pipeline->status, "-1");
444 continue;
445 }
446
447 if (cmd->pid == 0)
448 {
449 continue;
450 }
451
452 fd_t wait = open(F("/proc/%llu/wait", cmd->pid));
453 if (wait == ERR)
454 {
455 strcpy(pipeline->status, "-1");
456 continue;
457 }
458
459 memset(pipeline->status, 0, sizeof(pipeline->status));
460 size_t readCount = RETRY_EINTR(read(wait, pipeline->status, sizeof(pipeline->status)));
461 close(wait);
462 if (readCount == ERR)
463 {
464 strcpy(pipeline->status, "-1");
465 continue;
466 }
467 }
468}
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
int64_t y
Definition main.c:153
uint64_t builtin_execute(uint64_t argc, const char **argv)
Definition builtin.c:101
bool builtin_exists(const char *name)
Definition builtin.c:88
#define errno
Error number variable.
Definition errno.h:27
const char ** argsplit(const char *str, uint64_t maxLen, uint64_t *count)
Standardized argument parsing function.
Definition argsplit.c:3
fd_t dup2(fd_t oldFd, fd_t newFd)
System call for duplicating file descriptors, with a destination.
Definition dup2.c:8
uint64_t stat(const char *path, stat_t *stat)
System call for retrieving info about a file or directory.
Definition stat.c:8
fd_t open(const char *path)
System call for opening files.
Definition open.c:8
#define PIPE_READ
Pipe read end.
Definition io.h:45
uint64_t close(fd_t fd)
System call for closing files.
Definition close.c:8
fd_t dup(fd_t oldFd)
System call for duplicating file descriptors.
Definition dup.c:8
#define F(format,...)
Allocates a formatted string on the stack.
Definition io.h:66
size_t read(fd_t fd, void *buffer, size_t count)
System call for reading from files.
Definition read.c:8
#define PIPE_WRITE
Pipe write end.
Definition io.h:54
#define STDOUT_FILENO
Standard output file descriptor.
Definition io.h:35
char * sreadfile(const char *path)
Wrapper for reading an entire file directly into a null-terminated string.
Definition sreadfile.c:3
uint64_t open2(const char *path, fd_t fd[2])
System call for opening 2 file descriptors from one file.
Definition open2.c:8
#define STDERR_FILENO
Standard error file descriptor.
Definition io.h:36
#define RETRY_EINTR(expr)
Macro to automatically retry a function that returns an integer if it errors and errno == EINTR.
Definition io.h:601
#define STDIN_FILENO
Standard input file descriptor.
Definition io.h:34
@ INODE_DIR
Is a directory.
Definition io.h:343
pid_t spawn(const char **argv, spawn_flags_t flags)
System call for spawning new processes.
Definition spawn.c:6
@ SPAWN_STDIO_FDS
Only inherit stdin, stdout and stderr from the parent process.
Definition proc.h:62
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
__UINT64_TYPE__ pid_t
Process Identifier.
Definition pid_t.h:11
static pid_t pipeline_execute_cmd(cmd_t *cmd)
Definition pipeline.c:296
void pipeline_deinit(pipeline_t *pipeline)
Definition pipeline.c:264
void pipeline_wait(pipeline_t *pipeline)
Definition pipeline.c:435
uint64_t pipeline_init(pipeline_t *pipeline, const char *cmdline, fd_t stdin, fd_t stdout, fd_t stderr)
Definition pipeline.c:13
void pipeline_execute(pipeline_t *pipeline)
Definition pipeline.c:427
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
#define UINT64_MAX
Definition stdint.h:74
_PUBLIC int printf(const char *_RESTRICT format,...)
Definition printf.c:3
FILE * stdout
Definition std_streams.c:18
FILE * stderr
Definition std_streams.c:19
FILE * stdin
Definition std_streams.c:17
_PUBLIC int fprintf(FILE *_RESTRICT stream, const char *_RESTRICT format,...)
Definition fprintf.c:3
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strerror(int errnum)
Definition strerror.c:6
_PUBLIC char * strtok(char *_RESTRICT s1, const char *_RESTRICT s2)
Definition strtok.c:4
char * strdup(const char *src)
Definition strdup.c:5
_PUBLIC char * strcpy(char *_RESTRICT s1, const char *_RESTRICT s2)
Definition strcpy.c:3
_PUBLIC int strcmp(const char *s1, const char *s2)
Definition strcmp.c:3
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
_PUBLIC char * strchr(const char *s, int c)
Definition strchr.c:3
fd_t stdin
Definition pipeline.h:11
const char ** argv
Definition pipeline.h:9
Stat type.
Definition io.h:366
itype_t type
The type of the entries inode.
Definition io.h:369