diff options
author | onefang | 2021-07-06 14:12:03 +1000 |
---|---|---|
committer | onefang | 2021-07-06 14:12:03 +1000 |
commit | 9df93a76177822feb036e2875ad09f35627c53c3 (patch) | |
tree | 70ce139ea0330a64ce03f2baa3859d8cf27eb371 | |
parent | Add some libraries to sledjchisl. (diff) | |
download | opensim-SC-9df93a76177822feb036e2875ad09f35627c53c3.zip opensim-SC-9df93a76177822feb036e2875ad09f35627c53c3.tar.gz opensim-SC-9df93a76177822feb036e2875ad09f35627c53c3.tar.bz2 opensim-SC-9df93a76177822feb036e2875ad09f35627c53c3.tar.xz |
Lots of SledjChisl changes.
New command argument syntax.
Method of starting sims up in bulk, depending on number of CPUs.
Load all the sim config data at sledjchisl startup.
Convert to new .shini polyglot format for sim .ini files. Lets them be
scripts as well. Also moves them out of config/sim??/ directories.
Short sim names for where short legal names are best.
Figure out port numbers on the fly, putting the actual config file used
in tmp. Alas OpenSim screws the pooch and we need sim??/*.ini for that.
Extra text in validation emails, trying to get around dumb spam filters.
2021 age check update.
Add approver to Lua user records when approved.
Refactor the command checking and doing code.
Allow admins to group sims for startup timing.
Move simple backup script into sledjchisl.
Startup web stuff at end.
Diffstat (limited to '')
-rw-r--r-- | src/.sledjChisl.conf.lua | 1 | ||||
-rw-r--r-- | src/sledjchisl/sledjchisl.c | 898 |
2 files changed, 694 insertions, 205 deletions
diff --git a/src/.sledjChisl.conf.lua b/src/.sledjChisl.conf.lua index 6b8f29b..a817995 100644 --- a/src/.sledjChisl.conf.lua +++ b/src/.sledjChisl.conf.lua | |||
@@ -18,6 +18,7 @@ config = | |||
18 | ["Ttab"] = "SC"; | 18 | ["Ttab"] = "SC"; |
19 | ["loadAverageInc"] = 0.7; | 19 | ["loadAverageInc"] = 0.7; |
20 | ["simTimeOut"] = 45; -- seconds | 20 | ["simTimeOut"] = 45; -- seconds |
21 | ["bulkSims"] = 0; -- 0 means figure it out from number of CPUs. | ||
21 | ["webRoot"] = "/var/www/html"; | 22 | ["webRoot"] = "/var/www/html"; |
22 | ["webHost"] = "localhost"; | 23 | ["webHost"] = "localhost"; |
23 | ["URL"] = "sledjchisl.fcgi"; | 24 | ["URL"] = "sledjchisl.fcgi"; |
diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c index 42ed205..576f58f 100644 --- a/src/sledjchisl/sledjchisl.c +++ b/src/sledjchisl/sledjchisl.c | |||
@@ -2,18 +2,59 @@ | |||
2 | * | 2 | * |
3 | * Copyright 2020 David Seikel <sledjchisl@sledjhamr.org> | 3 | * Copyright 2020 David Seikel <sledjchisl@sledjhamr.org> |
4 | * Not in SUSv4. An entirely new invention, thus no web site either. | 4 | * Not in SUSv4. An entirely new invention, thus no web site either. |
5 | * | ||
6 | * Not using the usual taybox args system, coz it's not working as advertised. | ||
5 | 7 | ||
6 | USE_SLEDJCHISL(NEWTOY(sledjchisl, "m(mode):", TOYFLAG_USR|TOYFLAG_BIN)) | 8 | USE_SLEDJCHISL(NEWTOY(sledjchisl, "", TOYFLAG_USR|TOYFLAG_BIN)) |
7 | 9 | ||
8 | config SLEDJCHISL | 10 | config SLEDJCHISL |
9 | bool "sledjchisl" | 11 | bool "sledjchisl" |
10 | default y | 12 | default y |
11 | help | 13 | help |
12 | usage: sledjchisl [-m|--mode mode] | 14 | usage: sledjchisl [mode [arguments]] |
13 | 15 | ||
14 | opensim-SC management system. | 16 | opensim-SC management system. |
17 | |||
18 | Mode selects what sledjchisl will do - | ||
19 | create "Sim Name" x,y size | ||
20 | will create a sim. | ||
21 | start | ||
22 | start sim01 | ||
23 | start "Welcome sim" | ||
24 | will start a sim or everything. | ||
25 | backup | ||
26 | backup "Joan Smith" | ||
27 | backup sim01 | ||
28 | backup "Welcome sim" | ||
29 | will backup sim or everything. | ||
30 | gitar i "Joan Smith" | ||
31 | gitar o sim01 | ||
32 | gitar o "Welcome sim" | ||
33 | restart | ||
34 | restart sim01 | ||
35 | restart "Welcome sim" | ||
36 | will stop then start a sim, or everything. | ||
37 | status | ||
38 | status sim01 | ||
39 | status "Welcome sim" | ||
40 | will show status of a sim, or everything. | ||
41 | stop | ||
42 | stop sim01 | ||
43 | stop "Welcome sim" | ||
44 | will stop a sim, or everything. | ||
15 | */ | 45 | */ |
16 | 46 | ||
47 | /* | ||
48 | configs/sim01 - | ||
49 | backup-sim | ||
50 | start-sim | ||
51 | stop-sim | ||
52 | |||
53 | Currently they are all links to ../../current/scripts/start-sim, | ||
54 | they should be links to ../../current/bin/sledjchisl, | ||
55 | which itself is a link to ../src/build/toybox/generated/unstripped/toybox or ../src/build/toybox/toybox | ||
56 | |||
57 | */ | ||
17 | 58 | ||
18 | // TODO - figure out how to automate testing of this. | 59 | // TODO - figure out how to automate testing of this. |
19 | // Being all interactive and involving external web servers / viewers makes it hard. | 60 | // Being all interactive and involving external web servers / viewers makes it hard. |
@@ -54,7 +95,7 @@ extern char **environ; | |||
54 | // https://mariadb.com/kb/en/about-mariadb-connector-c/ Official docs. | 95 | // https://mariadb.com/kb/en/about-mariadb-connector-c/ Official docs. |
55 | // http://dev.mysql.com/doc/refman/5.5/en/c-api-function-overview.html MySQL docs. | 96 | // http://dev.mysql.com/doc/refman/5.5/en/c-api-function-overview.html MySQL docs. |
56 | // http://zetcode.com/db/mysqlc/ MySQL tutorial. | 97 | // http://zetcode.com/db/mysqlc/ MySQL tutorial. |
57 | #include <my_global.h> | 98 | //#include <my_global.h> |
58 | #include <mysql.h> | 99 | #include <mysql.h> |
59 | 100 | ||
60 | #include <qlibc.h> | 101 | #include <qlibc.h> |
@@ -71,16 +112,18 @@ extern char **environ; | |||
71 | // I deal with that by using a sed invokation when building toybox. | 112 | // I deal with that by using a sed invokation when building toybox. |
72 | #include "toys.h" | 113 | #include "toys.h" |
73 | 114 | ||
115 | typedef enum | ||
116 | { | ||
117 | CREATE = 0, | ||
118 | START = 1, | ||
119 | BACKUP = 2, | ||
120 | GITAR = 3, | ||
121 | RESTART = 4, | ||
122 | STATUS = 5, | ||
123 | STOP = 9 | ||
124 | } modes; | ||
74 | 125 | ||
75 | GLOBALS( | 126 | modes currentMode = START; |
76 | char *mode; | ||
77 | ) | ||
78 | |||
79 | #define TT this.sledjchisl | ||
80 | |||
81 | #define FLAG_m 2 | ||
82 | |||
83 | |||
84 | 127 | ||
85 | // Duplicate some small amount of code from qLibc, coz /, + and, = are not good choices, and the standard says we can pick those. | 128 | // Duplicate some small amount of code from qLibc, coz /, + and, = are not good choices, and the standard says we can pick those. |
86 | /** | 129 | /** |
@@ -282,10 +325,10 @@ typedef enum | |||
282 | // Silly "man getrandom" is bullshitting. | 325 | // Silly "man getrandom" is bullshitting. |
283 | // Note - this is Linux specific, it's calling a Linux kernel function. | 326 | // Note - this is Linux specific, it's calling a Linux kernel function. |
284 | // Remove this when we have a real getrandom(), and replace it with - | 327 | // Remove this when we have a real getrandom(), and replace it with - |
285 | // #include <sys/random.h> | 328 | //#include <sys/random.h> |
286 | #include <sys/syscall.h> | 329 | #include <sys/syscall.h> |
287 | #include <linux/random.h> | 330 | #include <linux/random.h> |
288 | int getrandom(void *b, size_t l, unsigned int f) | 331 | ssize_t getrandom(void *b, size_t l, unsigned int f) |
289 | { | 332 | { |
290 | return (int) syscall(SYS_getrandom, b, l, f); | 333 | return (int) syscall(SYS_getrandom, b, l, f); |
291 | } | 334 | } |
@@ -427,6 +470,7 @@ char *scBackup = ""; | |||
427 | char *scCache = ""; | 470 | char *scCache = ""; |
428 | char *scData = ""; | 471 | char *scData = ""; |
429 | char *scLog = ""; | 472 | char *scLog = ""; |
473 | char *scTemp = ""; | ||
430 | char *Tconsole = "SledjChisl"; | 474 | char *Tconsole = "SledjChisl"; |
431 | char *Tsocket = "opensim-tmux.socket"; | 475 | char *Tsocket = "opensim-tmux.socket"; |
432 | char *Ttab = "SC"; | 476 | char *Ttab = "SC"; |
@@ -439,8 +483,9 @@ int seshRenew = 10 * 60; | |||
439 | int idleTimeOut = 30 * 60; | 483 | int idleTimeOut = 30 * 60; |
440 | int seshTimeOut = 24 * 60 * 60; | 484 | int seshTimeOut = 24 * 60 * 60; |
441 | int newbieTimeOut = 30; | 485 | int newbieTimeOut = 30; |
442 | float loadAverageInc = 0.5; | 486 | float loadAverageInc = 0.7; |
443 | int simTimeOut = 45; | 487 | int simTimeOut = 45; |
488 | int bulkSims = 0; | ||
444 | boolean DEBUG = TRUE; | 489 | boolean DEBUG = TRUE; |
445 | qhashtbl_t *mimeTypes; | 490 | qhashtbl_t *mimeTypes; |
446 | qlist_t *dbRequests; | 491 | qlist_t *dbRequests; |
@@ -463,7 +508,7 @@ char *logTypes[] = | |||
463 | "36", "TIMEOUT", // cyan | 508 | "36", "TIMEOUT", // cyan |
464 | "97;40", "INFO", // white | 509 | "97;40", "INFO", // white |
465 | "90", "DEBUG", // grey | 510 | "90", "DEBUG", // grey |
466 | // VERBOSE? UNKNOWN? FATAL? SILENT? All from Android aparently. | 511 | // VERBOSE? UNKNOWN? FATAL? SILENT? All from Android apparently. |
467 | "35", "debug", // magenta | 512 | "35", "debug", // magenta |
468 | "34", "timeout", // blue | 513 | "34", "timeout", // blue |
469 | }; | 514 | }; |
@@ -647,12 +692,38 @@ float waitLoadAverage(float la, float extra, int timeout) | |||
647 | // Rob forget to do this, but at least he didn't declare it static. | 692 | // Rob forget to do this, but at least he didn't declare it static. |
648 | struct dirtree *dirtree_handle_callback(struct dirtree *new, int (*callback)(struct dirtree *node)); | 693 | struct dirtree *dirtree_handle_callback(struct dirtree *new, int (*callback)(struct dirtree *node)); |
649 | 694 | ||
695 | |||
696 | // A sim structure for holding all the stuff from the sim.ini file. | ||
697 | typedef struct _simData simData; | ||
698 | struct _simData | ||
699 | { | ||
700 | // portH is the HTTP port for the sim, portI is the UDP port for the sim. | ||
701 | int num, locX, locY, sizeX, sizeY, sizeZ, portH, portI, maxPrims; | ||
702 | char *name, *tab, *UUID, *regionType, *estate, *owner; | ||
703 | // char *nmbr; | ||
704 | }; | ||
705 | |||
650 | typedef struct _simList simList; | 706 | typedef struct _simList simList; |
651 | struct _simList | 707 | struct _simList |
652 | { | 708 | { |
653 | int len, num; | 709 | int len, num; |
654 | char **sims; | 710 | char **sims; |
711 | qtreetbl_t *tbl, *byTab; | ||
655 | }; | 712 | }; |
713 | simList *ourSims = NULL; | ||
714 | |||
715 | static int getIntFromIni(qlisttbl_t *ini, char *name) | ||
716 | { | ||
717 | int ret; | ||
718 | char *t = "0"; | ||
719 | |||
720 | t = ini->getstr(ini, name, false); | ||
721 | if (NULL == t) | ||
722 | t = "0"; | ||
723 | else if ('"' == t[0]) | ||
724 | t = qstrunchar(t, '"', '"'); | ||
725 | return strtol(t, NULL, 10); | ||
726 | } | ||
656 | 727 | ||
657 | static int filterSims(struct dirtree *node) | 728 | static int filterSims(struct dirtree *node) |
658 | { | 729 | { |
@@ -672,6 +743,7 @@ static int filterSims(struct dirtree *node) | |||
672 | return 0; | 743 | return 0; |
673 | } | 744 | } |
674 | 745 | ||
746 | /* | ||
675 | // We particularly don't want \ " ` | 747 | // We particularly don't want \ " ` |
676 | char *cleanSimName(char *name) | 748 | char *cleanSimName(char *name) |
677 | { | 749 | { |
@@ -690,19 +762,163 @@ char *cleanSimName(char *name) | |||
690 | 762 | ||
691 | return ret; | 763 | return ret; |
692 | } | 764 | } |
765 | */ | ||
766 | |||
767 | static int filterInis(struct dirtree *node) | ||
768 | { | ||
769 | if (!node->parent) return DIRTREE_RECURSE | DIRTREE_SHUTUP; | ||
770 | int l = strlen(node->name); | ||
771 | if (strncmp(&(node->name[l - 4]), ".ini", 4) == 0) | ||
772 | { | ||
773 | strncpy((char *) node->parent->extra, node->name, l - 4); | ||
774 | return DIRTREE_ABORT; | ||
775 | } | ||
776 | return 0; | ||
777 | } | ||
693 | 778 | ||
694 | simList *getSims() | 779 | simList *getSims() |
695 | { | 780 | { |
696 | simList *sims = xmalloc(sizeof(simList)); | 781 | if (NULL != ourSims) return ourSims; |
697 | memset(sims, 0, sizeof(simList)); | 782 | |
698 | char *path = xmprintf("%s/config", scRoot); | 783 | char *path = xmprintf("%s/config", scRoot), *newPath; |
699 | struct dirtree *new = dirtree_add_node(0, path, 0); | 784 | struct dirtree *new = dirtree_add_node(0, path, 0); |
700 | new->extra = (long) sims; | 785 | int i, j; |
786 | |||
787 | ourSims = xmalloc(sizeof(simList)); | ||
788 | memset(ourSims, 0, sizeof(simList)); | ||
789 | |||
790 | ourSims->tbl = qtreetbl(0); | ||
791 | ourSims->byTab = qtreetbl(0); | ||
792 | new->extra = (long) ourSims; | ||
701 | dirtree_handle_callback(new, filterSims); | 793 | dirtree_handle_callback(new, filterSims); |
702 | 794 | ||
703 | qsort(sims->sims, sims->num, sizeof(char *), qstrcmp); | 795 | qsort(ourSims->sims, ourSims->num, sizeof(char *), qstrcmp); |
704 | free(path); | 796 | free(path); |
705 | return sims; | 797 | |
798 | |||
799 | char *file = xmprintf("%s/sims.lua", scEtc); | ||
800 | char *tnm = "sims = -- Note these are .shini / tmux tab short names.\n{\n {['type'] = 'unsorted';\n"; | ||
801 | struct stat st; | ||
802 | int s = stat(file, &st); | ||
803 | int fd = -1; | ||
804 | size_t l = strlen(tnm); | ||
805 | |||
806 | if (s) | ||
807 | { | ||
808 | I("Creating sims %s.", file); | ||
809 | fd = notstdio(xcreate_stdio(file, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR)); | ||
810 | } | ||
811 | |||
812 | if (-1 != fd) | ||
813 | { | ||
814 | if (l != writeall(fd, tnm, l)) | ||
815 | perror_msg("Writing %s", file); | ||
816 | } | ||
817 | |||
818 | |||
819 | for (i = 0; i < ourSims->num; i++) | ||
820 | { | ||
821 | char *sim = ourSims->sims[i], *name = xmprintf("%s/config/%s", scRoot, sim); | ||
822 | qlisttbl_t *ini; | ||
823 | simData *simd = xmalloc(sizeof(simData)); | ||
824 | |||
825 | struct dirtree *new = dirtree_add_node(0, name, 0); | ||
826 | |||
827 | free(name); | ||
828 | name = xzalloc(1024); | ||
829 | new->extra = (long) name; | ||
830 | dirtree_handle_callback(new, filterInis); | ||
831 | if ('\0' != name[0]) | ||
832 | { | ||
833 | path = xmprintf("%s/config/%s/%s.ini", scRoot, sim, name); | ||
834 | newPath = xmprintf("%s/%s.shini", scEtc, name); | ||
835 | I("Reading .ini file %s", path); | ||
836 | ini = qconfig_parse_file(NULL, path, '='); | ||
837 | |||
838 | ini->putstr(ini, "INI FILE", name); | ||
839 | /* | ||
840 | [Region] | ||
841 | Location = "1,1" | ||
842 | InternalPort = "9008" | ||
843 | MaxPrims = 45000 | ||
844 | |||
845 | [Network] | ||
846 | http_listener_port = 9007 | ||
847 | */ | ||
848 | simd->num = getIntFromIni(ini, "Const.mysim"); | ||
849 | simd->name = qstrunchar(ini->getstr(ini, "Region.RegionName", false), '"', '"'); | ||
850 | simd->UUID = qstrunchar(ini->getstr(ini, "Region.RegionUUID", false), '"', '"'); | ||
851 | simd->regionType = qstrunchar(ini->getstr(ini, "Region.RegionType", false), '"', '"'); | ||
852 | simd->sizeX = getIntFromIni(ini, "Region.SizeX"); | ||
853 | simd->sizeY = getIntFromIni(ini, "Region.SizeY"); | ||
854 | simd->sizeZ = getIntFromIni(ini, "Region.SizeZ"); | ||
855 | simd->tab = name; | ||
856 | // simd->nmbr = sim; | ||
857 | ini->put(ini, "SIM DATA", simd, sizeof(simData)); | ||
858 | ourSims->tbl->put(ourSims->tbl, sim, ini, sizeof(qlisttbl_t)); | ||
859 | ourSims->byTab->put(ourSims->byTab, name, ini, sizeof(qlisttbl_t)); | ||
860 | |||
861 | if ((!qfile_exist(newPath))) | ||
862 | { | ||
863 | char *cmd = xmprintf("sed -E" | ||
864 | " -e 's#\\[Const]#\\[Const] ; fakeVariableCozOpenSim='' ; pushd ../current/bin; ./sledjchisl $1 `basename $0`; popd ; exit 0#'" | ||
865 | " -e 's/mysim=\"[[:digit:]]*\"/mysim=\"%s\"/'" | ||
866 | " -e 's/sim\\$\\{Const\\|mysim\\}/\\$\\{Const\\|mysim\\}/g'" | ||
867 | " %s >%s", simd->tab, path, newPath); | ||
868 | |||
869 | I("Writing .shini file %s", newPath); | ||
870 | D(cmd); | ||
871 | j = system(cmd); | ||
872 | if (!WIFEXITED(j)) | ||
873 | E("sed command failed!"); | ||
874 | else | ||
875 | { | ||
876 | free(cmd); | ||
877 | cmd = xmprintf("chmod ugo+x %s", newPath); | ||
878 | j = system(cmd); | ||
879 | if (!WIFEXITED(j)) | ||
880 | E("chmod command failed!"); | ||
881 | |||
882 | |||
883 | char *link = xmprintf("%s/%s.shini", scBin, simd->tab); | ||
884 | I("Symlinking %s to %s", newPath, link); | ||
885 | if (0 != symlink(newPath, link)) | ||
886 | perror_msg("Symlinking %s to %s", newPath, link); | ||
887 | free(link); | ||
888 | |||
889 | |||
890 | } | ||
891 | free(cmd); | ||
892 | } | ||
893 | } | ||
894 | free(newPath); | ||
895 | free(path); | ||
896 | |||
897 | |||
898 | if (-1 != fd) | ||
899 | { | ||
900 | tnm = xmprintf(" '%s', \n", simd->tab); | ||
901 | l = strlen(tnm); | ||
902 | if (l != writeall(fd, tnm, l)) | ||
903 | perror_msg("Writing %s", file); | ||
904 | free(tnm); | ||
905 | } | ||
906 | |||
907 | } | ||
908 | |||
909 | if (-1 != fd) | ||
910 | { | ||
911 | tnm = " },\n}\nreturn sims\n"; | ||
912 | l = strlen(tnm); | ||
913 | if (l != writeall(fd, tnm, l)) | ||
914 | perror_msg("Writing %s", file); | ||
915 | |||
916 | xclose(fd); | ||
917 | } | ||
918 | free(file); | ||
919 | |||
920 | |||
921 | return ourSims; | ||
706 | } | 922 | } |
707 | 923 | ||
708 | void freeSimList(simList *sims) | 924 | void freeSimList(simList *sims) |
@@ -712,69 +928,44 @@ void freeSimList(simList *sims) | |||
712 | for (i = 0; i < sims->num; i++) | 928 | for (i = 0; i < sims->num; i++) |
713 | free(sims->sims[i]); | 929 | free(sims->sims[i]); |
714 | free(sims->sims); | 930 | free(sims->sims); |
715 | free(sims); | ||
716 | } | ||
717 | 931 | ||
718 | static int filterInis(struct dirtree *node) | 932 | qtreetbl_obj_t obj; |
719 | { | 933 | memset((void*) &obj, 0, sizeof(obj)); // start from the minimum. |
720 | if (!node->parent) return DIRTREE_RECURSE | DIRTREE_SHUTUP; | 934 | sims->tbl->lock(sims->tbl); |
721 | int l = strlen(node->name); | 935 | while (sims->tbl->getnext(sims->tbl, &obj, false) == true) |
722 | if (strncmp(&(node->name[l - 4]), ".ini", 4) == 0) | 936 | { |
937 | char *name = qmemdup(obj.name, obj.namesize); // keep the name | ||
938 | size_t namesize = obj.namesize; // for removal argument | ||
939 | qlisttbl_t *ini = (qlisttbl_t *) obj.data; | ||
940 | if (NULL != ini) | ||
723 | { | 941 | { |
724 | strcpy((char *) node->parent->extra, node->name); | 942 | simData *simd = ini->get(ini, "SIM DATA", NULL, false); |
725 | return DIRTREE_ABORT; | ||
726 | } | ||
727 | return 0; | ||
728 | } | ||
729 | 943 | ||
730 | char *getSimName(char *sim) | 944 | if (NULL != simd) |
731 | { | ||
732 | char *ret = NULL; | ||
733 | char *c = xmprintf("%s/config/%s", scRoot, sim); | ||
734 | struct dirtree *new = dirtree_add_node(0, c, 0); | ||
735 | |||
736 | free(c); | ||
737 | c = xzalloc(1024); | ||
738 | new->extra = (long) c; | ||
739 | dirtree_handle_callback(new, filterInis); | ||
740 | if ('\0' != c[0]) | ||
741 | { | ||
742 | char *temp = NULL; | ||
743 | regex_t pat; | ||
744 | regmatch_t m[2]; | ||
745 | long len; | ||
746 | int fd; | ||
747 | |||
748 | temp = xmprintf("%s/config/%s/%s", scRoot, sim, c); | ||
749 | fd = xopenro(temp); | ||
750 | xregcomp(&pat, "RegionName = \"(.+)\"", REG_EXTENDED); | ||
751 | do | ||
752 | { | ||
753 | // TODO - get_line() is slow, and wont help much with DOS and Mac line endings. | ||
754 | // gio_gets() isn't any faster really, but deals with DOS line endings at least. | ||
755 | free(temp); | ||
756 | temp = get_line(fd); | ||
757 | if (temp) | ||
758 | { | 945 | { |
759 | if (!regexec(&pat, temp, 2, m, 0)) | 946 | free(simd->name); |
760 | { | 947 | free(simd->UUID); |
761 | // Return first parenthesized subexpression as string. | 948 | free(simd->regionType); |
762 | if (pat.re_nsub > 0) | 949 | // free(simd->estate); |
763 | { | 950 | // free(simd->owner); |
764 | ret = xmprintf("%.*s", (int) (m[1].rm_eo - m[1].rm_so), temp + m[1].rm_so); | 951 | free(simd); |
765 | free(temp); | ||
766 | break; | ||
767 | } | ||
768 | } | ||
769 | } | 952 | } |
770 | } while (temp); | 953 | // TODO - this leaks memory, but it's a bug in qLibc. Send the bug fix upstream. |
771 | regfree(&pat); | 954 | // It either leaks, or frees twice. Pffft |
772 | xclose(fd); | 955 | // ini->clear(ini); |
956 | // ini->free(ini); | ||
957 | ; | ||
958 | } | ||
959 | |||
960 | sims->tbl->remove_by_obj(sims->tbl, obj.name, obj.namesize); // remove | ||
961 | obj = sims->tbl->find_nearest(sims->tbl, name, namesize, false); // rewind one step back | ||
962 | free(name); // clean up | ||
773 | } | 963 | } |
774 | free(c); | 964 | sims->tbl->unlock(sims->tbl); |
775 | return ret; | 965 | sims->tbl->free(sims->tbl); |
776 | } | ||
777 | 966 | ||
967 | free(sims); | ||
968 | } | ||
778 | 969 | ||
779 | // Expects either "simXX" or "ROBUST". | 970 | // Expects either "simXX" or "ROBUST". |
780 | int checkSimIsRunning(char *sim) | 971 | int checkSimIsRunning(char *sim) |
@@ -3421,6 +3612,7 @@ char *checkLinky(reqData *Rd) | |||
3421 | ret = xmprintf("<p><font color='red'><b>You have an email waiting with a validation link in it, please check your email. " | 3612 | ret = xmprintf("<p><font color='red'><b>You have an email waiting with a validation link in it, please check your email. " |
3422 | "It will be from %s@%s, and it might be in your spam folder, coz these sorts of emails sometimes end up there. " | 3613 | "It will be from %s@%s, and it might be in your spam folder, coz these sorts of emails sometimes end up there. " |
3423 | "You should add that email address to your contacts, or otherwise let it through your spam filter. " | 3614 | "You should add that email address to your contacts, or otherwise let it through your spam filter. " |
3615 | "If your email client wont let you click the validation link, just copy and paste it into your web browser. " | ||
3424 | // "<a href='https://%s%s?hashish=%s'>%s</a>" | 3616 | // "<a href='https://%s%s?hashish=%s'>%s</a>" |
3425 | "</b></font></p>\n", | 3617 | "</b></font></p>\n", |
3426 | "grid_no_reply", Rd->Host, | 3618 | "grid_no_reply", Rd->Host, |
@@ -3646,15 +3838,22 @@ t("Write shs %s", tnm4); | |||
3646 | "\n" | 3838 | "\n" |
3647 | "Please go to this web link to validate your new account -\n" | 3839 | "Please go to this web link to validate your new account -\n" |
3648 | "https://%s%s?hashish=%s\n" | 3840 | "https://%s%s?hashish=%s\n" |
3841 | "If your email client wont let you click the validation\n" | ||
3842 | "link, just copy and paste it into your web browser.\n" | ||
3843 | "\n" | ||
3649 | "\n" | 3844 | "\n" |
3650 | "Do not reply to this email.\n" | 3845 | "Do not reply to this email.\n" |
3651 | "\n", | 3846 | "\n" |
3847 | "\n" | ||
3848 | "A copy of the grids Terms of Service that you agreed to\n" | ||
3849 | "when you created your account is included below.\n" | ||
3850 | "%s", | ||
3652 | Rd->Host, Rd->Host, Rd->Host, | 3851 | Rd->Host, Rd->Host, Rd->Host, |
3653 | getStrH(Rd->stuff, "email"), | 3852 | getStrH(Rd->stuff, "email"), |
3654 | Rd->Host, Rd->Host, | 3853 | Rd->Host, Rd->Host, |
3655 | first, last, | 3854 | first, last, |
3656 | first, last, Rd->Host, Rd->RUri, | 3855 | first, last, Rd->Host, Rd->RUri, |
3657 | Rd->Host, Rd->RUri, t1 | 3856 | Rd->Host, Rd->RUri, t1, ToS |
3658 | ); | 3857 | ); |
3659 | l = strlen(content); | 3858 | l = strlen(content); |
3660 | file = xmprintf("%s/sessions/%s.email", scCache, shs->leaf); | 3859 | file = xmprintf("%s/sessions/%s.email", scCache, shs->leaf); |
@@ -3894,6 +4093,7 @@ static void accountWrite(reqData *Rd) | |||
3894 | if (!writeLuaString (Rd, fd, file, "aboutMe", NULL)) goto notWritten; | 4093 | if (!writeLuaString (Rd, fd, file, "aboutMe", NULL)) goto notWritten; |
3895 | if (!writeLuaString (Rd, fd, file, "vouched", "off")) goto notWritten; | 4094 | if (!writeLuaString (Rd, fd, file, "vouched", "off")) goto notWritten; |
3896 | if (!writeLuaString (Rd, fd, file, "voucher", NULL)) goto notWritten; | 4095 | if (!writeLuaString (Rd, fd, file, "voucher", NULL)) goto notWritten; |
4096 | if (!writeLuaString (Rd, fd, file, "approver", NULL)) goto notWritten; | ||
3897 | if (!writeLuaString (Rd, fd, file, "link", link)) goto notWritten; | 4097 | if (!writeLuaString (Rd, fd, file, "link", link)) goto notWritten; |
3898 | l = strlen(end); | 4098 | l = strlen(end); |
3899 | if (l != writeall(fd, end, l)) | 4099 | if (l != writeall(fd, end, l)) |
@@ -3939,7 +4139,7 @@ notWritten: | |||
3939 | "UserLevel", | 4139 | "UserLevel", |
3940 | "UserFlags", | 4140 | "UserFlags", |
3941 | "UserTitle", | 4141 | "UserTitle", |
3942 | // "ServiceURLs", // No worky "text", filled with crap. | 4142 | // "ServiceURLs", // No worky "text", filled with crap. Leaving it blank works fine. |
3943 | "active", | 4143 | "active", |
3944 | NULL | 4144 | NULL |
3945 | }; | 4145 | }; |
@@ -4090,16 +4290,26 @@ notWritten: | |||
4090 | } | 4290 | } |
4091 | 4291 | ||
4092 | // load iar -m first last / password /opt/opensim_SC/backups/DefaultMember.IAR | 4292 | // load iar -m first last / password /opt/opensim_SC/backups/DefaultMember.IAR |
4093 | simList *sims = getSims(); | ||
4094 | struct sysinfo info; | 4293 | struct sysinfo info; |
4095 | float la; | 4294 | float la; |
4096 | 4295 | ||
4097 | sysinfo(&info); | 4296 | sysinfo(&info); |
4098 | la = info.loads[0]/65536.0; | 4297 | la = info.loads[0]/65536.0; |
4099 | 4298 | ||
4100 | for (i = 0; i < sims->num; i++) | 4299 | for (i = 0; i < ourSims->num; i++) |
4101 | { | 4300 | { |
4102 | char *sim = sims->sims[i], *name = getSimName(sims->sims[i]); | 4301 | char *sim = ourSims->sims[i], *name;// = getSimName(ourSims->sims[i], &nm, &num); |
4302 | |||
4303 | qlisttbl_t *ini = ourSims->tbl->get(ourSims->tbl, sim, NULL, false); | ||
4304 | if (NULL == ini) | ||
4305 | { | ||
4306 | E("Sim %s not found in ini list!", sim); | ||
4307 | // name = getSimName(ourSims->sims[i], &nm, &num); | ||
4308 | } | ||
4309 | else | ||
4310 | name = qstrunchar(ini->getstr(ini, "Region.RegionName", false), '"', '"'); | ||
4311 | |||
4312 | |||
4103 | 4313 | ||
4104 | if (checkSimIsRunning(sim)) | 4314 | if (checkSimIsRunning(sim)) |
4105 | { | 4315 | { |
@@ -4124,7 +4334,6 @@ T(c); | |||
4124 | } | 4334 | } |
4125 | free(name); | 4335 | free(name); |
4126 | } | 4336 | } |
4127 | freeSimList(sims); | ||
4128 | } | 4337 | } |
4129 | free(first); | 4338 | free(first); |
4130 | } | 4339 | } |
@@ -4796,8 +5005,8 @@ static int DoBValidate(reqData *Rd, inputForm *iF, inputValue *iV) | |||
4796 | else | 5005 | else |
4797 | { | 5006 | { |
4798 | i = atoi(t0); | 5007 | i = atoi(t0); |
4799 | // TODO - get this to use current year instead of 2020. | 5008 | // TODO - get this to use current year instead of 2021. |
4800 | if ((1900 > i) || (i > 2020)) | 5009 | if ((1900 > i) || (i > 2021)) |
4801 | { | 5010 | { |
4802 | bitch(Rd, "Please supply a year of birth.", "Out of range."); | 5011 | bitch(Rd, "Please supply a year of birth.", "Out of range."); |
4803 | ret++; | 5012 | ret++; |
@@ -4807,7 +5016,7 @@ static int DoBValidate(reqData *Rd, inputForm *iF, inputValue *iV) | |||
4807 | bitch(Rd, "Please supply a proper year of birth.", "Out of range, too old."); | 5016 | bitch(Rd, "Please supply a proper year of birth.", "Out of range, too old."); |
4808 | ret++; | 5017 | ret++; |
4809 | } | 5018 | } |
4810 | else if (i >2004) | 5019 | else if (i >2005) |
4811 | { | 5020 | { |
4812 | bitch(Rd, "This grid is Adult rated, you are too young.", "Out of range, too young."); | 5021 | bitch(Rd, "This grid is Adult rated, you are too young.", "Out of range, too young."); |
4813 | ret++; | 5022 | ret++; |
@@ -5074,6 +5283,7 @@ static void accountViewWeb(reqData *Rd, inputForm *oF, inputValue *oV) | |||
5074 | *level = getStrH(Rd->database, "UserAccounts.UserLevel"), | 5283 | *level = getStrH(Rd->database, "UserAccounts.UserLevel"), |
5075 | *email = getStrH(Rd->database, "UserAccounts.Email"), | 5284 | *email = getStrH(Rd->database, "UserAccounts.Email"), |
5076 | *voucher = getStrH(Rd->database, "Lua.voucher"), | 5285 | *voucher = getStrH(Rd->database, "Lua.voucher"), |
5286 | *approver = getStrH(Rd->database, "Lua.approver"), | ||
5077 | *about = getStrH(Rd->database, "Lua.aboutMe"); | 5287 | *about = getStrH(Rd->database, "Lua.aboutMe"); |
5078 | time_t crtd = atol(getStrH(Rd->database, "UserAccounts.Created")); | 5288 | time_t crtd = atol(getStrH(Rd->database, "UserAccounts.Created")); |
5079 | 5289 | ||
@@ -5086,6 +5296,7 @@ static void accountViewWeb(reqData *Rd, inputForm *oF, inputValue *oV) | |||
5086 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>Email :</b></span></font> %s</p>", email); | 5296 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>Email :</b></span></font> %s</p>", email); |
5087 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>UUID :</b></span></font> %s</p>", getStrH(Rd->database, "UserAccounts.PrincipalID")); | 5297 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>UUID :</b></span></font> %s</p>", getStrH(Rd->database, "UserAccounts.PrincipalID")); |
5088 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>Voucher :</b></span></font> %s</p>", voucher); | 5298 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>Voucher :</b></span></font> %s</p>", voucher); |
5299 | Rd->reply->addstrf(Rd->reply, "<p><font size='5'><span style='font-size: x-large'><b>Approver :</b></span></font> %s</p>", approver); | ||
5089 | HTMLtextArea(Rd->reply, "aboutMe", "About", 7, 50, 4, 16384, "", "off", "true", "soft", about, FALSE, TRUE); | 5300 | HTMLtextArea(Rd->reply, "aboutMe", "About", 7, 50, 4, 16384, "", "off", "true", "soft", about, FALSE, TRUE); |
5090 | accountWebSubs(Rd, oF); | 5301 | accountWebSubs(Rd, oF); |
5091 | accountWebFooter(Rd, oF); | 5302 | accountWebFooter(Rd, oF); |
@@ -5097,6 +5308,7 @@ static void accountEditWeb(reqData *Rd, inputForm *oF, inputValue *oV) | |||
5097 | *level = getStrH(Rd->database, "UserAccounts.UserLevel"), | 5308 | *level = getStrH(Rd->database, "UserAccounts.UserLevel"), |
5098 | *email = getStrH(Rd->database, "UserAccounts.Email"), | 5309 | *email = getStrH(Rd->database, "UserAccounts.Email"), |
5099 | *voucher = getStrH(Rd->database, "Lua.voucher"), | 5310 | *voucher = getStrH(Rd->database, "Lua.voucher"), |
5311 | *approver = getStrH(Rd->database, "Lua.approver"), | ||
5100 | *about = getStrH(Rd->database, "Lua.aboutMe"), | 5312 | *about = getStrH(Rd->database, "Lua.aboutMe"), |
5101 | *lvl = getLevel(atoi(level)); | 5313 | *lvl = getLevel(atoi(level)); |
5102 | short lv = atoi(level); | 5314 | short lv = atoi(level); |
@@ -5117,6 +5329,7 @@ static void accountEditWeb(reqData *Rd, inputForm *oF, inputValue *oV) | |||
5117 | { | 5329 | { |
5118 | qlisttbl_obj_t obj; | 5330 | qlisttbl_obj_t obj; |
5119 | 5331 | ||
5332 | HTMLhidden(Rd->reply, "approver", approver); | ||
5120 | HTMLselect(Rd->reply, "level", "level"); | 5333 | HTMLselect(Rd->reply, "level", "level"); |
5121 | memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call | 5334 | memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call |
5122 | accountLevels->lock(accountLevels); | 5335 | accountLevels->lock(accountLevels); |
@@ -5288,6 +5501,7 @@ T("Found Lua record."); | |||
5288 | Rd->database->putstr(Rd->database, "Lua.aboutMe", getStrH(tnm, "aboutMe")); | 5501 | Rd->database->putstr(Rd->database, "Lua.aboutMe", getStrH(tnm, "aboutMe")); |
5289 | Rd->database->putstr(Rd->database, "Lua.vouched", getStrH(tnm, "vouched")); | 5502 | Rd->database->putstr(Rd->database, "Lua.vouched", getStrH(tnm, "vouched")); |
5290 | Rd->database->putstr(Rd->database, "Lua.voucher", getStrH(tnm, "voucher")); | 5503 | Rd->database->putstr(Rd->database, "Lua.voucher", getStrH(tnm, "voucher")); |
5504 | Rd->database->putstr(Rd->database, "Lua.approver", getStrH(tnm, "approver")); | ||
5291 | } | 5505 | } |
5292 | // else if (rows) | 5506 | // else if (rows) |
5293 | if (rows) | 5507 | if (rows) |
@@ -5369,9 +5583,9 @@ static int accountDelSub(reqData *Rd, inputForm *iF, inputValue *iV) | |||
5369 | } | 5583 | } |
5370 | else | 5584 | else |
5371 | { | 5585 | { |
5372 | // check if logged in user is allowed to delete this account | 5586 | // TODO - check if logged in user is allowed to delete this account |
5373 | // delete user record | 5587 | // TODO - delete user record |
5374 | // log the user out if they are logged in | 5588 | // TODO - log the user out if they are logged in |
5375 | } | 5589 | } |
5376 | return ret; | 5590 | return ret; |
5377 | } | 5591 | } |
@@ -5464,7 +5678,8 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV) | |||
5464 | { | 5678 | { |
5465 | int ret = 0; | 5679 | int ret = 0; |
5466 | // Using body[user] here, coz we got to this page via a URL query. | 5680 | // Using body[user] here, coz we got to this page via a URL query. |
5467 | char *uuid = Rd->shs.UUID, *first = getStrH(Rd->body, "user"), *last = NULL; | 5681 | char *uuid = Rd->shs.UUID, *first = getStrH(Rd->body, "user"), *last = NULL, |
5682 | *level = getStrH(Rd->database, "UserAccounts.UserLevel"); | ||
5468 | int c = accountRead(Rd, NULL, first, last); | 5683 | int c = accountRead(Rd, NULL, first, last); |
5469 | 5684 | ||
5470 | if (1 != c) | 5685 | if (1 != c) |
@@ -5474,6 +5689,24 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV) | |||
5474 | } | 5689 | } |
5475 | else if ((0 == ret) && (strcmp("POST", Rd->Method) == 0)) | 5690 | else if ((0 == ret) && (strcmp("POST", Rd->Method) == 0)) |
5476 | { | 5691 | { |
5692 | char *lvl = getStrH(Rd->body, "level"); | ||
5693 | qlisttbl_obj_t obj; | ||
5694 | |||
5695 | if (strcmp(level, lvl) != 0) | ||
5696 | { | ||
5697 | if (200 <= Rd->shs.level) | ||
5698 | { | ||
5699 | I("%s %s approved by %s.", getStrH(Rd->database, "UserAccounts.FirstName"), getStrH(Rd->database, "UserAccounts.LastName"), Rd->shs.name); | ||
5700 | Rd->stuff->putstr(Rd->stuff, "approver", Rd->shs.name); | ||
5701 | } | ||
5702 | else | ||
5703 | { | ||
5704 | bitch(Rd, "Cannot change level.", "User level not high enough."); | ||
5705 | lvl = level; | ||
5706 | Rd->stuff->putstr(Rd->stuff, "approver", getStrH(Rd->database, "Lua.approver")); | ||
5707 | } | ||
5708 | } | ||
5709 | |||
5477 | Rd->stuff->putstr(Rd->stuff, "email", getStrH(Rd->database, "UserAccounts.Email")); | 5710 | Rd->stuff->putstr(Rd->stuff, "email", getStrH(Rd->database, "UserAccounts.Email")); |
5478 | Rd->stuff->putstr(Rd->stuff, "created", getStrH(Rd->database, "UserAccounts.Created")); | 5711 | Rd->stuff->putstr(Rd->stuff, "created", getStrH(Rd->database, "UserAccounts.Created")); |
5479 | Rd->stuff->putstr(Rd->stuff, "flags", getStrH(Rd->database, "UserAccounts.UserFlags")); | 5712 | Rd->stuff->putstr(Rd->stuff, "flags", getStrH(Rd->database, "UserAccounts.UserFlags")); |
@@ -5488,15 +5721,14 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV) | |||
5488 | Rd->stuff->putstr(Rd->stuff, "vouched", getStrH(Rd->database, "Lua.vouched")); | 5721 | Rd->stuff->putstr(Rd->stuff, "vouched", getStrH(Rd->database, "Lua.vouched")); |
5489 | Rd->stuff->putstr(Rd->stuff, "voucher", getStrH(Rd->database, "Lua.voucher")); | 5722 | Rd->stuff->putstr(Rd->stuff, "voucher", getStrH(Rd->database, "Lua.voucher")); |
5490 | 5723 | ||
5491 | char *lvl = getStrH(Rd->body, "level"); | ||
5492 | qlisttbl_obj_t obj; | ||
5493 | |||
5494 | memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call | 5724 | memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call |
5495 | accountLevels->lock(accountLevels); | 5725 | accountLevels->lock(accountLevels); |
5496 | while(accountLevels->getnext(accountLevels, &obj, NULL, false) == true) | 5726 | while(accountLevels->getnext(accountLevels, &obj, NULL, false) == true) |
5497 | { | 5727 | { |
5498 | if (strcmp(lvl, (char *) obj.data) == 0) | 5728 | if (strcmp(lvl, (char *) obj.data) == 0) |
5729 | { | ||
5499 | Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", obj.name); | 5730 | Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", obj.name); |
5731 | } | ||
5500 | } | 5732 | } |
5501 | accountLevels->unlock(accountLevels); | 5733 | accountLevels->unlock(accountLevels); |
5502 | accountWrite(Rd); | 5734 | accountWrite(Rd); |
@@ -5535,6 +5767,7 @@ static int accountValidateSub(reqData *Rd, inputForm *iF, inputValue *iV) | |||
5535 | Rd->stuff->putstr(Rd->stuff, "aboutMe", getStrH(Rd->database, "Lua.aboutMe")); | 5767 | Rd->stuff->putstr(Rd->stuff, "aboutMe", getStrH(Rd->database, "Lua.aboutMe")); |
5536 | Rd->stuff->putstr(Rd->stuff, "vouched", getStrH(Rd->database, "Lua.vouched")); | 5768 | Rd->stuff->putstr(Rd->stuff, "vouched", getStrH(Rd->database, "Lua.vouched")); |
5537 | Rd->stuff->putstr(Rd->stuff, "voucher", getStrH(Rd->database, "Lua.voucher")); | 5769 | Rd->stuff->putstr(Rd->stuff, "voucher", getStrH(Rd->database, "Lua.voucher")); |
5770 | Rd->stuff->putstr(Rd->stuff, "approver", getStrH(Rd->database, "Lua.approver")); | ||
5538 | Rd->shs.level = -100; | 5771 | Rd->shs.level = -100; |
5539 | Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-100"); | 5772 | Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-100"); |
5540 | accountWrite(Rd); | 5773 | accountWrite(Rd); |
@@ -5603,8 +5836,8 @@ d("Sub accountEditSub %s %s %s", uuid, first, last); | |||
5603 | } | 5836 | } |
5604 | else | 5837 | else |
5605 | { | 5838 | { |
5606 | // check if logged in user is allowed to make these changes | 5839 | // TODO - check if logged in user is allowed to make these changes |
5607 | // update user record | 5840 | // TODO - update user record |
5608 | } | 5841 | } |
5609 | return ret; | 5842 | return ret; |
5610 | } | 5843 | } |
@@ -6457,6 +6690,10 @@ void sledjchisl_main(void) | |||
6457 | I("qLibc version: qLibc only git tags for version numbers. Sooo, 2.4.4, unless I forgot to update this."); | 6690 | I("qLibc version: qLibc only git tags for version numbers. Sooo, 2.4.4, unless I forgot to update this."); |
6458 | I("toybox version: %s", TOYBOX_VERSION); | 6691 | I("toybox version: %s", TOYBOX_VERSION); |
6459 | 6692 | ||
6693 | T("SledjChisl arguments %d %d", (int)toys.optflags, (int)toys.optc); | ||
6694 | for (i = 0; i < toys.optc; i++) | ||
6695 | T(" argument %d %s", i, toys.optargs[i] ); | ||
6696 | |||
6460 | dbRequests = qlist(0); | 6697 | dbRequests = qlist(0); |
6461 | sigatexit(cleanup); | 6698 | sigatexit(cleanup); |
6462 | 6699 | ||
@@ -6517,6 +6754,7 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6517 | luaL_openlibs(L); // Load Lua libraries. | 6754 | luaL_openlibs(L); // Load Lua libraries. |
6518 | 6755 | ||
6519 | // Load the config scripts. | 6756 | // Load the config scripts. |
6757 | // TODO - should add something like current working directory here. Gets complicated, may have to go up or down a bit. | ||
6520 | char *cPaths[] = | 6758 | char *cPaths[] = |
6521 | { | 6759 | { |
6522 | ".sledjChisl.conf.lua", | 6760 | ".sledjChisl.conf.lua", |
@@ -6528,7 +6766,6 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6528 | }; | 6766 | }; |
6529 | struct stat st; | 6767 | struct stat st; |
6530 | 6768 | ||
6531 | |||
6532 | for (i = 0; cPaths[i]; i++) | 6769 | for (i = 0; cPaths[i]; i++) |
6533 | { | 6770 | { |
6534 | memset(toybuf, 0, sizeof(toybuf)); | 6771 | memset(toybuf, 0, sizeof(toybuf)); |
@@ -6583,6 +6820,7 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6583 | D("Setting DEBUG = %d", DEBUG); | 6820 | D("Setting DEBUG = %d", DEBUG); |
6584 | if ((vd = configs->get (configs, "loadAverageInc", NULL, false)) != NULL) {loadAverageInc = *((float *) vd); D("Setting loadAverageInc = %f", loadAverageInc);} | 6821 | if ((vd = configs->get (configs, "loadAverageInc", NULL, false)) != NULL) {loadAverageInc = *((float *) vd); D("Setting loadAverageInc = %f", loadAverageInc);} |
6585 | if ((vd = configs->get (configs, "simTimeOut", NULL, false)) != NULL) {simTimeOut = (int) *((float *) vd); D("Setting simTimeOut = %d", simTimeOut);} | 6822 | if ((vd = configs->get (configs, "simTimeOut", NULL, false)) != NULL) {simTimeOut = (int) *((float *) vd); D("Setting simTimeOut = %d", simTimeOut);} |
6823 | if ((vd = configs->get (configs, "bulkSims", NULL, false)) != NULL) {bulkSims = (int) *((float *) vd); D("Setting bulkSims = %d", bulkSims);} | ||
6586 | if ((tmp = configs->getstr(configs, "scRoot", false)) != NULL) {scRoot = tmp; D("Setting scRoot = %s", scRoot);} | 6824 | if ((tmp = configs->getstr(configs, "scRoot", false)) != NULL) {scRoot = tmp; D("Setting scRoot = %s", scRoot);} |
6587 | if ((tmp = configs->getstr(configs, "scUser", false)) != NULL) {scUser = tmp; D("Setting scUser = %s", scUser);} | 6825 | if ((tmp = configs->getstr(configs, "scUser", false)) != NULL) {scUser = tmp; D("Setting scUser = %s", scUser);} |
6588 | if ((tmp = configs->getstr(configs, "Tconsole", false)) != NULL) {Tconsole = tmp; D("Setting Tconsole = %s", Tconsole);} | 6826 | if ((tmp = configs->getstr(configs, "Tconsole", false)) != NULL) {Tconsole = tmp; D("Setting Tconsole = %s", Tconsole);} |
@@ -6609,6 +6847,7 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6609 | scCache = "/var/cache/opensim_SC"; | 6847 | scCache = "/var/cache/opensim_SC"; |
6610 | scData = "/var/lib/opensim_SC"; | 6848 | scData = "/var/lib/opensim_SC"; |
6611 | scLog = "/var/log/opensim_SC"; | 6849 | scLog = "/var/log/opensim_SC"; |
6850 | scTemp = "/tmp"; | ||
6612 | } | 6851 | } |
6613 | else if (strcmp("/usr/local", scRoot) == 0) | 6852 | else if (strcmp("/usr/local", scRoot) == 0) |
6614 | { | 6853 | { |
@@ -6620,6 +6859,7 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6620 | scCache = "/var/local/cache/opensim_SC"; | 6859 | scCache = "/var/local/cache/opensim_SC"; |
6621 | scData = "/var/local/lib/opensim_SC"; | 6860 | scData = "/var/local/lib/opensim_SC"; |
6622 | scLog = "/var/local/log/opensim_SC"; | 6861 | scLog = "/var/local/log/opensim_SC"; |
6862 | scTemp = "/tmp"; | ||
6623 | } | 6863 | } |
6624 | else // A place for everything to live, like /opt/opensim_SC | 6864 | else // A place for everything to live, like /opt/opensim_SC |
6625 | { | 6865 | { |
@@ -6642,6 +6882,7 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6642 | scCache = xmprintf("%s%s/var/cache", slsh, scRoot); | 6882 | scCache = xmprintf("%s%s/var/cache", slsh, scRoot); |
6643 | scData = xmprintf("%s%s/var/lib", slsh, scRoot); | 6883 | scData = xmprintf("%s%s/var/lib", slsh, scRoot); |
6644 | scLog = xmprintf("%s%s/var/log", slsh, scRoot); | 6884 | scLog = xmprintf("%s%s/var/log", slsh, scRoot); |
6885 | scTemp = xmprintf("%s%s/tmp", slsh, scRoot); | ||
6645 | } | 6886 | } |
6646 | 6887 | ||
6647 | 6888 | ||
@@ -6662,30 +6903,75 @@ jit library is loaded or the JIT compiler will not be activated. | |||
6662 | I("Not running inside the proper tmux server, starting it. %s == %s", eTMUX, toybuf); | 6903 | I("Not running inside the proper tmux server, starting it. %s == %s", eTMUX, toybuf); |
6663 | } | 6904 | } |
6664 | 6905 | ||
6665 | if (isTmux || isWeb) | 6906 | if (!isTmux) |
6666 | { | 6907 | { // Let's see if the proper tmux server is even running. |
6667 | char *d; | 6908 | memset(toybuf, 0, sizeof(toybuf)); |
6909 | snprintf(toybuf, sizeof(toybuf), "%s %s/%s -q list-sessions 2>/dev/null | grep -q %s:", Tcmd, scRun, Tsocket, Tconsole); | ||
6910 | i = system(toybuf); | ||
6911 | if (WIFEXITED(i)) | ||
6912 | { | ||
6913 | if (0 != WEXITSTATUS(i)) // No such session, create it. | ||
6914 | { | ||
6915 | memset(toybuf, 0, sizeof(toybuf)); | ||
6916 | if (strcmp(pw->pw_name, scUser) == 0) | ||
6917 | { | ||
6918 | snprintf(toybuf, sizeof(toybuf), | ||
6919 | "%s %s/%s new-session -d -s %s -n '%s' \\; split-window -bhp 50 -t '%s:' bash -c '/usr/bin/valgrind --leak-check=full ./sledjchisl; cd %s; bash'", | ||
6920 | Tcmd, scRun, Tsocket, Tconsole, Ttab, Tconsole, scRoot); | ||
6921 | } | ||
6922 | else | ||
6923 | { | ||
6924 | // The sudo is only so that the session is owned by opensim, otherwise it's owned by whoever ran this script, which is a likely security hole. | ||
6925 | // After the session is created, we rely on the scRun directory to be group sticky, so that anyone in the opensim group can attach to the tmux socket. | ||
6926 | snprintf(toybuf, sizeof(toybuf), | ||
6927 | "sudo -Hu %s %s %s/%s new-session -d -s %s -n '%s' \\; split-window -bhp 50 -t '%s:' bash -c '/usr/bin/valgrind --leak-check=full ./sledjchisl; cd %s; bash'", | ||
6928 | scUser, Tcmd, scRun, Tsocket, Tconsole, Ttab, Tconsole, scRoot); | ||
6929 | } | ||
6930 | i = system(toybuf); | ||
6931 | if (!WIFEXITED(i)) | ||
6932 | E("tmux new-session command failed! %s", toybuf); | ||
6933 | } | ||
6934 | // Join the session. | ||
6935 | memset(toybuf, 0, sizeof(toybuf)); | ||
6936 | snprintf(toybuf, sizeof(toybuf), "%s %s/%s select-window -t '%s' \\; attach-session -t '%s'", Tcmd, scRun, Tsocket, Tconsole, Tconsole); | ||
6937 | i = system(toybuf); | ||
6938 | if (!WIFEXITED(i)) | ||
6939 | E("tmux attach-session command failed! %s", toybuf); | ||
6940 | goto finished; | ||
6941 | } | ||
6942 | else | ||
6943 | E("tmux list-sessions command failed! %s", toybuf); | ||
6944 | } | ||
6668 | 6945 | ||
6669 | // Doing this here coz at this point we should be the correct user. | 6946 | |
6670 | if ((! qfile_exist(scBin)) && (! qfile_mkdir(scBin, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scBin); | 6947 | // Doing this here coz at this point we should be the correct user. |
6671 | if ((! qfile_exist(scEtc)) && (! qfile_mkdir(scEtc, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scEtc); | 6948 | I("Making directories in %s.", scRoot); |
6672 | if ((! qfile_exist(scLib)) && (! qfile_mkdir(scLib, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scLib); | 6949 | if ((! qfile_exist(scBin)) && (! qfile_mkdir(scBin, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scBin); |
6673 | if ((! qfile_exist(scRun)) && (! qfile_mkdir(scRun, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_ISGID, true))) C("Unable to create path %s", scRun); | 6950 | if ((! qfile_exist(scEtc)) && (! qfile_mkdir(scEtc, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scEtc); |
6674 | if ((! qfile_exist(scBackup)) && (! qfile_mkdir(scBackup, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scBackup); | 6951 | if ((! qfile_exist(scLib)) && (! qfile_mkdir(scLib, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scLib); |
6952 | if ((! qfile_exist(scRun)) && (! qfile_mkdir(scRun, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_ISGID, true))) C("Unable to create path %s", scRun); | ||
6953 | if ((! qfile_exist(scBackup)) && (! qfile_mkdir(scBackup, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scBackup); | ||
6675 | // TODO - the path to scCache/sledjchisl.socket needs to be readable by the www-data group. So the FCGI socket will work. | 6954 | // TODO - the path to scCache/sledjchisl.socket needs to be readable by the www-data group. So the FCGI socket will work. |
6676 | // AND it needs to be group sticky on opensimsc group. So the tmux socket will work. | 6955 | // AND it needs to be group sticky on opensimsc group. So the tmux socket will work. |
6677 | // So currently scCache is www-data readable, and scRun is group sticky. | 6956 | // So currently scCache is www-data readable, and scRun is group sticky. |
6678 | if ((! qfile_exist(scCache)) && (! qfile_mkdir(scCache, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scCache); | 6957 | if ((! qfile_exist(scCache)) && (! qfile_mkdir(scCache, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scCache); |
6679 | if ((! qfile_exist(scData)) && (! qfile_mkdir(scData, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scData); | 6958 | if ((! qfile_exist(scData)) && (! qfile_mkdir(scData, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scData); |
6680 | if ((! qfile_exist(scLog)) && (! qfile_mkdir(scLog, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scLog); | 6959 | if ((! qfile_exist(scLog)) && (! qfile_mkdir(scLog, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scLog); |
6681 | tmp = xmprintf("%s/sessions", scCache); | 6960 | if ((! qfile_exist(scTemp)) && (! qfile_mkdir(scTemp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scTemp); |
6682 | if ((! qfile_exist(tmp)) && (! qfile_mkdir(tmp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", tmp); | 6961 | tmp = xmprintf("%s/sessions", scCache); |
6683 | free(tmp); | 6962 | if ((! qfile_exist(tmp)) && (! qfile_mkdir(tmp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", tmp); |
6684 | tmp = xmprintf("%s/users", scData); | 6963 | free(tmp); |
6685 | if ((! qfile_exist(tmp)) && (! qfile_mkdir(tmp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", tmp); | 6964 | tmp = xmprintf("%s/users", scData); |
6686 | free(tmp); | 6965 | if ((! qfile_exist(tmp)) && (! qfile_mkdir(tmp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", tmp); |
6966 | free(tmp); | ||
6967 | |||
6968 | getSims(); | ||
6687 | 6969 | ||
6688 | 6970 | ||
6971 | if (isTmux || isWeb) | ||
6972 | { | ||
6973 | char *d; | ||
6974 | |||
6689 | mimeTypes = qhashtbl(0, 0); | 6975 | mimeTypes = qhashtbl(0, 0); |
6690 | mimeTypes->putstr(mimeTypes, "gz", "application/gzip"); | 6976 | mimeTypes->putstr(mimeTypes, "gz", "application/gzip"); |
6691 | mimeTypes->putstr(mimeTypes, "js", "application/javascript"); | 6977 | mimeTypes->putstr(mimeTypes, "js", "application/javascript"); |
@@ -7159,111 +7445,312 @@ fcgiDone: | |||
7159 | } | 7445 | } |
7160 | 7446 | ||
7161 | 7447 | ||
7162 | if (!isTmux) | ||
7163 | { // Let's see if the proper tmux server is even running. | ||
7164 | memset(toybuf, 0, sizeof(toybuf)); | ||
7165 | snprintf(toybuf, sizeof(toybuf), "%s %s/%s -q list-sessions 2>/dev/null | grep -q %s:", Tcmd, scRun, Tsocket, Tconsole); | ||
7166 | i = system(toybuf); | ||
7167 | if (WIFEXITED(i)) | ||
7168 | { | ||
7169 | if (0 != WEXITSTATUS(i)) // No such sesion, create it. | ||
7170 | { | ||
7171 | memset(toybuf, 0, sizeof(toybuf)); | ||
7172 | // The sudo is only so that the session is owned by opensim, otherwise it's owned by whoever ran this script, which is a likely security hole. | ||
7173 | // After the session is created, we rely on the scRun directory to be group sticky, so that anyone in the opensim group can attach to the tmux socket. | ||
7174 | snprintf(toybuf, sizeof(toybuf), | ||
7175 | "sudo -Hu %s %s %s/%s new-session -d -s %s -n '%s' \\; split-window -bhp 50 -t '%s:' bash -c '/usr/bin/valgrind --leak-check=full ./sledjchisl; cd %s; bash'", | ||
7176 | scUser, Tcmd, scRun, Tsocket, Tconsole, Ttab, Tconsole, scRoot); | ||
7177 | i = system(toybuf); | ||
7178 | if (!WIFEXITED(i)) | ||
7179 | E("tmux new-session command failed! %s", toybuf); | ||
7180 | } | ||
7181 | // Join the session. | ||
7182 | memset(toybuf, 0, sizeof(toybuf)); | ||
7183 | snprintf(toybuf, sizeof(toybuf), "%s %s/%s select-window -t '%s' \\; attach-session -t '%s'", Tcmd, scRun, Tsocket, Tconsole, Tconsole); | ||
7184 | i = system(toybuf); | ||
7185 | if (!WIFEXITED(i)) | ||
7186 | E("tmux attach-session command failed! %s", toybuf); | ||
7187 | goto finished; | ||
7188 | } | ||
7189 | else | ||
7190 | E("tmux list-sessions command failed! %s", toybuf); | ||
7191 | } | ||
7192 | 7448 | ||
7449 | char *target = NULL; | ||
7450 | struct sysinfo info; | ||
7451 | float la; | ||
7452 | // TODO - See https://stackoverflow.com/questions/2693948/how-do-i-retrieve-the-number-of-processors-on-c-linux, there are more portable ways, this seems to be GNU specific. | ||
7453 | int cpus = (int) sysconf(_SC_NPROCESSORS_CONF), cpusOnline = (int) sysconf(_SC_NPROCESSORS_ONLN); | ||
7454 | int doWait = 1; | ||
7455 | |||
7456 | if (0 == bulkSims) | ||
7457 | bulkSims = (cpusOnline / 3) - 1; | ||
7458 | I("There are %i CPUs, %i of them are online. Doing %i sims at once.", cpus, cpusOnline, bulkSims); | ||
7459 | sysinfo(&info); | ||
7460 | la = info.loads[0]/65536.0; | ||
7461 | |||
7462 | if (0 == toys.optc) | ||
7463 | ; | ||
7464 | else if (strcmp(toys.optargs[0], "create") == 0) | ||
7465 | currentMode = CREATE; | ||
7466 | else if (strcmp(toys.optargs[0], "start") == 0) | ||
7467 | currentMode = START; | ||
7468 | else if (strcmp(toys.optargs[0], "backup") == 0) | ||
7469 | currentMode = BACKUP; | ||
7470 | else if (strcmp(toys.optargs[0], "gitar") == 0) | ||
7471 | currentMode = GITAR; | ||
7472 | else if (strcmp(toys.optargs[0], "status") == 0) | ||
7473 | currentMode = STATUS; | ||
7474 | else if (strcmp(toys.optargs[0], "stop") == 0) | ||
7475 | currentMode = STOP; | ||
7476 | else | ||
7477 | target = toys.optargs[0]; | ||
7478 | if (2 == toys.optc) | ||
7479 | target = toys.optargs[1]; | ||
7480 | |||
7481 | T("ARGS - %i |%s| |%s|", currentMode, toys.optargs[0], target); | ||
7193 | 7482 | ||
7194 | simList *sims = getSims(); | 7483 | if ((START == currentMode) && !checkSimIsRunning("ROBUST")) |
7195 | if (1) | ||
7196 | { | 7484 | { |
7197 | struct sysinfo info; | 7485 | char *d = xmprintf("%s.{right}", Ttab); |
7198 | float la; | 7486 | char *c = xmprintf("cd %s/current/bin", scRoot); |
7199 | 7487 | ||
7200 | sysinfo(&info); | 7488 | I("ROBUST is starting up."); |
7201 | la = info.loads[0]/65536.0; | 7489 | sendTmuxCmd(d, c); |
7490 | free(c); | ||
7491 | c = xmprintf("mono Robust.exe -inidirectory=%s/config/ROBUST", scRoot); | ||
7492 | sendTmuxCmd(d, c); | ||
7493 | free(c); | ||
7494 | waitTmuxText(d, "INITIALIZATION COMPLETE FOR ROBUST"); | ||
7495 | I("ROBUST is done starting up."); | ||
7496 | la = waitLoadAverage(la, loadAverageInc / 3.0, simTimeOut / 3); | ||
7497 | free(d); | ||
7498 | } | ||
7202 | 7499 | ||
7203 | if (!checkSimIsRunning("ROBUST")) | 7500 | /* |
7204 | { | 7501 | sims = -- Note these are .shini / tmux tab short names. |
7205 | char *d = xmprintf("%s.{right}", Ttab); | 7502 | { |
7206 | char *c = xmprintf("cd %s/current/bin", scRoot); | 7503 | {["type"] = "Important"; "Welcome", "Sandbox", "Shops"}, |
7207 | 7504 | {["type"] = "Rentals"; "Karen", "Bob"}, | |
7208 | I("ROBUST is starting up."); | 7505 | {["type"] = "Freebies"; "Gifts", "Free"}, |
7209 | sendTmuxCmd(d, c); | 7506 | {["type"] = "unsorted"; "New"}, -- NOTE - this is where new ones go to by default. |
7210 | free(c); | 7507 | {["type"] = "Water"; ["number"] = 90; "Water0", "Water1", "Water2", "Water3", "Water4"}, |
7211 | c = xmprintf("mono Robust.exe -inidirectory=%s/config/ROBUST", scRoot); | 7508 | {["type"] = "Heavies"; ["number"] = 70; "DP", "ARSE"}, |
7212 | sendTmuxCmd(d, c); | 7509 | } |
7213 | free(c); | 7510 | */ |
7214 | waitTmuxText(d, "INITIALIZATION COMPLETE FOR ROBUST"); | 7511 | memset(toybuf, 0, sizeof(toybuf)); |
7215 | I("ROBUST is done starting up."); | 7512 | snprintf(toybuf, sizeof(toybuf), "%s/sims.lua", scEtc); |
7216 | la = waitLoadAverage(la, loadAverageInc / 3.0, simTimeOut / 3); | 7513 | if (0 == lstat(toybuf, &st)) |
7217 | free(d); | 7514 | { |
7218 | } | 7515 | int number = 1, count = 1; |
7219 | 7516 | ||
7220 | for (i = 0; i < sims->num; i++) | 7517 | I("Loading configuration file - %s", toybuf); |
7518 | status = luaL_loadfile(L, toybuf); | ||
7519 | if (status) // If something went wrong, error message is at the top of the stack. | ||
7520 | E("Couldn't load file: %s", lua_tostring(L, -1)); | ||
7521 | else | ||
7221 | { | 7522 | { |
7222 | char *sim = sims->sims[i], *name = getSimName(sims->sims[i]); | 7523 | result = lua_pcall(L, 0, LUA_MULTRET, 0); |
7223 | 7524 | if (result) | |
7224 | if (!checkSimIsRunning(sim)) | 7525 | E("Failed to run script: %s", lua_tostring(L, -1)); |
7526 | else | ||
7225 | { | 7527 | { |
7226 | char *nm = cleanSimName(name); | 7528 | lua_getglobal(L, "sims"); |
7227 | 7529 | ||
7228 | I("%s is starting up.", name); | 7530 | lua_pushnil(L); // lua_next() needs the last key at the top, but we don't start with one. |
7229 | memset(toybuf, 0, sizeof(toybuf)); | 7531 | while(lua_next(L, -2) != 0) // pushes key then value. |
7230 | snprintf(toybuf, sizeof(toybuf), "%s %s/%s new-window -dn '%s' -t '%s:%d' 'cd %s/current/bin; mono OpenSim.exe -inidirectory=%s/config/%s'", | 7532 | { // key -2 value -1 |
7231 | Tcmd, scRun, Tsocket, nm, Tconsole, i + 1, scRoot, scRoot, sim); | 7533 | if (lua_istable(L, -1)) |
7232 | int r = system(toybuf); | 7534 | { |
7233 | if (!WIFEXITED(r)) | 7535 | const char *type = "unsorted"; |
7234 | E("tmux new-window command failed!"); | 7536 | |
7235 | else | 7537 | lua_getfield(L, -1, "type"); |
7236 | { | 7538 | lua_getfield(L, -2, "number"); |
7237 | memset(toybuf, 0, sizeof(toybuf)); | 7539 | if (LUA_TNIL != lua_type(L, -2)) type = lua_tostring(L, -2); |
7238 | snprintf(toybuf, sizeof(toybuf), "INITIALIZATION COMPLETE FOR %s", name); | 7540 | if (LUA_TNIL != lua_type(L, -1)) number = lua_tonumber(L, -1); |
7239 | waitTmuxText(nm, toybuf); | 7541 | lua_pop(L, 2); |
7240 | I("%s is done starting up.", name); | 7542 | |
7241 | la = waitLoadAverage(la, loadAverageInc, simTimeOut); | 7543 | T("Doing sims of type %s starting at number %d", type, number); |
7544 | lua_pushnil(L); | ||
7545 | while(lua_next(L, -2) != 0) | ||
7546 | { | ||
7547 | char *sim = (char *) lua_tostring(L, -1); | ||
7548 | |||
7549 | if (LUA_TNUMBER == lua_type(L, -2)) | ||
7550 | { | ||
7551 | int num; | ||
7552 | char *nm = NULL; | ||
7553 | char *name;// = getSimName(ourSims->sims[i], &nm, &num); | ||
7554 | qlisttbl_t *ini = ourSims->byTab->get(ourSims->byTab, sim, NULL, false); | ||
7555 | simData *simd; | ||
7556 | |||
7557 | if (NULL == ini) | ||
7558 | { | ||
7559 | E("Sim %s not found in ini list!", sim); | ||
7560 | } | ||
7561 | else | ||
7562 | { | ||
7563 | simd = ini->get(ini, "SIM DATA", NULL, false); | ||
7564 | name = simd->name; | ||
7565 | nm = simd->tab; | ||
7566 | } | ||
7567 | |||
7568 | if (NULL != target) | ||
7569 | { | ||
7570 | int cont = TRUE; | ||
7571 | |||
7572 | memset(toybuf, 0, sizeof(toybuf)); | ||
7573 | snprintf(toybuf, sizeof(toybuf), "%s.shini", nm); | ||
7574 | if | ||
7575 | ( | ||
7576 | (strcmp(target, sim) == 0) || | ||
7577 | // (strcmp(target, simd->nmbr) == 0) || | ||
7578 | (strcmp(target, name) == 0) || | ||
7579 | (strcmp(target, nm) == 0) || | ||
7580 | (strcmp(target, toybuf) == 0) | ||
7581 | ) | ||
7582 | cont = FALSE; | ||
7583 | memset(toybuf, 0, sizeof(toybuf)); | ||
7584 | snprintf(toybuf, sizeof(toybuf), "%s.ini", nm); | ||
7585 | if (strcmp(target, toybuf) == 0) | ||
7586 | cont = FALSE; | ||
7587 | memset(toybuf, 0, sizeof(toybuf)); | ||
7588 | snprintf(toybuf, sizeof(toybuf), "sim%d.ini", number); | ||
7589 | if (strcmp(target, toybuf) == 0) | ||
7590 | cont = FALSE; | ||
7591 | if (cont) | ||
7592 | goto nextSim; | ||
7593 | } | ||
7594 | |||
7595 | doWait = (count % bulkSims); | ||
7596 | switch (currentMode) | ||
7597 | { | ||
7598 | case START : // "start sim01" "start 'Welcome sim'" "start Welcome.ini" "start Welcome" "start" start everything | ||
7599 | { // TODO - check if sim is down, but tmux window is still up, and close the tmux window first. | ||
7600 | if (!checkSimIsRunning(nm)) | ||
7601 | { | ||
7602 | char *path = xmprintf("%s/%s.shini", scEtc, nm); | ||
7603 | char *newPath = xmprintf("%s/sim%d/%s.ini", scTemp, number, nm); // Coz OpenSim. | ||
7604 | char *cmd = xmprintf("rm -fr %s/sim%d; mkdir -p %s/sim%d; sed -E" | ||
7605 | " -e 's/InternalPort[[:space:]]*=[[:space:]]*[[:digit:]]+/InternalPort = %d/'" | ||
7606 | " -e 's/InternalPort[[:space:]]*=[[:space:]]*\"[[:digit:]]+\"/InternalPort = %d/'" | ||
7607 | " -e 's/http_listener_port[[:space:]]*=[[:space:]]*[[:digit:]]+/http_listener_port = %d/'" | ||
7608 | " -e 's/http_listener_port[[:space:]]*=[[:space:]]*\"[[:digit:]]+\"/http_listener_port = %d/'" | ||
7609 | " %s >%s", | ||
7610 | scTemp, number, | ||
7611 | scTemp, number, | ||
7612 | 8004 + number * 2, | ||
7613 | 8004 + number * 2, | ||
7614 | 8005 + number * 2, | ||
7615 | 8005 + number * 2, | ||
7616 | path, newPath); | ||
7617 | int j; | ||
7618 | |||
7619 | D("Writing .ini file %s with ports %d %d", newPath, 8004 + number * 2, 8005 + number * 2); | ||
7620 | j = system(cmd); | ||
7621 | if (!WIFEXITED(j)) | ||
7622 | E("sed command failed!"); | ||
7623 | free(cmd); | ||
7624 | |||
7625 | I("%s is starting up in tab [%d:%s], from %s/sim%d. %i %i", name, number, nm, scTemp, number, doWait, count); | ||
7626 | memset(toybuf, 0, sizeof(toybuf)); | ||
7627 | snprintf(toybuf, sizeof(toybuf), "%s %s/%s new-window -dn '%s' -t '%s:%d' 'cd %s/current/bin; mono OpenSim.exe -inidirectory=%s/sim%d'", | ||
7628 | Tcmd, scRun, Tsocket, nm, Tconsole, number, scRoot, scTemp, number); | ||
7629 | int r = system(toybuf); | ||
7630 | if (!WIFEXITED(r)) | ||
7631 | E("tmux new-window command failed!"); | ||
7632 | else | ||
7633 | { | ||
7634 | if (0 == doWait) | ||
7635 | { | ||
7636 | memset(toybuf, 0, sizeof(toybuf)); | ||
7637 | snprintf(toybuf, sizeof(toybuf), "INITIALIZATION COMPLETE FOR %s", name); | ||
7638 | waitTmuxText(nm, toybuf); | ||
7639 | I("%s is done starting up.", name); | ||
7640 | la = waitLoadAverage(la, loadAverageInc, simTimeOut); | ||
7641 | } | ||
7642 | else | ||
7643 | I("Not waiting for %s to finish starting up.", name); | ||
7644 | count++; | ||
7645 | } | ||
7646 | } | ||
7647 | break; | ||
7648 | } | ||
7649 | |||
7650 | case BACKUP : // "backup 'onefang rejected'" "backup sim01" "backup 'Welcome Sim'" "backup" backup everything | ||
7651 | { // TODO - If it's not a sim code, and not a sim name, it's an account inventory. | ||
7652 | if (checkSimIsRunning(nm)) | ||
7653 | { | ||
7654 | struct timeval tv; | ||
7655 | time_t curtime; | ||
7656 | char date[DATE_TIME_LEN]; | ||
7657 | |||
7658 | |||
7659 | // TODO - should collect names of existing backups, both tmux / ini name and proper name. | ||
7660 | // Scan backups directory once before this for loop, add details to sims list. | ||
7661 | // strip off the last bit of file name (YYYY-mm-dd_HH:MM:SS.oar) to get the name | ||
7662 | // keep in mind some old files had munged names like "Tiffanie_s_Paradise-2021-06-23_05:11:38.oar" | ||
7663 | gettimeofday(&tv, NULL); | ||
7664 | curtime = tv.tv_sec; | ||
7665 | strftime(date, DATE_TIME_LEN, "%F_%T", localtime(&curtime)); | ||
7666 | I("%s is being backed up to %s/backups/%s-%s.oar.", name, scRoot, nm, date); | ||
7667 | memset(toybuf, 0, sizeof(toybuf)); | ||
7668 | snprintf(toybuf, sizeof(toybuf), "save oar --all %s/backups/%s-%s.oar", scRoot, nm, date); | ||
7669 | sendTmuxCmd(nm, toybuf); | ||
7670 | // if (0 == doWait) | ||
7671 | { | ||
7672 | memset(toybuf, 0, sizeof(toybuf)); | ||
7673 | snprintf(toybuf, sizeof(toybuf), "Finished writing out OAR for %s", name); | ||
7674 | waitTmuxText(nm, toybuf); | ||
7675 | I("%s is done backing up.", name); | ||
7676 | // TODO - should delete / gitAR the old ones now. | ||
7677 | // Have a config option for delete / gitAR. | ||
7678 | la = waitLoadAverage(la, loadAverageInc, simTimeOut); | ||
7679 | } | ||
7680 | } | ||
7681 | break; | ||
7682 | } | ||
7683 | |||
7684 | case CREATE : // "create name x,y size" | ||
7685 | { | ||
7686 | break; | ||
7687 | } | ||
7688 | |||
7689 | case GITAR : // "gitAR i name" "gitAR o name" | ||
7690 | { | ||
7691 | break; | ||
7692 | } | ||
7693 | |||
7694 | case STATUS : | ||
7695 | { | ||
7696 | break; | ||
7697 | } | ||
7698 | |||
7699 | case STOP : // "stop sim01" "stop 'Welcome Sim'" "stop" stop everything | ||
7700 | { | ||
7701 | if (checkSimIsRunning(nm)) | ||
7702 | { | ||
7703 | I("%s is stopping.", name); | ||
7704 | sendTmuxCmd(nm, "quit"); | ||
7705 | // There's three things that might happen - | ||
7706 | // Sim will quit, tmux tab will go away before we can see the shutdown message. | ||
7707 | // Sim will quit, tmux tab wont go away. Dunno yet if waitTmuxText() will still work. | ||
7708 | // Sim fails to quit, error message on the tab that we want to read, wont see the shutdown message. | ||
7709 | // Also sim might not have finished starting up, and may even not be accepting comands yet. | ||
7710 | // TODO - cater for and test them all. | ||
7711 | // Could also loop on checkSimIsRunning(sim) | ||
7712 | // memset(toybuf, 0, sizeof(toybuf)); | ||
7713 | // snprintf(toybuf, sizeof(toybuf), "[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); | ||
7714 | // waitTmuxText(nm, toybuf); | ||
7715 | // I("%s is done stopping.", name); | ||
7716 | // la = waitLoadAverage(la, loadAverageInc, simTimeOut); | ||
7717 | } | ||
7718 | break; | ||
7719 | } | ||
7720 | |||
7721 | default : | ||
7722 | { | ||
7723 | E("Unknown command! %s", toys.optargs[0]); | ||
7724 | break; | ||
7725 | } | ||
7726 | } | ||
7727 | nextSim: | ||
7728 | number++; | ||
7729 | } | ||
7730 | lua_pop(L, 1); // removes 'value'; keeps 'key' for next iteration | ||
7731 | } | ||
7732 | } | ||
7733 | |||
7734 | lua_pop(L, 1); | ||
7242 | } | 7735 | } |
7243 | free(nm); | ||
7244 | } | 7736 | } |
7245 | free(name); | ||
7246 | } | 7737 | } |
7247 | |||
7248 | } | ||
7249 | else if (!strcmp(cmd, "create")) // "create name x,y size" | ||
7250 | { | ||
7251 | } | ||
7252 | else if (!strcmp(cmd, "start")) // "start sim01" "start Welcome" "start" start everything | ||
7253 | { | ||
7254 | // TODO - check if sim is down, but tmux window is still up, and close the tmux window first. | ||
7255 | } | ||
7256 | else if (!strcmp(cmd, "backup")) // "backup onefang rejected" "backup sim01" "backup Welcome" "backup" backup everything | ||
7257 | { // If it's not a sim code, and not a sim name, it's an account inventory. | ||
7258 | } | 7738 | } |
7259 | else if (!strcmp(cmd, "gitAR")) // "gitAR i name" | 7739 | |
7260 | { | 7740 | |
7261 | } | 7741 | if ((START == currentMode) && checkSimIsRunning("ROBUST")) |
7262 | else if (!strcmp(cmd, "stop")) // "stop sim01" "stop Welcome" "stop" stop everything | ||
7263 | { | 7742 | { |
7743 | // Start up the web stuff. TODO - remove this once we handle the fcgi stuff ourselves. | ||
7744 | char *d = xmprintf("%s.{left}", Ttab); | ||
7745 | char *c = xmprintf("cd %s/current/src;" | ||
7746 | " spawn-fcgi -n -u %s -s %s/sledjchisl.socket -M 0660 -G www-data -- " | ||
7747 | "/usr/bin/valgrind --leak-check=full build/toybox/generated/unstripped/toybox sledjchisl", | ||
7748 | scRoot, scUser, scCache); | ||
7749 | sendTmuxCmd(d, c); | ||
7750 | free(c); | ||
7751 | free(d); | ||
7264 | } | 7752 | } |
7265 | 7753 | ||
7266 | freeSimList(sims); | ||
7267 | 7754 | ||
7268 | /* | 7755 | /* |
7269 | double sum; | 7756 | double sum; |
@@ -7328,6 +7815,7 @@ fcgiDone: | |||
7328 | */ | 7815 | */ |
7329 | 7816 | ||
7330 | finished: | 7817 | finished: |
7818 | freeSimList(ourSims); | ||
7331 | 7819 | ||
7332 | // An example of calling a toy directly. | 7820 | // An example of calling a toy directly. |
7333 | // printf("\n\n"); | 7821 | // printf("\n\n"); |