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