]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cwfs/sub.c
kernel: keep segment locked for data2txt
[plan9front.git] / sys / src / cmd / cwfs / sub.c
1 #include "all.h"
2 #include "io.h"
3
4 enum {
5         Slop = 256,     /* room at the start of a message buf for proto hdrs */
6 };
7
8 Filsys*
9 fsstr(char *p)
10 {
11         Filsys *fs;
12
13         for(fs=filsys; fs->name; fs++)
14                 if(strcmp(fs->name, p) == 0)
15                         return fs;
16         return 0;
17 }
18
19 Filsys*
20 dev2fs(Device *dev)
21 {
22         Filsys *fs;
23
24         for(fs=filsys; fs->name; fs++)
25                 if(fs->dev == dev)
26                         return fs;
27         return 0;
28 }
29
30 /*
31  * allocate 'count' contiguous channels
32  * of type 'type' and return pointer to base
33  */
34 Chan*
35 fs_chaninit(int type, int count, int data)
36 {
37         uchar *p;
38         Chan *cp, *icp;
39         int i;
40
41         p = malloc(count * (sizeof(Chan)+data));
42         icp = (Chan*)p;
43         for(i = 0; i < count; i++) {
44                 cp = (Chan*)p;
45                 cp->next = chans;
46                 chans = cp;
47                 cp->type = type;
48                 cp->chan = cons.chano;
49                 cons.chano++;
50                 strncpy(cp->whoname, "<none>", sizeof cp->whoname);
51                 wlock(&cp->reflock);
52                 wunlock(&cp->reflock);
53                 rlock(&cp->reflock);
54                 runlock(&cp->reflock);
55
56                 p += sizeof(Chan);
57                 if(data){
58                         cp->pdata = p;
59                         p += data;
60                 }
61         }
62         return icp;
63 }
64
65 void
66 fileinit(Chan *cp)
67 {
68         File *f, *prev;
69         Tlock *t;
70         int h;
71
72 loop:
73         lock(&flock);
74         for (h=0; h < nelem(flist); h++)
75                 for (prev=0, f = flist[h]; f; prev=f, f=f->next) {
76                         if(f->cp != cp)
77                                 continue;
78                         if(prev) {
79                                 prev->next = f->next;
80                                 f->next = flist[h];
81                                 flist[h] = f;
82                         }
83                         flist[h] = f->next;
84                         unlock(&flock);
85
86                         qlock(f);
87                         if(t = f->tlock) {
88                                 if(t->file == f)
89                                         t->time = 0;    /* free the lock */
90                                 f->tlock = 0;
91                         }
92                         if(f->open & FREMOV)
93                                 doremove(f, 0);
94                         freewp(f->wpath);
95                         f->open = 0;
96                         authfree(f->auth);
97                         f->auth = 0;
98                         f->cp = 0;
99                         qunlock(f);
100                         goto loop;
101                 }
102         unlock(&flock);
103 }
104
105 enum { NOFID = (ulong)~0 };
106
107 /*
108  * returns a locked file structure
109  */
110 File*
111 filep(Chan *cp, ulong fid, int flag)
112 {
113         File *f;
114         int h;
115
116         if(fid == NOFID)
117                 return 0;
118
119         h = (long)(uintptr)cp + fid;
120         if(h < 0)
121                 h = ~h;
122         h %= nelem(flist);
123
124 loop:
125         lock(&flock);
126         for(f=flist[h]; f; f=f->next)
127                 if(f->fid == fid && f->cp == cp){
128                         /*
129                          * Already in use is an error
130                          * when called from attach or clone (walk
131                          * in 9P2000). The console uses FID[12] and
132                          * never clunks them so catch that case.
133                          */
134                         if(flag == 0 || cp == cons.chan)
135                                 goto out;
136                         unlock(&flock);
137                         return 0;
138                 }
139
140         if(flag) {
141                 f = newfp();
142                 if(f) {
143                         f->fid = fid;
144                         f->cp = cp;
145                         f->wpath = 0;
146                         f->tlock = 0;
147                         f->doffset = 0;
148                         f->dslot = 0;
149                         f->auth = 0;
150                         f->next = flist[h];
151                         flist[h] = f;
152                         goto out;
153                 }
154         }
155         unlock(&flock);
156         return 0;
157
158 out:
159         unlock(&flock);
160         qlock(f);
161         if(f->fid == fid && f->cp == cp)
162                 return f;
163         qunlock(f);
164         goto loop;
165 }
166
167 /*
168  * always called with flock locked
169  */
170 File*
171 newfp(void)
172 {
173         static int first;
174         File *f;
175         int start, i;
176
177         i = first;
178         start = i;
179         do {
180                 f = &files[i];
181                 i++;
182                 if(i >= conf.nfile)
183                         i = 0;
184                 if(f->cp)
185                         continue;
186                 first = i;
187                 return f;
188         } while(i != start);
189
190         fprint(2, "out of files\n");
191         return 0;
192 }
193
194 void
195 freefp(File *fp)
196 {
197         Chan *cp;
198         File *f, *prev;
199         int h;
200
201         if(!fp || !(cp = fp->cp))
202                 return;
203
204         h = (long)(uintptr)cp + fp->fid;
205         if(h < 0)
206                 h = ~h;
207         h %= nelem(flist);
208
209         lock(&flock);
210         for(prev=0,f=flist[h]; f; prev=f,f=f->next)
211                 if(f == fp) {
212                         if(prev)
213                                 prev->next = f->next;
214                         else
215                                 flist[h] = f->next;
216                         break;
217                 }
218         fp->cp = 0;
219         unlock(&flock);
220 }
221
222 int
223 iaccess(File *f, Dentry *d, int m)
224 {
225         /* uid none gets only other permissions */
226         if(f->uid != 0) {
227                 /*
228                  * owner
229                  */
230                 if(f->uid == d->uid)
231                         if((m<<6) & d->mode)
232                                 return 0;
233                 /*
234                  * group membership
235                  */
236                 if(ingroup(f->uid, d->gid))
237                         if((m<<3) & d->mode)
238                                 return 0;
239         }
240
241         /*
242          * other
243          */
244         if(m & d->mode) {
245                 if((d->mode & DDIR) && (m == DEXEC))
246                         return 0;
247                 if(!ingroup(f->uid, 9999))
248                         return 0;
249         }
250
251         /*
252          * various forms of superuser
253          */
254         if(wstatallow)
255                 return 0;
256         if(duallow != 0 && duallow == f->uid)
257                 if((d->mode & DDIR) && (m == DREAD || m == DEXEC))
258                         return 0;
259
260         return 1;
261 }
262
263 Tlock*
264 tlocked(Iobuf *p, Dentry *d)
265 {
266         Tlock *t, *t1;
267         Off qpath;
268         Timet tim;
269         Device *dev;
270
271         tim = toytime();
272         qpath = d->qid.path;
273         dev = p->dev;
274
275 again:
276         t1 = 0;
277         for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {
278                 if(t->qpath == qpath)
279                 if(t->time >= tim)
280                 if(t->dev == dev)
281                         return nil;             /* its locked */
282                 if(t1 != nil && t->time == 0)
283                         t1 = t;                 /* remember free lock */
284         }
285         if(t1 == 0) {
286                 // reclaim old locks
287                 lock(&tlocklock);
288                 for(t=tlocks+NTLOCK-1; t>=tlocks; t--)
289                         if(t->time < tim) {
290                                 t->time = 0;
291                                 t1 = t;
292                         }
293                 unlock(&tlocklock);
294         }
295         if(t1) {
296                 lock(&tlocklock);
297                 if(t1->time != 0) {
298                         unlock(&tlocklock);
299                         goto again;
300                 }
301                 t1->dev = dev;
302                 t1->qpath = qpath;
303                 t1->time = tim + TLOCK;
304                 unlock(&tlocklock);
305         }
306         /* botch
307          * out of tlock nodes simulates
308          * a locked file
309          */
310         return t1;
311 }
312
313 Wpath*
314 newwp(void)
315 {
316         static int si = 0;
317         int i;
318         Wpath *w, *sw, *ew;
319
320         i = si + 1;
321         if(i < 0 || i >= conf.nwpath)
322                 i = 0;
323         si = i;
324         sw = &wpaths[i];
325         ew = &wpaths[conf.nwpath];
326         for(w=sw;;) {
327                 w++;
328                 if(w >= ew)
329                         w = &wpaths[0];
330                 if(w == sw) {
331                         fprint(2, "out of wpaths\n");
332                         return 0;
333                 }
334                 if(w->refs)
335                         continue;
336                 lock(&wpathlock);
337                 if(w->refs) {
338                         unlock(&wpathlock);
339                         continue;
340                 }
341                 w->refs = 1;
342                 w->up = 0;
343                 unlock(&wpathlock);
344                 return w;
345         }
346
347 }
348
349 void
350 freewp(Wpath *w)
351 {
352         lock(&wpathlock);
353         for(; w; w=w->up)
354                 w->refs--;
355         unlock(&wpathlock);
356 }
357
358 Off
359 qidpathgen(Device *dev)
360 {
361         Iobuf *p;
362         Superb *sb;
363         Off path;
364
365         p = getbuf(dev, superaddr(dev), Brd|Bmod);
366         if(!p || checktag(p, Tsuper, QPSUPER))
367                 panic("newqid: super block");
368         sb = (Superb*)p->iobuf;
369         sb->qidgen++;
370         path = sb->qidgen;
371         putbuf(p);
372         return path;
373 }
374
375 /* truncating to length > 0 */
376 static void
377 truncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i)
378 {
379         int pastlast;
380         Off a;
381
382         pastlast = ts->pastlast;
383         a = ((Off *)p->iobuf)[i];
384         if (d > 0 || pastlast)
385                 buffree(dev, a, d, ts);
386         if (pastlast) {
387                 ((Off *)p->iobuf)[i] = 0;
388                 p->flags |= Bmod|Bimm;
389         } else if (d == 0 && ts->relblk == ts->lastblk)
390                 ts->pastlast = 1;
391         if (d == 0)
392                 ts->relblk++;
393 }
394
395 /*
396  * free the block at `addr' on dev.
397  * if it's an indirect block (d [depth] > 0),
398  * first recursively free all the blocks it names.
399  *
400  * ts->relblk is the block number within the file of this
401  * block (or the first data block eventually pointed to via
402  * this indirect block).
403  */
404 void
405 buffree(Device *dev, Off addr, int d, Truncstate *ts)
406 {
407         Iobuf *p;
408         Off a;
409         int i, pastlast;
410
411         if(!addr)
412                 return;
413         pastlast = (ts == nil? 1: ts->pastlast);
414         /*
415          * if this is an indirect block, recurse and free any
416          * suitable blocks within it (possibly via further indirect blocks).
417          */
418         if(d > 0) {
419                 d--;
420                 p = getbuf(dev, addr, Brd);
421                 if(p) {
422                         if (ts == nil)          /* common case: create */
423                                 for(i=INDPERBUF-1; i>=0; i--) {
424                                         a = ((Off *)p->iobuf)[i];
425                                         buffree(dev, a, d, nil);
426                                 }
427                         else                    /* wstat truncation */
428                                 for (i = 0; i < INDPERBUF; i++)
429                                         truncfree(ts, dev, d, p, i);
430                         putbuf(p);
431                 }
432         }
433         if (!pastlast)
434                 return;
435         /*
436          * having zeroed the pointer to this block, add it to the free list.
437          * stop outstanding i/o
438          */
439         p = getbuf(dev, addr, Bprobe);
440         if(p) {
441                 p->flags &= ~(Bmod|Bimm);
442                 putbuf(p);
443         }
444         /*
445          * dont put written worm
446          * blocks into free list
447          */
448         if(dev->type == Devcw) {
449                 i = cwfree(dev, addr);
450                 if(i)
451                         return;
452         }
453         p = getbuf(dev, superaddr(dev), Brd|Bmod);
454         if(!p || checktag(p, Tsuper, QPSUPER))
455                 panic("buffree: super block");
456         addfree(dev, addr, (Superb*)p->iobuf);
457         putbuf(p);
458 }
459
460 Off
461 bufalloc(Device *dev, int tag, long qid, int uid)
462 {
463         Iobuf *bp, *p;
464         Superb *sb;
465         Off a, n;
466
467         p = getbuf(dev, superaddr(dev), Brd|Bmod);
468         if(!p || checktag(p, Tsuper, QPSUPER)) {
469                 fprint(2, "bufalloc: super block\n");
470                 if(p)
471                         putbuf(p);
472                 return 0;
473         }
474         sb = (Superb*)p->iobuf;
475
476 loop:
477         n = --sb->fbuf.nfree;
478         sb->tfree--;
479         if(n < 0 || n >= FEPERBUF) {
480                 fprint(2, "bufalloc: %Z: bad freelist\n", dev);
481                 n = 0;
482                 sb->fbuf.free[0] = 0;
483         }
484         a = sb->fbuf.free[n];
485         if(n <= 0) {
486                 if(a == 0) {
487                         sb->tfree = 0;
488                         sb->fbuf.nfree = 1;
489                         if(dev->type == Devcw) {
490                                 n = uid;
491                                 if(n < 0 || n >= nelem(growacct))
492                                         n = 0;
493                                 growacct[n]++;
494                                 if(cwgrow(dev, sb, uid))
495                                         goto loop;
496                         }
497                         putbuf(p);
498                         fprint(2, "fs %Z full uid=%d\n", dev, uid);
499                         return 0;
500                 }
501                 bp = getbuf(dev, a, Brd);
502                 if(!bp || checktag(bp, Tfree, QPNONE)) {
503                         if(bp)
504                                 putbuf(bp);
505                         putbuf(p);
506                         return 0;
507                 }
508                 sb->fbuf = *(Fbuf*)bp->iobuf;
509                 putbuf(bp);
510         }
511
512         bp = getbuf(dev, a, Bmod);
513         memset(bp->iobuf, 0, RBUFSIZE);
514         settag(bp, tag, qid);
515         if(tag == Tind1 || tag == Tind2 ||
516 #ifndef COMPAT32
517             tag == Tind3 || tag == Tind4 ||  /* add more Tind tags here ... */
518 #endif
519             tag == Tdir)
520                 bp->flags |= Bimm;
521         putbuf(bp);
522         putbuf(p);
523         return a;
524 }
525
526 /*
527  * what are legal characters in a name?
528  * only disallow control characters.
529  * a) utf avoids control characters.
530  * b) '/' may not be the separator
531  */
532 int
533 checkname(char *n)
534 {
535         int i, c;
536
537         if(n == 0 || *n == 0)
538                 return Ename;
539         if(*n == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)))
540                 return Edot;
541         for(i=1; i<NAMELEN; i++) {
542                 c = n[i] & 0xff;
543                 if(c == 0)
544                         return 0;
545                 if(c < 040)
546                         return Ename;
547         }
548         return Etoolong;
549 }
550
551 void
552 addfree(Device *dev, Off addr, Superb *sb)
553 {
554         int n;
555         Iobuf *p;
556
557         n = sb->fbuf.nfree;
558         if(n < 0 || n > FEPERBUF)
559                 panic("addfree: bad freelist");
560         if(n >= FEPERBUF) {
561                 p = getbuf(dev, addr, Bmod|Bimm);
562                 if(p == 0)
563                         panic("addfree: getbuf");
564                 *(Fbuf*)p->iobuf = sb->fbuf;
565                 settag(p, Tfree, QPNONE);
566                 putbuf(p);
567                 n = 0;
568         }
569         sb->fbuf.free[n++] = addr;
570         sb->fbuf.nfree = n;
571         sb->tfree++;
572         if(addr >= sb->fsize)
573                 sb->fsize = addr+1;
574 }
575
576 /*
577 static int
578 Yfmt(Fmt* fmt)
579 {
580         Chan *cp;
581         char s[20];
582
583         cp = va_arg(fmt->args, Chan*);
584         sprint(s, "C%d.%.3d", cp->type, cp->chan);
585         return fmtstrcpy(fmt, s);
586 }
587  */
588
589 static int
590 Zfmt(Fmt* fmt)
591 {
592         Device *d;
593         int c, c1;
594         char s[100];
595
596         d = va_arg(fmt->args, Device*);
597         if(d == nil) {
598                 sprint(s, "Z***");
599                 goto out;
600         }
601         c = c1 = '\0';
602         switch(d->type) {
603         default:
604                 sprint(s, "D%d", d->type);
605                 break;
606         case Devwren:
607                 c = 'w';
608                 /* fallthrough */
609         case Devworm:
610                 if (c == '\0')
611                         c = 'r';
612                 /* fallthrough */
613         case Devlworm:
614                 if (c == '\0')
615                         c = 'l';
616                 if(d->wren.file)
617                         snprint(s, sizeof(s), "%c\"%s\"", c, d->wren.file);
618                 else if(d->wren.ctrl == 0 && d->wren.lun == 0)
619                         sprint(s, "%c%d", c, d->wren.targ);
620                 else
621                         sprint(s, "%c%d.%d.%d", c, d->wren.ctrl, d->wren.targ,
622                                 d->wren.lun);
623                 break;
624         case Devmcat:
625                 c = '(';
626                 c1 = ')';
627                 /* fallthrough */
628         case Devmlev:
629                 if (c == '\0') {
630                         c = '[';
631                         c1 = ']';
632                 }
633                 /* fallthrough */
634         case Devmirr:
635                 if (c == '\0') {
636                         c = '{';
637                         c1 = '}';
638                 }
639                 if(d->cat.first == d->cat.last)
640                         sprint(s, "%c%Z%c", c, d->cat.first, c1);
641                 else if(d->cat.first->link == d->cat.last)
642                         sprint(s, "%c%Z%Z%c", c, d->cat.first, d->cat.last, c1);
643                 else
644                         sprint(s, "%c%Z-%Z%c", c, d->cat.first, d->cat.last, c1);
645                 break;
646         case Devro:
647                 sprint(s, "o%Z%Z", d->ro.parent->cw.c, d->ro.parent->cw.w);
648                 break;
649         case Devcw:
650                 sprint(s, "c%Z%Z", d->cw.c, d->cw.w);
651                 break;
652         case Devjuke:
653                 sprint(s, "j%Z%Z", d->j.j, d->j.m);
654                 break;
655         case Devfworm:
656                 sprint(s, "f%Z", d->fw.fw);
657                 break;
658         case Devpart:
659                 sprint(s, "p(%Z)%ld.%ld", d->part.d, d->part.base, d->part.size);
660                 break;
661         case Devswab:
662                 sprint(s, "x%Z", d->swab.d);
663                 break;
664         case Devnone:
665                 sprint(s, "n");
666                 break;
667         }
668 out:
669         return fmtstrcpy(fmt, s);
670 }
671
672 static int
673 Gfmt(Fmt* fmt)
674 {
675         int t;
676         char *s;
677
678         t = va_arg(fmt->args, int);
679         s = "<badtag>";
680         if(t >= 0 && t < MAXTAG)
681                 s = tagnames[t];
682         return fmtstrcpy(fmt, s);
683 }
684
685 void
686 formatinit(void)
687 {
688         quotefmtinstall();
689 //      fmtinstall('Y', Yfmt);  /* print channels */
690         fmtinstall('Z', Zfmt);  /* print devices */
691         fmtinstall('G', Gfmt);  /* print tags */
692         fmtinstall('T', Tfmt);  /* print times */
693 //      fmtinstall('E', eipfmt);        /* print ether addresses */
694         fmtinstall('I', eipfmt);        /* print ip addresses */
695 }
696
697 void
698 rootream(Device *dev, Off addr)
699 {
700         Iobuf *p;
701         Dentry *d;
702
703         p = getbuf(dev, addr, Bmod|Bimm);
704         memset(p->iobuf, 0, RBUFSIZE);
705         settag(p, Tdir, QPROOT);
706         d = getdir(p, 0);
707         strcpy(d->name, "/");
708         d->uid = -1;
709         d->gid = -1;
710         d->mode = DALLOC | DDIR |
711                 ((DREAD|DEXEC) << 6) |
712                 ((DREAD|DEXEC) << 3) |
713                 ((DREAD|DEXEC) << 0);
714         d->qid = QID9P1(QPROOT|QPDIR,0);
715         d->atime = time(nil);
716         d->mtime = d->atime;
717         d->muid = 0;
718         putbuf(p);
719 }
720
721 void
722 superream(Device *dev, Off addr)
723 {
724         Iobuf *p;
725         Superb *s;
726         Off i;
727
728         p = getbuf(dev, addr, Bmod|Bimm);
729         memset(p->iobuf, 0, RBUFSIZE);
730         settag(p, Tsuper, QPSUPER);
731
732         s = (Superb*)p->iobuf;
733         s->fstart = 2;
734         s->fsize = devsize(dev);
735         s->fbuf.nfree = 1;
736         s->qidgen = 10;
737         for(i = s->fsize-1; i >= addr+2; i--)
738                 addfree(dev, i, s);
739         putbuf(p);
740 }
741
742 struct
743 {
744         Lock;
745         Msgbuf  *smsgbuf;
746         Msgbuf  *lmsgbuf;
747 } msgalloc;
748
749 /*
750  * pre-allocate some message buffers at boot time.
751  * if this supply is exhausted, more will be allocated as needed.
752  */
753 void
754 mbinit(void)
755 {
756         Msgbuf *mb;
757         Rabuf *rb;
758         int i;
759
760         lock(&msgalloc);
761         unlock(&msgalloc);
762         msgalloc.lmsgbuf = 0;
763         msgalloc.smsgbuf = 0;
764         for(i=0; i<conf.nlgmsg; i++) {
765                 mb = malloc(sizeof(Msgbuf));
766                 mb->magic = Mbmagic;
767                 mb->xdata = malloc(LARGEBUF+Slop);
768                 mb->flags = LARGE;
769                 mbfree(mb);
770                 cons.nlarge++;
771         }
772         for(i=0; i<conf.nsmmsg; i++) {
773                 mb = malloc(sizeof(Msgbuf));
774                 mb->magic = Mbmagic;
775                 mb->xdata = malloc(SMALLBUF+Slop);
776                 mb->flags = 0;
777                 mbfree(mb);
778                 cons.nsmall++;
779         }
780         memset(mballocs, 0, sizeof(mballocs));
781
782         lock(&rabuflock);
783         unlock(&rabuflock);
784         rabuffree = 0;
785         for(i=0; i<1000; i++) {
786                 rb = malloc(sizeof(*rb));
787                 rb->link = rabuffree;
788                 rabuffree = rb;
789         }
790 }
791
792 Msgbuf*
793 mballoc(int count, Chan *cp, int category)
794 {
795         Msgbuf *mb;
796
797         lock(&msgalloc);
798         if(count > SMALLBUF) {
799                 if(count > LARGEBUF)
800                         panic("msgbuf count");
801                 mb = msgalloc.lmsgbuf;
802                 if(mb == nil) {
803                         mb = malloc(sizeof(Msgbuf));
804                         mb->xdata = malloc(LARGEBUF+Slop);
805                         cons.nlarge++;
806                 } else
807                         msgalloc.lmsgbuf = mb->next;
808                 mb->flags = LARGE;
809         } else {
810                 mb = msgalloc.smsgbuf;
811                 if(mb == nil) {
812                         mb = malloc(sizeof(Msgbuf));
813                         mb->xdata = malloc(SMALLBUF+Slop);
814                         cons.nsmall++;
815                 } else
816                         msgalloc.smsgbuf = mb->next;
817                 mb->flags = 0;
818         }
819         mballocs[category]++;
820         unlock(&msgalloc);
821         mb->magic = Mbmagic;
822         mb->count = count;
823         mb->chan = cp;
824         mb->next = 0;
825         mb->param = 0;
826         mb->category = category;
827         mb->data = mb->xdata+Slop;
828         return mb;
829 }
830
831 void
832 mbfree(Msgbuf *mb)
833 {
834         if(mb == nil)
835                 return;
836         assert(mb->magic == Mbmagic);
837         if (mb->magic != Mbmagic)
838                 panic("mbfree: bad magic 0x%lux", mb->magic);
839         if(mb->flags & BTRACE)
840                 print("mbfree: BTRACE cat=%d flags=%ux, caller %#p\n",
841                         mb->category, mb->flags, getcallerpc(&mb));
842
843         if(mb->flags & FREE)
844                 panic("mbfree already free");
845
846         lock(&msgalloc);
847         mballocs[mb->category]--;
848         mb->flags |= FREE;
849         if(mb->flags & LARGE) {
850                 mb->next = msgalloc.lmsgbuf;
851                 msgalloc.lmsgbuf = mb;
852         } else {
853                 mb->next = msgalloc.smsgbuf;
854                 msgalloc.smsgbuf = mb;
855         }
856         mb->data = 0;
857         mb->magic = 0;
858         unlock(&msgalloc);
859 }
860
861 /*
862  * returns 1 if n is prime
863  * used for adjusting lengths
864  * of hashing things.
865  * there is no need to be clever
866  */
867 int
868 prime(vlong n)
869 {
870         long i;
871
872         if((n%2) == 0)
873                 return 0;
874         for(i=3;; i+=2) {
875                 if((n%i) == 0)
876                         return 0;
877                 if((vlong)i*i >= n)
878                         return 1;
879         }
880 }
881
882 char*
883 getwrd(char *word, char *line)
884 {
885         int c, n;
886
887         while(isascii(*line) && isspace(*line) && *line != '\n')
888                 line++;
889         for(n = 0; n < Maxword; n++) {
890                 c = *line;
891                 if(c == '\0' || isascii(c) && isspace(c))
892                         break;
893                 line++;
894                 *word++ = c;
895         }
896         *word = 0;
897         return line;
898 }
899
900 void
901 hexdump(void *a, int n)
902 {
903         char s1[30], s2[4];
904         uchar *p;
905         int i;
906
907         p = a;
908         s1[0] = 0;
909         for(i = 0; i < n; i++) {
910                 sprint(s2, " %.2ux", p[i]);
911                 strcat(s1, s2);
912                 if((i&7) == 7) {
913                         print("%s\n", s1);
914                         s1[0] = 0;
915                 }
916         }
917         if(s1[0])
918                 print("%s\n", s1);
919 }
920
921 void*
922 fs_recv(Queue *q, int)
923 {
924         void *a;
925         int i, c;
926
927         if(q == nil)
928                 panic("recv null q");
929         qlock(q);
930         while((c = q->count) <= 0)
931                 rsleep(&q->empty);
932         i = q->loc;
933         a = q->args[i];
934         i++;
935         if(i >= q->size)
936                 i = 0;
937         q->loc = i;
938         q->count = c-1;
939         rwakeup(&q->full);                      /* no longer full */
940         qunlock(q);
941         return a;
942 }
943
944 void
945 fs_send(Queue *q, void *a)
946 {
947         int i, c;
948
949         if(q == nil)
950                 panic("send null q");
951         qlock(q);
952         while((c = q->count) >= q->size)
953                 rsleep(&q->full);
954         i = q->loc + c;
955         if(i >= q->size)
956                 i -= q->size;
957         q->args[i] = a;
958         q->count = c+1;
959         rwakeup(&q->empty);                     /* no longer empty */
960         qunlock(q);
961 }
962
963 Queue*
964 newqueue(int size, char *name)
965 {
966         Queue *q;
967
968         q = malloc(sizeof(Queue) + (size-1)*sizeof(void*));
969         q->size = size;
970         q->full.l = q->empty.l = &q->QLock;
971         q->name = name;
972         return q;
973 }
974
975 int
976 devread(Device *d, Off b, void *c)
977 {
978         int e;
979
980         for (;;)
981                 switch(d->type) {
982                 case Devcw:
983                         return cwread(d, b, c);
984
985                 case Devjuke:
986                         d = d->j.m;
987                         break;
988
989                 case Devro:
990                         return roread(d, b, c);
991
992                 case Devwren:
993                         return wrenread(d, b, c);
994
995                 case Devworm:
996                 case Devlworm:
997                         return wormread(d, b, c);
998
999                 case Devfworm:
1000                         return fwormread(d, b, c);
1001
1002                 case Devmcat:
1003                         return mcatread(d, b, c);
1004
1005                 case Devmlev:
1006                         return mlevread(d, b, c);
1007
1008                 case Devmirr:
1009                         return mirrread(d, b, c);
1010
1011                 case Devpart:
1012                         return partread(d, b, c);
1013
1014                 case Devswab:
1015                         e = devread(d->swab.d, b, c);
1016                         if(e == 0)
1017                                 swab(c, 0);
1018                         return e;
1019
1020                 case Devnone:
1021                         fprint(2, "read from device none(%lld)\n", (Wideoff)b);
1022                         return 1;
1023                 default:
1024                         panic("illegal device in devread: %Z %lld",
1025                                 d, (Wideoff)b);
1026                         return 1;
1027                 }
1028 }
1029
1030 int
1031 devwrite(Device *d, Off b, void *c)
1032 {
1033         int e;
1034
1035         /*
1036          * set readonly to non-0 to prevent all writes;
1037          * mainly for trying dangerous experiments.
1038          */
1039         if (readonly)
1040                 return 0;
1041         for (;;)
1042                 switch(d->type) {
1043                 case Devcw:
1044                         return cwwrite(d, b, c);
1045
1046                 case Devjuke:
1047                         d = d->j.m;
1048                         break;
1049
1050                 case Devro:
1051                         fprint(2, "write to ro device %Z(%lld)\n", d, (Wideoff)b);
1052                         return 1;
1053
1054                 case Devwren:
1055                         return wrenwrite(d, b, c);
1056
1057                 case Devworm:
1058                 case Devlworm:
1059                         return wormwrite(d, b, c);
1060
1061                 case Devfworm:
1062                         return fwormwrite(d, b, c);
1063
1064                 case Devmcat:
1065                         return mcatwrite(d, b, c);
1066
1067                 case Devmlev:
1068                         return mlevwrite(d, b, c);
1069
1070                 case Devmirr:
1071                         return mirrwrite(d, b, c);
1072
1073                 case Devpart:
1074                         return partwrite(d, b, c);
1075
1076                 case Devswab:
1077                         swab(c, 1);
1078                         e = devwrite(d->swab.d, b, c);
1079                         swab(c, 0);
1080                         return e;
1081
1082                 case Devnone:
1083                         /* checktag() can generate blocks with type devnone */
1084                         return 0;
1085                 default:
1086                         panic("illegal device in devwrite: %Z %lld",
1087                                 d, (Wideoff)b);
1088                         return 1;
1089                 }
1090 }
1091
1092 Devsize
1093 devsize(Device *d)
1094 {
1095         for (;;)
1096                 switch(d->type) {
1097                 case Devcw:
1098                 case Devro:
1099                         return cwsize(d);
1100
1101                 case Devjuke:
1102                         d = d->j.m;
1103                         break;
1104
1105                 case Devwren:
1106                         return wrensize(d);
1107
1108                 case Devworm:
1109                 case Devlworm:
1110                         return wormsize(d);
1111
1112                 case Devfworm:
1113                         return fwormsize(d);
1114
1115                 case Devmcat:
1116                         return mcatsize(d);
1117
1118                 case Devmlev:
1119                         return mlevsize(d);
1120
1121                 case Devmirr:
1122                         return mirrsize(d);
1123
1124                 case Devpart:
1125                         return partsize(d);
1126
1127                 case Devswab:
1128                         d = d->swab.d;
1129                         break;
1130                 default:
1131                         panic("illegal device in devsize: %Z", d);
1132                         return 0;
1133                 }
1134 }
1135
1136 /* result is malloced */
1137 char *
1138 sdof(Device *d)
1139 {
1140         static char name[256];
1141
1142         for (;;)
1143                 switch(d->type) {
1144                 case Devjuke:
1145                         d = d->j.j;             /* robotics */
1146                         break;
1147                 case Devwren:
1148                         snprint(name, sizeof name, "/dev/sd%d%d", d->wren.ctrl,
1149                                 d->wren.targ);
1150                         return strdup(name);
1151                 case Devswab:
1152                         d = d->swab.d;
1153                         break;
1154                 default:
1155                         panic("illegal device in sdof: %Z", d);
1156                         return nil;
1157                 }
1158 }
1159
1160 Off
1161 superaddr(Device *d)
1162 {
1163         for (;;)
1164                 switch(d->type) {
1165                 default:
1166                         return SUPER_ADDR;
1167                 case Devcw:
1168                 case Devro:
1169                         return cwsaddr(d);
1170                 case Devswab:
1171                         d = d->swab.d;
1172                         break;
1173                 }
1174 }
1175
1176 Off
1177 getraddr(Device *d)
1178 {
1179         for (;;)
1180                 switch(d->type) {
1181                 default:
1182                         return ROOT_ADDR;
1183                 case Devcw:
1184                 case Devro:
1185                         return cwraddr(d);
1186                 case Devswab:
1187                         d = d->swab.d;
1188                         break;
1189                 }
1190 }
1191
1192 void
1193 devream(Device *d, int top)
1194 {
1195         Device *l;
1196
1197 loop:
1198         if(chatty)
1199                 print("\tdevream %Z %d\n", d, top);
1200         switch(d->type) {
1201         default:
1202                 fprint(2, "devream: unknown dev type %Z\n", d);
1203                 return;
1204
1205         case Devcw:
1206                 devream(d->cw.w, 0);
1207                 devream(d->cw.c, 0);
1208                 if(top) {
1209                         wlock(&mainlock);
1210                         cwream(d);
1211                         wunlock(&mainlock);
1212                 }
1213                 devinit(d);
1214                 return;
1215
1216         case Devfworm:
1217                 devream(d->fw.fw, 0);
1218                 fwormream(d);
1219                 break;
1220
1221         case Devpart:
1222                 devream(d->part.d, 0);
1223                 break;
1224
1225         case Devmlev:
1226         case Devmcat:
1227         case Devmirr:
1228                 for(l=d->cat.first; l; l=l->link)
1229                         devream(l, 0);
1230                 break;
1231
1232         case Devjuke:
1233         case Devworm:
1234         case Devlworm:
1235         case Devwren:
1236                 break;
1237
1238         case Devswab:
1239                 d = d->swab.d;
1240                 goto loop;
1241         }
1242         devinit(d);
1243         if(top) {
1244                 wlock(&mainlock);
1245                 rootream(d, ROOT_ADDR);
1246                 superream(d, SUPER_ADDR);
1247                 wunlock(&mainlock);
1248         }
1249 }
1250
1251 void
1252 devrecover(Device *d)
1253 {
1254         for (;;) {
1255                 if(chatty)
1256                         print("recover %Z\n", d);
1257                 switch(d->type) {
1258                 default:
1259                         fprint(2, "devrecover: unknown dev type %Z\n", d);
1260                         return;
1261
1262                 case Devcw:
1263                         wlock(&mainlock);       /* recover */
1264                         cwrecover(d);
1265                         wunlock(&mainlock);
1266                         return;
1267
1268                 case Devswab:
1269                         d = d->swab.d;
1270                         break;
1271                 }
1272         }
1273 }
1274
1275 void
1276 devinit(Device *d)
1277 {
1278         for (;;) {
1279                 if(d->init)
1280                         return;
1281                 d->init = 1;
1282                 if(chatty)
1283                         print("\tdevinit %Z\n", d);
1284                 switch(d->type) {
1285                 default:
1286                         fprint(2, "devinit: unknown device %Z\n", d);
1287                         return;
1288
1289                 case Devro:
1290                         cwinit(d->ro.parent);
1291                         return;
1292
1293                 case Devcw:
1294                         cwinit(d);
1295                         return;
1296
1297                 case Devjuke:
1298                         jukeinit(d);
1299                         return;
1300
1301                 case Devwren:
1302                         wreninit(d);
1303                         return;
1304
1305                 case Devworm:
1306                 case Devlworm:
1307                         return;
1308
1309                 case Devfworm:
1310                         fworminit(d);
1311                         return;
1312
1313                 case Devmcat:
1314                         mcatinit(d);
1315                         return;
1316
1317                 case Devmlev:
1318                         mlevinit(d);
1319                         return;
1320
1321                 case Devmirr:
1322                         mirrinit(d);
1323                         return;
1324
1325                 case Devpart:
1326                         partinit(d);
1327                         return;
1328
1329                 case Devswab:
1330                         d = d->swab.d;
1331                         break;
1332
1333                 case Devnone:
1334                         return;
1335                 }
1336         }
1337 }
1338
1339 void
1340 swab2(void *c)
1341 {
1342         uchar *p;
1343         int t;
1344
1345         p = c;
1346
1347         t = p[0];
1348         p[0] = p[1];
1349         p[1] = t;
1350 }
1351
1352 void
1353 swab4(void *c)
1354 {
1355         uchar *p;
1356         int t;
1357
1358         p = c;
1359
1360         t = p[0];
1361         p[0] = p[3];
1362         p[3] = t;
1363
1364         t = p[1];
1365         p[1] = p[2];
1366         p[2] = t;
1367 }
1368
1369 void
1370 swab8(void *c)
1371 {
1372         uchar *p;
1373         int t;
1374
1375         p = c;
1376
1377         t = p[0];
1378         p[0] = p[7];
1379         p[7] = t;
1380
1381         t = p[1];
1382         p[1] = p[6];
1383         p[6] = t;
1384
1385         t = p[2];
1386         p[2] = p[5];
1387         p[5] = t;
1388
1389         t = p[3];
1390         p[3] = p[4];
1391         p[4] = t;
1392 }
1393
1394 /*
1395  * swab a block
1396  *      flag = 0 -- convert from foreign to native
1397  *      flag = 1 -- convert from native to foreign
1398  */
1399 void
1400 swab(void *c, int flag)
1401 {
1402         uchar *p;
1403         Tag *t;
1404         int i, j;
1405         Dentry *d;
1406         Cache *h;
1407         Bucket *b;
1408         Superb *s;
1409         Fbuf *f;
1410         Off *l;
1411
1412         /* swab the tag */
1413         p = (uchar*)c;
1414         t = (Tag*)(p + BUFSIZE);
1415         if(!flag) {
1416                 swab2(&t->pad);
1417                 swab2(&t->tag);
1418                 swaboff(&t->path);
1419         }
1420
1421         /* swab each block type */
1422         switch(t->tag) {
1423         default:
1424                 fprint(2, "no swab for tag=%G rw=%d\n", t->tag, flag);
1425                 hexdump(p, 256);
1426                 panic("swab");
1427                 break;
1428
1429         case Tsuper:
1430                 s = (Superb*)p;
1431                 swaboff(&s->fbuf.nfree);
1432                 for(i=0; i<FEPERBUF; i++)
1433                         swaboff(&s->fbuf.free[i]);
1434                 swaboff(&s->fstart);
1435                 swaboff(&s->fsize);
1436                 swaboff(&s->tfree);
1437                 swaboff(&s->qidgen);
1438                 swaboff(&s->cwraddr);
1439                 swaboff(&s->roraddr);
1440                 swaboff(&s->last);
1441                 swaboff(&s->next);
1442                 break;
1443
1444         case Tdir:
1445                 for(i=0; i<DIRPERBUF; i++) {
1446                         d = (Dentry*)p + i;
1447                         swab2(&d->uid);
1448                         swab2(&d->gid);
1449                         swab2(&d->mode);
1450                         swab2(&d->muid);
1451                         swaboff(&d->qid.path);
1452                         swab4(&d->qid.version);
1453                         swaboff(&d->size);
1454                         for(j=0; j<NDBLOCK; j++)
1455                                 swaboff(&d->dblock[j]);
1456                         for (j = 0; j < NIBLOCK; j++)
1457                                 swaboff(&d->iblocks[j]);
1458                         swab4(&d->atime);
1459                         swab4(&d->mtime);
1460                 }
1461                 break;
1462
1463         case Tind1:
1464         case Tind2:
1465 #ifndef COMPAT32
1466         case Tind3:
1467         case Tind4:
1468         /* add more Tind tags here ... */
1469 #endif
1470                 l = (Off *)p;
1471                 for(i=0; i<INDPERBUF; i++) {
1472                         swaboff(l);
1473                         l++;
1474                 }
1475                 break;
1476
1477         case Tfree:
1478                 f = (Fbuf*)p;
1479                 swaboff(&f->nfree);
1480                 for(i=0; i<FEPERBUF; i++)
1481                         swaboff(&f->free[i]);
1482                 break;
1483
1484         case Tbuck:
1485                 for(i=0; i<BKPERBLK; i++) {
1486                         b = (Bucket*)p + i;
1487                         swab4(&b->agegen);
1488                         for(j=0; j<CEPERBK; j++) {
1489                                 swab2(&b->entry[j].age);
1490                                 swab2(&b->entry[j].state);
1491                                 swaboff(&b->entry[j].waddr);
1492                         }
1493                 }
1494                 break;
1495
1496         case Tcache:
1497                 h = (Cache*)p;
1498                 swaboff(&h->maddr);
1499                 swaboff(&h->msize);
1500                 swaboff(&h->caddr);
1501                 swaboff(&h->csize);
1502                 swaboff(&h->fsize);
1503                 swaboff(&h->wsize);
1504                 swaboff(&h->wmax);
1505                 swaboff(&h->sbaddr);
1506                 swaboff(&h->cwraddr);
1507                 swaboff(&h->roraddr);
1508                 swab4(&h->toytime);
1509                 swab4(&h->time);
1510                 break;
1511
1512         case Tnone:     // unitialized
1513         case Tfile:     // someone elses problem
1514         case Tvirgo:    // bit map -- all bytes
1515         case Tconfig:   // configuration string -- all bytes
1516                 break;
1517         }
1518
1519         /* swab the tag */
1520         if(flag) {
1521                 swab2(&t->pad);
1522                 swab2(&t->tag);
1523                 swaboff(&t->path);
1524         }
1525 }