xrxs/xrxs.c

476 lines
10 KiB
C
Raw Normal View History

2021-06-13 17:22:58 +00:00
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <stdio.h>
2021-06-24 07:17:34 +00:00
#include <dirent.h>
#include <libString.h>
#include <string.h>
#include "err.h"
#include "command.h"
#include "util.h"
#include "aux.h"
#include "cart.h"
#include "universe.h"
#include "realm.h"
#include "user.h"
2021-06-24 07:17:34 +00:00
#define CARTSPATH "./carts"
#define REALMSPATH "./realms"
2021-06-28 21:37:59 +00:00
int chatty9p = 1;
2021-06-13 17:22:58 +00:00
static Tree* tree;
2021-07-01 07:45:48 +00:00
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. We have logout() for now...
*/
2021-07-01 07:45:48 +00:00
int i = 0;
int l = 0;
int vacancy = 0;
2021-07-01 07:45:48 +00:00
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);
2021-07-01 07:45:48 +00:00
return;
}
2021-07-01 07:45:48 +00:00
if (*usr == 0) {
scpy(username, usr, l + 1);
vacancy = 1;
2021-07-01 07:45:48 +00:00
break;
}
}
if (vacancy) {
respond(r, nil);
} else {
respond(r, EUFULL);
}
2021-07-01 07:45:48 +00:00
}
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, 0);
}
2021-06-16 05:46:47 +00:00
}
}
int logout(char* uname) {
int i;
UserInfo* u = users_table;
for (i = 0; i < 64; i++) {
if (scmp(uname, u->name)) {
*(u->name) = 0;
u->password = 0;
if (u->realm != nil)
leave_realm(users_table, uname);
if (u->cart != nil)
unload_cart(users_table, uname);
return 1;
2021-06-16 05:46:47 +00:00
}
u++;
2021-06-16 05:46:47 +00:00
}
return 0;
2021-06-13 17:22:58 +00:00
}
void protect(char* uname, char* password) {
UserInfo* u = find_user(users_table, uname);
if (u != nil && u->realm != nil) {
u->realm->password = hash(password, 0);
}
}
void write_ctl(Req* r) {
char cmd[16] = {0};
2021-06-28 21:37:59 +00:00
char* c = r->ifcall.data;
2021-06-29 18:56:21 +00:00
int i;
2021-06-28 21:37:59 +00:00
for (i = 0; i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) {
2021-06-29 18:56:21 +00:00
ccat(cmd, *c++);
2021-06-28 21:37:59 +00:00
}
if (*c == ' ')
c++;
scsw(c, '\n', 0);
fprintf(stderr, "%s(%s)\n", cmd, c);
uvlong const cmd_hashv = hash(cmd, 0);
2021-06-28 21:37:59 +00:00
switch (cmd_hashv) {
case LOGIN:
login(r->fid->uid, c);
break;
case LOAD:
load_cart(users_table, r->fid->uid, c);
break;
case CREATE:
create_realm(users_table, r->fid->uid, c);
break;
case PROTECT:
protect(r->fid->uid, c);
break;
case ENTER:
enter_realm(users_table, r->fid->uid, c);
break;
case LEAVE:
leave_realm(users_table, 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_cart(users_table, r->fid->uid);
break;
}
2021-06-29 18:56:21 +00:00
r->ofcall.count = r->ifcall.count;
r->fid->file->dir.length = r->ifcall.count;
respond(r, nil);
2021-06-28 21:37:59 +00:00
}
void write_universe(Req* r) {
char key[16] = {0};
char value[64] = {0};
char* c = r->ifcall.data;
UserInfo* u = find_user(users_table, r->fid->uid);
Atom* a;
int i;
for (i = 0; i < 15 && i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) {
ccat(key, *c++);
}
c++;
for (i = 0; i < 63 && i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) {
ccat(value, *c++);
}
if (u != nil && u->realm != nil && u->realm->universe != nil) {
a = get_atom(u->realm->universe, key);
if (a != nil) {
scpy(value, a->value, 64);
} else {
a = malloc(sizeof(Atom));
scpy(key, a->name, 16);
scpy(value, a->value, 64);
a->next = nil;
set_atom(u->realm->universe, a);
}
}
r->ofcall.count = r->ifcall.count;
r->fid->file->dir.length = r->ifcall.count;
respond(r, nil);
}
void xrxs_write(Req* r) {
2021-06-29 18:56:21 +00:00
Aux* a = r->fid->file->aux;
switch (a->type) {
case CTL:
write_ctl(r);
break;
case UNIVERSE:
write_universe(r);
2021-06-28 21:37:59 +00:00
break;
case SCOPE:
// write_scope(r);
2021-06-28 21:37:59 +00:00
default:
respond(r, nil);
break;
}
}
2021-07-01 07:45:48 +00:00
void read_users(Req* r) {
char buf[2113] = {0};
2021-07-01 07:45:48 +00:00
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');
2021-07-01 07:45:48 +00:00
break;
}
}
for (i = 0; i < 64; i++) {
if (
scmp(users_table[i].name, "\0") ||
scmp(users_table[i].name, r->fid->uid)) {
continue;
2021-07-01 07:45:48 +00:00
}
scat(buf, users_table[i].name);
ccat(buf, '\n');
2021-07-01 07:45:48 +00:00
}
ccat(buf, 0);
2021-07-01 07:45:48 +00:00
readstr(r, buf);
respond(r, nil);
}
String** list_dir(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;
}
void read_carts(Req* r) {
String** carts = list_dir(CARTSPATH);
String** c = carts;
char data[4096] = {0};
while (*c != nil) {
scat(data, (*c)->base);
ccat(data, '\n');
c++;
}
readstr(r, data);
respond(r, nil);
}
void read_slot(Req* r) {
UserInfo* u = find_user(users_table, r->fid->uid);
if (u == nil)
goto end;
if (u->cart == nil)
goto end;
readstr(r, u->cart->rom);
end:
respond(r, nil);
}
void read_data(Req* r, FileType t) {
UserInfo* u = find_user(users_table, r->fid->uid);
if (u->cart == nil)
goto end;
switch (t) {
case SPRITE_DATA:
readstr(r, u->cart->sprite_data);
break;
case AUDIO_DATA:
readstr(r, u->cart->audio_data);
break;
case TEXT_DATA:
readstr(r, u->cart->txt_data);
break;
}
end:
respond(r, nil);
}
void read_realms(Req* r) {
UserInfo* user = find_user(users_table, r->fid->uid);
char realm_path[128] = {0};
String** realms;
String** rr;
Realm* realm;
char data[4096] = {0};
int i, u, m, p;
char ubuf[8] = {0};
char mbuf[8] = {0};
char pbuf[2] = {0};
if (user->cart == nil)
respond(r, nil);
scat(realm_path, "carts/");
scat(realm_path, user->cart->name);
scat(realm_path, "/realms");
realms = list_dir(realm_path);
rr = realms;
while (*rr != nil) {
scat(data, (*rr)->base);
ccat(data, ' ');
realm = parse_realm(user->cart->name, (*rr)->base);
m = realm->max;
p = realm->password ? 1 : 0;
for (i = u = 0; i < 64; i++) {
if (
users_table[i].realm != nil &&
scmp(users_table[i].realm->name, realm->name))
u++;
}
itoa(u, ubuf, 10);
scat(data, ubuf);
ccat(data, ' ');
itoa(m, mbuf, 10);
scat(data, mbuf);
ccat(data, ' ');
itoa(p, pbuf, 10);
scat(data, pbuf);
ccat(data, '\n');
rr++;
}
readstr(r, data);
respond(r, nil);
}
void xrxs_read(Req* r) {
Aux* a = r->fid->file->aux;
switch (a->type) {
case USERS:
2021-07-01 07:45:48 +00:00
read_users(r);
break;
case CARTS:
read_carts(r);
break;
case SLOT:
read_slot(r);
break;
case SPRITE_DATA:
case AUDIO_DATA:
case TEXT_DATA:
read_data(r, a->type);
break;
case REALMS:
read_realms(r);
break;
case UNIVERSE:
2021-07-01 07:45:48 +00:00
// read_universe(r);
break;
case SCOPE:
// read_scope(r);
break;
case RANDOM:
// read_random(r);
break;
case GRANDOM:
// read_grandom(r);
break;
default:
respond(r, nil);
2021-06-28 21:37:59 +00:00
break;
}
}
void fs_destroy_file(File* f) {
2021-06-29 18:56:21 +00:00
Aux* a = f->aux;
if (a && a->data) {
free(a->data);
free(a);
} else if (a) {
free(a);
2021-06-16 05:46:47 +00:00
}
}
Srv fs = {.attach = xrxs_attach, .read = xrxs_read, .write = xrxs_write};
2021-06-13 17:22:58 +00:00
int threadmaybackground(void) { return 1; }
2021-06-16 05:46:47 +00:00
void threadmain(int argc, char* argv[]) {
char* mtpt = nil;
char* usocket = nil;
int i;
/* if -h CMD is given, print the hash value of CMD */
if (argc == 3 && scmp(argv[1], "-h")) {
printf("%llu\n", hash(argv[2], 0));
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) */
2021-06-13 17:22:58 +00:00
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);
}
}
}
2021-06-29 18:56:21 +00:00
fs.foreground = 1;
fs.tree = alloctree(nil, nil, DMDIR | 0777, fs_destroy_file);
tree = fs.tree;
2021-07-01 07:45:48 +00:00
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(
walkfile(tree->root, "data"),
"sprite",
nil,
0400,
create_aux(SPRITE_DATA)));
closefile(createfile(
walkfile(tree->root, "data"),
"audio",
nil,
0400,
create_aux(AUDIO_DATA)));
closefile(createfile(
walkfile(tree->root, "data"),
"text",
nil,
0400,
create_aux(TEXT_DATA)));
closefile(createfile(tree->root, "realms", nil, 0400, create_aux(REALMS)));
closefile(createfile(
tree->root,
"universe",
nil,
DMAPPEND | 0600,
create_aux(UNIVERSE)));
closefile(
createfile(tree->root, "scope", nil, DMAPPEND | 0600, create_aux(SCOPE)));
closefile(createfile(tree->root, "random", nil, 0400, create_aux(RANDOM)));
closefile(createfile(tree->root, "grandom", nil, 0400, create_aux(GRANDOM)));
2021-07-01 07:45:48 +00:00
if (argc >= 3) {
if (mtpt != nil && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)
sysfatal("mountpoint %s does not exist", mtpt);
2021-06-13 17:22:58 +00:00
2021-07-01 07:45:48 +00:00
threadpostmountsrv(&fs, usocket, mtpt, MREPL | MCREATE);
threadexits(0);
} else {
srv(&fs);
}
}