#include #include #include #include #include <9p.h> #include #include #include #include "err.h" #include "command.h" #include "util.h" #include "aux.h" #include "cart.h" #include "universe.h" #include "realm.h" #include "user.h" int chatty9p = 1; static Tree* tree; static UserInfo users_table[64]; void xrxs_attach(Req* r) { /* As it is, once the user detaches, they will stay in the table * until the server restarts. We have to figure out some way * to detect a detach to remove them... You can't delay respond() * or the attach will never complete. */ int i = 0; int l = 0; int vacancy = 0; char* usr; char* username = r->ifcall.uname; usr = username; while (*usr) { l++; usr++; } for (i = 0; i < 64; i++) { usr = users_table[i].name; if (scmp(usr, username)) { respond(r, EUNAME); return; } if (*usr == 0) { scpy(username, usr, l + 1); vacancy = 1; break; } } if (vacancy) { respond(r, nil); } else { respond(r, EUFULL); } } void login(char* uname, char* password) { int i; for (i = 0; i < 64; i++) { if (scmp(uname, users_table[i].name)) { users_table[i].password = hash(password); } } } int logout(char* uname) { int i; fprintf(stderr, uname); for (i = 0; i < 64; i++) { if (scmp(uname, users_table[i].name)) { *(users_table[i].name) = 0; users_table[i].password = 0; /* free cart */ /* free realm */ return 1; } } return 0; } int load(char* cart) { /* 1. get file handle to cartridge file * 2. make cartridge file available in CART.data for this user * 3. add cartridge name to user's UserInfo * 4. if cartridge data dir is not empty, walk it * 5. for each file in data dir, create corresponding * data file in DATA/ for this user, grab a file handle, and make * the data available in DATA.data */ return 1; } int rcreate(char* realm) { // create is taken in the libc header! /* 1. split input by space -- if 2+ elements, second element * is the max number of members (default 4) * 2. check if realm exists; return 0 if it does * 3. create real files in the realms directory and fill as * appropriate */ return 1; } int protect(char* password) { /* 1. if current realm has a password already, return 0; * 2. otherwise, hash the password and put it after the * member limit in the realm file */ return 1; } int enter(char* realm) { /* 1. get password for realm; if none, skip to 3 * 2. check password for current user against it; * return 0 if different * 3. if member limit already met, return 0 * 4. otherwise, insert username in the realm * and the realm name in the user's UserInfo */ return 1; } int leave(char* uname) { /* 1. if not in a realm, return 0; * 2. else remove self from realm file * and remove realm from user's UserInfo */ return 1; } int save(char* uname) { /* 1. flush this user's universe to the realm; * maybe this is not needed */ return 1; } int reset(char* uname) { /* 1. save * 2. leave * 3. clear this user's password * 4. the client should now be able to restart execution * of the cartridge safely */ return 1; } int unload(char* uname) { /* 1. reset * 2. clear cartridge data from CART->data for this user * 3. destroy all files in DATA/ for this user * 4. remove cartridge from UserInfo for thi user * 5. the client should now be able to unload * the cartridge from memory safely and restart * the 'firmware' ROM execution */ return 1; } void write_ctl(Req* r) { char cmd[16] = {0}; char* c = r->ifcall.data; int i; for (i = 0; i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) { ccat(cmd, *c++); } fprintf(stderr, cmd); uvlong const cmd_hashv = hash(cmd); switch (cmd_hashv) { case LOGIN: login(r->fid->uid, c); break; case LOAD: // load(c); break; case CREATE: // rcreate(c); break; case PROTECT: // protect(c); break; case ENTER: // enter(c); break; case LEAVE: // leave(r->fid->uid); break; case LOGOUT: logout(r->fid->uid); break; case SAVE: // save(r->fid->uid); break; case RESET: // reset(r->fid->uid); break; case UNLOAD: // unload(r->fid->uid); break; } r->ofcall.count = r->ifcall.count; r->fid->file->dir.length = r->ifcall.count; respond(r, nil); } void xrxs_write(Req* r) { Aux* a = r->fid->file->aux; switch (a->type) { case CTL: write_ctl(r); break; case UNIVERSE: // write_universe(r); break; default: respond(r, nil); break; } } void read_users(Req* r) { char buf[2113] = {0}; int i; for (i = 0; i < 64; i++) { if (scmp(users_table[i].name, r->fid->uid)) { scat(buf, users_table[i].name); ccat(buf, '\n'); break; } } for (i = 0; i < 64; i++) { if ( scmp(users_table[i].name, "\0") || scmp(users_table[i].name, r->fid->uid)) { continue; } scat(buf, users_table[i].name); ccat(buf, '\n'); } ccat(buf, 0); readstr(r, buf); respond(r, nil); } void xrxs_read(Req* r) { Aux* a = r->fid->file->aux; switch (a->type) { case USERS: read_users(r); break; case CARTS: // read_carts(r); break; case SLOT: // read_slot(r); break; case DATA: // read_data(r); break; case REALMS: // read_realms(r); break; case UNIVERSE: // read_universe(r); break; default: respond(r, nil); break; } } void fs_destroy_file(File* f) { Aux* a = f->aux; if (a && a->data) { free(a->data); free(a); } else if (a) { free(a); } } String** listdir(char* path) { String** self = malloc(128 * sizeof(String*)); DIR* dir; struct dirent* ent; int i = 0; char* c; if ((dir = opendir(path)) != NULL) { while ((ent = readdir(dir)) != NULL) { c = ent->d_name; if (scmp(c, ".") || scmp(c, "..")) { continue; } self[i] = s_new(); while (*c) { s_putc(self[i], *c++); } s_terminate(self[i++]); } closedir(dir); } self[i] = nil; return self; } Srv fs = {.attach = xrxs_attach, .read = xrxs_read, .write = xrxs_write}; int threadmaybackground(void) { return 1; } void threadmain(int argc, char* argv[]) { char* mtpt = nil; char* usocket = nil; int i; String** cart; /* if -h CMD is given, print the hash value of CMD */ if (argc == 3 && scmp(argv[1], "-h")) { printf("%llu\n", hash(argv[2])); return; } /* if -m PATH is supplied, mount on PATH */ /* if -s NAME is supplied, create a socket for the namespace */ /* otherwise, just use srv() (for wrapping with socat or inetd) */ if (argc >= 3) { for (i = 0; i < argc; i++) { if (scmp(argv[i], "-m")) { mtpt = argv[++i]; printf("serving on %s", mtpt); } else if (scmp(argv[i], "-s")) { usocket = argv[++i]; printf("serving socket namespace %s", usocket); } } } fs.foreground = 1; fs.tree = alloctree(nil, nil, DMDIR | 0777, fs_destroy_file); tree = fs.tree; closefile( createfile(tree->root, "ctl", nil, DMAPPEND | 0300, create_aux(CTL))); closefile(createfile(tree->root, "carts", nil, 0400, create_aux(CARTS))); closefile(createfile(tree->root, "users", nil, 0400, create_aux(USERS))); closefile(createfile(tree->root, "slot", nil, 0400, create_aux(SLOT))); closefile(createfile(tree->root, "data", nil, DMDIR | 0500, nil)); closefile(createfile(tree->root, "realms", nil, 0400, create_aux(REALMS))); closefile( createfile(tree->root, "universe", nil, 0600, create_aux(UNIVERSE))); /*String** carts = listdir("carts/"); cart = carts; while (*cart) { // just concatenate the carts into a multiline string, and put it in CARTS.data }*/ if (argc >= 3) { if (mtpt != nil && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0) sysfatal("mountpoint %s does not exist", mtpt); threadpostmountsrv(&fs, usocket, mtpt, MREPL | MCREATE); threadexits(0); } else { srv(&fs); } }