+libm
[meinos.git] / apps / sh / main.c
blobde6455dab8cee0a7fb6ed9eb803c465eac298ddf
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <stdio.h>
21 int main() {
22 FILE *terminal = fopen("/dev/console","r+");
23 fprintf(terminal,"sh: This command shell isn't used anymore.\n");
24 return 0;
27 #if 0
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <sys/utsname.h>
36 #include <pwd.h>
37 #include <dirent.h>
38 #include <errno.h>
39 #include <llist.h>
40 #include <misc.h>
42 #include <readline/readline.h>
43 #include <readline/history.h>
45 typedef struct {
46 const char *cmd;
47 int (*func)(char **argv);
48 } shell_builtin_cmd_t;
50 typedef struct {
51 pid_t pid;
52 char *path;
53 char **argv;
54 char *stdin;
55 char *stdout;
56 char *stderr;
57 } shell_job_t;
59 static struct utsname utsname;
60 static struct passwd *passwd;
61 static llist_t joblist;
62 static char *terminal_device;
64 static void usage(char *cmd,int err) {
65 FILE *out = err?stderr:stdout;
66 fprintf(out,"Usage: %s\n");
67 exit(err);
70 /**
71 * Gets command from shell
72 * @return Command line
74 static char *shell_get_command() {
75 char *cwd = getcwd(NULL,0);
76 char *prompt;
77 char *input;
79 asprintf(&prompt,"%s@%s:%s> ",passwd!=NULL?passwd->pw_name:"nobody",utsname.nodename,cwd);
80 input = readline(prompt);
81 if (input!=NULL) {
82 if (input[0]!=0) add_history(input);
84 else return NULL;
86 free(prompt);
87 free(cwd);
88 return input;
91 /**
92 * Parses an command line argument
93 * @param arg Command line argument
94 * @param len Length of argument
95 * @return Parse arguments
97 static char *shell_parse_arg(char *arg,size_t len) {
98 char *new = malloc(len+1);
99 size_t i,j;
101 for (i=0,j=0;i<len;i++,j++) {
102 if (arg[i]=='\\' && i+1<len) { // escape code
103 i++;
104 if (arg[i]=='\\') new[j] = '\\'; // backslash
105 else if (arg[i]=='\"') new[j] = '\"'; // quotation mark
106 else if (arg[i]=='a') new[j] = '\a'; // alert
107 else if (arg[i]=='b') new[j] = '\b'; // backspace
108 else if (arg[i]=='f') new[j] = '\f'; // form feed
109 else if (arg[i]=='n') new[j] = '\n'; // new line
110 else if (arg[i]=='r') new[j] = '\r'; // carriage return
111 else if (arg[i]=='t') new[j] = '\t'; // horizontal tab
112 else if (arg[i]=='v') new[j] = '\v'; // vertical tab
113 else if (arg[i]=='0') { // character in octal
114 char *endp;
115 int num = strtoul(arg+i,&endp,8);
116 if (errno==0) {
117 new[j] = num;
118 i += (endp-(arg+i))-1;
120 else {
121 new[j] = arg[i];
122 perror("strtoul");
125 else new[j] = '\\';
127 else new[j] = arg[i];
130 new[j] = 0;
132 return new;
136 * Parses a command line string
137 * @param cmd Command line string
138 * @return Argument vector
140 static char **shell_parse_cmd(char *cmd,int *background) {
141 int quote = 0;
142 char *cur = cmd;
143 char *next;
144 char **argv = NULL;
145 int argc = 0;
146 *background = 0;
148 do {
149 // skip spaces
150 while (*cur==' ') cur++;
151 if (*cur==0) break;
153 // find next space (or quotation mark)
154 next = strchr(cur,quote?'\"':' ');
155 if (next==NULL) next = cmd+strlen(cmd);
157 // if next character is a quotation mark, activate qoutation mode
158 //if (*next=='\"') qoute = 1;
160 // add current to argv
161 argv = realloc(argv,(argc+1)*sizeof(char*));
162 argv[argc++] = shell_parse_arg(cur,next-cur);
163 cur = next+1;
164 } while (*next!=0);
166 if (argc>0) {
167 if (strcmp(argv[argc-1],"&")==0) {
168 *background = 1;
169 argc--;
170 argv[argc] = NULL;
172 else {
173 argv = realloc(argv,(argc+1)*sizeof(char*));
174 argv[argc] = NULL;
176 return argv;
178 else return NULL;
181 static int shell_builtin_exit(char **argv) {
182 return 1;
185 static int shell_builtin_help(char **argv) {
186 printf("Built-in commands:\n"
187 " exit Exit shell\n"
188 " cd DIR Change working directory to DIR\n"
189 " ls [DIR] List content of DIR\n"
190 " help Show this help dialog\n"
191 " version Show version\n");
192 return 0;
195 static int shell_builtin_version(char **argv) {
196 printf("%s %s\n",utsname.sysname,utsname.version);
197 return 0;
200 static int shell_builtin_cd(char **argv) {
201 if (argv[1]!=NULL) {
202 if (chdir(argv[1])==-1) fprintf(stderr,"sh: cd: %s: %s\n",argv[1],strerror(errno));
204 return 0;
207 static char ls_filetype(mode_t mode) {
208 if (S_ISBLK(mode)) return 'b';
209 else if (S_ISCHR(mode)) return 'c';
210 else if (S_ISDIR(mode)) return 'd';
211 else if (S_ISFIFO(mode)) return 'f';
212 else if (S_ISLNK(mode)) return 'l';
213 else if (S_ISSOCK(mode)) return 's';
214 else return '-';
217 static char *ls_perm(mode_t mode) {
218 static char buf[10];
219 snprintf(buf,10,"%c%c%c%c%c%c%c%c%c",mode&S_IRUSR?'r':'-',mode&S_IWUSR?'w':'-',mode&S_IXUSR?'x':'-',mode&S_IRGRP?'r':'-',mode&S_IWGRP?'w':'-',mode&S_IXGRP?'x':'-',mode&S_IROTH?'r':'-',mode&S_IWOTH?'w':'-',mode&S_IXOTH?'x':'-');
220 return buf;
223 static int shell_builtin_ls(char **argv) {
224 char *path = argv[1]==NULL?".":argv[1];
226 DIR *dir = opendir(path);
227 if (dir!=NULL) {
228 struct dirent *dirent;
229 do {
230 dirent = readdir(dir);
231 if (dirent!=NULL) {
232 if (strcmp(dirent->d_name,".")!=0 && strcmp(dirent->d_name,"..")!=0) {
233 struct stat stbuf;
234 struct passwd *owner;
235 char *file;
236 asprintf(&file,"%s/%s",path,dirent->d_name);
237 if (stat(file,&stbuf)==-1) printf("Error (%d): %s\n",errno,strerror(errno));
238 owner = getpwuid(stbuf.st_uid);
239 printf("%c%s %s % 5d %s\n",ls_filetype(stbuf.st_mode),ls_perm(stbuf.st_mode),owner!=NULL?owner->pw_name:"root",stbuf.st_size,dirent->d_name);
242 } while (dirent!=NULL);
243 return 0;
245 else return 1;
248 static int shell_builtin_pwd(char **argv) {
249 char *cwd = getcwd(NULL,0);
250 puts(cwd);
251 free(cwd);
252 return 0;
255 static int shell_builtin_cls(char **argv) {
256 fputs("\x1B[2J",stdout);
257 return 0;
260 static int shell_run_builtin(char **argv) {
261 shell_builtin_cmd_t shell_builtin_cmds[] = {
262 { .cmd = "exit", .func = shell_builtin_exit },
263 { .cmd = "logout", .func = shell_builtin_exit },
264 { .cmd = "help", .func = shell_builtin_help },
265 { .cmd = "version", .func = shell_builtin_version },
266 { .cmd = "cd", .func = shell_builtin_cd },
267 { .cmd = "ls", .func = shell_builtin_ls },
268 { .cmd = "pwd", .func = shell_builtin_pwd },
269 { .cmd = "cls", .func = shell_builtin_cls }
271 size_t i;
273 for (i=0;i<sizeof(shell_builtin_cmds)/sizeof(shell_builtin_cmd_t);i++) {
274 if (strcmp(argv[0],shell_builtin_cmds[i].cmd)==0) return shell_builtin_cmds[i].func(argv);
277 return -1;
280 static char *shell_find_path(char *cmd) {
281 char *path;
282 /// @todo read from PATH enviroment variable
283 asprintf(&path,"/boot/bin/%s",cmd);
284 return path;
287 static int shell_run_binary(char **argv,int background) {
288 shell_job_t *job = malloc(sizeof(shell_job_t));
289 job->path = shell_find_path(argv[0]);
290 job->argv = argv;
291 job->stdin = terminal_device;
292 job->stdout = terminal_device;
293 job->stderr = terminal_device;
294 job->pid = execute(job->path,argv,job->stdin,job->stdout,job->stderr);
296 if (job->pid==-1) {
297 free(job->path);
298 free(job);
299 return -1;
302 if (background) {
303 llist_push(joblist,job);
304 printf("+[%d]\n",job->pid);
306 else {
307 int status;
308 waitpid(job->pid,&status,0);
310 free(job->path);
311 free(job);
313 if (status!=0) fprintf(stderr,"sh: %s: returned with %d\n",argv[0],status);
316 return 0;
320 * Runs shell interactive
322 static void shell_interactive() {
323 int status = 0;
325 while (status!=1) {
326 size_t i;
327 char **argv;
328 char *cmd;
329 int background = 0;
331 if ((cmd = shell_get_command())==NULL) break;
333 if ((argv = shell_parse_cmd(cmd,&background))!=NULL) {
334 if ((status = shell_run_builtin(argv))==-1) {
335 if (shell_run_binary(argv,background)==-1) fprintf(stderr,"sh: %s: command not found\n",argv[0]);
338 for (i=0;argv[i];i++) free(argv[i]);
339 free(argv);
342 free(cmd);
346 int main(int argc,char *argv[]) {
347 int c;
349 terminal_device = "/dev/console";
351 while ((c = getopt(argc,argv,":hvw:t:"))!=-1) {
352 switch(c) {
353 case 'w':
354 chdir(optarg);
355 break;
356 case 't':
357 terminal_device = optarg;
358 break;
359 case 'h':
360 usage(argv[0],0);
361 break;
362 case 'v':
363 printf("sh v0.1\n(c) 2008 Janosch Graef\n");
364 return 0;
365 break;
366 case '?':
367 fprintf(stderr,"Unrecognized option: -%c\n", optopt);
368 usage(argv[0],1);
369 break;
373 FILE *terminal = fopen(terminal_device,"r+");
374 if (terminal==NULL) return 1;
375 FILE *stdin_bak = stdin;
376 FILE *stdout_bak = stdout;
377 FILE *stderr_bak = stderr;
378 stdin = terminal;
379 stdout = terminal;
380 stderr = terminal;
382 uname(&utsname);
383 passwd = getpwuid(getuid());
384 shell_interactive();
386 stdin = stdin_bak;
387 stdout = stdout_bak;
388 stderr = stderr_bak;
389 fclose(terminal);
391 return 0;
393 #endif