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 <sys/types.h>
26 #include <sys/utsname.h>
33 #include <readline/readline.h>
34 #include <readline/history.h>
36 #define TERMINAL_DEVICE "/dev/console"
40 int (*func
)(char **argv
);
41 } shell_builtin_cmd_t
;
52 struct utsname utsname
;
53 struct passwd
*passwd
;
56 static void usage(char *cmd
,int err
) {
57 FILE *out
= err
?stderr
:stdout
;
58 fprintf(out
,"Usage: %s\n");
63 * Gets command from shell
64 * @return Command line
66 static char *shell_get_command() {
67 char *cwd
= getcwd(NULL
,0);
71 asprintf(&prompt
,"%s@%s:%s> ",passwd
!=NULL
?passwd
->pw_name
:"nobody",utsname
.nodename
,cwd
);
72 input
= readline(prompt
);
74 if (input
[0]!=0) add_history(input
);
84 * Converts a string with an octal number to an integer
85 * @param string String holding octal number
86 * @return String as integer
88 static int octal2num(char *str
) {
92 int num
= strtoul(buf
,NULL
,8);
97 * Parses an command line argument
98 * @param arg Command line argument
99 * @param len Length of argument
100 * @return Parse arguments
102 static char *shell_parse_arg(char *arg
,size_t len
) {
103 char *new = malloc(len
+1);
106 for (i
=0,j
=0;i
<len
;i
++,j
++) {
107 if (arg
[i
]=='\\' && i
+1<len
) { // escape code
109 if (arg
[i
]=='\\') new[j
] = '\\'; // backslash
110 else if (arg
[i
]=='\"') new[j
] = '\"'; // quotation mark
111 else if (arg
[i
]=='a') new[j
] = '\a'; // alert
112 else if (arg
[i
]=='b') new[j
] = '\b'; // backspace
113 else if (arg
[i
]=='f') new[j
] = '\f'; // form feed
114 else if (arg
[i
]=='n') new[j
] = '\n'; // new line
115 else if (arg
[i
]=='r') new[j
] = '\r'; // carriage return
116 else if (arg
[i
]=='t') new[j
] = '\t'; // horizontal tab
117 else if (arg
[i
]=='v') new[j
] = '\v'; // vertical tab
118 else if (arg
[i
]=='0' && arg
[i
+1]!=0 && arg
[i
+2]!=0 && arg
[i
+3]!=0) {
119 // character in octal
120 new[j
] = octal2num(arg
+i
+1);
123 else new[j
] = arg
[i
];
132 * Parses a command line string
133 * @param cmd Command line string
134 * @return Argument vector
136 static char **shell_parse_cmd(char *cmd
) {
145 while (*cur
==' ') cur
++;
148 // find next space (or quotation mark)
149 next
= strchr(cur
,quote
?'\"':' ');
150 if (next
==NULL
) next
= cmd
+strlen(cmd
);
152 // if next character is a quotation mark, activate qoutation mode
153 //if (*next=='\"') qoute = 1;
155 // add current to argv
156 argv
= realloc(argv
,(argc
+1)*sizeof(char*));
157 argv
[argc
++] = shell_parse_arg(cur
,next
-cur
);
162 argv
= realloc(argv
,(argc
+1)*sizeof(char*));
169 static int shell_builtin_exit(char **argv
) {
173 static int shell_builtin_help(char **argv
) {
174 printf("Built-in commands:\n"
176 " cd DIR Change working directory to DIR\n"
177 " ls [DIR] List content of DIR\n"
178 " help Show this help dialog\n"
179 " version Show version\n");
183 static int shell_builtin_version(char **argv
) {
184 printf("%s %s\n",utsname
.sysname
,utsname
.version
);
188 static int shell_builtin_cd(char **argv
) {
190 if (chdir(argv
[1])==-1) fprintf(stderr
,"sh: cd: %s: %s\n",argv
[1],strerror(errno
));
195 static char ls_filetype(mode_t mode
) {
196 if (S_ISBLK(mode
)) return 'b';
197 else if (S_ISCHR(mode
)) return 'c';
198 else if (S_ISDIR(mode
)) return 'd';
199 else if (S_ISFIFO(mode
)) return 'f';
200 else if (S_ISLNK(mode
)) return 'l';
201 else if (S_ISSOCK(mode
)) return 's';
205 static char *ls_perm(mode_t mode
) {
207 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':'-');
211 static int shell_builtin_ls(char **argv
) {
212 char *path
= argv
[1]==NULL
?".":argv
[1];
214 DIR *dir
= opendir(path
);
216 struct dirent
*dirent
;
218 dirent
= readdir(dir
);
220 if (strcmp(dirent
->d_name
,".")!=0 && strcmp(dirent
->d_name
,"..")!=0) {
222 struct passwd
*owner
;
224 asprintf(&file
,"%s/%s",path
,dirent
->d_name
);
225 if (stat(file
,&stbuf
)==-1) printf("Error (%d): %s\n",errno
,strerror(errno
));
226 owner
= getpwuid(stbuf
.st_uid
);
227 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
);
230 } while (dirent
!=NULL
);
236 int shell_builtin_cat(char **argv
) {
239 if (argv
[1]==NULL
) in
= stdin
;
241 in
= fopen(argv
[1],"r");
242 if (in
==NULL
) return 1;
247 size_t size
= fread(buf
,1,512,in
);
248 fwrite(buf
,1,size
,stdout
);
254 /*int shell_builtin_echo(char **argv) {
256 for (i=1;argv[i]!=NULL;i++) printf("%s%s",argv[i],argv[i+1]!=NULL?" ":"");
261 int shell_builtin_test(char **argv
) {
265 printf("Creating FIFO...\n");
266 mknod("foobar",S_IFIFO
|0755,0);
268 printf("Opening end A (w)...\n");
269 FILE *enda
= fopen("foobar","w");
270 if (enda
==NULL
) return 1;
272 printf("Opening end B (r)...\n");
273 FILE *endb
= fopen("foobar","r");
274 if (endb
==NULL
) return 1;
276 printf("Opening end C (r)...\n");
277 FILE *endc
= fopen("foobar","r");
278 if (endc
==NULL
) return 1;
280 printf("Opening end D (w)...\n");
281 FILE *endd
= fopen("foobar","w");
282 if (endd
==NULL
) return 1;
284 printf("Writing to A...\n");
285 n
= fputs("Hello World\n",enda
);
287 printf("Written %d bytes\n",n
);
289 printf("Reading from B...\n");
290 if (fgets(buf
,32,endb
)==NULL
) return 1;
291 printf("\"%s\"\n",buf
);
293 printf("Reading from C...\n");
294 if (fgets(buf
,32,endc
)==NULL
) return 1;
295 printf("\"%s\"\n",buf
);
297 printf("Writing to D...\n");
298 n
= fputs("Hallo Welt\n",endd
);
300 printf("Written %d bytes\n",n
);
302 printf("Reading from B...\n");
303 if (fgets(buf
,32,endb
)==NULL
) return 1;
304 printf("\"%s\"\n",buf
);
306 printf("Reading from C...\n");
307 if (fgets(buf
,32,endc
)==NULL
) return 1;
308 printf("\"%s\"\n",buf
);
313 /// @todo Sourcecode von utils/echo.c cat.c (und ls.c) hierher und main() in shell_builtin_* umbennen.
314 static int shell_run_builtin(char **argv
) {
315 shell_builtin_cmd_t shell_builtin_cmds
[] = {
316 { .cmd
= "exit", .func
= shell_builtin_exit
},
317 { .cmd
= "help", .func
= shell_builtin_help
},
318 { .cmd
= "version", .func
= shell_builtin_version
},
319 { .cmd
= "cd", .func
= shell_builtin_cd
},
320 { .cmd
= "ls", .func
= shell_builtin_ls
},
321 { .cmd
= "cat", .func
= shell_builtin_cat
},
322 //{ .cmd = "echo", .func = shell_builtin_echo },
323 { .cmd
= "test", .func
= shell_builtin_test
}
327 for (i
=0;i
<sizeof(shell_builtin_cmds
)/sizeof(shell_builtin_cmd_t
);i
++) {
328 if (strcmp(argv
[0],shell_builtin_cmds
[i
].cmd
)==0) return shell_builtin_cmds
[i
].func(argv
);
334 static char *shell_find_path(char *cmd
) {
336 /// @todo read from PATH enviroment variable
337 asprintf(&path
,"/boot/bin/%s",cmd
);
341 static int shell_run_binary(char **argv
,int background
) {
342 shell_job_t
*job
= malloc(sizeof(shell_job_t
));
343 job
->path
= shell_find_path(argv
[0]);
345 job
->stdin
= TERMINAL_DEVICE
;
346 job
->stdout
= TERMINAL_DEVICE
;
347 job
->stderr
= TERMINAL_DEVICE
;
348 job
->pid
= execute(job
->path
,argv
,job
->stdin
,job
->stdout
,job
->stderr
);
357 llist_push(joblist
,job
);
358 printf("+[%d]\n",job
->pid
);
362 waitpid(job
->pid
,&status
,0);
367 if (status
!=0) fprintf(stderr
,"sh: %s: returned with %d\n",argv
[0],status
);
374 * Runs shell interactive
376 static void shell_interactive() {
384 if ((cmd
= shell_get_command())==NULL
) break;
386 if ((argv
= shell_parse_cmd(cmd
))!=NULL
) {
387 if ((status
= shell_run_builtin(argv
))==-1) {
388 if (shell_run_binary(argv
,0)==-1) fprintf(stderr
,"sh: %s: command not found\n",argv
[0]);
391 for (i
=0;argv
[i
];i
++) free(argv
[i
]);
399 int main(int argc
,char *argv
[]) {
402 FILE *terminal
= fopen(TERMINAL_DEVICE
,"r+");
403 if (terminal
==NULL
) return 1;
405 FILE *stdin_bak
= stdin
;
406 FILE *stdout_bak
= stdout
;
407 FILE *stderr_bak
= stderr
;
412 while ((c
= getopt(argc
,argv
,":hv"))!=-1) {
418 printf("sh v0.1\n(c) 2008 Janosch Graef\n");
422 fprintf(stderr
,"Unrecognized option: -%c\n", optopt
);
429 passwd
= getpwuid(getuid());