5 Slop = 256, /* room at the start of a message buf for proto hdrs */
13 for(fs=filsys; fs->name; fs++)
14 if(strcmp(fs->name, p) == 0)
24 for(fs=filsys; fs->name; fs++)
31 * allocate 'count' contiguous channels
32 * of type 'type' and return pointer to base
35 fs_chaninit(int count, int data)
41 p = ialloc((uintptr)count * (sizeof(Chan)+data), 0);
43 for(i = 0; i < count; i++) {
47 cp->chan = cons.chano;
49 snprint(cp->whoname, sizeof(cp->whoname), "<none>");
51 wunlock(&cp->reflock);
53 runlock(&cp->reflock);
73 for (h=0; h < nelem(flist); h++)
74 for (prev=0, f = flist[h]; f; prev=f, f=f->next) {
88 t->time = 0; /* free the lock */
104 enum { NOFID = (ulong)~0 };
107 * returns a locked file structure
110 filep(Chan *cp, ulong fid, int flag)
118 h = (long)(uintptr)cp + fid;
125 for(f=flist[h]; f; f=f->next)
126 if(f->fid == fid && f->cp == cp){
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.
133 if(flag == 0 || cp == cons.chan)
160 if(f->fid == fid && f->cp == cp)
167 * always called with flock locked
189 fprint(2, "out of files\n");
200 if(!fp || !(cp = fp->cp))
203 h = (long)(uintptr)cp + fp->fid;
209 for(prev=0,f=flist[h]; f; prev=f,f=f->next)
212 prev->next = f->next;
222 iaccess(File *f, Dentry *d, int m)
224 /* uid none gets only other permissions */
235 if(ingroup(f->uid, d->gid))
243 * walk directories regardless.
244 * otherwise its impossible to get
245 * from the root to noworld's directories.
247 if((d->mode & DDIR) && (m == DEXEC))
249 if(!ingroup(f->uid, 9999))
253 /* read access for du */
254 if(duallow != 0 && duallow == f->uid)
255 if((d->mode & DDIR) && (m == DREAD || m == DEXEC))
259 return !isallowed(f);
265 if(f->cp == cons.chan)
273 return f->uid == allowed;
278 tlocked(Iobuf *p, Dentry *d)
291 for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {
292 if(t->qpath == qpath)
295 return nil; /* its locked */
296 if(t1 != nil && t->time == 0)
297 t1 = t; /* remember free lock */
302 for(t=tlocks+NTLOCK-1; t>=tlocks; t--)
317 t1->time = tim + TLOCK;
321 * out of tlock nodes simulates
335 if(i < 0 || i >= conf.nwpath)
339 ew = &wpaths[conf.nwpath];
345 fprint(2, "out of wpaths\n");
373 qidpathgen(Device *dev)
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;
385 } while(path == QPDIR);
390 /* truncating to length > 0 */
392 truncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i)
397 pastlast = ts->pastlast;
398 a = ((Off *)p->iobuf)[i];
399 if (d > 0 || pastlast)
400 buffree(dev, a, d, ts);
402 ((Off *)p->iobuf)[i] = 0;
403 p->flags |= Bmod|Bimm;
404 } else if (d == 0 && ts->relblk == ts->lastblk)
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.
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).
420 buffree(Device *dev, Off addr, int d, Truncstate *ts)
428 pastlast = (ts == nil? 1: ts->pastlast);
430 * if this is an indirect block, recurse and free any
431 * suitable blocks within it (possibly via further indirect blocks).
435 p = getbuf(dev, addr, Brd);
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);
442 else /* wstat truncation */
443 for (i = 0; i < INDPERBUF; i++)
444 truncfree(ts, dev, d, p, i);
451 * having zeroed the pointer to this block, add it to the free list.
452 * stop outstanding i/o
454 p = getbuf(dev, addr, Bprobe);
456 p->flags &= ~(Bmod|Bimm);
460 * dont put written worm
461 * blocks into free list
463 if(dev->type == Devcw) {
464 i = cwfree(dev, addr);
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);
476 bufalloc(Device *dev, int tag, long qid, int uid)
482 p = getbuf(dev, superaddr(dev), Brd|Bmod);
483 if(!p || checktag(p, Tsuper, QPSUPER)) {
484 fprint(2, "bufalloc: super block\n");
489 sb = (Superb*)p->iobuf;
492 n = --sb->fbuf.nfree;
494 if(n < 0 || n >= FEPERBUF) {
495 fprint(2, "bufalloc: %Z: bad freelist\n", dev);
497 sb->fbuf.free[0] = 0;
499 a = sb->fbuf.free[n];
504 if(dev->type == Devcw) {
506 if(n < 0 || n >= nelem(growacct))
509 if(cwgrow(dev, sb, uid))
513 fprint(2, "fs %Z full uid=%d\n", dev, uid);
516 bp = getbuf(dev, a, Brd);
517 if(!bp || checktag(bp, Tfree, QPNONE)) {
523 sb->fbuf = *(Fbuf*)bp->iobuf;
527 bp = getbuf(dev, a, Bmod);
528 memset(bp->iobuf, 0, RBUFSIZE);
529 settag(bp, tag, qid);
530 if(tag == Tind1 || tag == Tind2 ||
532 tag == Tind3 || tag == Tind4 || /* add more Tind tags here ... */
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.
552 if(n == 0 || *n == 0)
554 if(*n == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)))
556 for(i=1; i<NAMELEN; i++) {
560 if(c < 040 || c == '/')
567 addfree(Device *dev, Off addr, Superb *sb)
573 if(n < 0 || n > FEPERBUF)
574 panic("addfree: bad freelist");
576 p = getbuf(dev, addr, Bmod|Bimm);
578 panic("addfree: getbuf");
579 *(Fbuf*)p->iobuf = sb->fbuf;
580 settag(p, Tfree, QPNONE);
584 sb->fbuf.free[n++] = addr;
587 if(addr >= sb->fsize)
598 cp = va_arg(fmt->args, Chan*);
599 sprint(s, "C%d.%.3d", cp->type, cp->chan);
600 return fmtstrcpy(fmt, s);
611 d = va_arg(fmt->args, Device*);
619 sprint(s, "D%d", d->type);
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);
636 sprint(s, "%c%d.%d.%d", c, d->wren.ctrl, d->wren.targ,
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);
659 sprint(s, "%c%Z-%Z%c", c, d->cat.first, d->cat.last, c1);
662 sprint(s, "o%Z%Z", d->ro.parent->cw.c, d->ro.parent->cw.w);
665 sprint(s, "c%Z%Z", d->cw.c, d->cw.w);
668 sprint(s, "j%Z%Z", d->j.j, d->j.m);
671 sprint(s, "f%Z", d->fw.fw);
674 sprint(s, "p(%Z)%ld.%ld", d->part.d, d->part.base, d->part.size);
677 sprint(s, "x%Z", d->swab.d);
684 return fmtstrcpy(fmt, s);
693 t = va_arg(fmt->args, int);
695 if(t >= 0 && t < MAXTAG)
697 return fmtstrcpy(fmt, s);
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 */
713 rootream(Device *dev, Off addr)
718 p = getbuf(dev, addr, Bmod|Bimm);
719 memset(p->iobuf, 0, RBUFSIZE);
720 settag(p, Tdir, QPROOT);
722 strcpy(d->name, "/");
725 d->mode = DALLOC | DDIR | 0775;
726 d->qid = QID9P1(QPROOT|QPDIR,0);
727 d->atime = time(nil);
734 superream(Device *dev, Off addr)
740 p = getbuf(dev, addr, Bmod|Bimm);
741 memset(p->iobuf, 0, RBUFSIZE);
742 settag(p, Tsuper, QPSUPER);
744 s = (Superb*)p->iobuf;
746 s->fsize = devsize(dev);
749 for(i = s->fsize-1; i >= addr+2; i--)
762 * pre-allocate some message buffers at boot time.
763 * if this supply is exhausted, more will be allocated as needed.
774 msgalloc.lmsgbuf = 0;
775 msgalloc.smsgbuf = 0;
776 for(i=0; i<conf.nlgmsg; i++) {
777 mb = ialloc(sizeof(Msgbuf), 0);
779 mb->xdata = ialloc(LARGEBUF+Slop, 0);
784 for(i=0; i<conf.nsmmsg; i++) {
785 mb = ialloc(sizeof(Msgbuf), 0);
787 mb->xdata = ialloc(SMALLBUF+Slop, 0);
792 memset(mballocs, 0, sizeof(mballocs));
797 for(i=0; i<1000; i++) {
798 rb = ialloc(sizeof(*rb), 0);
799 rb->link = rabuffree;
805 mballoc(int count, Chan *cp, int category)
810 if(count > SMALLBUF) {
812 panic("msgbuf count");
813 mb = msgalloc.lmsgbuf;
815 mb = ialloc(sizeof(Msgbuf), 0);
816 mb->xdata = ialloc(LARGEBUF+Slop, 0);
819 msgalloc.lmsgbuf = mb->next;
822 mb = msgalloc.smsgbuf;
824 mb = ialloc(sizeof(Msgbuf), 0);
825 mb->xdata = ialloc(SMALLBUF+Slop, 0);
828 msgalloc.smsgbuf = mb->next;
831 mballocs[category]++;
838 mb->category = category;
839 mb->data = mb->xdata+Slop;
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));
855 panic("mbfree already free");
858 mballocs[mb->category]--;
860 if(mb->flags & LARGE) {
861 mb->next = msgalloc.lmsgbuf;
862 msgalloc.lmsgbuf = mb;
864 mb->next = msgalloc.smsgbuf;
865 msgalloc.smsgbuf = mb;
873 * returns 1 if n is prime
874 * used for adjusting lengths
876 * there is no need to be clever
894 getwrd(char *word, char *line)
898 while(isascii(*line) && isspace(*line) && *line != '\n')
900 for(n = 0; n < Maxword; n++) {
902 if(c == '\0' || isascii(c) && isspace(c))
912 hexdump(void *a, int n)
920 for(i = 0; i < n; i++) {
921 sprint(s2, " %.2ux", p[i]);
924 fprint(2, "%s\n", s1);
929 fprint(2, "%s\n", s1);
932 extern int cas(long *p, long ov, long nv);
935 fs_recv(Queue *q, int)
941 if(v == 0 || cas(&q->count, v, v-1) == 0)
942 semacquire(&q->count, 1);
945 if(++q->rp >= &q->args[q->size])
948 semrelease(&q->avail, 1);
953 fs_send(Queue *q, void *a)
958 if(v == 0 || cas(&q->avail, v, v-1) == 0)
959 semacquire(&q->avail, 1);
962 if(++q->wp >= &q->args[q->size])
965 semrelease(&q->count, 1);
969 newqueue(int size, char *name)
973 q = ialloc(sizeof(Queue) + (size-1)*sizeof(void*), 0);
984 devread(Device *d, Off b, void *c)
991 return cwread(d, b, c);
998 return roread(d, b, c);
1001 return wrenread(d, b, c);
1005 return wormread(d, b, c);
1008 return fwormread(d, b, c);
1011 return mcatread(d, b, c);
1014 return mlevread(d, b, c);
1017 return mirrread(d, b, c);
1020 return partread(d, b, c);
1023 e = devread(d->swab.d, b, c);
1029 fprint(2, "read from device none(%lld)\n", (Wideoff)b);
1032 panic("illegal device in devread: %Z %lld",
1039 devwrite(Device *d, Off b, void *c)
1044 * set readonly to non-0 to prevent all writes;
1045 * mainly for trying dangerous experiments.
1052 return cwwrite(d, b, c);
1059 fprint(2, "write to ro device %Z(%lld)\n", d, (Wideoff)b);
1063 return wrenwrite(d, b, c);
1067 return wormwrite(d, b, c);
1070 return fwormwrite(d, b, c);
1073 return mcatwrite(d, b, c);
1076 return mlevwrite(d, b, c);
1079 return mirrwrite(d, b, c);
1082 return partwrite(d, b, c);
1086 e = devwrite(d->swab.d, b, c);
1091 /* checktag() can generate blocks with type devnone */
1094 panic("illegal device in devwrite: %Z %lld",
1121 return fwormsize(d);
1139 panic("illegal device in devsize: %Z", d);
1144 /* result is malloced */
1148 static char name[256];
1153 d = d->j.j; /* robotics */
1156 snprint(name, sizeof name, "/dev/sd%d%d", d->wren.ctrl,
1158 return strdup(name);
1163 panic("illegal device in sdof: %Z", d);
1169 superaddr(Device *d)
1201 devream(Device *d, int top)
1207 print("\tdevream %Z %d\n", d, top);
1210 fprint(2, "devream: unknown dev type %Z\n", d);
1214 devream(d->cw.w, 0);
1215 devream(d->cw.c, 0);
1225 devream(d->fw.fw, 0);
1230 devream(d->part.d, 0);
1236 for(l=d->cat.first; l; l=l->link)
1253 rootream(d, ROOT_ADDR);
1254 superream(d, SUPER_ADDR);
1260 devrecover(Device *d)
1264 print("recover %Z\n", d);
1267 fprint(2, "devrecover: unknown dev type %Z\n", d);
1271 wlock(&mainlock); /* recover */
1291 print("\tdevinit %Z\n", d);
1294 fprint(2, "devinit: unknown device %Z\n", d);
1298 cwinit(d->ro.parent);
1404 * flag = 0 -- convert from foreign to native
1405 * flag = 1 -- convert from native to foreign
1408 swab(void *c, int flag)
1422 t = (Tag*)(p + BUFSIZE);
1429 /* swab each block type */
1432 fprint(2, "no swab for tag=%G rw=%d\n", t->tag, flag);
1439 swaboff(&s->fbuf.nfree);
1440 for(i=0; i<FEPERBUF; i++)
1441 swaboff(&s->fbuf.free[i]);
1442 swaboff(&s->fstart);
1445 swaboff(&s->qidgen);
1446 swaboff(&s->cwraddr);
1447 swaboff(&s->roraddr);
1453 for(i=0; i<DIRPERBUF; i++) {
1459 swaboff(&d->qid.path);
1460 swab4(&d->qid.version);
1462 for(j=0; j<NDBLOCK; j++)
1463 swaboff(&d->dblock[j]);
1464 for (j = 0; j < NIBLOCK; j++)
1465 swaboff(&d->iblocks[j]);
1476 /* add more Tind tags here ... */
1479 for(i=0; i<INDPERBUF; i++) {
1488 for(i=0; i<FEPERBUF; i++)
1489 swaboff(&f->free[i]);
1493 for(i=0; i<BKPERBLK; i++) {
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);
1513 swaboff(&h->sbaddr);
1514 swaboff(&h->cwraddr);
1515 swaboff(&h->roraddr);
1520 case Tnone: // unitialized
1521 case Tfile: // someone elses problem
1522 case Tvirgo: // bit map -- all bytes
1523 case Tconfig: // configuration string -- all bytes