refactor: separate syscall interfaces from kernel space, into posix compliant structure.
[lunaix-os.git] / lunaix-os / kernel / demos / simple_sh.c
1 #include <lunaix/ioctl.h>
2 #include <lunaix/status.h>
3
4 #include <usr/fcntl.h>
5 #include <usr/signal.h>
6 #include <usr/sys/dirent.h>
7 #include <usr/sys/lunaix.h>
8 #include <usr/sys/mann.h>
9 #include <usr/unistd.h>
10
11 #include <klibc/string.h>
12 #include <ulibc/stdio.h>
13
14 char pwd[512];
15 char cat_buf[1024];
16
17 /*
18     Simple shell - (actually this is not even a shell)
19     It just to make the testing more easy.
20 */
21
22 void
23 parse_cmdline(char* line, char** cmd, char** arg_part)
24 {
25     strrtrim(line);
26     line = strltrim_safe(line);
27     int l = 0;
28     char c = 0;
29     while ((c = line[l])) {
30         if (c == ' ') {
31             line[l++] = 0;
32             break;
33         }
34         l++;
35     }
36     *cmd = line;
37     *arg_part = strltrim_safe(line + l);
38 }
39
40 void
41 sh_printerr()
42 {
43     int errno = geterrno();
44     switch (errno) {
45         case ENOTDIR:
46             printf("Error: Not a directory\n");
47             break;
48         case ENOENT:
49             printf("Error: No such file or directory\n");
50             break;
51         case EINVAL:
52             printf("Error: Invalid parameter or operation\n");
53             break;
54         case ENOTSUP:
55             printf("Error: Not supported\n");
56             break;
57         case EROFS:
58             printf("Error: File system is read only\n");
59             break;
60         case ENOMEM:
61             printf("Error: Out of memory\n");
62             break;
63         case EISDIR:
64             printf("Error: This is a directory\n");
65             break;
66         default:
67             printf("Error: (%d)\n", errno);
68             break;
69     }
70 }
71
72 void
73 sigint_handle(int signum)
74 {
75     return;
76 }
77
78 void
79 do_cat(const char* file)
80 {
81     int fd = open(file, 0);
82     if (fd < 0) {
83         sh_printerr();
84     } else {
85         int sz;
86         while ((sz = read(fd, cat_buf, 1024)) > 0) {
87             write(stdout, cat_buf, sz);
88         }
89         if (sz < 0) {
90             sh_printerr();
91         }
92         close(fd);
93         printf("\n");
94     }
95 }
96
97 void
98 do_ls(const char* path)
99 {
100     int fd = open(path, 0);
101     if (fd < 0) {
102         sh_printerr();
103     } else {
104         struct lx_dirent ent = { .d_offset = 0 };
105         int status;
106         while ((status = sys_readdir(fd, &ent)) == 1) {
107             if (ent.d_type == DT_DIR) {
108                 printf(" \033[3m%s\033[39;49m\n", ent.d_name);
109             } else {
110                 printf(" %s\n", ent.d_name);
111             }
112         }
113
114         if (status < 0)
115             sh_printerr();
116
117         close(fd);
118     }
119 }
120
121 void
122 do_mcat(const char* file)
123 {
124     int fd = open(file, 0);
125     if (fd < 0) {
126         sh_printerr();
127     } else {
128         void* p = mmap(NULL, 2048, 0, 0, fd, 0);
129         if ((int)p < 0) {
130             sh_printerr();
131         } else {
132             printf("%s\n", p);
133         }
134         munmap(p, 1);
135         close(fd);
136         printf("\n");
137     }
138 }
139
140 void
141 sh_loop()
142 {
143     char buf[512];
144     char *cmd, *argpart;
145     pid_t p;
146     signal(SIGINT, sigint_handle);
147
148     // set our shell as foreground process
149     // (unistd.h:tcsetpgrp is essentially a wrapper of this)
150     // stdout (by default, unless user did smth) is the tty we are currently at
151     ioctl(stdout, TIOCSPGRP, getpgid());
152
153     while (1) {
154         getcwd(pwd, 512);
155         printf("[\033[2m%s\033[39;49m]$ ", pwd);
156         size_t sz = read(stdin, buf, 511);
157         if (sz < 0) {
158             printf("fail to read user input (%d)\n", geterrno());
159             return;
160         }
161         buf[sz] = '\0';
162         parse_cmdline(buf, &cmd, &argpart);
163         if (cmd[0] == 0) {
164             printf("\n");
165             goto cont;
166         }
167         if (streq(cmd, "cd")) {
168             if (chdir(argpart) < 0) {
169                 sh_printerr();
170             }
171             goto cont;
172         } else if (streq(cmd, "clear")) {
173             ioctl(stdout, TIOCCLSBUF);
174             goto cont;
175         } else if (streq(cmd, "ls")) {
176             if (!(p = fork())) {
177                 do_ls(argpart);
178                 _exit(0);
179             }
180         } else if (streq(cmd, "cat")) {
181             if (!(p = fork())) {
182                 do_cat(argpart);
183                 _exit(0);
184             }
185         } else if (streq(cmd, "mcat")) {
186             if (!(p = fork())) {
187                 do_mcat(argpart);
188                 _exit(0);
189             }
190         } else {
191             printf("unknow command\n");
192             goto cont;
193         }
194         setpgid(p, getpgid());
195         waitpid(p, NULL, 0);
196     cont:
197         printf("\n");
198     }
199 }
200
201 void
202 sh_main()
203 {
204     printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
205     if (!fork()) {
206         sh_loop();
207         _exit(0);
208     }
209     wait(NULL);
210 }