fiss

Friedel's Initialization and Service Supervision
Log | Files | Refs | LICENSE

serdo.c (2684B)


      1 #include "arg.h"
      2 #define _GNU_SOURCE
      3 
      4 #include <ctype.h>
      5 #include <fcntl.h>
      6 #include <fmt.h>
      7 #include <linux/limits.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <sys/stat.h>
     12 #include <sys/wait.h>
     13 #include <unistd.h>
     14 
     15 #define MAXENV 256
     16 
     17 const char* current_prog(void) {
     18 	return "serdo";
     19 }
     20 
     21 char* envp[MAXENV + 2];
     22 int   envc;
     23 
     24 int continueonerror;
     25 
     26 extern const struct builtin {
     27 	const char* name;
     28 	int (*func)(int argv, char** argc);
     29 } builtins[];
     30 
     31 static int spawn(int argc, char** argv) {
     32 	pid_t pid;
     33 	int   status;
     34 
     35 	for (const struct builtin* bi = builtins; bi->name; bi++) {
     36 		if (!strcmp(argv[0], bi->name))
     37 			return bi->func(argc, argv);
     38 	}
     39 
     40 	switch (pid = fork()) {
     41 		case -1:
     42 			fprint(1, "unable to fork: %r\n");
     43 			exit(1);
     44 		case 0:
     45 			execvpe(argv[0], argv, envp);
     46 			fprint(1, "unable to exec: %r\n");
     47 			_exit(1);
     48 	}
     49 
     50 	if (waitpid(pid, &status, 0) == -1)
     51 		fprint(1, "unable to waid for process: %r\n");
     52 
     53 	if (!WIFEXITED(status))
     54 		return -1;
     55 
     56 	return WEXITSTATUS(status);
     57 }
     58 
     59 static int doline(char* line, ssize_t line_size) {
     60 	int    rc;
     61 	int    i          = 0;
     62 	int    spacecount = 0;
     63 	int    argc       = 0;
     64 	char** argv;
     65 
     66 	while (isspace(line[i])) i++;
     67 
     68 	if (line[i] == '#')
     69 		return 0;
     70 
     71 	for (int j = i; j < line_size; j++)
     72 		if (isspace(line[j])) spacecount++;
     73 
     74 	argv = malloc((spacecount + 1) * sizeof(char*));
     75 
     76 	while (i < line_size && line[i] != '\n') {
     77 		if (line[i] == '"') {
     78 			i++;
     79 			argv[argc++] = &line[i];
     80 			while (i < line_size && line[i - 1] == '\\' && line[i] != '"') i++;
     81 			line[i++] = '\0';
     82 		} else if (line[i] == '\'') {
     83 			i++;
     84 			argv[argc++] = &line[i];
     85 			while (i < line_size && line[i - 1] == '\\' && line[i] != '\'') i++;
     86 			line[i++] = '\0';
     87 		} else {
     88 			argv[argc++] = &line[i];
     89 			while (i < line_size && !isspace(line[i])) i++;
     90 			line[i++] = '\0';
     91 		}
     92 
     93 		while (i < line_size && isspace(line[i])) i++;
     94 	}
     95 
     96 	argv[argc] = NULL;
     97 
     98 	rc = spawn(argc, argv);
     99 	free(argv);
    100 	return rc;
    101 }
    102 
    103 int execute(FILE* file) {
    104 	int     rc         = 0;
    105 	char*   line       = NULL;
    106 	size_t  line_alloc = 0;
    107 	ssize_t line_size;
    108 
    109 	while ((line_size = getline(&line, &line_alloc, file)) > 0) {
    110 		if ((rc = doline(line, line_size)) && !continueonerror)
    111 			break;
    112 	}
    113 	if (line)
    114 		free(line);
    115 
    116 	return rc;
    117 }
    118 
    119 int main(int argc, char* argv[], char* env[]) {
    120 	FILE* f;
    121 	(void) argc;
    122 
    123 	for (envc = 0; envc < MAXENV && env[envc]; ++envc)
    124 		envp[envc] = env[envc];
    125 
    126 	envp[envc] = 0;
    127 
    128 	SHIFT(1);
    129 
    130 	if (argc > 1 && !strcmp(*argv, "-c")) {
    131 		continueonerror = 1;
    132 		SHIFT(1);
    133 	}
    134 
    135 	if (argc > 1) {
    136 		if (!(f = fopen(*argv, "r"))) {
    137 			fprint(1, "unable to open %s: %r\n", *argv);
    138 			return 1;
    139 		}
    140 	} else
    141 		f = stdin;
    142 
    143 	return execute(f);
    144 }