]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/os.c
cc, ?[acl]: fix gethunk() and move common memory allocator code to cc/compat
[plan9front.git] / sys / src / cmd / os.c
1 #include <u.h>
2 #include <libc.h>
3
4 enum {
5         Fstdin,
6         Fstdout,
7         Fstderr,
8         Fwait,
9         Fctl,
10         Nfd,
11 };
12
13 enum {
14         Pcopyin,
15         Pcopyout,
16         Pcopyerr,
17         Preadwait,
18         Npid,
19 };
20
21 char *mnt = "/mnt/term/cmd";
22 char *dir = nil;
23 char buf[8192];
24 int fd[Nfd] = {-1};
25 int pid[Npid];
26 int nice, foreground = 1;
27
28 void
29 killstdin(void)
30 {
31         if(pid[Pcopyin] != 0)
32                 postnote(PNPROC, pid[Pcopyin], "kill");
33 }
34
35 void
36 killproc(void)
37 {
38         if(fd[Fctl] >= 0)
39                 write(fd[Fctl], "kill", 4);
40 }
41
42 int
43 catch(void*, char *msg)
44 {
45         if(strcmp(msg, "interrupt") == 0
46         || strcmp(msg, "hangup") == 0
47         || strcmp(msg, "kill") == 0){
48                 killproc();
49                 return 1;
50         }
51         return 0;
52 }
53
54 void
55 fd01(int fd0, int fd1)
56 {
57         int i;
58
59         if(fd0 >= 0 && fd0 != 0){
60                 if(dup(fd0, 0) < 0)
61                         sysfatal("dup: %r");
62         }
63         if(fd1 >= 0 && fd1 != 1){
64                 if(dup(fd1, 1) < 0)
65                         sysfatal("dup: %r");
66         }
67         for(i = 0; i<Nfd; i++){
68                 if(fd[i] > 2)
69                         close(fd[i]);
70                 if(fd[i] == fd0)
71                         fd[i] = 0;
72                 else if(fd[i] == fd1)
73                         fd[i] = 1;
74                 else
75                         fd[i] = -1;
76         }
77 }
78
79 void
80 copy(void)
81 {
82         int n;
83
84         while((n = read(0, buf, sizeof(buf))) > 0)
85                 if(write(1, buf, n) != n)
86                         break;
87 }
88
89 void
90 usage(void)
91 {
92         fprint(2, "%s: [ -b ] [ -m mountpoint ] [ -d dir ] [ -n ] [ -N level ] cmd [ arg... ]\n", argv0);
93         exits("usage");
94 }
95
96 void
97 main(int argc, char **argv)
98 {
99         Waitmsg *w;
100         char *s;
101         int n;
102
103         quotefmtinstall();
104
105         ARGBEGIN {
106         case 'b':
107                 foreground = 0;
108                 break;
109         case 'm':
110                 mnt = cleanname(EARGF(usage()));
111                 break;
112         case 'd':
113                 dir = EARGF(usage());
114                 break;
115         case 'n':
116                 nice = 1;
117                 break;
118         case 'N':
119                 nice = atoi(EARGF(usage()));
120                 break;
121         default:
122                 usage();
123         } ARGEND;
124
125         if(argc < 1)
126                 usage();
127
128         seprint(buf, &buf[sizeof(buf)], "%s/clone", mnt);
129         if((fd[Fctl] = open(buf, ORDWR)) < 0)
130                 sysfatal("open: %r");
131         s = &buf[strlen(mnt)+1];
132         if((n = read(fd[Fctl], s, &buf[sizeof(buf)-1]-s)) < 0)
133                 sysfatal("read clone: %r");
134         while(n > 0 && buf[n-1] == '\n')
135                 n--;
136         s += n;
137
138         seprint(s, &buf[sizeof(buf)], "/wait");
139         if((fd[Fwait] = open(buf, OREAD)) < 0)
140                 sysfatal("open: %r");
141
142         if(foreground){
143                 seprint(s, &buf[sizeof(buf)], "/data");
144                 if((fd[Fstdin] = open(buf, OWRITE)) < 0)
145                         sysfatal("open: %r");
146
147                 seprint(s, &buf[sizeof(buf)], "/data");
148                 if((fd[Fstdout] = open(buf, OREAD)) < 0)
149                         sysfatal("open: %r");
150
151                 seprint(s, &buf[sizeof(buf)], "/stderr");
152                 if((fd[Fstderr] = open(buf, OREAD)) < 0)
153                         sysfatal("open: %r");
154         }
155
156         if(dir != nil){
157                 if(fprint(fd[Fctl], "dir %q", dir) < 0)
158                         sysfatal("cannot change directory: %r");
159         } else {
160                 /*
161                  * try to automatically change directory if we are in
162                  * /mnt/term or /mnt/term/root, but unlike -d flag,
163                  * do not error when the dir ctl command fails.
164                  */
165                 if((s = strrchr(mnt, '/')) != nil){
166                         n = s - mnt;
167                         dir = getwd(buf, sizeof(buf));
168                         if(strncmp(dir, mnt, n) == 0 && (dir[n] == 0 || dir[n] == '/')){
169                                 dir += n;
170                                 if(strncmp(dir, "/root", 5) == 0 && (dir[5] == 0 || dir[5] == '/'))
171                                         dir += 5;
172                                 if(*dir == 0)
173                                         dir = "/";
174                                 /* hack for win32: /C:... -> C:/... */
175                                 if(dir[1] >= 'A' && dir[1] <= 'Z' && dir[2] == ':')
176                                         dir[0] = dir[1], dir[1] = ':', dir[2] = '/';
177                                 fprint(fd[Fctl], "dir %q", dir);
178                         }
179                 }
180         }
181
182         if(nice != 0)
183                 fprint(fd[Fctl], "nice %d", nice);
184
185         if(foreground)
186                 fprint(fd[Fctl], "killonclose");
187
188         s = seprint(buf, &buf[sizeof(buf)], "exec");
189         while(*argv != nil){
190                 s = seprint(s, &buf[sizeof(buf)], " %q", *argv++);
191                 if(s >= &buf[sizeof(buf)-1])
192                         sysfatal("too many arguments");
193         }
194
195         if(write(fd[Fctl], buf, s - buf) < 0)
196                 sysfatal("write: %r");
197
198         if((pid[Preadwait] = fork()) == -1)
199                 sysfatal("fork: %r");
200         if(pid[Preadwait] == 0){
201                 fd01(fd[Fwait], 2);
202                 if((n = read(0, buf, sizeof(buf)-1)) < 0)
203                         rerrstr(buf, sizeof(buf));
204                 else {
205                         char *f[5];
206
207                         while(n > 0 && buf[n-1] == '\n')
208                                 n--;
209                         buf[n] = 0;
210                         if(tokenize(buf, f, 5) == 5)
211                                 exits(f[4]);
212                 }
213                 exits(buf);
214         }
215
216         if(foreground){
217                 if((pid[Pcopyerr] = fork()) == -1)
218                         sysfatal("fork: %r");
219                 if(pid[Pcopyerr] == 0){
220                         fd01(fd[Fstderr], 2);
221                         copy();
222                         rerrstr(buf, sizeof(buf));
223                         exits(buf);
224                 }
225                 if((pid[Pcopyout] = fork()) == -1)
226                         sysfatal("fork: %r");
227                 if(pid[Pcopyout] == 0){
228                         fd01(fd[Fstdout], 1);
229                         copy();
230                         rerrstr(buf, sizeof(buf));
231                         exits(buf);
232                 }
233                 if((pid[Pcopyin] = fork()) == -1)
234                         sysfatal("fork: %r");
235                 if(pid[Pcopyin] == 0){
236                         fd01(0, fd[Fstdin]);
237                         copy();
238                         rerrstr(buf, sizeof(buf));
239                         exits(buf);
240                 }
241         }
242         fd01(fd[Fctl], 2);
243         atexit(killstdin);
244         atnotify(catch, 1);
245
246         while((w = wait()) != nil){
247                 if((s = strstr(w->msg, ": ")) == nil)
248                         s = w->msg;
249                 else
250                         s += 2;
251                 for(n = 0; n < Npid; n++){
252                         if(pid[n] == w->pid){
253                                 pid[n] = 0;
254                                 break;
255                         }
256                 }
257                 if(n == Preadwait)
258                         exits(s);
259                 free(w);
260         }
261 }