diff options
author | Jakob Kaivo <jkk@ung.org> | 2019-03-13 21:47:51 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2019-03-13 21:47:51 -0400 |
commit | a088e851fb45fe38e6a228770fa5d0c04cddb7f5 (patch) | |
tree | ccec5f171001fde3ad8d18b8241a8c1f441a77fc |
migrate to gitlab
-rw-r--r-- | Makefile | 43 | ||||
-rw-r--r-- | alias.c | 94 | ||||
-rw-r--r-- | bg.c | 8 | ||||
-rw-r--r-- | builtins.c | 167 | ||||
-rw-r--r-- | cd.c | 122 | ||||
-rw-r--r-- | command.c | 72 | ||||
-rw-r--r-- | dot.c | 28 | ||||
-rw-r--r-- | eval.c | 39 | ||||
-rw-r--r-- | exec.c | 48 | ||||
-rw-r--r-- | exit.c | 52 | ||||
-rw-r--r-- | export.c | 100 | ||||
-rw-r--r-- | false.c | 24 | ||||
-rw-r--r-- | fc.c | 8 | ||||
-rw-r--r-- | fg.c | 8 | ||||
-rw-r--r-- | getopts.c | 8 | ||||
-rw-r--r-- | hash.c | 8 | ||||
-rw-r--r-- | init.c | 51 | ||||
-rw-r--r-- | interactive.c | 58 | ||||
-rw-r--r-- | jobs.c | 8 | ||||
-rw-r--r-- | kill.c | 101 | ||||
-rw-r--r-- | main.c | 105 | ||||
-rw-r--r-- | newgrp.c | 7 | ||||
-rw-r--r-- | parse.c | 178 | ||||
-rw-r--r-- | pwd.c | 64 | ||||
-rw-r--r-- | read.c | 68 | ||||
-rw-r--r-- | readonly.c | 28 | ||||
-rw-r--r-- | set.c | 135 | ||||
-rw-r--r-- | sh.h | 68 | ||||
-rw-r--r-- | sh.l | 65 | ||||
-rw-r--r-- | sh.y | 312 | ||||
-rw-r--r-- | shift.c | 28 | ||||
-rw-r--r-- | times.c | 51 | ||||
-rw-r--r-- | trap.c | 183 | ||||
-rw-r--r-- | true.c | 24 | ||||
-rw-r--r-- | type.c | 7 | ||||
-rw-r--r-- | ulimit.c | 61 | ||||
-rw-r--r-- | umask.c | 68 | ||||
-rw-r--r-- | unset.c | 28 | ||||
-rw-r--r-- | wait.c | 8 |
39 files changed, 2535 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8e9252e --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +.POSIX: + +.SUFFIXES: .cat .msg + +default: all + +CFLAGS=-g -Wall -Wextra -Wpedantic -Werror -Wno-unused-function + +UTILITY=sh +SOURCES=alias.c bg.c builtins.c cd.c command.c false.c fc.c fg.c getopts.c \ + hash.c jobs.c kill.c newgrp.c pwd.c read.c set.c main.c true.c type.c \ + ulimit.c umask.c wait.c \ + dot.c eval.c exec.c exit.c export.c readonly.c shift.c times.c trap.c \ + unset.c \ + interactive.c parse.c init.c +HEADERS=sh.h +OBJECTS=alias.o bg.o builtins.o cd.o command.o false.o fc.o fg.o getopts.o \ + hash.o jobs.o kill.o newgrp.o pwd.o read.o set.o main.o true.o type.o \ + ulimit.o umask.o wait.o \ + dot.o eval.o exec.o exit.o export.o readonly.o shift.o times.o trap.o \ + unset.o \ + interactive.o parse.o init.o \ + sh.tab.o sh.yy.o +BUILTINS=alias bg cd command false fc fg getopts jobs kill newgrp pwd read \ + true ulimit umask unalias wait + +all: $(UTILITY) $(L10N) $(BUILTINS) + +sh: $(OBJECTS) $(HEADERS) + $(CC) -o $@ $(CFLAGS) $(OBJECTS) -ly -ll + +$(BUILTINS): $(UTILITY) + #ln -s $(UTILITY) $@ + for i in $(BUILTINS); do ln -s sh $$i; done + +sh.yy.c: sh.l sh.tab.h + $(LEX) -t sh.l > $@ + +sh.tab.h sh.tab.c: sh.y + $(YACC) -b sh -tvd sh.y + +clean: + rm -f *.o $(L10N) $(UTILITY) $(BUILTINS) sh.tab.[ch] sh.yy.c @@ -0,0 +1,94 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct alias { + char *alias; + char *command; +}; + +static struct alias *aliases = NULL; + +static void set_alias(const char *alias, const char *command) +{ + (void)alias; (void)command; +} + +char * sh_get_alias(const char *alias) +{ + if (aliases == NULL) { + return NULL; + } + + for (int i = 0; aliases[i].alias; i++) { + if (!strcmp(aliases[i].alias, alias)) { + return aliases[i].command; + } + } + + return NULL; +} + +static void show_alias(const char *alias) +{ + char *command = sh_get_alias(alias); + if (command) { + printf("%s=%s\n", alias, command); + } else { + fprintf(stderr, "alias: %s: not found\n", alias); + } +} + +int alias_main(int argc, char *argv[]) +{ + while (getopt(argc, argv, "") != -1) { + return 1; + } + + if (argv[optind] == NULL) { + for (int i = 0; aliases && aliases[i].alias; i++) { + printf("%s=%s\n", aliases[i].alias, aliases[i].command); + } + return 0; + } + + do { + char *a = argv[optind++]; + char *eq = strchr(a, '='); + if (eq) { + *eq = '\0'; + set_alias(a, eq + 1); + } else { + show_alias(a); + } + } while (optind < argc); + + return 0; +} + +int unalias_main(int argc, char **argv) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} @@ -0,0 +1,8 @@ +#define _XOPEN_SOURCE 700 +#include <stdio.h> + +int bg_main(int argc, char *argv[]) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} diff --git a/builtins.c b/builtins.c new file mode 100644 index 0000000..886ebaf --- /dev/null +++ b/builtins.c @@ -0,0 +1,167 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stddef.h> +#include <string.h> +#include <libgen.h> +#include <unistd.h> + +struct builtin { + const char *name; + int (*main)(int argc, char *argv[]); +}; + +/* Special built-ins */ +/* break */ +/* : */ +/* continue */ +int dot_main(int argc, char *argv[]); +int eval_main(int argc, char *argv[]); +int exec_main(int argc, char *argv[]); +int exit_main(int argc, char *argv[]); +int export_main(int argc, char *argv[]); +int readonly_main(int argc, char *argv[]); +/* return */ +int set_main(int argc, char *argv[]); +int shift_main(int argc, char *argv[]); +int times_main(int argc, char *argv[]); +int trap_main(int argc, char *argv[]); +int unset_main(int argc, char *argv[]); + +static struct builtin special_builtins[] = { + { "break", NULL }, + { ":", NULL }, + { "continue", NULL }, + { ".", dot_main }, + { "eval", eval_main }, + { "exec", exec_main }, + { "exit", exit_main }, + { "export", export_main }, + { "readonly", readonly_main }, + { "return", NULL }, + { "set", set_main }, + { "shift", shift_main }, + { "times", times_main }, + { "trap", trap_main }, + { "unset", unset_main }, + { 0, 0 }, +}; + +/* Regular built-ins */ +int alias_main(int argc, char *argv[]); +int bg_main(int argc, char *argv[]); +int cd_main(int argc, char *argv[]); +int command_main(int argc, char *argv[]); +int false_main(int argc, char *argv[]); +int fc_main(int argc, char *argv[]); +int fg_main(int argc, char *argv[]); +int getopts_main(int argc, char *argv[]); +int jobs_main(int argc, char *argv[]); +int kill_main(int argc, char *argv[]); +int newgrp_main(int argc, char *argv[]); +int pwd_main(int argc, char *argv[]); +int read_main(int argc, char *argv[]); +int true_main(int argc, char *argv[]); +int ulimit_main(int argc, char *argv[]); +int umask_main(int argc, char *argv[]); +int unalias_main(int argc, char *argv[]); +int wait_main(int argc, char *argv[]); + +static struct builtin regular_builtins[] = { + { "alias", alias_main }, + { "bg", bg_main }, + { "cd", cd_main }, + { "command", command_main }, + { "false", false_main }, + { "fc", fc_main }, + { "fg", fg_main }, + { "getopts", getopts_main }, + { "jobs", jobs_main }, + { "kill", kill_main }, + { "newgrp", newgrp_main }, + { "pwd", pwd_main }, + { "read", read_main }, + { "true", true_main }, + { "ulimit", ulimit_main }, + { "umask", umask_main }, + { "unalias", unalias_main }, + { "wait", wait_main }, + { 0, 0 }, +}; + +static int (*sh_getbuiltin(const char *util, struct builtin *bi))(int argc, char *argv[]) +{ + for (int i = 0; bi[i].name; i++) { + if (!strcmp(bi[i].name, util)) { + return bi[i].main; + } + } + + return NULL; +} + +int sh_builtin(int argc, char *argv[]) +{ + char *util = basename(argv[0]); + if (!strcmp(util, "break")) { + return BREAK; + } else if (!strcmp(util, ":")) { + return 0; + } else if (!strcmp(util, "continue")) { + return CONTINUE; + } else if (!strcmp(util, "return")) { + return RETURN; + } + + int (*m)(int, char *[]) = sh_getbuiltin(util, special_builtins); + if (m == NULL) { + m = sh_getbuiltin(util, regular_builtins); + if (m == NULL) { + return 1; + } + } + + optind = 1; + opterr = 1; + optarg = NULL; + + return m(argc, argv); +} + +static int is_builtin(const char *util, struct builtin *bi) +{ + for (int i = 0; bi[i].name; i++) { + if (!strcmp(bi[i].name, util)) { + return 1; + } + } + + return 0; +} + +int sh_is_special_builtin(const char *util) +{ + return is_builtin(util, special_builtins); +} + +int sh_is_regular_builtin(const char *util) +{ + return is_builtin(util, regular_builtins); +} @@ -0,0 +1,122 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> + +#define FLAG_L (1) +#define FLAG_P (2) + +static int cd(char *path, int flag) +{ + int alloced = 0; + int print = 0; + + if (path == NULL) { + path = getenv("HOME"); + if (path == NULL || !strcmp(path, "")) { + fprintf(stderr, "cd: Directory not specified and HOME not found\n"); + return 1; + } + } + + if (!strcmp(path, "-")) { + path = getenv("OLDPWD"); + print = 1; + } + + /* + if (!(path[0] == '/' || !strncmp(path, "./", 2) || !strncmp(path, "../", 3))) { + char *opath = path; + path = sh_find_in_path(opath, "CDPATH"); + if (path == NULL) { + fprintf(stderr, "cd: %s not found in CDPATH\n", opath); + return 1; + } + alloced = 1; + } + */ + + if (flag != FLAG_P) { + if (path[0] != '/') { + char *base = getenv("PWD"); + char newpath[strlen(base) + strlen(path)]; + sprintf(newpath, "%s/%s", base, path); + strcpy(path, newpath); + } + + /* TODO: canonicalize path */ + /* TODO: shorten to <= PATH_MAX */ + } + + char *oldpwd = getenv("PWD"); + if (chdir(path) != 0) { + if (alloced) { + free(path); + } + + fprintf(stderr, "cd: Couldn't change to %s: %s\n", path, strerror(errno)); + return 1; + } + + if (alloced) { + free(path); + } + + if (print) { + puts(path); + } + + setenv("OLDPWD", oldpwd, 1); + setenv("PWD", path, 1); + return 0; +} + +int cd_main(int argc, char *argv[]) +{ + int flag = 0; + int c; + + while ((c = getopt(argc, argv, ":LP")) != -1) { + switch (c) { + case 'L': + flag = FLAG_L; + break; + + case 'P': + flag = FLAG_P; + break; + + default: + return 1; + } + } + + if (optind < argc - 1) { + fprintf(stderr, "cd: too many arguments\n"); + return 1; + } + + return cd(argv[optind], flag); +} diff --git a/command.c b/command.c new file mode 100644 index 0000000..0307927 --- /dev/null +++ b/command.c @@ -0,0 +1,72 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#define _XOPEN_SOURCE 700 +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int show(const char *cmd, const char *path, bool showtype) +{ + (void)cmd; (void)path; (void)showtype; + return 0; +} + +int command_main(int argc, char *argv[]) +{ + char *path = getenv("PATH"); + char defaultpath[PATH_MAX]; + bool showcommand = false; + bool showtype = false; + + int c = 0; + while ((c = getopt(argc, argv, "pvV")) != -1) { + switch(c) { + case 'p': + confstr(_CS_PATH, defaultpath, sizeof(defaultpath)); + path = defaultpath; + break; + + case 'V': + showtype = true; + /* fallthru */ + case 'v': + showcommand = true; + break; + + default: + return 1; + } + } + + if (showcommand && optind != argc - 1) { + fprintf(stderr, "command: Options -v and -V require command and no arguments\n"); + return 1; + } + + if (showcommand) { + return show(argv[optind], path, showtype); + } + + /* Run command */ + + return 0; +} @@ -0,0 +1,28 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <unistd.h> + +int dot_main(int argc, char *argv[]) +{ + printf("%s: not implemented\n", argv[0]); + return argc; +} @@ -0,0 +1,39 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct sh_redirect *sh_add_redirect(int fd, int direction, char *name) +{ + struct sh_redirect *red = malloc(sizeof(*red)); + red->fd = fd; + red->direction = direction; + red->name = strdup(name); + return red; +} + +int eval_main(int argc, char *argv[]) +{ + printf("%s: not implemented\n", argv[0]); + return argc; +} @@ -0,0 +1,48 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int exec_main(int argc, char *argv[]) +{ + while (getopt(argc, argv, "") != -1) { + return 1; + } + + if (argv[optind] == NULL) { + /* keep redirects for this shell */ + return 0; + } + + char *path = sh_find_in_path(argv[optind], "PATH"); + if (path == NULL) { + fprintf(stderr, "exec: %s: %s\n", argv[optind], strerror(ENOENT)); + exit(127); + } + + execve(path, argv + optind, exported_environ); + fprintf(stderr, "exec: %s: %s\n", argv[optind], strerror(errno)); + exit(126); + return 126; +} @@ -0,0 +1,52 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int exit_main(int argc, char *argv[]) +{ + static int exiting = 0; + + while (getopt(argc, argv, "") != -1) { + return 1; + } + + if (optind < argc - 1) { + fprintf(stderr, "exit: only one exit status supported\n"); + return 1; + } + + int r = 0; + + if (argv[optind]) { + r = atoi(argv[optind]); + } + + if (exiting == 0) { + exiting = 1; + sh_trap(0); + } + + exit(r); + _exit(r); + return r; +} diff --git a/export.c b/export.c new file mode 100644 index 0000000..214a3d4 --- /dev/null +++ b/export.c @@ -0,0 +1,100 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +char **exported_environ = NULL; +static int nexports = 0; + +void sh_export(const char *env) +{ + char *value = getenv(env); + if (value == NULL) { + return; + } + size_t klen = strlen(env); + + char *keyval = calloc(klen + strlen(value) + 2, 1); + sprintf(keyval, "%s=%s", env, value); + + for (int i = 0; i < nexports; i++) { + if (!strncmp(exported_environ[i], env, klen) + && exported_environ[i][klen] == '=') { + free(exported_environ[i]); + exported_environ[i] = keyval; + return; + } + } + + nexports++; + exported_environ = realloc(exported_environ, + nexports * sizeof(*exported_environ)); + exported_environ[nexports-1] = keyval; +} + +int export_main(int argc, char *argv[]) +{ + int print = 0; + + int c; + while ((c = getopt(argc, argv, "p")) != EOF) { + switch (c) { + case 'p': /** print exported variables **/ + print = 1; + break; + + default: + return 1; + } + } + + if (print && argv[optind] != NULL) { + fprintf(stderr, "export: can't display and export at the same time\n"); + return 1; + } + + if (print) { + for (char **e = exported_environ; e && *e; e++) { + char *env = strdup(*e); + size_t len = strlen(env); + if (env[len - 1] == '=') { + env[len - 1] = '\0'; + } + printf("export %s\n", env); + free(env); + } + return 0; + } + + do { + char *var = argv[optind++]; + char *eq = strchr(var, '='); + if (eq) { + putenv(var); + *eq = '\0'; + } + sh_export(var); + } while (optind < argc); + + return 0; +} @@ -0,0 +1,24 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +int false_main(int argc, char *argv[]) +{ + (void)argc; (void)argv; + return 1; +} @@ -0,0 +1,8 @@ +#include <stdio.h> + +int +fc_main(int argc, char **argv) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} @@ -0,0 +1,8 @@ +#define _XOPEN_SOURCE 700 +#include <stdio.h> + +int fg_main(int argc, char *argv[]) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} diff --git a/getopts.c b/getopts.c new file mode 100644 index 0000000..263b1a2 --- /dev/null +++ b/getopts.c @@ -0,0 +1,8 @@ +#define _XOPEN_SOURCE 700 +#include <stdio.h> + +int getopts_main(int argc, char *argv[]) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} @@ -0,0 +1,8 @@ +#include <stdio.h> + +int +hash_main(int argc, char **argv) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} @@ -0,0 +1,51 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +extern char **environ; + +void sh_init(int interactive) +{ + if (interactive && getuid() == geteuid() && getgid() == getegid()) { + char *env = getenv("ENV"); + if (env) { + /* + char *profile = sh_expand(env); + sh_source(env); + free(profile); + */ + } + } + + /* export all inherited environment variables */ + char **exp = environ; + while (exp && *exp) { + char *e = strdup(*exp); + char *eq = strchr(e, '='); + *eq = '\0'; + sh_export(e); + free(e); + exp++; + } +} diff --git a/interactive.c b/interactive.c new file mode 100644 index 0000000..7460327 --- /dev/null +++ b/interactive.c @@ -0,0 +1,58 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> + +static char *sh_getline(char **cmdline) +{ + char *prompt = getenv(*cmdline ? "PS2" : "PS1"); + /* wordexpand prompt */ + fprintf(stderr, "%s", prompt); + + size_t n = 0; + getline(cmdline, &n, stdin); + return *cmdline; +} + +int sh_interactive(void) +{ + while (!feof(stdin)) { + char *cmdline = NULL; + sh_getline(&cmdline); + + if (cmdline == NULL) { + break; + } + + struct command *command = sh_parse(cmdline); + while (command == NULL) { + /* append more text */ + /* attempt parsing again */ + } + + sh_execute(command); + + free(cmdline); + sh_freecmd(command); + } + + return 0; +} @@ -0,0 +1,8 @@ +#define _XOPEN_SOURCE 700 +#include <stdio.h> + +int jobs_main(int argc, char *argv[]) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} @@ -0,0 +1,101 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <ctype.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> + +struct { + char *name; + int num; +} ksigs[] = { + { "ABRT", SIGABRT }, + { "ALRM", SIGALRM }, + { "BUS", SIGBUS }, + { "CHLD", SIGCHLD }, + { "CONT", SIGCONT }, + { "FPE", SIGFPE }, + { "HUP", SIGHUP }, + { "ILL", SIGILL }, + { "INT", SIGINT }, + { "KILL", SIGKILL }, + { "PIPE", SIGPIPE }, + { "QUIT", SIGQUIT }, + { "SEGV", SIGSEGV }, + { "STOP", SIGSTOP }, + { "TERM", SIGTERM }, + { "TSTP", SIGTSTP }, + { "TTIN", SIGTTIN }, + { "TTOU", SIGTTOU }, + { "USR1", SIGUSR1 }, + { "USR2", SIGUSR2 }, + { "POLL", SIGPOLL }, + { "PROF", SIGPROF }, + { "SYS", SIGSYS }, + { "TRAP", SIGTRAP }, + { "URG", SIGURG }, + { "VTALRM", SIGVTALRM }, + { "XCPU", SIGXCPU }, + { "XFSZ", SIGXFSZ }, +}; +size_t nsigs = sizeof(ksigs) / sizeof(ksigs[0]); + +int kill_main(int argc, char *argv[]) +{ + char *signame = "TERM"; + int list = 0; + + opterr = 0; + int c; + while ((c = getopt(argc, argv, "s:l") != -1)) { + switch (c) { + case 's': /** send signal [signal_name] **/ + signame = optarg; + break; + + case 'l': + list = 1; + break; + + default: + if (isdigit(optopt) || isupper(optopt)) { + signame = argv[optind]; + break; + } + fprintf(stderr, "kill: unknown option '-%c'\n", optopt); + //return 1; + } + } + + if (list) { + if (argv[optind]) { + } + + for (size_t i = 0; i < nsigs; i++) { + printf("%s%c", ksigs[i].name, i < nsigs - 1 ? ' ' : '\n'); + } + return 0; + } + + printf("%s\n", signame); + + return 0; +} @@ -0,0 +1,105 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libgen.h> +#include <unistd.h> + +int sh_main(int argc, char *argv[]) +{ + enum { STDIN, INTERACTIVE, COMMAND } mode = STDIN; + int c; + while ((c = getopt(argc, argv, "abCefhimnuvxo:cs")) != -1) { + switch (c) { + case 'a': /** export all variables **/ + case 'b': /** notify of background job completions **/ + case 'C': /** don't clobber existing files with > **/ + case 'e': /** exit on failure **/ + case 'f': /** disable pathname expansion **/ + case 'h': /** hash utilities in functions when defined **/ + case 'n': /** read commands but don't execute **/ + case 'u': /** don't expand unset parameters **/ + case 'v': /** echo input to /stderr/ **/ + case 'x': /** enable tracing **/ + sh_set(c, 1); + break; + + case 'o': /** enable [option] **/ + sh_seto(optarg, 1); + break; + + case 'c': /** execute [command_string] and return **/ + mode = COMMAND; + break; + + case 'i': /** run an interactive shell **/ + mode = INTERACTIVE; + break; + + case 's': /** read commands from /stdin/ **/ + mode = STDIN; + break; + + default: + return 1; + } + } + + while (argv[optind] && argv[optind][0] == '+') { + /* consume these */ + optind++; + } + + if (mode == COMMAND) { + /* shift argv */ + execvp(argv[optind], argv + optind); + fprintf(stderr, "sh: %s: %s\n", argv[optind], strerror(errno)); + return 1; + } + + if (argv[optind] == NULL && isatty(STDIN_FILENO) && isatty(STDERR_FILENO)) { + mode = INTERACTIVE; + } + + sh_init(mode == INTERACTIVE); + + /* set $1-$# */ + + if (mode == INTERACTIVE) { + return sh_interactive(); + } + + /* mode is STDIN */ + return yyparse(); +} + +int main(int argc, char *argv[]) +{ + putenv("PS1=$ "); + char *base = basename(argv[0]); + if (sh_is_regular_builtin(base)) { + return sh_builtin(argc, argv); + } + + return sh_main(argc, argv); +} diff --git a/newgrp.c b/newgrp.c new file mode 100644 index 0000000..3148df1 --- /dev/null +++ b/newgrp.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int newgrp_main(int argc, char **argv) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} @@ -0,0 +1,178 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> + +struct simple_command { + int argc; + char **argv; + char **redirection; +}; + +struct pipeline_command { + struct simple_command s; +}; + +struct list_command { + struct simple_command s; +}; + +struct compound_command { + enum { GROUPING, FOR, CASE, IF, UNTIL } type; + struct simple_command *commands; +}; + +struct command { + enum { EMPTY, SIMPLE, PIPELINE, LIST, COMPOUND } type; + union { + struct simple_command simple; + struct pipeline_command pipeline; + struct list_command list; + struct compound_command compound; + } cmd; +}; + +struct command *sh_parse(const char *cmdline) +{ + char *l = strdup(cmdline); + char *start = l; + while (isspace(*start)) { + start++; + } + + char *end = l + strlen(l) - 1; + while (isspace(*end) && end > start) { + *end = '\0'; + end--; + } + + struct command *cmd = calloc(1, sizeof(*cmd)); + if (cmd == NULL) { + /* TODO: should probably crash here */ + return cmd; + } + + cmd->type = SIMPLE; + cmd->cmd.simple.argv = calloc(100, sizeof(char *)); + + char *next = strtok(start, " "); + do { + cmd->cmd.simple.argv[cmd->cmd.simple.argc++] = strdup(next); + } while ((next = strtok(NULL, " ")) != NULL); + + free(l); + return cmd; +} + +void sh_freecmd(struct command *command) +{ + if (command->type == SIMPLE) { + struct simple_command *c = &(command->cmd.simple); + for (int i = 0; c->argv[i]; i++) { + free(c->argv[i]); + } + } + free(command); +} + +char *sh_find_in_path(const char *file, const char *pathvar) +{ + char *path = getenv(pathvar); + if (path == NULL) { + return NULL; + } + + path = strdup(path); + char *checkpath = strtok(path, ":"); + do { + char fullpath[strlen(checkpath) + strlen(file) + 2]; + sprintf(fullpath, "%s/%s", checkpath, file); + if (access(fullpath, F_OK) == 0) { + free(path); + return strdup(fullpath); + } + } while ((checkpath = strtok(NULL, ":")) != NULL); + + free(path); + return NULL; +} + +int sh_simple_command(struct simple_command *c) +{ + char *path = c->argv[0]; + + if (!strchr(path, '/')) { + if (sh_is_special_builtin(path)) { + return sh_builtin(c->argc, c->argv); + } + + /* + if (sh_is_function(path)) { + return sh_function(c->argc, c->argv); + } + */ + + if (sh_is_regular_builtin(path)) { + return sh_builtin(c->argc, c->argv); + } + + path = sh_find_in_path(path, "PATH"); + } + + if (path == NULL) { + fprintf(stderr, "sh: %s: %s\n", c->argv[0], strerror(ENOENT)); + } + + pid_t pid = fork(); + if (pid == 0) { + execv(path, c->argv/*, exported_environ*/); + fprintf(stderr, "sh: %s: %s\n", path, strerror(errno)); + exit(1); + } + free(path); + + if (pid < 0) { + perror("sh"); + return 1; + } + + int rv; + waitpid(pid, &rv, 0); + return rv; +} + +int sh_execute(struct command *command) +{ + if (command->type == EMPTY) { + return 0; + } + + if (command->type == SIMPLE) { + return sh_simple_command(&(command->cmd.simple)); + } + + return 0; +} @@ -0,0 +1,64 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011, Jakob Kaivo <jakob@kaivo.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +const char *pwd_desc = "return working directory name"; +const char *pwd_inv = "pwd [-L|-P]"; + +int +pwd_main (int argc, char **argv) +{ + //char mode = 'L'; + char *cwd; + int c; + + while ((c = getopt (argc, argv, ":LP")) != -1) { + switch (c) { + case 'L': + case 'P': + ////mode = c; + break; + default: + return 1; + } + } + + if (optind < argc) + return 1; + + // FIXME: + // if (mode == 'L') + // if (cwd !~ /./ && cwd !~ /../) + // print (cwd); + // else if (strlen (cwd) > PATH_MAX && NO_DOT_OR_DOT_DOT) + // unspecified + // else + // mode = 'P'; + // if (mode == 'P') + // decompose_to_shortest_path + // print (decomposed) + cwd = (char*)getenv ("PWD"); + printf ("%s\n", cwd); + + return 0; +} @@ -0,0 +1,68 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int read_main(int argc, char *argv[]) +{ + int escapes = 1; + + int c; + while ((c = getopt(argc, argv, "r")) != -1) { + switch (c) { + case 'r': /** do not interpet \ escapes **/ + escapes = 0; + break; + + default: + return 1; + } + } + + if (argv[optind] == NULL) { + fprintf(stderr, "read: at least one variable required\n"); + return 1; + } + + while (argv[optind]) { + char *line = NULL; + size_t n = 0; + + getline(&line, &n, stdin); + + /* strip trailing newline */ + if (escapes) { + } + + setenv(argv[optind], line, 1); + + if (sh_get('a')) { + sh_export(argv[optind]); + } + + free(line); + + optind++; + } + + return 0; +} diff --git a/readonly.c b/readonly.c new file mode 100644 index 0000000..93809cc --- /dev/null +++ b/readonly.c @@ -0,0 +1,28 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <unistd.h> + +int readonly_main(int argc, char *argv[]) +{ + printf("%s: not implemented\n", argv[0]); + return argc; +} @@ -0,0 +1,135 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static struct option { + char c; + char *s; + int value; +} sh_options[] = { + { 'a', "allexport", 0 }, + { 'b', NULL, 0 }, + { 'C', "noclobber", 0 }, + { 'e', "errexit", 0 }, + { 'f', "noglob", 0 }, + { 'h', NULL, 0 }, + { 'm', "monitor", 0 }, + { 'n', NULL, 0 }, + { 'u', "nounset", 0 }, + { 'v', "verbose", 0 }, + { 'x', "xtrace", 0 }, + { '-', "ignoreeof", 0 }, + { '-', "nolog", 0 }, + { '-', "vi", 0 }, +}; +static size_t noptions = sizeof(sh_options) / sizeof(sh_options[0]); + +void sh_set(char option, int value) +{ + for (size_t i = 0; i < noptions; i++) { + if (sh_options[i].c == option) { + sh_options[i].value = value; + return; + } + } +} + +int sh_get(char option) +{ + for (size_t i = 0; i < noptions; i++) { + if (sh_options[i].c == option) { + return sh_options[i].value; + } + } + return 0; +} + +void sh_seto(char *option, int value) +{ + for (size_t i = 0; i < noptions; i++) { + if (sh_options[i].s && !strcmp(sh_options[i].s, option)) { + sh_options[i].value = value; + return; + } + } +} + +int sh_geto(char *option) +{ + for (size_t i = 0; i < noptions; i++) { + if (sh_options[i].s && !strcmp(sh_options[i].s, option)) { + return sh_options[i].value; + } + } + return 0; +} + +int set_main(int argc, char *argv[]) +{ + int show = 0; + + int c; + while ((c = getopt(argc, argv, ":abCefhmnuvxo:")) != -1) { + switch (c) { + case 'a': + case 'b': + case 'C': + case 'e': + case 'f': + case 'h': + case 'm': + case 'n': + case 'u': + case 'v': + case 'x': + sh_set(c, 1); + break; + + case 'o': + sh_seto(optarg, 1); + break; + + case ':': + if (optopt == 'o') { + show = 1; + } else { + return 1; + } + break; + + default: + return 1; + } + } + + if (show) { + for (size_t i = 0; i < noptions; i++) { + if (sh_options[i].value) { + putchar(sh_options[i].c); + } + } + putchar('\n'); + } + + return 0; +} @@ -0,0 +1,68 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#define _XOPEN_SOURCE 700 +#define _POSIX_C_SOURCE 200809L + +struct sh_redirect { + int fd; + enum { WRITE, APPEND, OVERWRITE, WRITEFD, READWRITE, READ, READFD, READHERE, READDASH } direction; + char *name; +}; + +struct sh_redirect *sh_add_redirect(int fd, int direction, char *name); + +struct sh_command { + int argc; + char *cmd; + char **argv; + struct sh_redirect *redirect; +}; + +struct command; +struct command *sh_parse(const char *cmdline); +void sh_freecmd(struct command *cmd); +int sh_execute(struct command *cmd); + +void sh_set(char option, int value); +void sh_seto(char *option, int value); +int sh_get(char option); +int sh_geto(char *option); + +int sh_interactive(void); + +int sh_is_special_builtin(const char *util); +int sh_is_regular_builtin(const char *util); +int (*sh_get_builtin(const char *util))(int argc, char *argv[]); +int sh_builtin(int argc, char *argv[]); + +enum { BREAK = -1, CONTINUE = -2, RETURN = -3 }; + +char *sh_find_in_path(const char *file, const char *pathvar); + +void sh_export(const char *var); +extern char **exported_environ; + +void sh_init(int interactive); + +enum { HUP = 1, INT = 2, QUIT = 3, ABRT = 6, KILL = 9, ALRM = 14, TERM = 15 }; + +void sh_trap(int trapno); + +int yyparse(void); @@ -0,0 +1,65 @@ +%{ +#include "sh.h" +#include "sh.tab.h" +/* thanks, flex, for implicitly declaring identifiers */ +/* bonus points for something that isn't part of ISO C */ +extern int fileno(FILE *); +%} + +NAME [_a-zA-Z0-9] +NONDIGIT [_a-zA-Z] +DIGIT [0-9] +WHITESPACE [ \t] +OPERATOR [()|;&<>] + +%s FOR +%x COMMENT + +%% + +"#" { BEGIN COMMENT; } +<COMMENT>. ; +<COMMENT>\n { BEGIN INITIAL; } + +"&&"/. { return AND_IF; } +"||"/. { return OR_IF; } +";;"/. { return DSEMI; } +"<<"/. { return DLESS; } +">>"/. { return DGREAT; } +"<&"/. { return LESSAND; } +">&"/. { return GREATAND; } +"<>"/. { return LESSGREAT; } +"<<-"/. { return DLESSDASH; } +">|"/. { return CLOBBER; } + +"if" { return If; } +"then" { return Then; } +"else" { return Else; } +"elif" { return Elif; } +"fi" { return Fi; } +"do" { return Do; } +"done" { BEGIN INITIAL; return Done; } +"case" { return Case; } +"esac" { return Esac; } +"while" { return While; } +"until" { return Until; } +"for" { BEGIN FOR; return For; } + +"{" { return Lbrace; } +"}" { return Rbrace; } +"!" { return Bang; } + +"in" { return In; } + +{OPERATOR}/. { return yytext[0]; } + +{DIGIT}+/< { yylval.n = atoi(yytext); return IO_NUMBER; } +{DIGIT}+/> { yylval.n = atoi(yytext); return IO_NUMBER; } + +\n { return NEWLINE; } + +<FOR>{NONDIGIT}{NAME}* { yylval.s = yytext; return NAME; } + +[^ \t\n()|;&<>]+ { yylval.s = yytext; return WORD; } + +{WHITESPACE} ; @@ -0,0 +1,312 @@ +%{ +#include "sh.h" +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/* Thanks, Bison, for implicitly declaring identifiers */ +extern int yylex(void); +extern int yyerror(const char *); +extern char *yytext; +%} + +%union { + int n; + char *s; + struct sh_command *cmd; + struct sh_redirect *redir; +} + +%token<s> WORD ASSIGNMENT_WORD NAME +%token NEWLINE +%token<n> IO_NUMBER +%token AND_IF OR_IF DSEMI +%token DLESS DGREAT LESSAND GREATAND LESSGREAT DLESSDASH +%token CLOBBER +%token If Then Else Elif Fi Do Done +%token Case Esac While Until For +%token Lbrace Rbrace Bang +%token In + + /* %type<cmd> simple_command */ +%type<s> filename here_end cmd_name cmd_word +%type<redir> io_redirect io_file io_here + +%start complete_command +%% +complete_command : list separator + | list + ; + +list : list separator_op and_or + | and_or + ; + +and_or : pipeline + | and_or AND_IF linebreak pipeline + | and_or OR_IF linebreak pipeline + ; + +pipeline : pipe_sequence + | Bang pipe_sequence + ; + +pipe_sequence : command + | pipe_sequence '|' linebreak command + ; + +command : simple_command + | compound_command + | compound_command redirect_list + | function_definition + ; + +compound_command : brace_group + | subshell + | for_clause + | case_clause + | if_clause + | while_clause + | until_clause + ; + +subshell : '(' compound_list ')' + ; + +compound_list : term + | newline_list term + | term separator + | newline_list term separator + ; + +term : term separator and_or + | and_or + ; + +for_clause : For name linebreak do_group + | For name linebreak in sequential_sep do_group + | For name linebreak in wordlist sequential_sep do_group + ; + +name : NAME { /* apply rule 5 */ + printf("NAME: %s\n", yytext); + } + ; + +in : In /* apply rule 6 */ + ; + +wordlist : wordlist WORD + | WORD { + printf("WORD: %s\n", yytext); + } + ; + +case_clause : Case WORD linebreak in linebreak case_list Esac + | Case WORD linebreak in linebreak case_list_ns Esac + | Case WORD linebreak in linebreak Esac + ; + +case_list_ns : case_list case_item_ns + | case_item_ns + ; + +case_list : case_list case_item + | case_item + ; + +case_item_ns : pattern ')' linebreak + | pattern ')' compound_list linebreak + | '(' pattern ')' linebreak + | '(' pattern ')' compound_list linebreak + ; + +case_item : pattern ')' linebreak DSEMI linebreak + | pattern ')' compound_list DSEMI linebreak + | '(' pattern ')' linebreak DSEMI linebreak + | '(' pattern ')' compound_list DSEMI linebreak + ; + +pattern : WORD /* apply rule 4 */ + | pattern '|' WORD /* do *NOT* apply rule 4 */ + ; + +if_clause : If compound_list Then compound_list else_part Fi + | If compound_list Then compound_list Fi + ; + +else_part : Elif compound_list Then compound_list + | Elif compound_list Then compound_list else_part + | Else compound_list + ; + +while_clause : While compound_list do_group + ; + +until_clause : Until compound_list do_group + ; + +function_definition : fname '(' ')' linebreak function_body + +function_body : compound_command /* apply rule 9 */ + | compound_command redirect_list /* apply rule 9 */ + ; + +fname : NAME /* apply rule 8 */ + ; + +brace_group : Lbrace compound_list Rbrace + ; + +do_group : Do compound_list Done /* apply rule 6 */ + ; + +simple_command : cmd_prefix cmd_word cmd_suffix + | cmd_prefix cmd_word { + printf("simple_command:cmd_prefix '%s'\n", $2); + } + | cmd_prefix + | cmd_name cmd_suffix { + printf("simple_command:'%s' cmd_suffix\n", $1); + } + | cmd_name { + printf("simple_command:'%s'\n", $1); + } + ; + +cmd_name : WORD { + /* rule 7a */ + $$ = strdup($1); + } + ; + +cmd_word : WORD { + /* rule 7b */ + $$ = strdup($1); + } + ; + +cmd_prefix : io_redirect + | cmd_prefix io_redirect + | ASSIGNMENT_WORD + | cmd_prefix ASSIGNMENT_WORD + ; + +cmd_suffix : io_redirect + | cmd_suffix io_redirect + | WORD { + printf("cmd_suffix:WORD:%s\n", $1); + } + | cmd_suffix WORD { + printf("cmd_suffix:cmd_suffix WORD:%s\n", $2); + } + ; + +redirect_list : io_redirect { + printf("Redirect fd %d, dir %d, name %s\n", $1->fd, $1->direction, $1->name); + } + | redirect_list io_redirect { + printf("Redirect fd %d, dir %d, name %s\n", $2->fd, $2->direction, $2->name); + } + ; + +io_redirect : io_file { + $$ = $1; + printf("Redirect fd %d to %s\n", $1->fd, $1->name); + } + | IO_NUMBER io_file { + $2->fd = $1; + printf("Redirect fd %d to %s\n", $2->fd, $2->name); + $$ = $2; + } + | io_here { + printf("Redirect fd %d until %s\n", $1->fd, $1->name); + $$ = $1; + } + | IO_NUMBER io_here { + $2->fd = $1; + printf("Redirect fd %d until %s\n", $2->fd, $2->name); + $$ = $2; + } + ; + +io_file : '<' filename { + $$ = sh_add_redirect(STDIN_FILENO, READ, $2); + } + | LESSAND filename { + $$ = sh_add_redirect(STDIN_FILENO, READFD, $2); + } + | '>' filename { + $$ = sh_add_redirect(STDOUT_FILENO, WRITE, $2); + } + | GREATAND filename { + $$ = sh_add_redirect(STDOUT_FILENO, WRITEFD, $2); + } + | DGREAT filename { + $$ = sh_add_redirect(STDOUT_FILENO, APPEND, $2); + } + | LESSGREAT filename { + $$ = sh_add_redirect(-1, READWRITE, $2); + } + | CLOBBER filename { + $$ = sh_add_redirect(STDOUT_FILENO, OVERWRITE, $2); + } + ; + +filename : WORD { + /* rule 2 */ + $$ = yytext; + } + ; + +io_here : DLESS here_end { + $$ = sh_add_redirect(STDIN_FILENO, READHERE, $2); + } + | DLESSDASH here_end { + $$ = sh_add_redirect(STDIN_FILENO, READDASH, $2); + } + ; + +here_end : WORD { + /* rule 3 */ + $$ = yytext; + } + ; + +newline_list : NEWLINE { + puts("newline_list:NEWLINE"); + } + | newline_list NEWLINE { + puts("newline_list:newline_list:NEWLINE"); + } + ; + +linebreak : newline_list { + puts("linebreak:newline_list"); + } + | /* empty */ + ; + +separator_op : '&' { + puts("separator_op:&"); + } + | ';' { + puts("separator_op:;"); + } + ; + +separator : separator_op linebreak { + puts("separator: separator_op linebreak"); + } + | newline_list { + puts("separator:newline_list"); + } + ; + +sequential_sep : ';' linebreak { + puts("sequential_sep:; linebreak"); + } + | newline_list { + puts("sequential_sep:newline_list"); + } + ; @@ -0,0 +1,28 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <unistd.h> + +int shift_main(int argc, char *argv[]) +{ + printf("%s: not implemented\n", argv[0]); + return argc; +} @@ -0,0 +1,51 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <time.h> +#include <sys/times.h> +#include <unistd.h> + +#define clocktos(c) ((double)(c) / (double)CLOCKS_PER_SEC) +#define clocktom(c) ((long)clocktos(c) / 60) +#define clocktof(c) ((double)(clocktos(c)) - (double)(clocktom(c) * 60)) + +/* The Standard specifies an exit status of "Zero." with no other options. */ + +int times_main(int argc, char *argv[]) +{ + while (getopt(argc, argv, "") != -1) { + /* produce warning only */ + } + + if (argv[optind]) { + fprintf(stderr, "times: no arguments supported\n"); + /* keep going */ + } + + struct tms tms; + times(&tms); + printf("%ldm%fs %ldm%fs\n%ldm%fs %ldm%fs\n", + clocktom(tms.tms_utime), clocktof(tms.tms_utime), + clocktom(tms.tms_stime), clocktof(tms.tms_stime), + clocktom(tms.tms_cutime), clocktof(tms.tms_cutime), + clocktom(tms.tms_cstime), clocktof(tms.tms_cstime)); + return 0; +} @@ -0,0 +1,183 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> + +static struct { + char *name; + char *value; +} traps[] = { + [0] = { "EXIT", 0 }, + [SIGABRT] = { "ABRT", 0 }, + [SIGALRM] = { "ALRM", 0 }, + [SIGBUS] = { "BUS", 0 }, + [SIGCHLD] = { "CHLD", 0 }, + [SIGCONT] = { "CONT", 0 }, + [SIGFPE] = { "FPE", 0 }, + [SIGHUP] = { "HUP", 0 }, + [SIGILL] = { "ILL", 0 }, + [SIGINT] = { "INT", 0 }, + [SIGKILL] = { "KILL", 0 }, + [SIGPIPE] = { "PIPE", 0 }, + [SIGQUIT] = { "QUIT", 0 }, + [SIGSEGV] = { "SEGV", 0 }, + [SIGSTOP] = { "STOP", 0 }, + [SIGTERM] = { "TERM", 0 }, + [SIGTSTP] = { "TSTP", 0 }, + [SIGTTIN] = { "TTIN", 0 }, + [SIGTTOU] = { "TTOU", 0 }, + [SIGUSR1] = { "USR1", 0 }, + [SIGUSR2] = { "USR2", 0 }, + [SIGPOLL] = { "POLL", 0 }, + [SIGPROF] = { "PROF", 0 }, + [SIGSYS] = { "SYS", 0 }, + [SIGTRAP] = { "TRAP", 0 }, + [SIGURG] = { "URG", 0 }, + [SIGVTALRM] = { "VTALRM", 0 }, + [SIGXCPU] = { "XCPU", 0 }, + [SIGXFSZ] = { "XFSZ", 0 }, +}; +static size_t ntraps = sizeof(traps) / sizeof(traps[0]); + +static char *tnums[] = { + [0] = "EXIT", + [HUP] = "HUP", + [INT] = "INT", + [QUIT] = "QUIT", + [ABRT] = "ABRT", + [KILL] = "KILL", + [ALRM] = "ALRM", + [TERM] = "TERM", +}; +static size_t nnums = sizeof(tnums) / sizeof(tnums[0]); + +static int trap_num(const char *name) +{ + if (!strcmp(name, "0")) { + return 0; + } + + int t = atoi(name); + if (t != 0) { + if ((size_t)t < nnums && tnums[t] != NULL) { + name = tnums[t]; + } + } + + for (size_t i = 0; i < ntraps; i++) { + if (traps[i].name && !strcmp(traps[i].name, name)) { + return i; + } + } + fprintf(stderr, "trap: unknown trap '%s'\n", name); + return -1; +} + +static int trap_reset(const char *trap) +{ + int t = trap_num(trap); + if (t == -1) { + return 1; + } + + free(traps[t].value); + traps[t].value = NULL; + signal(t, SIG_DFL); + return 0; +} + +void sh_trap(int trapno) +{ + if (traps[trapno].value) { + /* sh_eval(traps[trapno].value); */ + } +} + +static int trap_set(const char *trap, const char *action) +{ + int t = trap_num(trap); + if (t == -1) { + return 1; + } + + if (t == SIGKILL || t == SIGSTOP) { + fprintf(stderr, "trap: setting trap for %s is undefined\n", trap); + return 1; + } + + if (traps[t].value) { + free(traps[t].value); + } + traps[t].value = strdup(action); + + if (!strcmp(action, "")) { + signal(t, SIG_IGN); + } else { + signal(t, sh_trap); + } + + return 0; +} + +int trap_main(int argc, char *argv[]) +{ + while (getopt(argc, argv, "") != -1) { + return 1; + } + + if (argv[optind] == NULL) { + for (size_t i = 0; i < ntraps; i++) { + if (traps[i].value) { + printf("trap -- %s %s\n", traps[i].value, traps[i].name); + } + } + return 0; + } + + char *action = argv[optind]; + int r = 0; + + /* FIXME */ + if (atoi(action) > 0) { + do { + r |= trap_reset(argv[optind++]); + } while (argv[optind]); + return r; + } + + optind++; + + if (!strcmp(action, "-")) { + do { + r |= trap_reset(argv[optind++]); + } while (argv[optind]); + return r; + } + + do { + r |= trap_set(argv[optind++], action); + } while (argv[optind]); + + return r; +} @@ -0,0 +1,24 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +int true_main(int argc, char *argv[]) +{ + (void)argc; (void)argv; + return 0; +} @@ -0,0 +1,7 @@ +#include <stdio.h> + +int type_main(int argc, char **argv) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} diff --git a/ulimit.c b/ulimit.c new file mode 100644 index 0000000..3367a61 --- /dev/null +++ b/ulimit.c @@ -0,0 +1,61 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <stdlib.h> +#include <sys/resource.h> +#include <unistd.h> + +#define BLOCKSIZE (512) + +int ulimit_main(int argc, char *argv[]) +{ + int c; + while ((c = getopt(argc, argv, "f")) != -1) { + switch (c) { + case 'f': /** set or report limit in blocks **/ + /* is default */ + break; + + default: + return 1; + } + } + + if (argv[optind]) { + struct rlimit rl; + rl.rlim_cur = atoi(argv[optind]) * BLOCKSIZE; + if (setrlimit(RLIMIT_FSIZE, &rl) == -1) { + perror("ulimit"); + return 1; + } + return 0; + } + + struct rlimit rl; + getrlimit(RLIMIT_FSIZE, &rl); + if (rl.rlim_cur == RLIM_INFINITY) { + printf("unlimited\n"); + } else { + printf("%ld\n", rl.rlim_cur / BLOCKSIZE); + } + + return 0; +} @@ -0,0 +1,68 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> + +int umask_main(int argc, char *argv[]) +{ + int symbolic = 0; + + int c; + while ((c = getopt(argc, argv, "S")) != -1) { + switch (c) { + case 'S': /** produce symbolic output **/ + symbolic = 1; + break; + + default: + return 1; + } + } + + if (argv[optind]) { + fprintf(stderr, "umask: TODO\n"); + return 1; + } + + mode_t mask = umask(0); + umask(mask); + + if (symbolic) { + fputs("u=", stdout); + fputs(mask & S_IRUSR ? "" : "r", stdout); + fputs(mask & S_IWUSR ? "" : "w", stdout); + fputs(mask & S_IXUSR ? "" : "x", stdout); + fputs(",g=", stdout); + fputs(mask & S_IRGRP ? "" : "r", stdout); + fputs(mask & S_IWGRP ? "" : "w", stdout); + fputs(mask & S_IXGRP ? "" : "x", stdout); + fputs(",o=", stdout); + fputs(mask & S_IRGRP ? "" : "r", stdout); + fputs(mask & S_IWGRP ? "" : "w", stdout); + fputs(mask & S_IXGRP ? "" : "x", stdout); + putchar('\n'); + } else { + printf("%04o\n", mask); + } + + return 0; +} @@ -0,0 +1,28 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sh.h" +#include <stdio.h> +#include <unistd.h> + +int unset_main(int argc, char *argv[]) +{ + printf("%s: not implemented\n", argv[0]); + return argc; +} @@ -0,0 +1,8 @@ +#include <stdio.h> + +int +wait_main(int argc, char **argv) +{ + printf("Sorry, %s isn't implemented yet.\n", argv[0]); + return argc; +} |