10aed0b57ad4570f9222812bed4094291d840e60
[lunaix-os.git] / lunaix-os / uprog / sh.c
1 #include <errno.h>
2 #include <signal.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/ioctl.h>
6 #include <unistd.h>
7
8 char pwd[512];
9 char cat_buf[1024];
10
11 /*
12     Simple shell - (actually this is not even a shell)
13     It just to make the testing more easy.
14 */
15
16 #define WS_CHAR(c)                                                             \
17     (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == '\r')
18
19 void
20 strrtrim(char* str)
21 {
22     size_t l = strlen(str);
23     while (l < (size_t)-1) {
24         char c = str[l];
25         if (!c || WS_CHAR(c)) {
26             l--;
27             continue;
28         }
29         break;
30     }
31     str[l + 1] = '\0';
32 }
33
34 char*
35 strltrim_safe(char* str)
36 {
37     size_t l = 0;
38     char c = 0;
39     while ((c = str[l]) && WS_CHAR(c)) {
40         l++;
41     }
42
43     if (!l)
44         return str;
45     return strcpy(str, str + l);
46 }
47
48 void
49 parse_cmdline(char* line, char** cmd, char** arg_part)
50 {
51     strrtrim(line);
52     line = strltrim_safe(line);
53     int l = 0;
54     char c = 0;
55     while ((c = line[l])) {
56         if (c == ' ') {
57             line[l++] = 0;
58             break;
59         }
60         l++;
61     }
62     *cmd = line;
63     if (c) {
64         *arg_part = strltrim_safe(line + l);
65     } else {
66         *arg_part = NULL;
67     }
68 }
69
70 void
71 sh_printerr()
72 {
73     switch (errno) {
74         case 0:
75             break;
76         case ENOTDIR:
77             printf("Error: Not a directory\n");
78             break;
79         case ENOENT:
80             printf("Error: No such file or directory\n");
81             break;
82         case EINVAL:
83             printf("Error: Invalid parameter or operation\n");
84             break;
85         case ENOTSUP:
86             printf("Error: Not supported\n");
87             break;
88         case EROFS:
89             printf("Error: File system is read only\n");
90             break;
91         case ENOMEM:
92             printf("Error: Out of memory\n");
93             break;
94         case EISDIR:
95             printf("Error: This is a directory\n");
96             break;
97         default:
98             printf("Error: (%d)\n", errno);
99             break;
100     }
101 }
102
103 void
104 sigint_handle(int signum)
105 {
106     return;
107 }
108
109 void
110 sh_exec(const char* name, const char** argv)
111 {
112     if (!strcmp(name, "cd")) {
113         chdir(argv[0]);
114         sh_printerr();
115         return;
116     }
117
118     pid_t p;
119     if (!(p = fork())) {
120         if (execve(name, argv, NULL)) {
121             sh_printerr();
122         }
123         _exit(1);
124     }
125     setpgid(p, getpgid());
126     waitpid(p, NULL, 0);
127 }
128
129 void
130 sh_loop()
131 {
132     char buf[512];
133     char *cmd, *argpart;
134     signal(SIGINT, sigint_handle);
135
136     // set our shell as foreground process
137     // (unistd.h:tcsetpgrp is essentially a wrapper of this)
138     // stdout (by default, unless user did smth) is the tty we are currently at
139     ioctl(stdout, TIOCSPGRP, getpgid());
140
141     char* argv[] = { 0, 0 };
142
143     while (1) {
144         getcwd(pwd, 512);
145         printf("[\033[2m%s\033[39;49m]$ ", pwd);
146         size_t sz = read(stdin, buf, 511);
147
148         if (sz < 0) {
149             printf("fail to read user input (%d)\n", geterrno());
150             return;
151         }
152
153         buf[sz] = '\0';
154
155         // currently, this shell only support single argument
156         parse_cmdline(buf, &cmd, &argv[0]);
157
158         if (cmd[0] == 0) {
159             printf("\n");
160             goto cont;
161         }
162
163         // cmd=="exit"
164         if (*(unsigned int*)cmd == 0x74697865U) {
165             break;
166         }
167
168         sh_exec(cmd, (const char**)&argv);
169     cont:
170         printf("\n");
171     }
172 }
173
174 void
175 main()
176 {
177     printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
178     sh_loop();
179     _exit(0);
180 }