]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/5e/fs.c
cwfs: fix listen filedescriptor leaks
[plan9front.git] / sys / src / cmd / 5e / fs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include "dat.h"
7 #include "fns.h"
8
9 static char *luser;
10 extern int pflag;
11
12 enum
13 {
14         Qdir,
15         Qtrace,
16         Qargs,
17         Qctl,
18         Qfd,
19         Qfpregs,
20         Qkregs,
21         Qmem,
22         Qnote,
23         Qnoteid,
24         Qnotepg,
25         Qns,
26         Qproc,
27         Qregs,
28         Qsegment,
29         Qstatus,
30         Qtext,
31         Qwait,
32         Qprofile,
33         Qsyscall,
34         NQid,
35 };
36
37 typedef struct Aux Aux;
38 typedef struct Dirtab Dirtab;
39 struct Dirtab {
40         char name[28];
41         Qid qid;
42         vlong length;
43         long perm;
44 };
45 struct Aux {
46         Process *p;
47         int fd;
48         Dirtab *d;
49 };
50
51 Dirtab procdir[] =
52 {
53         "args",         {Qargs},        0,                      0660,
54         "ctl",          {Qctl},         0,                      0600,
55         "fd",           {Qfd},          0,                      0444,
56         "fpregs",       {Qfpregs},      0,                      0400,
57         "kregs",        {Qkregs},       18 * 4,                 0400,
58         "mem",          {Qmem},         0,                      0400,
59         "note",         {Qnote},        0,                      0000,
60         "noteid",       {Qnoteid},      0,                      0664,
61         "notepg",       {Qnotepg},      0,                      0000,
62         "ns",           {Qns},          0,                      0444,
63         "proc",         {Qproc},        0,                      0400,
64         "regs",         {Qregs},        18 * 4,                 0400,
65         "segment",      {Qsegment},     0,                      0444,
66         "status",       {Qstatus},      176,                    0444,
67         "text",         {Qtext},        0,                      0400,
68         "wait",         {Qwait},        0,                      0400,
69         "profile",      {Qprofile},     0,                      0400,
70         "syscall",      {Qsyscall},     0,                      0400,   
71         "",             {0},            0,                      0,
72 };
73
74 static char *
75 readin(int pid, char *file)
76 {
77         char *name, *buf;
78         int fd, rc;
79         
80         name = smprint("#p/%d/%s", pid, file);
81         fd = open(name, OREAD);
82         if(fd < 0)
83                 return nil;
84         buf = malloc(1024);
85         rc = read(fd, buf, 1023);
86         if(rc < 0)
87                 return nil;
88         buf[rc] = 0;
89         free(name);
90         close(fd);
91         return buf;
92 }
93
94 static int
95 calcmem(Process *p)
96 {
97         int i, r;
98         
99         r = 0;
100         for(i = 0; i < SEGNUM; i++) {
101                 if(i == SEGSTACK)
102                         continue;
103                 if(p->S[i] == nil)
104                         continue;
105                 r += p->S[i]->size;
106         }
107         r = (r + 1023) / 1024;
108         return r;
109 }
110
111 static int
112 copymem(Process *p, char *buf, u32int addr, int len)
113 {
114         int i, n, r;
115
116         r = len;
117         while(len > 0) {
118                 for(i = 0; i < SEGNUM; i++) {
119                         if(p->S[i] == nil)
120                                 continue;
121                         if(p->S[i]->start <= addr && p->S[i]->start + p->S[i]->size > addr)
122                                 break;
123                 }
124                 if(i == SEGNUM) {
125                         werrstr("bad arg in syscall");
126                         return -1;
127                 }
128                 n = p->S[i]->start + p->S[i]->size - addr;
129                 if(n > len)
130                         n = len;
131                 memcpy(buf, (char*)p->S[i]->data + addr - p->S[i]->start, n);
132                 len -= n;
133                 buf += n;
134         }
135         return r;
136 }
137
138 static char *
139 segments(Process *p)
140 {
141         char *r, *s;
142         static char *names[] = {
143                 [SEGTEXT] "Text",
144                 [SEGSTACK] "Stack",
145                 [SEGDATA] "Data",
146                 [SEGBSS] "Bss",
147         };
148         int i;
149         
150         r = emalloc(1024);
151         s = r;
152         for(i = 0; i < SEGNUM; i++) {
153                 if(p->S[i] == nil)
154                         continue;
155                 s += sprint(s, "%-7s%c  %.8ux %.8ux %4ld\n", names[i], i == SEGTEXT ? 'R' : ' ', p->S[i]->start, p->S[i]->start + p->S[i]->size, p->S[i]->dref->ref);
156         }
157         return r;
158 }
159
160 static void
161 procattach(Req *req)
162 {
163         req->fid->qid = (Qid) {0, 0, 0x80};
164         req->fid->aux = emallocz(sizeof(Aux));
165         ((Aux *) req->fid->aux)->fd = -1;
166         req->ofcall.qid = req->fid->qid;
167         respond(req, nil);
168 }
169
170 static char *
171 procwalk(Fid *fid, char *name, Qid *qid)
172 {
173         int pid;
174         char buf[20];
175         Dirtab *d;
176         Aux *a;
177         
178         a = fid->aux;
179         if(fid->qid.path == 0) {
180                 pid = atoi(name);
181                 sprint(buf, "%d", pid);
182                 if(strcmp(buf, name) != 0 || (a->p = findproc(pid)) == nil)
183                         return "file does not exist";
184                 *qid = (Qid) {pid * NQid, 0, 0x80};
185                 fid->qid = *qid;
186                 return nil;
187         }
188         if((fid->qid.path % NQid) == 0) {
189                 for(d = procdir; d->name[0] != 0; d++)
190                         if(strcmp(d->name, name) == 0)
191                                 break;
192                 if(d->name[0] == 0)
193                         return "file does not exist";
194                 *qid = d->qid;
195                 qid->path += fid->qid.path;
196                 fid->qid = *qid;
197                 a->d = d;
198                 return nil;
199         }
200         return "the front fell off";
201 }
202
203 static char *
204 procclone(Fid *old, Fid *new)
205 {
206         new->aux = emallocz(sizeof(Aux));
207         memcpy(new->aux, old->aux, sizeof(Aux));
208         return nil;
209 }
210
211 static void
212 procopen(Req *req)
213 {
214         Aux *a;
215         
216         a = req->fid->aux;
217         switch((int)(req->fid->qid.path % NQid)) {
218         case Qtext:
219                 a->fd = open((char*)(a->p->path + 1), OREAD);
220                 break;
221         default:
222                 respond(req, nil);
223                 return;
224         }
225         if(a->fd < 0)
226                 responderror(req);
227         else
228                 respond(req, nil);
229 }
230
231 static void
232 procdestroyfid(Fid *fid)
233 {
234         Aux *a;
235         
236         a = fid->aux;
237         free(a);
238 }
239
240 static int
241 procgen(int n, Dir *d, void *)
242 {
243         int i;
244         Process *p;
245         
246         p = &plist;
247         for(i = 0;; i++) {
248                 p = p->next;
249                 if(p == &plist)
250                         return -1;
251                 if(i == n)
252                         break;
253         }
254         d->uid = estrdup9p(luser);
255         d->gid = estrdup9p(luser);
256         d->muid = estrdup9p(luser);
257         d->name = smprint("%d", p->pid);
258         d->mode = DMDIR | 0555;
259         d->qid = (Qid) {p->pid * NQid, 0, 0x80};
260         return 0;
261 }
262
263 static int
264 procsubgen(int n, Dir *d, void *)
265 {
266         Dirtab *di;
267         
268         if(n >= nelem(procdir) - 1)
269                 return -1;
270         
271         di = procdir + n;
272         d->uid = estrdup9p(luser);
273         d->gid = estrdup9p(luser);
274         d->muid = estrdup9p(luser);
275         d->name = estrdup9p(di->name);
276         d->mode = di->perm;
277         d->length = di->length;
278         d->qid = di->qid;
279         return 0;
280 }
281
282 static void
283 procread(Req *req)
284 {
285         Aux *a;
286         Process *p;
287         char *buf;
288         int rc;
289
290         a = req->fid->aux;
291         if(a == nil) {
292                 respond(req, "the front fell off");
293                 return;
294         }
295         if(req->fid->qid.path == 0) {
296                 dirread9p(req, procgen, nil);
297                 respond(req, nil);
298                 return;
299         }
300         p = a->p;
301         switch((int)(req->fid->qid.path % NQid)) {
302         case Qdir:
303                 dirread9p(req, procsubgen, nil);
304                 respond(req, nil);
305                 break;
306         case Qstatus:
307                 buf = readin(p->pid, "status");
308                 if(buf == nil)
309                         responderror(req);
310                 else {
311                         memset(buf, ' ', 27);
312                         memcpy(buf, p->name, strlen(p->name));
313                         sprint(buf + 149, "%d", calcmem(p));
314                         buf[strlen(buf)] = ' ';
315                         readstr(req, buf);
316                         free(buf);
317                         respond(req, nil);
318                 }
319                 break;
320         case Qsegment:
321                 buf = segments(p);
322                 readstr(req, buf);
323                 free(buf);
324                 respond(req, nil);
325                 break;
326         case Qtext:
327                 rc = pread(a->fd, req->ofcall.data, req->ifcall.count, req->ifcall.offset);
328                 if(rc >= 0) {
329                         req->ofcall.count = rc;
330                         respond(req, nil);
331                 } else
332                         responderror(req);
333                 break;
334         case Qmem:
335                 rc = copymem(p, req->ofcall.data, req->ifcall.offset, req->ifcall.count);
336                 if(rc >= 0) {
337                         req->ofcall.count = rc;
338                         respond(req, nil);
339                 } else
340                         responderror(req);
341                 break;
342         case Qregs:
343                 buf = emallocz(18 * 4);
344                 memcpy(buf, p->R, 15 * 4);
345                 memcpy(buf + 16 * 4, &p->CPSR, 4);
346                 memcpy(buf + 17 * 4, p->R + 15, 4);
347                 readbuf(req, buf, 18 * 4);
348                 free(buf);
349                 respond(req, nil);
350                 break;
351         default:
352                 respond(req, "the front fell off");
353         }
354 }
355
356 static void
357 writeto(Req *req, char *fmt, ...)
358 {
359         int fd, rc;
360         va_list va;
361         char *file;
362         
363         va_start(va, fmt);
364         file = vsmprint(fmt, va);
365         va_end(va);
366         fd = open(file, OWRITE);
367         free(file);
368         if(fd < 0) {
369                 responderror(req);
370                 return;
371         }
372         rc = write(fd, req->ifcall.data, req->ifcall.count);
373         req->ofcall.count = rc;
374         if(rc < req->ifcall.count)
375                 responderror(req);
376         else
377                 respond(req, nil);
378         close(fd);
379 }
380
381 static void
382 procwrite(Req *req)
383 {
384         switch((int)(req->fid->qid.path % NQid)) {
385         case Qnote:
386                 writeto(req, "#p/%lld/note", req->fid->qid.path / NQid);
387                 break;
388         default:
389                 respond(req, "the front fell off");
390         }
391 }
392
393 static void
394 procstat(Req *req)
395 {
396         Aux *a;
397         Dir *d;
398         
399         d = &req->d;
400         a = req->fid->aux;
401         if(a == nil) {
402                 respond(req, "the front fell off");
403                 return;
404         }
405         d->qid = req->fid->qid;
406         if(a->d != nil) {
407                 d->mode = a->d->perm;
408                 d->length = a->d->length;
409                 d->name = strdup(a->d->name);
410         } else {
411                 d->mode = 0555 | DMDIR;
412                 if(d->qid.path != 0)
413                         d->name = smprint("%lld", d->qid.path / NQid);
414         }
415         d->uid = strdup(luser);
416         d->gid = strdup(luser);
417         d->muid = strdup(luser);
418         respond(req, nil);
419 }
420
421 static Srv procsrv = {
422         .attach = procattach,
423         .walk1 = procwalk,
424         .clone = procclone,
425         .destroyfid = procdestroyfid,
426         .open = procopen,
427         .read = procread,
428         .stat = procstat,
429 };
430
431 void
432 initfs(char *name, char *mtpt)
433 {
434         luser = getuser();
435         remove("/srv/armproc");
436         postmountsrv(&procsrv, name, mtpt, MREPL);
437 }