From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.2 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.4 Received: (qmail 13322 invoked from network); 5 Jun 2022 01:00:05 -0000 Received: from 9front.inri.net (168.235.81.73) by inbox.vuxu.org with ESMTPUTF8; 5 Jun 2022 01:00:05 -0000 Received: from mail.posixcafe.org ([45.76.19.58]) by 9front; Sat Jun 4 20:58:26 -0400 2022 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posixcafe.org; s=20200506; t=1654390702; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=OLSAMpqRdu3u8uEq2MEoLW959wvjcJS8igl3yKtNdBQ=; b=QTgkx7iE4qPd1LmrE7py89H7yesIEN2iJ0Xm9oUErnA+eR13T2Vz1SyDv0FsPzLGFHKC7m Vpe4heVU2rfsjvvKEnsdHp+5auyyDXMBOdsruRXPlE0g06w09jyF2c8MMmZaLr9UksxDcg pPwZZq3+/cu+0tAVOIWTnN6LcI3gnvg= Received: from [192.168.168.200] (161-97-228-135.lpcnextlight.net [161.97.228.135]) by mail.posixcafe.org (OpenSMTPD) with ESMTPSA id fb88b0bc (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO) for <9front@9front.org>; Sat, 4 Jun 2022 19:58:22 -0500 (CDT) Message-ID: <59355e7b-9c12-90f8-d4b4-989f1fa30f26@posixcafe.org> Date: Sat, 4 Jun 2022 18:57:50 -0600 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.1 Content-Language: en-US To: 9front@9front.org From: Jacob Moody Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: responsive browser firewall database Subject: [9front] Pitch for devskel Reply-To: 9front@9front.org Precedence: bulk I have been trying to find ergonomic ways of building restricted namespaces. One issue that I keep running in to, and that I've discussed before, is the need for skeleton directories. Devskel is an iteration on making these skeleton directories easier to create. This adds a new device, '#z', that can be walked to produce a single skeleton file or directory. For example walking #z/ls gives you a directory with a single empty 'ls' file within it. A 'd' attach argument can be given to have this 'ls' file become a empty directory instead: #zd/ls Each attach of '#z' can at most 'make up' one skeleton; after the first walk from the root the hierarchy becomes stable. The 'e' attach option instead makes the root directory always empty. An example of using this to build a /bin with only bind and ls. term% bind -b '#zd/bin.new' /bin term% bind '#z/ls' /bin/bin.new term% bind -a '#z/bind' /bin/bin.new term% ls /bin/bin.new /bin/bin.new/bind /bin/bin.new/ls term% bind /bin/bind /bin/bin.new/bind term% bind /bin/ls /bin/bin.new/ls term% bind /bin/bin.new /bin term% ls /bin/ /bin/bind /bin/ls term% Why devskel instead of mntgen? 1. mntgen only exposes directories 2. mntgen permits more then a single directory to be made up 3. mntgen shows folders that other clients have walked to. 3 could just be labeled as a bug. 1 and 2 could be specified in attach options but I am not sure what the semantics should be for specifying both. Using mntgen would also require the use of /srv, and I do prefer having this separated from /srv. thanks, moody diff 926be5e34eb633bc3e22b013705f5474d21aa735 uncommitted --- /dev/null +++ b//sys/src/9/port/devskel.c @@ -1,0 +1,237 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "netif.h" + +typedef struct Skel Skel; +struct Skel { + int ref; + QLock lk; + char name[KNAMELEN]; + char mode; +}; + +struct +{ + QLock lk; + ulong path; +} skelalloc; + +enum{ + Qroot, + Qdir, + Qskel, +}; + +static Chan* +skelattach(char *spec) +{ + Chan *c; + Skel *f; + uvlong path; + + c = devattach('z', spec); + + f = smalloc(sizeof *f); + if(spec != nil && spec[0] != '\0' && strchr("de", spec[0]) != nil) + f->mode = spec[0]; + else + f->mode = 'f'; + + f->ref = 1; + + qlock(&skelalloc.lk); + path = skelalloc.path++; + qunlock(&skelalloc.lk); + + mkqid(&c->qid, NETQID(path, Qroot), 0, QTDIR); + c->aux = f; + return c; +} + +static int +step(Chan *c, Dir *dp, int direction) +{ + Skel *f; + Qid qid; + ulong perm; + uvlong path; + char *name; + + perm = 0555|DMDIR; + path = NETTYPE(c->qid.path); + f = c->aux; + name = f->name; + + path += direction; + if(!f->name[0] && path != Qroot) + return -1; + + switch(path){ + case Qroot: + mkqid(&qid, Qroot, 0, QTDIR); + name = "#z"; + break; + case Qdir: + mkqid(&qid, Qdir, 0, QTDIR); + break; + case Qskel: + switch(f->mode){ + case 'd': + mkqid(&qid, Qskel, 0, QTDIR); + break; + case 'f': + default: + mkqid(&qid, Qskel, 0, QTFILE); + perm = 0666; + break; + } + break; + default: + return -1; + } + + qid.path = NETQID(NETID(c->qid.path), qid.path); + devdir(c, qid, name, 0, eve, perm, dp); + return 1; +} + + +static int +skelgen(Chan *c, char *name, Dirtab *, int, int s, Dir *dp) +{ + Skel *f; + + f = c->aux; + //First walk away from root + if(name && !f->name[0] && f->mode != 'e' && NETTYPE(c->qid.path) == Qroot) + utfecpy(f->name, f->name + sizeof f->name, name); + + if(s != DEVDOTDOT) + s++; + + return step(c, dp, s); +} + +static Walkqid* +skelwalk(Chan *c, Chan *nc, char **name, int nname) +{ + Walkqid *wq; + Skel *f; + + f = c->aux; + qlock(&f->lk); + if(waserror()){ + qunlock(&f->lk); + nexterror(); + } + + wq = devwalk(c, nc, name, nname, nil, 0, skelgen); + if(wq != nil && wq->clone != nil && wq->clone != c){ + if(f->ref <= 0) + panic("devskel ref"); + f->ref++; + } + qunlock(&f->lk); + poperror(); + return wq; +} + +static Chan* +skelopen(Chan *c, int omode) +{ + if(!(c->qid.type & QTDIR)) + error(Eperm); + if(omode != OREAD) + error(Ebadarg); + + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; +} + +static void +skelclose(Chan *c) +{ + Skel *f; + + f = c->aux; + qlock(&f->lk); + f->ref--; + if(f->ref == 0){ + qunlock(&f->lk); + free(f); + } else + qunlock(&f->lk); +} + +static long +skelread(Chan *c, void *va, long n, vlong) +{ + Skel *f; + long nout; + + if(!(c->qid.type & QTDIR)) + error(Eperm); + + f = c->aux; + qlock(&f->lk); + if(waserror()){ + qunlock(&f->lk); + nexterror(); + } + nout = devdirread(c, va, n, nil, 0, skelgen); + qunlock(&f->lk); + poperror(); + return nout; +} + +static long +skelwrite(Chan *, void *, long, vlong) +{ + error(Eperm); + return 0; +} + +static int +skelstat(Chan *c, uchar *db, int n) +{ + Skel *f; + Dir dir; + + f = c->aux; + qlock(&f->lk); + step(c, &dir, 0); + qunlock(&f->lk); + + n = convD2M(&dir, db, n); + if(n < BIT16SZ) + error(Eshortstat); + return n; +} + +Dev skeldevtab = { + 'z', + "skel", + + devreset, + devinit, + devshutdown, + skelattach, + skelwalk, + skelstat, + skelopen, + devcreate, + skelclose, + skelread, + devbread, + skelwrite, + devbwrite, + devremove, + devwstat, +};