aboutsummaryrefslogtreecommitdiff
path: root/smash/exec.c
blob: 11620a552a15e0afd410ddecd481b25a64c711e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "exec.h"

#include "../lib/sys/execve.h"
#include "../lib/sys/fork.h"
#include "../lib/sys/wait4.h"
#include "../lib/sys/pipe.h"
#include "../lib/sys/dup2.h"
#include "../lib/sys/close.h"
#include "../lib/sys/exit.h"
#include "../lib/cstr/cstr.h"
#include "../lib/io/io.h"
#include "../lib/env/env.h"
#include "../lib/malloc/malloc.h"

#include "parser.h"
#include "builtin.h"

void print_call(char **argv)
{
	while (*argv) {
		write(STDOUT_FD, *argv, cstr_length(*argv));
		write(STDOUT_FD, "\n", 1);
		++argv;
	}
}

void __execenv(const char **argv)
{
	const char *path = getenv("PATH");
	const char *end;
	char *filename;

	while (*path) {
		end = path;

		while (*end && *end != ':') ++end;

		filename = malloc((end - path) + cstr_length(argv[0]) + 2);

		for (int i = 0; i < end - path; ++i)
			filename[i] = path[i];

		filename[end - path] = '/';

		for (int i = 0; i < cstr_length(argv[0]) + 1; ++i)
			filename[(end - path) + i + 1] = argv[0][i];

		execve(filename, argv, getenvp());
		free(filename);

		path = end;

		if (*path == ':')
			++path;
	}

	execve(argv[0], argv, getenvp());
}

void exec(char *line)
{
	expression_list_t *exps = new_expression_from_line(line);
	expression_list_t *exp = exps;

	int pid;
	int pipefd[2][2];
	pipefd[0][PIPE_IN] = STDOUT_FD;
	pipefd[0][PIPE_OUT] = STDIN_FD;

	while (exp) {
		char **argv = new_argv(exp->call);

		pipe(pipefd[1]);

		if (has_builtin_with_name(argv[0])) {
			run_builtin(argv[0], (const char**)argv);
			break;
		}

		pid = fork();

		if (pid == 0) {
			if (pipefd[0][PIPE_OUT] != STDIN_FD) {
				dup2(pipefd[0][PIPE_OUT], STDIN_FD);
				close(pipefd[0][PIPE_OUT]);
				close(pipefd[0][PIPE_IN]);
			}
			if (exp->next)
				dup2(pipefd[1][PIPE_IN], STDOUT_FD);

			close(pipefd[1][PIPE_OUT]);
			close(pipefd[1][PIPE_IN]);

			__execenv(argv);
			wstdf("command not found: %s\n", argv[0]);
			exit(-1);
		}

		if (pipefd[0][PIPE_OUT] != STDIN_FD) {
			close(pipefd[0][PIPE_IN]);
			close(pipefd[0][PIPE_OUT]);
		}
		close(pipefd[1][PIPE_IN]);

		pipefd[0][0] = pipefd[1][0];
		pipefd[0][1] = pipefd[1][1];

		free_argv(argv);

		wait4(pid, 0, 0);
		exp = exp->next;
	}

	free_expression(exps);
}

#ifdef EXEC_UNIT_TEST

int main() {
	char *argv[] = { "ls" };
	__execenv(argv);
}

#endif