matrix now sets up default PATH
[akaros.git] / user / apps / parlib / run_binary.c
1 #include <assert.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/wait.h>
7 #include <fcntl.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <parlib.h>
12 #include <newlib_backend.h>
13
14 int shell_exec(const char* cmdline)
15 {
16         #define MY_MAX_ARGV 16
17         char* argv[MY_MAX_ARGV+1] = {0};
18         char* p0 = strdup(cmdline);
19         char* p = p0;
20         for(int i = 0; i < MY_MAX_ARGV; i++)
21         {
22                 argv[i] = p;
23                 p = strchr(p,' ');
24                 if(p)
25                         *p++ = 0;
26                 else
27                         break;
28         }
29
30         int ret = fork();
31         if(ret == 0)
32         {
33                 char** envp = environ;
34                 const char* path = NULL;
35                 int nenv;
36                 for(nenv = 0; environ[nenv]; nenv++)
37                         if(strncmp(environ[nenv],"PATH=",5) == 0)
38                                 path = environ[nenv]+5;
39                 assert(path);
40
41                 char* fn = NULL, *buf = NULL;
42                 if(strchr(argv[0],'/'))
43                 {
44                         if(access(argv[0],X_OK) == 0)
45                                 fn = argv[0];
46                 }
47                 else
48                 {
49                         buf = (char*)malloc(sizeof(char)*(strlen(argv[0])+strlen(path)+2));
50                         while(fn == NULL)
51                         {
52                                 const char* end = strchr(path,':');
53                                 int len = end ? end-path : strlen(path);
54                                 memcpy(buf,path,len);
55                                 if(len && buf[len-1] != '/')
56                                         buf[len++] = '/';
57                                 strcpy(buf+len,argv[0]);
58
59                                 if(access(buf,X_OK) == 0)
60                                         fn = buf;
61                                 if(end == NULL)
62                                         break;
63                                 path = end+1;
64                         }
65                 }
66
67                 if(fn == NULL)
68                 {
69                         printf("%s: not found\n",argv[0]);
70                         exit(1);
71                 }
72
73                 execve(fn,argv,envp);
74                 free(buf);
75                 perror("execvp");
76                 exit(1);
77         }
78         else if(ret > 0)
79         {
80                 int status;
81                 if(wait(&status))
82                         perror("wait");
83                 else
84                         debug_in_out("%s returned %d\n",argv[0],status);
85         }
86         else
87                 perror("fork");
88
89         free(p0);
90         return 0;
91 }
92
93 extern char * readline(const char *prompt);
94
95 #define MALLOC_SIZE     1048576
96 #define READ_SIZE       1024
97
98 int run_binary_filename(const char* cmdline, size_t colors)
99 {
100         int ret = 0;
101
102         const char* cmdptr = cmdline;
103         char argv_buf[PROCINFO_MAX_ARGV_SIZE] = {0};
104         intreg_t* argv = (intreg_t*)argv_buf;
105         argv[0] = 0;
106         int argc;
107         for(argc = 0; ; argc++)
108         {
109                 while(*cmdptr == ' ')
110                         cmdptr++;
111                 if(*cmdptr == 0)
112                         break;
113
114                 char* p = strchr(cmdptr,' ');
115                 int len = p == NULL ? 1+strlen(cmdptr) : 1+p-cmdptr;
116
117                 argv[argc+1] = argv[argc]+len;
118
119                 if(p == NULL)
120                 {
121                         argc++;
122                         break;
123                 }
124
125                 cmdptr = p;
126         }
127         for(int i = 0; i < argc; i++)
128         {
129                 intreg_t offset = argv[i];
130                 argv[i] += (argc+1)*sizeof(char*);
131                 memcpy(argv_buf+argv[i],cmdline+offset,argv[i+1]-offset-1);
132                 argv_buf[argv[i]+argv[i+1]-offset-1] = 0;
133         }
134         argv[argc] = 0;
135
136         char* filename = argv_buf+argv[0];
137         int fd = open(filename, O_RDONLY, 0);
138         if(fd < 0)
139         {
140                 printf("open failed\n");
141                 ret = -1;
142                 goto open_error;
143         }
144         
145         int total_bytes_read = 0;
146         int bytes_read = 0;
147         int bufsz = 0;
148         void* binary_buf = NULL;
149         
150         while(1) {
151                 if(total_bytes_read+READ_SIZE > bufsz)
152                 {
153                         void* temp_buf = realloc(binary_buf,bufsz+MALLOC_SIZE);
154                         if(temp_buf == NULL)
155                         {
156                                 printf("realloc failed\n");
157                                 ret = -1;
158                                 goto realloc_error;
159                         }
160
161                         binary_buf = temp_buf;
162                         bufsz += MALLOC_SIZE;
163                 }
164
165                 bytes_read = read(fd, binary_buf+total_bytes_read, READ_SIZE);
166                 total_bytes_read += bytes_read;
167                 if(bytes_read < 0)
168                 {
169                         printf("read error\n");
170                         ret = -1;
171                         goto read_error;
172                 }
173                 if(bytes_read == 0) break;
174         }
175         //printf("Loading Binary: %s, ROMSIZE: %d\n",filename,total_bytes_read);
176         ret = sys_run_binary(binary_buf, total_bytes_read, argv_buf, colors);
177         if(ret < 0)
178                 fprintf(stderr, "Error: Unable to run remote binary\n");
179         else
180                 syscall(SYS_yield,0,0,0,0,0);
181
182 read_error:
183 realloc_error:
184         free(binary_buf);
185         close(fd);
186 open_error:
187         return ret;
188 }
189
190 void run_binary(size_t colors)
191 {
192         char* readline_result = readline("\nEnter name of binary to execute: ");
193         if (readline_result == NULL) {
194                 printf("Error reading from console.\n");
195                 return;
196         }
197         run_binary_filename(readline_result, colors);
198 }
199