📄 9user.c
字号:
#include "stdinc.h"#include "9.h"enum { NUserHash = 1009,};typedef struct Ubox Ubox;typedef struct User User;typedef struct User { char* uid; char* uname; char* leader; char** group; int ngroup; User* next; /* */ User* ihash; /* lookup by .uid */ User* nhash; /* lookup by .uname */} User;#pragma varargck type "U" User*typedef struct Ubox { User* head; User* tail; int nuser; int len; User* ihash[NUserHash]; /* lookup by .uid */ User* nhash[NUserHash]; /* lookup by .uname */} Ubox;static struct { VtLock* lock; Ubox* box;} ubox;static char usersDefault[] = { "adm:adm:adm:sys\n" "none:none::\n" "noworld:noworld::\n" "sys:sys::glenda\n" "glenda:glenda:glenda:\n"};static char* usersMandatory[] = { "adm", "none", "noworld", "sys", nil,};char* uidadm = "adm";char* unamenone = "none";char* uidnoworld = "noworld";static u32intuserHash(char* s){ uchar *p; u32int hash; hash = 0; for(p = (uchar*)s; *p != '\0'; p++) hash = hash*7 + *p; return hash % NUserHash;}static User*_userByUid(Ubox* box, char* uid){ User *u; if(box != nil){ for(u = box->ihash[userHash(uid)]; u != nil; u = u->ihash){ if(strcmp(u->uid, uid) == 0) return u; } } vtSetError("uname: uid '%s' not found", uid); return nil;}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;}static User*_userByUname(Ubox* box, char* uname){ User *u; if(box != nil){ for(u = box->nhash[userHash(uname)]; u != nil; u = u->nhash){ if(strcmp(u->uname, uname) == 0) return u; } } vtSetError("uname: uname '%s' not found", uname); return nil;}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;}static int_groupMember(Ubox* box, char* group, char* member, int whenNoGroup){ int i; User *g, *m; /* * Is 'member' a member of 'group'? * Note that 'group' is a 'uid' and not a 'uname'. * A 'member' is automatically in their own group. */ if((g = _userByUid(box, group)) == nil) return whenNoGroup; if((m = _userByUname(box, member)) == nil) return 0; if(m == g) return 1; for(i = 0; i < g->ngroup; i++){ if(strcmp(g->group[i], member) == 0) return 1; } return 0;}intgroupWriteMember(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_groupRemMember(Ubox* box, User* g, char* member){ int i; if(_userByUname(box, member) == nil) return 0; for(i = 0; i < g->ngroup; i++){ if(strcmp(g->group[i], member) == 0) break; } if(i >= g->ngroup){ if(strcmp(g->uname, member) == 0) vtSetError("uname: '%s' always in own group", member); else vtSetError("uname: '%s' not in group '%s'", member, g->uname); return 0; } vtMemFree(g->group[i]); box->len -= strlen(member); if(g->ngroup > 1) box->len--; g->ngroup--; switch(g->ngroup){ case 0: vtMemFree(g->group); g->group = nil; break; default: while(i < g->ngroup){ g->group[i] = g->group[i+1]; i++; } /*FALLTHROUGH*/ case 1: g->group = vtMemRealloc(g->group, (g->ngroup)*sizeof(char*)); break; } return 1;}static int_groupAddMember(Ubox* box, User* g, char* member){ User *u; if((u = _userByUname(box, member)) == nil) return 0; if(_groupMember(box, g->uid, u->uname, 0)){ if(strcmp(g->uname, member) == 0) vtSetError("uname: '%s' always in own group", member); else vtSetError("uname: '%s' already in group '%s'", member, g->uname); return 0; } g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*)); g->group[g->ngroup] = vtStrDup(member); box->len += strlen(member); g->ngroup++; if(g->ngroup > 1) box->len++; return 1;}intgroupMember(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;}intgroupLeader(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 voiduserFree(User* u){ int i; vtMemFree(u->uid); vtMemFree(u->uname); if(u->leader != nil) vtMemFree(u->leader); if(u->ngroup){ for(i = 0; i < u->ngroup; i++) vtMemFree(u->group[i]); vtMemFree(u->group); } vtMemFree(u);}static User*userAlloc(char* uid, char* uname){ User *u; u = vtMemAllocZ(sizeof(User)); u->uid = vtStrDup(uid); u->uname = vtStrDup(uname); return u;}intvalidUserName(char* name){ Rune *r; static Rune invalid[] = L"#:,()"; for(r = invalid; *r != '\0'; r++){ if(utfrune(name, *r)) return 0; } return 1;}static intuserFmt(Fmt* fmt){ User *u; int i, r; u = va_arg(fmt->args, User*); r = fmtprint(fmt, "%s:%s:", u->uid, u->uname); if(u->leader != nil) r += fmtprint(fmt, u->leader); r += fmtprint(fmt, ":"); if(u->ngroup){ r += fmtprint(fmt, u->group[0]); for(i = 1; i < u->ngroup; i++) r += fmtprint(fmt, ",%s", u->group[i]); } return r;}static intusersFileWrite(Ubox* box){ Fs *fs; User *u; int i, r; Fsys *fsys; char *p, *q, *s; File *dir, *file; if((fsys = fsysGet("main")) == nil) return 0; fsysFsRlock(fsys); fs = fsysGetFs(fsys); /* * BUG: * the owner/group/permissions need to be thought out. */ r = 0; if((dir = fileOpen(fs, "/active")) == nil) goto tidy0; if((file = fileWalk(dir, uidadm)) == nil) file = fileCreate(dir, uidadm, ModeDir|0775, uidadm); fileDecRef(dir); if(file == nil) goto tidy; dir = file; if((file = fileWalk(dir, "users")) == nil) file = fileCreate(dir, "users", 0664, uidadm); fileDecRef(dir); if(file == nil) goto tidy; if(!fileTruncate(file, uidadm)) goto tidy; p = s = vtMemAlloc(box->len+1); q = p + box->len+1; for(u = box->head; u != nil; u = u->next){ p += snprint(p, q-p, "%s:%s:", u->uid, u->uname); if(u->leader != nil) p+= snprint(p, q-p, u->leader); p += snprint(p, q-p, ":"); if(u->ngroup){ p += snprint(p, q-p, u->group[0]); for(i = 1; i < u->ngroup; i++) p += snprint(p, q-p, ",%s", u->group[i]); } p += snprint(p, q-p, "\n"); } r = fileWrite(file, s, box->len, 0, uidadm); vtMemFree(s);tidy: if(file != nil) fileDecRef(file);tidy0: fsysFsRUnlock(fsys); fsysPut(fsys); return r;}static voiduboxRemUser(Ubox* box, User *u){ User **h, *up; h = &box->ihash[userHash(u->uid)]; for(up = *h; up != nil && up != u; up = up->ihash) h = &up->ihash; assert(up == u); *h = up->ihash; box->len -= strlen(u->uid); h = &box->nhash[userHash(u->uname)]; for(up = *h; up != nil && up != u; up = up->nhash) h = &up->nhash; assert(up == u); *h = up->nhash; box->len -= strlen(u->uname); h = &box->head; for(up = *h; up != nil && strcmp(up->uid, u->uid) != 0; up = up->next) h = &up->next; assert(up == u); *h = u->next; u->next = nil; box->len -= 4; box->nuser--;}static voiduboxAddUser(Ubox* box, User* u){ User **h, *up; h = &box->ihash[userHash(u->uid)]; u->ihash = *h; *h = u; box->len += strlen(u->uid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -