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