]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rdbfs.c
9bootfat: rename open() to fileinit and make it static as its really a internal funct...
[plan9front.git] / sys / src / cmd / rdbfs.c
1 /*
2  * Remote debugging file system
3  */
4
5 #include <u.h>
6 #include <libc.h>
7 #include <auth.h>
8 #include <fcall.h>
9 #include <bio.h>
10 #include <thread.h>
11 #include <9p.h>
12
13 int dbg = 0;
14 #define DBG     if(dbg)fprint
15
16 enum {
17         NHASH = 4096,
18         Readlen = 4,
19         Pagequantum = 1024,
20 };
21
22 /* caching memory pages: a lot of space to avoid serial communications */
23 Lock pglock;
24 typedef struct  Page    Page;
25 struct Page {   /* cached memory contents */
26         Page *link;
27         ulong len;
28         ulong addr;
29         int count;
30         uchar val[Readlen];
31 };
32
33 Page *pgtab[NHASH];
34
35 Page *freelist;
36
37 /* called with pglock locked */
38 Page*
39 newpg(void)
40 {
41         int i;
42         Page *p, *q;
43
44         if(freelist == nil){
45                 p = malloc(sizeof(Page)*Pagequantum);
46                 if(p == nil)
47                         sysfatal("out of memory");
48
49                 for(i=0, q=p; i<Pagequantum-1; i++, q++)
50                         q->link = q+1;
51                 q->link = nil;
52
53                 freelist = p;
54         }
55         p = freelist;
56         freelist = freelist->link;
57         return p;
58 }
59
60 #define PHIINV 0.61803398874989484820
61 uint
62 ahash(ulong addr)
63 {
64         return (uint)floor(NHASH*fmod(addr*PHIINV, 1.0));
65 }
66
67 int
68 lookup(ulong addr, uchar *val, ulong count)
69 {
70         Page *p;
71
72         lock(&pglock);
73         for(p=pgtab[ahash(addr)]; p; p=p->link){
74                 if(p->addr == addr && p->count == count){
75                         memmove(val, p->val, count);
76                         unlock(&pglock);
77                         return 1;
78                 }
79         }
80         unlock(&pglock);
81         return 0;
82 }
83
84 void
85 insert(ulong addr, uchar *val, int count)
86 {
87         Page *p;
88         uint h;
89
90         lock(&pglock);
91         p = newpg();
92         p->addr = addr;
93         p->count = count;
94         memmove(p->val, val, count);
95         h = ahash(addr);
96         p->link = pgtab[h];
97         p->len = pgtab[h] ? pgtab[h]->len+1 : 1;
98         pgtab[h] = p;
99         unlock(&pglock);
100 }
101
102 void
103 flushcache(void)
104 {
105         int i;
106         Page *p;
107
108         lock(&pglock);
109         for(i=0; i<NHASH; i++){
110                 if(p=pgtab[i]){
111                         for(;p->link; p=p->link)
112                                 ;
113                         p->link = freelist;
114                         freelist = p;
115                 }
116                 pgtab[i] = nil;
117         }
118         unlock(&pglock);
119 }
120
121 enum
122 {
123         Xctl    = 1,
124         Xfpregs,
125         Xkregs,
126         Xmem,
127         Xproc,
128         Xregs,
129         Xtext,
130         Xstatus,
131
132 };
133
134 int     textfd;
135 int     rfd;
136 Biobuf  rfb;
137 char*   portname = "/dev/eia0";
138 char*   textfile = "/386/9pc";
139 char*   procname = "1";
140 Channel* rchan;
141
142 void
143 usage(void)
144 {
145         fprint(2, "usage: rdbfs [-p procnum] [-t textfile] [serialport]\n");
146         exits("usage");
147 }
148
149 void
150 noalarm(void*, char *msg)
151 {
152         if(strstr(msg, "alarm"))
153                 noted(NCONT);
154         noted(NDFLT);
155 }
156
157 /*
158  *      send and receive responses on the serial line
159  */
160 void
161 eiaread(void*)
162 {
163         Req *r;
164         char *p;
165         uchar *data;
166         char err[ERRMAX];
167         char buf[1000];
168         int i, tries;
169
170         notify(noalarm);
171         while(r = recvp(rchan)){
172                 DBG(2, "got %F: here goes...", &r->ifcall);
173                 if(r->ifcall.count > Readlen)
174                         r->ifcall.count = Readlen;
175                 r->ofcall.count = r->ifcall.count;
176                 if(r->type == Tread && lookup(r->ifcall.offset, (uchar*)r->ofcall.data, r->ofcall.count)){
177                         respond(r, nil);
178                         continue;
179                 }
180                 for(tries=0; tries<5; tries++){
181                         if(r->type == Twrite){
182                                 DBG(2, "w%.8lux %.8lux...", (ulong)r->ifcall.offset, *(ulong*)r->ifcall.data);
183                                 fprint(rfd, "w%.8lux %.8lux\n", (ulong)r->ifcall.offset, *(ulong*)r->ifcall.data);
184                         }else if(r->type == Tread){
185                                 DBG(2, "r%.8lux...", (ulong)r->ifcall.offset);
186                                 fprint(rfd, "r%.8lux\n", (ulong)r->ifcall.offset);
187                         }else{
188                                 respond(r, "oops");
189                                 break;
190                         }
191                         for(;;){
192                                 werrstr("");
193                                 alarm(500);
194                                 p=Brdline(&rfb, '\n');
195                                 alarm(0);
196                                 if(p == nil){
197                                         rerrstr(err, sizeof err);
198                                         DBG(2, "error %s\n", err);
199                                         if(strstr(err, "alarm") || strstr(err, "interrupted"))
200                                                 break;
201                                         if(Blinelen(&rfb) == 0) // true eof
202                                                 sysfatal("eof on serial line?");
203                                         Bread(&rfb, buf, Blinelen(&rfb)<sizeof buf ? Blinelen(&rfb) : sizeof buf);
204                                         continue;
205                                 }
206                                 p[Blinelen(&rfb)-1] = 0;
207                                 if(p[0] == '\r')
208                                         p++;
209                                 DBG(2, "serial %s\n", p);
210                                 if(p[0] == 'R'){
211                                         if(strtoul(p+1, 0, 16) == (ulong)r->ifcall.offset){
212                                                 /* we know that data can handle Readlen bytes */
213                                                 data = (uchar*)r->ofcall.data;
214                                                 for(i=0; i<r->ifcall.count; i++)
215                                                         data[i] = strtol(p+1+8+1+3*i, 0, 16);
216                                                 insert(r->ifcall.offset, data, r->ifcall.count);
217                                                 respond(r, nil);
218                                                 goto Break2;
219                                         }else
220                                                 DBG(2, "%.8lux ≠ %.8lux\n", strtoul(p+1, 0, 16), (ulong)r->ifcall.offset);
221                                 }else if(p[0] == 'W'){
222                                         respond(r, nil);
223                                         goto Break2;
224                                 }else{
225                                         DBG(2, "unknown message\n");
226                                 }
227                         }
228                 }
229         Break2:;
230         }
231 }
232
233 void
234 attachremote(char* name)
235 {
236         int fd;
237         char buf[128];
238
239         print("attach %s\n", name);
240         rfd = open(name, ORDWR);
241         if(rfd < 0)
242                 sysfatal("can't open remote %s", name);
243
244         sprint(buf, "%sctl", name);
245         fd = open(buf, OWRITE);
246         if(fd < 0)
247                 sysfatal("can't set baud rate on %s", buf);
248         write(fd, "B9600", 6);
249         close(fd);
250         Binit(&rfb, rfd, OREAD);
251 }
252
253 void
254 fsopen(Req *r)
255 {
256         char buf[ERRMAX];
257
258         switch((uintptr)r->fid->file->aux){
259         case Xtext:
260                 close(textfd);
261                 textfd = open(textfile, OREAD);
262                 if(textfd < 0) {
263                         snprint(buf, sizeof buf, "text: %r");
264                         respond(r, buf);
265                         return;
266                 }
267                 break;
268         }               
269         respond(r, nil);
270 }
271
272 void
273 fsread(Req *r)
274 {
275         int i, n;
276         char buf[512];
277
278         switch((uintptr)r->fid->file->aux) {
279         case Xfpregs:
280         case Xproc:
281         case Xregs:
282                 respond(r, "Egreg");
283                 break;
284         case Xkregs:
285         case Xmem:
286                 if(sendp(rchan, r) != 1){
287                         snprint(buf, sizeof buf, "rdbfs sendp: %r");
288                         respond(r, buf);
289                         return;
290                 }
291                 break;
292         case Xtext:
293                 n = pread(textfd, r->ofcall.data, r->ifcall.count, r->ifcall.offset);
294                 if(n < 0) {
295                         rerrstr(buf, sizeof buf);
296                         respond(r, buf);
297                         break;
298                 }
299                 r->ofcall.count = n;
300                 respond(r, nil);
301                 break;
302         case Xstatus:
303                 n = sprint(buf, "%-28s%-28s%-28s", "remote", "system", "New");
304                 for(i = 0; i < 9; i++)
305                         n += sprint(buf+n, "%-12d", 0);
306                 readstr(r, buf);
307                 respond(r, nil);
308                 break;
309         default:
310                 respond(r, "unknown read");
311         }
312 }
313
314 void
315 fswrite(Req *r)
316 {
317         char buf[ERRMAX];
318
319         switch((uintptr)r->fid->file->aux) {
320         case Xctl:
321                 if(strncmp(r->ifcall.data, "kill", 4) == 0 ||
322                    strncmp(r->ifcall.data, "exit", 4) == 0) {
323                         respond(r, nil);
324                         postnote(PNGROUP, getpid(), "umount");
325                         exits(nil);
326                 }else if(strncmp(r->ifcall.data, "refresh", 7) == 0){
327                         flushcache();
328                         respond(r, nil);
329                 }else if(strncmp(r->ifcall.data, "hashstats", 9) == 0){
330                         int i;
331                         lock(&pglock);
332                         for(i=0; i<NHASH; i++)
333                                 if(pgtab[i])
334                                         print("%lud ", pgtab[i]->len);
335                         print("\n");
336                         unlock(&pglock);
337                         respond(r, nil);
338                 }else
339                         respond(r, "permission denied");
340                 break;
341         case Xkregs:
342         case Xmem:
343                 if(sendp(rchan, r) != 1) {
344                         snprint(buf, sizeof buf, "rdbfs sendp: %r");
345                         respond(r, buf);
346                         return;
347                 }
348                 break;
349         default:
350                 respond(r, "Egreg");
351                 break;
352         }
353 }
354
355 struct {
356         char *s;
357         int id;
358         int mode;
359 } tab[] = {
360         "ctl",          Xctl,           0222,
361         "fpregs",       Xfpregs,        0666,
362         "kregs",        Xkregs,         0666,
363         "mem",          Xmem,           0666,
364         "proc",         Xproc,          0444,
365         "regs",         Xregs,          0666,
366         "text",         Xtext,          0444,
367         "status",       Xstatus,        0444,
368 };
369
370 void
371 killall(Srv*)
372 {
373         postnote(PNGROUP, getpid(), "kill");
374 }
375
376 Srv fs = {
377 .open=  fsopen,
378 .read=  fsread,
379 .write= fswrite,
380 .end=   killall,
381 };
382
383 void
384 threadmain(int argc, char **argv)
385 {
386         int i, p[2];
387         File *dir;
388
389         rfork(RFNOTEG);
390         ARGBEGIN{
391         case 'D':
392                 chatty9p++;
393                 break;
394         case 'd':
395                 dbg = 1;
396                 break;
397         case 'p':
398                 procname = EARGF(usage());
399                 break;
400         case 't':
401                 textfile = EARGF(usage());
402                 break;
403         default:
404                 usage();
405         }ARGEND;
406
407         switch(argc){
408         case 0:
409                 break;
410         case 1:
411                 portname = argv[0];
412                 break;
413         default:
414                 usage();
415         }
416
417         rchan = chancreate(sizeof(Req*), 10);
418         attachremote(portname);
419         if(pipe(p) < 0)
420                 sysfatal("pipe: %r");
421
422         fmtinstall('F', fcallfmt);
423         proccreate(eiaread, nil, 8192);
424
425         fs.tree = alloctree("rdbfs", "rdbfs", DMDIR|0555, nil);
426         dir = createfile(fs.tree->root, procname, "rdbfs", DMDIR|0555, 0);
427         for(i=0; i<nelem(tab); i++)
428                 closefile(createfile(dir, tab[i].s, "rdbfs", tab[i].mode, (void*)tab[i].id));
429         closefile(dir);
430         threadpostmountsrv(&fs, nil, "/proc", MBEFORE);
431         exits(0);
432 }
433