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