#include #include #include #include #include <9p.h> #include #include #include #include #include /* clang-format off */ char clca(char c) { return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; } /* char to lowercase */ char cuca(char c) { return c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c; } /* char to uppercase */ int slen(char *s) { int i = 0; while(s[i] && s[++i]) { ; } return i; } /* string length */ char *st__(char *s, char (*fn)(char)) { int i = 0; char c; while((c = s[i])) s[i++] = fn(c); return s; } char *stuc(char *s) { return st__(s, cuca); } /* string to uppercase */ char *stlc(char *s) { return st__(s, clca); } /* string to lowercase */ char *scpy(char *src, char *dst, int len) { int i = 0; while((dst[i] = src[i]) && i < len - 2) i++; dst[i + 1] = '\0'; return dst; } /* string copy */ int scmp(char *a, char *b) { int i = 0; while(a[i] == b[i]) if(!a[i++]) return 1; return 0; } /* string compare */ char *scsw(char *s, char a, char b) { int i = 0; char c; while((c = s[i])) s[i++] = c == a ? b : c; return s; } /* string char swap */ char *scat(char *dst, const char *src) { char *ptr = dst + slen(dst); while(*src) *ptr++ = *src++; *ptr = '\0'; return dst; } /* string cat */ int ssin(char *s, char *ss) { int a = 0, b = 0; while(s[a]) { if(s[a] == ss[b]) { if(!ss[b + 1]) return a - b; b++; } else b = 0; a++; } return -1; } /* string substring index */ char *ccat(char *dst, char c) { int len = slen(dst); dst[len] = c; dst[len + 1] = '\0'; return dst; } /* clang-format on */ int chatty9p = 1; static char Ebad[] = "something bad happened"; static char Enomem[] = "no memory"; static char Euname[] = "username is already taken"; static Tree* tree; typedef enum { LOGIN = 208176873, LOAD = 5626172, CREATE = 7083959236, PROTECT = 295480618573, ENTER = 195024746, LEAVE = 207662601, LOGOUT = 7702552890, SAVE = 5962355, RESET = 218931595, UNLOAD = 8325026851 } Command; typedef enum { CTL = 1, USERS, CARTS, SLOT, DATA, REALMS, UNIVERSE } FileType; typedef struct Aux Aux; struct Aux { FileType type; char* data; int count; }; Aux* create_aux(FileType t) { Aux* self = (Aux*)malloc(sizeof(Aux)); self->type = t; self->data = nil; self->count = 0; return self; } typedef struct UserInfo UserInfo; struct UserInfo { char name[32]; uvlong password; ushort id; }; static UserInfo users_table[64]; uvlong hash(char* str) { uvlong h; uchar* p; h = 0; for (p = (unsigned char*)str; *p != '\0'; p++) h = 37 * h + *p; return h; // or, h % ARRAY_SIZE; } 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. */ static ushort id = 1; int i = 0; int l = 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); users_table[i].id = id++; break; } } respond(r, nil); } 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].id = 0; users_table[i].password = 0; return 1; } } return 0; } 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: // create(c); break; case PROTECT: // protect(c); break; case ENTER: // enter(c); break; case LEAVE: // leave(c); break; case LOGOUT: logout(r->fid->uid); break; case SAVE: // save(); break; case RESET: // reset(); break; case UNLOAD: // unload(); 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); } }