/*
* arch-tag: main
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "shell.h"
struct sh_command_t {
char* name;
int argc;
char* argv[SH_MAXARGS];
short flags;
char* stdin_filename;
char* stdout_filename;
};
void sh_print_prompt(void)
{
}
void sh_readline(char* buf)
{
fgets(buf
, SH_MAXLINELEN
, stdin
);
}
int sh_parseline(char* line, struct sh_command_t* command)
{
char** p;
int i, rdr_in_pos, rdr_out_pos;
command->flags = 0;
for(p = command->argv, command->argc = 0; (*p = (char*) strsep(&line, " \n\t")) != NULL; )
if (**p != '\0') { // Skip repeated spaces
// Don't process more than SH_MAXARGS args
if (p + 1 >= &(command->argv[SH_MAXARGS]))
break;
command->argc++;
p++;
}
for (i = 0, rdr_in_pos = 0, rdr_out_pos = 0;
i < command->argc;
i++) {
if (*(command->argv[i]) == '&') {
//printf("%d %s\n", i, *(command->argv + i));
if (!rdr_in_pos && !rdr_out_pos)
p = command->argv + i;
command->flags |= SH_CMD_BACKGROUND;
} else if (*(command->argv[i]) == '>') {
//printf("%d %s\n", i, *(command->argv + i));
if (!rdr_in_pos)
p = command->argv + i;
rdr_out_pos = i;
command->flags |= SH_CMD_REDIRECT_OUT;
command->stdout_filename = *(command->argv + i + 1);
} else if (*(command->argv[i]) == '<') {
//printf("%d %s\n", i, *(command->argv + i));
if (!rdr_out_pos)
p = command->argv + i;
rdr_in_pos = i;
command->flags |= SH_CMD_REDIRECT_IN;
command->stdin_filename = *(command->argv + i + 1);
}
}
*p = NULL;
command->argc = p - command->argv;
return command->argc;
}
int sh_getpathv(char** pathv)
{
int pathc;
char** p, *path;
// TODO: make a copy?
path
= (char*) getenv("PATH");
for(p = pathv, pathc = 0; (*p = (char*) strsep(&path, ":")) != NULL; )
if (**p != '\0') {
if (p + 1 >= &pathv[SH_MAXPATHS])
break;
pathc++;
p++;
}
return pathc;
}
int sh_check_exec(const char* fullpath)
{
// XXX possible race condition
return access(fullpath, X_OK);
}
char* sh_lookup_path(char* name, int pathc, char** pathv)
{
int i, fp_size, fd, path_len, last_sl_pos;
char* fullpath, *curr_dir, *ex_dir;
// TODO: check for absolute and relative paths
if (*name == '/') {
if (sh_check_exec(name) == 0)
return name;
else
return NULL;
}
// TODO: use realpath(3) instead.
if (*name == '.') { // Hack to do relative pathnames
if ((curr_dir = getcwd(NULL, 0)) == NULL) {
}
if ((ex_dir
= (char*) malloc(strlen(curr_dir
) + 1)) == NULL
) {
}
// locate the last '/'
for (i
= 0, path_len
= strlen(ex_dir
);
i < path_len;
i++) {
// printf("%c\n", ex_dir[i]);
if (ex_dir[i] == '/') {
last_sl_pos = i;
// printf("found '/' %d\n", i);
}
}
ex_dir[last_sl_pos] = 0;
name = name + last_sl_pos + 1;
if ((fd = open(ex_dir, O_RDONLY)) < 0) {
}
//printf("%d %s %s\n", last_sl_pos, ex_dir, name);
if (fchdir(fd) < 0) {
}
if ((ex_dir = getcwd(NULL, 0)) == NULL) {
}
if (chdir(curr_dir) < 0) {
}
if (asprintf(&fullpath, "%s/%s", ex_dir, name) < 0) {
}
// printf("%s\n", fullpath);
if (sh_check_exec(fullpath) == 0)
return fullpath;
else {
return NULL;
}
}
for (i = 0; i < pathc; i++) {
if ((fullpath
= (char*) malloc(fp_size
)) == NULL
) {
}
snprintf(fullpath
, fp_size
, "%s/%s", pathv
[i
], name
);
//printf("%s\n", fullpath);
if (sh_check_exec(fullpath) == 0)
return fullpath;
}
return NULL;
}
void sh_exec_child(struct sh_command_t* command)
{
int in_fd, out_fd;
if (command->flags & SH_CMD_REDIRECT_IN) {
// printf("redirecting stdin to %s\n", command->stdin_filename);
close(0);
if ((in_fd = open(command->stdin_filename, O_RDONLY)) < 0) {
}
}
if (command->flags & SH_CMD_REDIRECT_OUT) {
// printf("redirecting stdout to %s\n", command->stdout_filename);
close(1);
if ((out_fd = open(command->stdout_filename, O_WRONLY | O_CREAT)) < 0) {
}
if (fchmod(out_fd, 400) < 0) {
}
}
execv(command->name, command->argv);
}
int main(int argc, char** argv)
{
char* buf;
struct sh_command_t command;
char* pathv[SH_MAXPATHS];
int pathc;
pid_t pid;
pathc = sh_getpathv(pathv);
while(1) {
if ((buf
= (char*) malloc(SH_MAXLINELEN
)) == NULL
) {
}
sh_print_prompt();
sh_readline(buf);
if (sh_parseline(buf, &command) == 0)
goto done;
if ((command.name = sh_lookup_path(command.argv[0], pathc, pathv)) == NULL) {
printf("Command not found: %s\n", command.
argv[0]);
goto done;
}
if ((pid = fork()) == 0) {
sh_exec_child(&command);
}
if (!(command.flags & SH_CMD_BACKGROUND))
waitpid(pid, NULL, 0);
else
done:
}
}