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/>.
22 FILE *terminal
= fopen("/dev/console","r+");
23 fprintf(terminal
,"sh: This command shell isn't used anymore.\n");
28 #include <sys/types.h>
35 #include <sys/utsname.h>
42 #include <readline/readline.h>
43 #include <readline/history.h>
47 int (*func
)(char **argv
);
48 } shell_builtin_cmd_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");
71 * Gets command from shell
72 * @return Command line
74 static char *shell_get_command() {
75 char *cwd
= getcwd(NULL
,0);
79 asprintf(&prompt
,"%s@%s:%s> ",passwd
!=NULL
?passwd
->pw_name
:"nobody",utsname
.nodename
,cwd
);
80 input
= readline(prompt
);
82 if (input
[0]!=0) add_history(input
);
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);
101 for (i
=0,j
=0;i
<len
;i
++,j
++) {
102 if (arg
[i
]=='\\' && i
+1<len
) { // escape code
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
115 int num
= strtoul(arg
+i
,&endp
,8);
118 i
+= (endp
-(arg
+i
))-1;
127 else new[j
] = arg
[i
];
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
) {
150 while (*cur
==' ') cur
++;
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
);
167 if (strcmp(argv
[argc
-1],"&")==0) {
173 argv
= realloc(argv
,(argc
+1)*sizeof(char*));
181 static int shell_builtin_exit(char **argv
) {
185 static int shell_builtin_help(char **argv
) {
186 printf("Built-in commands:\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");
195 static int shell_builtin_version(char **argv
) {
196 printf("%s %s\n",utsname
.sysname
,utsname
.version
);
200 static int shell_builtin_cd(char **argv
) {
202 if (chdir(argv
[1])==-1) fprintf(stderr
,"sh: cd: %s: %s\n",argv
[1],strerror(errno
));
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';
217 static char *ls_perm(mode_t mode
) {
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':'-');
223 static int shell_builtin_ls(char **argv
) {
224 char *path
= argv
[1]==NULL
?".":argv
[1];
226 DIR *dir
= opendir(path
);
228 struct dirent
*dirent
;
230 dirent
= readdir(dir
);
232 if (strcmp(dirent
->d_name
,".")!=0 && strcmp(dirent
->d_name
,"..")!=0) {
234 struct passwd
*owner
;
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
);
248 static int shell_builtin_pwd(char **argv
) {
249 char *cwd
= getcwd(NULL
,0);
255 static int shell_builtin_cls(char **argv
) {
256 fputs("\x1B[2J",stdout
);
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
}
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
);
280 static char *shell_find_path(char *cmd
) {
282 /// @todo read from PATH enviroment variable
283 asprintf(&path
,"/boot/bin/%s",cmd
);
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]);
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
);
303 llist_push(joblist
,job
);
304 printf("+[%d]\n",job
->pid
);
308 waitpid(job
->pid
,&status
,0);
313 if (status
!=0) fprintf(stderr
,"sh: %s: returned with %d\n",argv
[0],status
);
320 * Runs shell interactive
322 static void shell_interactive() {
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
]);
346 int main(int argc
,char *argv
[]) {
349 terminal_device
= "/dev/console";
351 while ((c
= getopt(argc
,argv
,":hvw:t:"))!=-1) {
357 terminal_device
= optarg
;
363 printf("sh v0.1\n(c) 2008 Janosch Graef\n");
367 fprintf(stderr
,"Unrecognized option: -%c\n", optopt
);
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
;
383 passwd
= getpwuid(getuid());