Add makefile
[minish.git] / src / minish.c
blob6360552f69245e13b4433ca952e1147fba1f34db
1 #define _POSIX_C_SOURCE 200809L
3 #include <fcntl.h> // O_RDONLY,open
4 #include <locale.h> // LC_ALL,setlocale
5 #include <signal.h> /* SIGHUP,SIGINT,SIGQUIT,SIGTSTP,SIGTTOU,
6 * SIG_DFL,SIG_ERR,SIG_IGN,signal,raise
7 */
8 #include <stdio.h> // feof,ferror,fputs,perror,stderr,stdin
9 #include <stdlib.h> // EXIT_FAILURE,exit
10 #include <stdnoreturn.h> // noreturn
11 #include <sys/wait.h> /* WIFSIGNALED,WIFSTOPPED,WSTOPSIG,WTERMSIG,
12 * WUNTRACED,waitpid
14 #include <unistd.h> // close,dup2,execv,fork,pid_t,setpgid,tcsetpgrp
16 #define TRY(f, ...) do {\
17 if (f(__VA_ARGS__) == -1) {\
18 pexit(#f "()");\
20 } while (0)
22 static noreturn void pexit(char const* const filename) {
23 fputs("minish: ", stderr);
24 perror(filename);
25 exit(EXIT_FAILURE);
28 static void try_signal(int const signum, void (* const handler)(int)) {
29 if (signal(signum, handler) == SIG_ERR) {
30 pexit("signal()");
34 int main(int argc, char** argv) {
35 setlocale(LC_ALL, "");
36 if (argc > 1) {
37 int const input = open(argv[1], O_RDONLY);
38 if (input == -1) {
39 pexit(argv[1]);
41 TRY(dup2, input, 0);
42 try_signal(SIGINT, SIG_IGN);
43 try_signal(SIGQUIT, SIG_IGN);
44 try_signal(SIGTSTP, SIG_IGN);
46 int s;
47 do {
48 pid_t const pid = fork();
49 switch (pid) {
50 case -1: pexit("fork()");
51 case 0:
52 if (argc > 1) {
53 try_signal(SIGINT, SIG_DFL);
54 try_signal(SIGQUIT, SIG_DFL);
55 try_signal(SIGTSTP, SIG_DFL);
56 } else {
57 TRY(setpgid, 0, 0);
58 char const* const tty = "/dev/tty";
59 int const fd = open(tty, O_RDONLY);
60 if (fd == -1) {
61 pexit(tty);
63 try_signal(SIGTTOU, SIG_IGN);
64 TRY(tcsetpgrp, fd, getpid());
65 try_signal(SIGTTOU, SIG_DFL);
66 close(fd);
68 char const* const name = "minish-once";
69 execl("./minish-once", name, (char const*)0);
70 pexit(name);
72 TRY(waitpid, pid, &s, WUNTRACED);
73 if (argc > 1) {
74 if (WIFSIGNALED(s)) {
75 switch (WTERMSIG(s)) {
76 case SIGINT:
77 try_signal(SIGINT, SIG_DFL);
78 raise(SIGINT);
79 case SIGQUIT: return EXIT_FAILURE;
82 if (WIFSTOPPED(s) && WSTOPSIG(s) == SIGTSTP) {
83 try_signal(SIGTSTP, SIG_DFL);
84 raise(SIGTSTP);
87 } while (!WIFSIGNALED(s) || WTERMSIG(s) != SIGHUP);