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>
25 #include <sys/utsname.h>
30 #include <readline/readline.h>
31 #include <readline/history.h>
33 #define TERMINAL_DEVICE "/dev/console"
37 int (*func
)(char **argv
);
38 } shell_builtin_cmd_t
;
49 struct utsname utsname
;
50 struct passwd
*passwd
;
52 static void usage(char *cmd
,int err
) {
53 FILE *out
= err
?stderr
:stdout
;
54 fprintf(out
,"Usage: %s\n");
58 * Gets command from shell
59 * @return Command line
61 static char *shell_get_command() {
62 char *cwd
= getcwd(NULL
,0);
66 asprintf(&prompt
,"%s@%s:%s> ",passwd
!=NULL
?passwd
->pw_name
:"nobody",utsname
.nodename
,cwd
);
67 input
= readline(prompt
);
68 if (input
&& input
[0]!=0) add_history(input
);
77 * Converts a string with an octal number to an integer
78 * @param string String holding octal number
79 * @return String as integer
81 static int octal2num(char *str
) {
85 int num
= strtoul(buf
,NULL
,8);
90 * Parses an command line argument
91 * @param arg Command line argument
92 * @param len Length of argument
93 * @return Parse arguments
95 static char *shell_parse_arg(char *arg
,size_t len
) {
96 char *new = malloc(len
+1);
99 for (i
=0,j
=0;i
<len
;i
++,j
++) {
100 if (arg
[i
]=='\\' && i
+1<len
) { // escape code
102 if (arg
[i
]=='\\') new[j
] = '\\'; // backslash
103 else if (arg
[i
]=='\"') new[j
] = '\"'; // quotation mark
104 else if (arg
[i
]=='a') new[j
] = '\a'; // alert
105 else if (arg
[i
]=='b') new[j
] = '\b'; // backspace
106 else if (arg
[i
]=='f') new[j
] = '\f'; // form feed
107 else if (arg
[i
]=='n') new[j
] = '\n'; // new line
108 else if (arg
[i
]=='r') new[j
] = '\r'; // carriage return
109 else if (arg
[i
]=='t') new[j
] = '\t'; // horizontal tab
110 else if (arg
[i
]=='v') new[j
] = '\v'; // vertical tab
111 else if (arg
[i
]=='0' && arg
[i
+1]!=0 && arg
[i
+2]!=0 && arg
[i
+3]!=0) {
112 // character in octal
113 new[j
] = octal2num(arg
+i
+1);
116 else new[j
] = arg
[i
];
125 * Parses a command line string
126 * @param cmd Command line string
127 * @return Argument vector
129 static char **shell_parse_cmd(char *cmd
) {
136 // skip beginning spaces
137 while (*cur
==' ') cur
++;
140 // find next space (or quotation mark)
141 next
= strchr(cur
,quote
?'\"':' ');
142 if (next
==NULL
) next
= cmd
+strlen(cmd
);
143 // if next character is a quotation mark, activate qoute mode
144 //if (*next=='\"') mode = 1;
147 //while (*next==' ') next++;
149 // add current to argv
150 argv
= realloc(argv
,(argc
+1)*sizeof(char*));
151 argv
[argc
++] = shell_parse_arg(cur
,next
-cur
);
155 argv
= realloc(argv
,(argc
+1)*sizeof(char*));
161 static int shell_builtin_exit(char **argv
) {
165 static int shell_builtin_cd(char **argv
) {
167 if (chdir(argv
[1])==-1) fprintf(stderr
,"sh: cd: %s: %s\n",argv
[1],strerror(errno
));
172 static int shell_builtin_help(char **argv
) {
173 printf("Built-in commands:\n"
175 " cd DIR Change working directory to DIR\n"
176 " help Show this help dialog\n"
177 " version Show version\n");
181 static int shell_builtin_version(char **argv
) {
182 printf("%s %s\n",utsname
.sysname
,utsname
.version
);
186 static int shell_run_builtin(char **argv
) {
187 shell_builtin_cmd_t shell_builtin_cmds
[] = {
188 { .cmd
= "exit", .func
= shell_builtin_exit
},
189 { .cmd
= "cd", .func
= shell_builtin_cd
},
190 { .cmd
= "help", .func
= shell_builtin_help
},
191 { .cmd
= "version", .func
= shell_builtin_version
}
195 for (i
=0;i
<sizeof(shell_builtin_cmds
)/sizeof(shell_builtin_cmd_t
);i
++) {
196 if (strcmp(argv
[0],shell_builtin_cmds
[i
].cmd
)==0) return shell_builtin_cmds
[i
].func(argv
);
202 static char *shell_find_path(char *cmd
) {
204 /// @todo read from PATH enviroment variable
205 asprintf(&path
,"/boot/bin/%s",cmd
);
209 static int shell_run_binary(char **argv
,int background
) {
210 shell_proc_t
*proc
= malloc(sizeof(shell_proc_t
));
211 proc
->path
= shell_find_path(argv
[0]);
213 proc
->pid
= execute(proc
->path
,argv
,&(proc
->stdin
),&(proc
->stdout
),&(proc
->stderr
));
226 waitpid(proc
->pid
,&status
,0);
234 if (status
!=0) fprintf(stderr
,"sh: %s: returned with %d\n",argv
[0],status
);
241 * Runs shell interactive
243 static void shell_interactive() {
249 char *cmd
= shell_get_command();
251 if (cmd
==NULL
) break;
252 argv
= shell_parse_cmd(cmd
);
254 if ((status
= shell_run_builtin(argv
))==-1) {
255 if (shell_run_binary(argv
,0)==-1) fprintf(stderr
,"sh: %s: command not found\n",argv
[0]);
259 for (i
=0;argv
[i
];i
++) free(argv
[i
]);
264 int main(int argc
,char *argv
[]) {
267 FILE *terminal
= fopen(TERMINAL_DEVICE
,"r+");
268 if (terminal
==NULL
) return 1;
269 FILE *stdin_bak
= stdin
;
270 FILE *stdout_bak
= stdout
;
271 FILE *stderr_bak
= stderr
;
276 while ((c
= getopt(argc
,argv
,":hv"))!=-1) {
282 printf("sh v0.1\n(c) 2008 Janosch Graef\n");
286 fprintf(stderr
,"Unrecognized option: -%c\n", optopt
);
293 passwd
= getpwuid(getuid());