void fsSnapshotRemove(Fs *fs) { vtRLock(fs->elk); fsRsearch(fs, "/snapshot"); vtRUnlock(fs->elk); }
static void fidLock(Fid* fid, int flags) { if(flags & FidFWlock){ vtLock(fid->lock); fid->flags = flags; } else vtRLock(fid->lock); /* * Callers of file* routines are expected to lock fsys->fs->elk * before making any calls in order to make sure the epoch doesn't * change underfoot. With the exception of Tversion and Tattach, * that implies all 9P functions need to lock on entry and unlock * on exit. Fortunately, the general case is the 9P functions do * fidGet on entry and fidPut on exit, so this is a convenient place * to do the locking. * No fsys->fs->elk lock is required if the fid is being created * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by * FidFWlock so the setting and testing of FidFCreate here and in * fidUnlock below is always done under fid->lock. * A side effect is that fidFree is called with the fid locked, and * must call fidUnlock only after it has disposed of any File * resources still held. */ if(!(flags & FidFCreate)) fsysFsRlock(fid->fsys); }
int groupWriteMember(char* uname) { int ret; /* * If there is a ``write'' group, then only its members can write * to the file system, no matter what the permission bits say. * * To users not in the ``write'' group, the file system appears * read only. This is used to serve sources.cs.bell-labs.com * to the world. * * Note that if there is no ``write'' group, then this routine * makes it look like everyone is a member -- the opposite * of what groupMember does. * * We use this for sources.cs.bell-labs.com. * If this slows things down too much on systems that don't * use this functionality, we could cache the write group lookup. */ vtRLock(ubox.lock); ret = _groupMember(ubox.box, "write", uname, 1); vtRUnlock(ubox.lock); return ret; }
static int cmdLstn(int argc, char* argv[]) { int dflag, flags; Lstn *lstn; char *usage = "usage: listen [-dIN] [address]"; dflag = 0; flags = 0; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; case 'I': flags |= ConIPCheck; break; case 'N': flags |= ConNoneAllow; break; }ARGEND switch(argc){ default: return cliError(usage); case 0: vtRLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next) consPrint("\t%s\t%s\n", lstn->address, lstn->dir); vtRUnlock(lbox.lock); break; case 1: if(!dflag){ if(lstnAlloc(argv[0], flags) == nil) return 0; break; } vtLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ if(strcmp(lstn->address, argv[0]) != 0) continue; if(lstn->afd != -1){ close(lstn->afd); lstn->afd = -1; } break; } vtUnlock(lbox.lock); if(lstn == nil){ vtSetError("listen: '%s' not found", argv[0]); return 0; } break; } return 1; }
int fsVac(Fs *fs, char *name, uint8_t score[VtScoreSize]) { int r; DirEntry de; Entry e, ee; File *f; vtRLock(fs->elk); f = fileOpen(fs, name); if(f == nil){ vtRUnlock(fs->elk); return 0; } if(!fileGetSources(f, &e, &ee) || !fileGetDir(f, &de)){ fileDecRef(f); vtRUnlock(fs->elk); return 0; } fileDecRef(f); r = mkVac(fs->z, fs->blockSize, &e, &ee, &de, score); vtRUnlock(fs->elk); return r; }
static int fsNeedArch(Fs *fs, uint archMinute) { int need; File *f; char buf[100]; Tm now; uint32_t then; then = time(0); now = *localtime(then); /* back up to yesterday if necessary */ if(now.hour < archMinute/60 || now.hour == archMinute/60 && now.min < archMinute%60) now = *localtime(then-86400); snprint(buf, sizeof buf, "/archive/%d/%02d%02d", now.year+1900, now.mon+1, now.mday); need = 1; vtRLock(fs->elk); f = fileOpen(fs, buf); if(f){ need = 0; fileDecRef(f); } vtRUnlock(fs->elk); return need; }
int groupLeader(char* group, char* member) { int r; User *g; /* * Is 'member' the leader of 'group'? * Note that 'group' is a 'uid' and not a 'uname'. * Uname 'none' cannot be a group leader. */ if(strcmp(member, unamenone) == 0 || group == nil) return 0; vtRLock(ubox.lock); if((g = _userByUid(ubox.box, group)) == nil){ vtRUnlock(ubox.lock); return 0; } if(g->leader != nil){ if(strcmp(g->leader, member) == 0){ vtRUnlock(ubox.lock); return 1; } r = 0; } else r = _groupMember(ubox.box, group, member, 0); vtRUnlock(ubox.lock); return r; }
static int fileRLock(File *f) { assert(!vtCanLock(f->fs->elk)); vtRLock(f->lk); if(!chkSource(f)){ fileRUnlock(f); return 0; } return 1; }
static void fsMetaFlush(void *a) { int rv; Fs *fs = a; vtRLock(fs->elk); rv = fileMetaFlush(fs->file, 1); vtRUnlock(fs->elk); if(rv > 0) cacheFlush(fs->cache, 0); }
int groupMember(char* group, char* member) { int r; if(group == nil) return 0; vtRLock(ubox.lock); r = _groupMember(ubox.box, group, member, 0); vtRUnlock(ubox.lock); return r; }
static int cmdUsers(int argc, char* argv[]) { Ubox *box; int dflag, r, wflag; char *file; char *usage = "usage: users [-d | -r file] [-w]"; dflag = wflag = 0; file = nil; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; case 'r': file = ARGF(); if(file == nil) return cliError(usage); break; case 'w': wflag = 1; break; }ARGEND if(argc) return cliError(usage); if(dflag && file) return cliError("cannot use -d and -r together"); if(dflag) uboxInit(usersDefault, sizeof(usersDefault)); else if(file){ if(usersFileRead(file) == 0) return 0; } vtRLock(ubox.lock); box = ubox.box; consPrint("\tnuser %d len %d\n", box->nuser, box->len); r = 1; if(wflag) r = usersFileWrite(box); vtRUnlock(ubox.lock); return r; }
char* uidByUname(char* uname) { User *u; char *uid; vtRLock(ubox.lock); if((u = _userByUname(ubox.box, uname)) == nil){ vtRUnlock(ubox.lock); return nil; } uid = vtStrDup(u->uid); vtRUnlock(ubox.lock); return uid; }
char* unameByUid(char* uid) { User *u; char *uname; vtRLock(ubox.lock); if((u = _userByUid(ubox.box, uid)) == nil){ vtRUnlock(ubox.lock); return nil; } uname = vtStrDup(u->uname); vtRUnlock(ubox.lock); return uname; }
void fsSnapshotCleanup(Fs *fs, uint32_t age) { uint32_t lo; /* * Find the best low epoch we can use, * given that we need to save all the unventied archives * and all the snapshots younger than age. */ vtRLock(fs->elk); lo = fs->ehi; fsEsearch(fs, "/archive", 0, &lo); fsEsearch(fs, "/snapshot", time(0)-age*60, &lo); vtRUnlock(fs->elk); fsEpochLow(fs, lo); fsSnapshotRemove(fs); }
void fsClose(Fs *fs) { vtRLock(fs->elk); periodicKill(fs->metaFlush); snapClose(fs->snap); if(fs->file){ fileMetaFlush(fs->file, 0); if(!fileDecRef(fs->file)) vtFatal("fsClose: files still in use: %r\n"); } fs->file = nil; sourceClose(fs->source); cacheFree(fs->cache); if(fs->arch) archFree(fs->arch); vtMemFree(fs->name); vtRUnlock(fs->elk); vtLockFree(fs->elk); memset(fs, ~0, sizeof(Fs)); vtMemFree(fs); }
static void topLevel(char *name) { Fs *fs; File *root; /* ok, now we can open as a fs */ fs = fsOpen(name, z, 100, OReadWrite); if(fs == nil) vtFatal("could not open file system: %r"); vtRLock(fs->elk); root = fsGetRoot(fs); if(root == nil) vtFatal("could not open root: %r"); addFile(root, "active", 0555); addFile(root, "archive", 0555); addFile(root, "snapshot", 0555); fileDecRef(root); if(iso9660file) iso9660copy(fs); vtRUnlock(fs->elk); fsClose(fs); }
Fs * fsOpen(char *file, VtSession *z, int32_t ncache, int mode) { int fd, m; uint8_t oscore[VtScoreSize]; Block *b, *bs; Disk *disk; Fs *fs; Super super; switch(mode){ default: vtSetError(EBadMode); return nil; case OReadOnly: m = OREAD; break; case OReadWrite: m = ORDWR; break; } fd = open(file, m); if(fd < 0){ vtSetError("open %s: %r", file); return nil; } bwatchInit(); disk = diskAlloc(fd); if(disk == nil){ vtSetError("diskAlloc: %R"); close(fd); return nil; } fs = vtMemAllocZ(sizeof(Fs)); fs->mode = mode; fs->name = vtStrDup(file); fs->blockSize = diskBlockSize(disk); fs->elk = vtLockAlloc(); fs->cache = cacheAlloc(disk, z, ncache, mode); if(mode == OReadWrite && z) fs->arch = archInit(fs->cache, disk, fs, z); fs->z = z; b = cacheLocal(fs->cache, PartSuper, 0, mode); if(b == nil) goto Err; if(!superUnpack(&super, b->data)){ blockPut(b); vtSetError("bad super block"); goto Err; } blockPut(b); fs->ehi = super.epochHigh; fs->elo = super.epochLow; //fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ /* * Perhaps it failed because the block is copy-on-write. * Do the copy and try again. */ if(mode == OReadOnly || strcmp(vtGetError(), EBadRoot) != 0) goto Err; b = cacheLocalData(fs->cache, super.active, BtDir, RootTag, OReadWrite, 0); if(b == nil){ vtSetError("cacheLocalData: %R"); goto Err; } if(b->l.epoch == fs->ehi){ blockPut(b); vtSetError("bad root source block"); goto Err; } b = blockCopy(b, RootTag, fs->ehi, fs->elo); if(b == nil) goto Err; localToGlobal(super.active, oscore); super.active = b->addr; bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite); if(bs == nil){ blockPut(b); vtSetError("cacheLocal: %R"); goto Err; } superPack(&super, bs->data); blockDependency(bs, b, 0, oscore, nil); blockPut(b); blockDirty(bs); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ vtSetError("sourceRoot: %R"); goto Err; } } //fprint(2, "%s: got fs source\n", argv0); vtRLock(fs->elk); fs->file = fileRoot(fs->source); fs->source->file = fs->file; /* point back */ vtRUnlock(fs->elk); if(fs->file == nil){ vtSetError("fileRoot: %R"); goto Err; } //fprint(2, "%s: got file root\n", argv0); if(mode == OReadWrite){ fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000); fs->snap = snapInit(fs); } return fs; Err: fprint(2, "%s: fsOpen error\n", argv0); fsClose(fs); return nil; }
static int cmdSrv(int argc, char* argv[]) { Con *con; Srv *srv; char *usage = "usage: srv [-APWdp] [service]"; int conflags, dflag, fd[2], mode, pflag, r; dflag = 0; pflag = 0; conflags = 0; mode = 0666; ARGBEGIN{ default: return cliError(usage); case 'A': conflags |= ConNoAuthCheck; break; case 'I': conflags |= ConIPCheck; break; case 'N': conflags |= ConNoneAllow; break; case 'P': conflags |= ConNoPermCheck; mode = 0600; break; case 'W': conflags |= ConWstatAllow; mode = 0600; break; case 'd': dflag = 1; break; case 'p': pflag = 1; mode = 0600; break; }ARGEND if(pflag && (conflags&ConNoPermCheck)){ vtSetError("srv: cannot use -P with -p"); return 0; } switch(argc){ default: return cliError(usage); case 0: vtRLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next) consPrint("\t%s\t%d\n", srv->service, srv->srvfd); vtRUnlock(sbox.lock); return 1; case 1: if(!dflag) break; vtLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next){ if(strcmp(srv->service, argv[0]) != 0) continue; srvFree(srv); break; } vtUnlock(sbox.lock); if(srv == nil){ vtSetError("srv: '%s' not found", argv[0]); return 0; } return 1; } if(pipe(fd) < 0){ vtSetError("srv pipe: %r"); return 0; } if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ close(fd[0]); close(fd[1]); return 0; } if(pflag) r = consOpen(fd[1], srv->srvfd, -1); else{ con = conAlloc(fd[1], srv->mntpnt, conflags); if(con == nil) r = 0; else r = 1; } if(r == 0){ close(fd[1]); vtLock(sbox.lock); srvFree(srv); vtUnlock(sbox.lock); } return r; }
static int cmdUname(int argc, char* argv[]) { User *u, *up; int d, dflag, i, r; char *p, *uid, *uname; char *createfmt = "fsys main create /active/usr/%s %s %s d775"; char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]"; dflag = 0; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; }ARGEND if(argc < 1){ if(!dflag) return cliError(usage); vtRLock(ubox.lock); uboxDump(ubox.box); vtRUnlock(ubox.lock); return 1; } uname = argv[0]; argc--; argv++; if(argc == 0){ vtRLock(ubox.lock); if((u = _userByUname(ubox.box, uname)) == nil){ vtRUnlock(ubox.lock); return 0; } consPrint("\t%U\n", u); vtRUnlock(ubox.lock); return 1; } vtLock(ubox.lock); u = _userByUname(ubox.box, uname); while(argc--){ if(argv[0][0] == '%'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } p = &argv[0][1]; if((up = _userByUname(ubox.box, p)) != nil){ vtSetError("uname: uname '%s' already exists", up->uname); vtUnlock(ubox.lock); return 0; } for(i = 0; usersMandatory[i] != nil; i++){ if(strcmp(usersMandatory[i], uname) != 0) continue; vtSetError("uname: uname '%s' is mandatory", uname); vtUnlock(ubox.lock); return 0; } d = strlen(p) - strlen(u->uname); for(up = ubox.box->head; up != nil; up = up->next){ if(up->leader != nil){ if(strcmp(up->leader, u->uname) == 0){ vtMemFree(up->leader); up->leader = vtStrDup(p); ubox.box->len += d; } } for(i = 0; i < up->ngroup; i++){ if(strcmp(up->group[i], u->uname) != 0) continue; vtMemFree(up->group[i]); up->group[i] = vtStrDup(p); ubox.box->len += d; break; } } uboxRemUser(ubox.box, u); vtMemFree(u->uname); u->uname = vtStrDup(p); uboxAddUser(ubox.box, u); } else if(argv[0][0] == '='){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ if(argv[0][1] != '\0'){ vtUnlock(ubox.lock); return 0; } } if(u->leader != nil){ ubox.box->len -= strlen(u->leader); vtMemFree(u->leader); u->leader = nil; } if(up != nil){ u->leader = vtStrDup(up->uname); ubox.box->len += strlen(u->leader); } } else if(argv[0][0] == '+'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ vtUnlock(ubox.lock); return 0; } if(!_groupAddMember(ubox.box, u, up->uname)){ vtUnlock(ubox.lock); return 0; } } else if(argv[0][0] == '-'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ vtUnlock(ubox.lock); return 0; } if(!_groupRemMember(ubox.box, u, up->uname)){ vtUnlock(ubox.lock); return 0; } } else{ if(u != nil){ vtSetError("uname: uname '%s' already exists", u->uname); vtUnlock(ubox.lock); return 0; } uid = argv[0]; if(*uid == ':') uid++; if((u = _userByUid(ubox.box, uid)) != nil){ vtSetError("uname: uid '%s' already exists", u->uid); vtUnlock(ubox.lock); return 0; } u = userAlloc(uid, uname); uboxAddUser(ubox.box, u); if(argv[0][0] != ':'){ // should have an option for the mode and gid p = smprint(createfmt, uname, uname, uname); r = cliExec(p); vtMemFree(p); if(r == 0){ vtUnlock(ubox.lock); return 0; } } } argv++; } if(usersFileWrite(ubox.box) == 0){ vtUnlock(ubox.lock); return 0; } if(dflag) uboxDump(ubox.box); vtUnlock(ubox.lock); return 1; }