#include #include #include #include #include <9p.h> #include #include #include #include #include #define CARTSLOC "./carts/" #define CTL_HASHV 139931 #define SHUTDOWN_HASHV 11192337284248 /* 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"; 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]; ushort id; }; static UserInfo users_table[64]; void xrxs_attach(Req* r) { 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 fsread(Req* r) { Aux* a; vlong offset; long count; a = r->fid->file->aux; offset = r->ifcall.offset; count = r->ifcall.count; /*print("read %ld %lld\n", *count, offset); */ if (offset >= a->count) { r->ofcall.count = 0; respond(r, nil); return; } if (offset + count >= a->count) count = a->count - offset; memmove(r->ofcall.data, a->data + offset, count); r->ofcall.count = count; respond(r, nil); } unsigned long long hash(char* str) { unsigned long long h; unsigned char* p; h = 0; for (p = (unsigned char*)str; *p != '\0'; p++) h = 37 * h + *p; return h; // or, h % ARRAY_SIZE; } void fswrite(Req* r) { void* v; Aux* a; vlong offset; long count; a = r->fid->file->aux; offset = r->ifcall.offset; count = r->ifcall.count; if (offset + count >= a->count) { v = realloc(a->data, offset + count); if (v == nil) { respond(r, Enomem); return; } a->data = v; a->count = offset + count; r->fid->file->dir.length = a->count; } memmove(a->data + offset, r->ifcall.data, count); r->ofcall.count = count; respond(r, nil); } void write_ctl(Req* r) { char cmd[16]; char* c = r->ifcall.data; int i; for (i = 0; i < r->ifcall.count; i++) { ccat(cmd, *c++); } unsigned long long const cmd_hashv = hash(cmd); switch (cmd_hashv) { default: 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[2112] = {0}; int i; for (i = 0; i < 64; i++) { if (scmp(users_table[i].name, "\0")) { break; } scat(buf, users_table[i].name); if (i == 63) { ccat(buf, 0); } else { ccat(buf, '\n'); } } 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 fsopen(Req* r) { respond(r, nil); } void wstat(Req* r) { respond(r, nil); } 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, .open = fsopen, .read = xrxs_read, .write = xrxs_write, .create = fsopen, .wstat = wstat}; int threadmaybackground(void) { return 1; } void threadmain(int argc, char* argv[]) { Tree* tree; char* mtpt = nil; char* usocket = nil; int i; String** cart; /* 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, "carts", nil, 0444, create_aux(CARTS))); closefile( createfile(tree->root, "ctl", nil, DMAPPEND | 0300, create_aux(CTL))); closefile(createfile(tree->root, "users", nil, 0444, create_aux(USERS))); /*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); } }