subu-0 lib compiles again
authorThomas Walker Lynch <thomas.lynch@reasoningtechnology.com>
Tue, 2 Apr 2019 18:31:31 +0000 (20:31 +0200)
committerThomas Walker Lynch <thomas.lynch@reasoningtechnology.com>
Tue, 2 Apr 2019 18:31:31 +0000 (20:31 +0200)
67 files changed:
makefile
module/da/include/da.h [new file with mode: 0644]
module/da/lib/libda.a [new file with mode: 0644]
module/da/makefile
module/da/makefile-flags
module/da/src/da.lib.c
module/da/src/da.lib.h
module/da/test/exec/test_da [new file with mode: 0755]
module/da/test/lib/libtest.a [new file with mode: 0644]
module/da/test/makefile-flags
module/debug/include/debug.h [new file with mode: 0644]
module/debug/lib/libda.a [deleted file]
module/debug/lib/libdebug.a [new file with mode: 0644]
module/debug/makefile
module/debug/makefile-flags
module/dispatch/include/dispatch.h [new file with mode: 0644]
module/dispatch/lib/libdispatch.a [new file with mode: 0644]
module/dispatch/makefile
module/dispatch/makefile-flags
module/dispatch/trc/dispatch.trc.c
module/share/include/da.h
module/share/include/db.h [deleted file]
module/share/include/debug.h [new file with mode: 0644]
module/subu-0/include/subu.h [new file with mode: 0644]
module/subu-0/lib/libsubu-0.a [new file with mode: 0644]
module/subu-0/makefile
module/subu-0/makefile-flags
module/subu-0/trc/common.lib.c [deleted file]
module/subu-0/trc/common.trc.c [new file with mode: 0644]
module/subu-0/trc/db.lib.c [deleted file]
module/subu-0/trc/subu-bind-all.cli.c [deleted file]
module/subu-0/trc/subu-bind-all.trc.c [new file with mode: 0644]
module/subu-0/trc/subu-bind.cli.c [deleted file]
module/subu-0/trc/subu-bind.trc.c [new file with mode: 0644]
module/subu-0/trc/subu-mk-0.cli.c [deleted file]
module/subu-0/trc/subu-mk-0.trc.c [new file with mode: 0644]
module/subu-0/trc/subu-rm-0.cli.c [deleted file]
module/subu-0/trc/subu-rm-0.trc.c [new file with mode: 0644]
module/subu-0/trc/subu.lib.c [deleted file]
module/subu-0/trc/subu.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb-init.cli.c [deleted file]
module/subu-0/trc/subudb-init.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb-number.cli.c [deleted file]
module/subu-0/trc/subudb-number.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb-rel-get.cli.c [deleted file]
module/subu-0/trc/subudb-rel-get.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb-rel-put.cli.c [deleted file]
module/subu-0/trc/subudb-rel-put.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb-rel-rm.cli.c [deleted file]
module/subu-0/trc/subudb-rel-rm.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb-subus.cli.c [deleted file]
module/subu-0/trc/subudb-subus.trc.c [new file with mode: 0644]
module/subu-0/trc/subudb.trc.c [new file with mode: 0644]
module/subu-0/try/makefile [new file with mode: 0644]
module/tranche/exec/tranche [new file with mode: 0755]
module/tranche/exec/tranche-make [new file with mode: 0755]
module/tranche/exec/tranche-target [new file with mode: 0755]
module/tranche/include/tranche.h [new file with mode: 0644]
module/tranche/lib/libtranche.a [new file with mode: 0644]
module/tranche/makefile
module/tranche/makefile-flags
module/tranche/src/tranche.lib.c
module/tranche/test/try/test4.out.expected
tool/bin/tranche
tool/bin/tranche-make
tool/bin/tranche-target
tool/lib/makefile-cc

index 06d6508..287b43b 100755 (executable)
--- a/makefile
+++ b/makefile
@@ -4,23 +4,23 @@ MAKEABLE=\
        module/da/test\
        module/debug\
        module/tranche\
-       module/dispatch
+       module/dispatch\
+       module/subu-0
 
 .PHONY: all
 all:
-       $(foreach dir, $(MAKEABLE), \
-         -make -C $$dir dist-clean dep lib exec share
-       )
+       for dir in $(MAKEABLE); do pushd $$dir; make dist-clean dep lib exec share; popd; done
 
-.PHONY: all
+.PHONY: dep
+dep:
+       for dir in $(MAKEABLE); do pushd $$dir; make dep; popd; done
+
+.PHONY: update
 update:
-       $(foreach dir, $(MAKEABLE), \
-         -make -C $$dir lib exec share
-       )
+       for dir in $(MAKEABLE); do pushd $$dir; make lib exec share; popd; done
 
 .PHONY: info
 info:
-       @echo "SRCDIRS:" $(SRCDIRS)
        @echo "MAKEABLE:" $(MAKEABLE)
 
 .PHONY: clean
@@ -28,8 +28,7 @@ clean:
        for dir in $(MAKEABLE); do pushd $$dir; make clean; popd; done
 
 .PHONY: dist-clean
-dist-clean : 
-       for dir in $(MAKEABLE); do pushd $$dir; make dist-clean; popd; done
+dist-clean : clean
        for i in $(wildcard module/share/lib/*); do rm $$i; done
        for i in $(wildcard module/share/inc/*); do rm $$i; done
        for i in $(wildcard module/share/bin/*); do rm $$i; done
diff --git a/module/da/include/da.h b/module/da/include/da.h
new file mode 100644 (file)
index 0000000..8195c4a
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DA_LIB_H
+#define DA_LIB_H
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef struct Da{
+  char *base;
+  char *end; // one byte/one element off the end of the array
+  size_t size; // size >= (end - base) + 1;
+  size_t element_size;
+} Da;
+
+#define RETURN(dap, r)                      \
+  { da_free_elements(dap); return r; }
+
+
+void da_alloc(Da *dap, size_t element_size);
+void da_free(Da *dap);
+void da_rewind(Da *dap);
+bool da_emptyq(Da *dap);
+size_t da_length(Da *dap);
+void da_rebase(Da *dap, char *old_base, void *pta);
+char *da_expand(Da *dap);
+bool da_boundq(Da *dap);
+
+char *da_index(Da *dap, size_t i);
+char *da_push_alloc(Da *dap);
+char *da_push(Da *dap, void *element);
+bool da_pop(Da *dap, void *element);
+
+bool da_endq(Da *dap, void *pt);
+void da_map(Da *dap, void f(void *, void *), void *closure);
+
+void da_free_elements(Da *dap);
+
+void da_ints_print(Da *dap, char *sep);
+
+void da_strings_print(Da *dap, char *sep);
+bool da_strings_exists(Da *string_arrp, char *test_string);
+void da_strings_set_insert(Da *string_arrp, char *proffered_string, void destruct(void *));
+void da_strings_set_union(Da *string_arrp, Da *proffered_string_arrp, void destruct(void *));
+
+
+char *da_string_input(Da *dap, FILE *file);
+void da_string_push(Da *dap0, char *string);
+
+void da_cat(Da *dap_base, Da *dap_cat);
+
+#endif
+
diff --git a/module/da/lib/libda.a b/module/da/lib/libda.a
new file mode 100644 (file)
index 0000000..28db3cb
Binary files /dev/null and b/module/da/lib/libda.a differ
index 80b385d..2a50e4e 100644 (file)
@@ -16,8 +16,8 @@ dep:
 
 .PHONY: lib
 lib:
-       $(MAKE) $@
        cp $(SRCDIR)/da.lib.h $(INCDIR)/da.h
+       $(MAKE) $@
 
 .PHONY: exec
 exec:
index ae5fb48..25ae25d 100644 (file)
@@ -6,7 +6,7 @@ DOCDIR=doc
 EXECDIR=exec
 INCDIR=include
 LIBDIR=lib
-SHAREDIR=../share
+SHAREDIR=$(realpath $(PROJECT_SUBU)/module/share)
 SRCDIR=src
 TESTDIR=test
 TMPDIR=tmp
@@ -23,9 +23,8 @@ ECHO= echo
 
 # compiler and flags
 C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-Llib -lda 
+CFLAGS=-std=gnu11 -fPIC -I$(SRCDIR) -I$(INCDIR) -I$(SHAREDIR)/include -ggdb -Werror -DDEBUG -DDEBUGDB 
+LINKFLAGS=-L$(LIBDIR) -l$(MODULE)
 
 
 
index 18abb99..543e95d 100644 (file)
@@ -69,10 +69,18 @@ char *da_index(Da *dap, size_t i){
   return pt;
 }
 
-void da_push(Da *dap, void *element){
-  if( dap->end >= dap->base + dap->size ) da_expand(dap);
-  memcpy(dap->end, element, dap->element_size);
+// allocate space for a new element at the end of the array
+char *da_push_alloc(Da *dap){
+  size_t element_off = dap->end - dap->base;
   dap->end += dap->element_size;
+  if( dap->end > dap->base + dap->size ) da_expand(dap);
+  return dap->base + element_off;
+}
+
+char *da_push(Da *dap, void *element){
+  char *element_pt = da_push_alloc(dap);
+  memcpy(element_pt, element, dap->element_size);
+  return element_pt;
 }
 
 bool da_pop(Da *dap, void *element){
index 518e72c..8195c4a 100644 (file)
@@ -12,7 +12,7 @@ typedef struct Da{
 } Da;
 
 #define RETURN(dap, r)                      \
-  { da_map(dap, da_free, NULL); return r; }
+  { da_free_elements(dap); return r; }
 
 
 void da_alloc(Da *dap, size_t element_size);
@@ -25,7 +25,8 @@ char *da_expand(Da *dap);
 bool da_boundq(Da *dap);
 
 char *da_index(Da *dap, size_t i);
-void da_push(Da *dap, void *element);
+char *da_push_alloc(Da *dap);
+char *da_push(Da *dap, void *element);
 bool da_pop(Da *dap, void *element);
 
 bool da_endq(Da *dap, void *pt);
diff --git a/module/da/test/exec/test_da b/module/da/test/exec/test_da
new file mode 100755 (executable)
index 0000000..1b5765d
Binary files /dev/null and b/module/da/test/exec/test_da differ
diff --git a/module/da/test/lib/libtest.a b/module/da/test/lib/libtest.a
new file mode 100644 (file)
index 0000000..49e4695
Binary files /dev/null and b/module/da/test/lib/libtest.a differ
index 37ea9c1..686a0f8 100644 (file)
@@ -23,7 +23,7 @@ ECHO= echo
 
 # compiler and flags
 C=gcc
-CFLAGS=-std=gnu11 -fPIC -I../include -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I../include -Werror
+CFLAGS=-std=gnu11 -fPIC -Iinclude -I../include -ggdb -Werror -DDEBUG -DDEBUGDB 
+#CFLAGS=-std=gnu11 -fPIC -Iinclude -I../include -Werror
 LINKFLAGS= -Llib -L../lib -ltest -lda
 
diff --git a/module/debug/include/debug.h b/module/debug/include/debug.h
new file mode 100644 (file)
index 0000000..f1be3d8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef DB_LIB_H
+#define DB_LIB_H
+
+int debug_printf(const char *format, ...);
+
+#endif
diff --git a/module/debug/lib/libda.a b/module/debug/lib/libda.a
deleted file mode 100644 (file)
index c6e819f..0000000
Binary files a/module/debug/lib/libda.a and /dev/null differ
diff --git a/module/debug/lib/libdebug.a b/module/debug/lib/libdebug.a
new file mode 100644 (file)
index 0000000..df2a6dd
Binary files /dev/null and b/module/debug/lib/libdebug.a differ
index 181818b..a19b90e 100644 (file)
@@ -16,8 +16,8 @@ dep:
 
 .PHONY: lib
 lib:
+       cp $(SRCDIR)/debug.lib.h $(INCDIR)/debug.h
        $(MAKE) $@
-       cp $(SRCDIR)/db.lib.h $(INCDIR)/db.h
 
 %::
        $(MAKE) $@
index 65ef1be..4dfd9bf 100644 (file)
@@ -1,12 +1,12 @@
 
-MODULE=db
+MODULE=debug
 
 DEPRDIR=deprecated
 DOCDIR=doc
 EXECDIR=exec
 INCDIR=include
 LIBDIR=lib
-SHAREDIR=../share
+SHAREDIR=$(realpath $(PROJECT_SUBU)/module/share)
 SRCDIR=src
 TESTDIR=test
 TMPDIR=tmp
@@ -23,9 +23,8 @@ ECHO= echo
 
 # compiler and flags
 C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-Llib -ldb
+CFLAGS=-std=gnu11 -fPIC -I$(SRCDIR) -I$(INCDIR) -I$(SHAREDIR)/include -ggdb -Werror -DDEBUG -DDEBUGDB 
+LINKFLAGS=-L$(LIBDIR) -l$(MODULE)
 
 
 
diff --git a/module/dispatch/include/dispatch.h b/module/dispatch/include/dispatch.h
new file mode 100644 (file)
index 0000000..8b99d43
--- /dev/null
@@ -0,0 +1,32 @@
+  /*
+    Runs a command or function as its own process.
+
+    The return status integer from command or function must be greater than ERR_DISPATCH.
+    In the case of dispatch_exec, we only have a promise from the user to not dispatch
+    non compliant commands.
+
+  */
+  #ifndef DISPATCH_LIB_H
+  #define DISPATCH_LIB_H
+  #include <sys/types.h>
+  #include <unistd.h>
+
+  #define ERR_DISPATCH -1024
+  #define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024
+  #define ERR_DISPATCH_F_FORK -1025
+  #define ERR_DISPATCH_F_SETEUID -1026
+  #define ERR_DISPATCH_F_SETEGID -1027
+  #define ERR_DISPATCH_NULL_EXECUTABLE -1028
+  #define ERR_DISPATCH_EXEC -1029
+
+  // currently both dispatcher and dispatchee strings are statically allocated
+  struct dispatch_ctx{
+    char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.)
+    char *dispatchee; // name of the function being dispatched
+    int err; // error code as listed below, or status returned from dispatchee
+  };
+void dispatch_f_mess(char *fname, int err, char *dispatchee);
+int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg);
+int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid);
+int dispatch_exec(char **argv, char **envp);
+#endif
diff --git a/module/dispatch/lib/libdispatch.a b/module/dispatch/lib/libdispatch.a
new file mode 100644 (file)
index 0000000..70d2fff
Binary files /dev/null and b/module/dispatch/lib/libdispatch.a differ
index ab3ffe5..add0ff2 100644 (file)
@@ -34,8 +34,8 @@ dep:
 
 .PHONY: lib
 lib:
-       $(MAKE) $@
        cp $(SRCDIR)/dispatch.lib.h $(INCDIR)/dispatch.h
+       $(MAKE) $@
 
 %::
        $(MAKE) $@
index 854b84f..a50b71c 100644 (file)
@@ -24,10 +24,8 @@ ECHO= echo
 
 # compiler and flags
 C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -Werror
-
-LINKFLAGS=-L1_lib -lda 
+CFLAGS=-std=gnu11 -fPIC -I$(SRCDIR) -I$(INCDIR) -I$(SHAREDIR)/include  -ggdb -Werror -DDEBUG -DDEBUGDB 
+LINKFLAGS=-L$(LIBDIR) -L(SHAREDIR)/lib -ldebug
 
 
 
index c24b0ab..f08602c 100644 (file)
@@ -39,7 +39,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
-#include <db.h>
+#include <debug.h>
 #include "dispatch.lib.h"
 
 #tranche dispatch.lib.h
index 518e72c..8195c4a 100644 (file)
@@ -12,7 +12,7 @@ typedef struct Da{
 } Da;
 
 #define RETURN(dap, r)                      \
-  { da_map(dap, da_free, NULL); return r; }
+  { da_free_elements(dap); return r; }
 
 
 void da_alloc(Da *dap, size_t element_size);
@@ -25,7 +25,8 @@ char *da_expand(Da *dap);
 bool da_boundq(Da *dap);
 
 char *da_index(Da *dap, size_t i);
-void da_push(Da *dap, void *element);
+char *da_push_alloc(Da *dap);
+char *da_push(Da *dap, void *element);
 bool da_pop(Da *dap, void *element);
 
 bool da_endq(Da *dap, void *pt);
diff --git a/module/share/include/db.h b/module/share/include/db.h
deleted file mode 100644 (file)
index f1be3d8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef DB_LIB_H
-#define DB_LIB_H
-
-int debug_printf(const char *format, ...);
-
-#endif
diff --git a/module/share/include/debug.h b/module/share/include/debug.h
new file mode 100644 (file)
index 0000000..f1be3d8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef DB_LIB_H
+#define DB_LIB_H
+
+int debug_printf(const char *format, ...);
+
+#endif
diff --git a/module/subu-0/include/subu.h b/module/subu-0/include/subu.h
new file mode 100644 (file)
index 0000000..683ddb3
--- /dev/null
@@ -0,0 +1,62 @@
+  typedef unsigned int uint;
+  /*
+    Fedora 29's sss_cache is checking the inherited uid instead of the effective
+    uid, so setuid root scripts will fail when calling sss_cache.
+
+    Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root 
+    program subu-mk-0.
+  */
+  #define BUG_SSS_CACHE_RUID 1
+  // extern char *DB_File;
+  extern char DB_File[];
+  extern uint Subuhome_Perms;
+  extern uint First_Max_Subunumber;
+  extern char Subuland_Extension[];
+  /*
+  The db file is maintained in SQLite
+
+  Because linux user names are limited length, subu user names are of a compact
+  form: _s<number>.  A separate table translates the numbers into the subu names.
+
+  Each of these returns SQLITE_OK upon success
+  */
+  #include <sqlite3.h>
+  int db_begin(sqlite3 *db);
+  int db_commit(sqlite3 *db);
+  int db_rollback(sqlite3 *db);
+  int subudb_schema(sqlite3 *db);
+  int subudb_number_get(sqlite3 *db, int *n);
+  int subudb_number_set(sqlite3 *db, int n);
+  int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username);
+  int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username);
+  typedef struct{
+    char *subuname; // the name that masteru chose for his or her subu
+    char *subu_username;  // the adduser name we gave it, typically of the s<number>
+  } subudb_subu_element;
+  int subudb_Masteru_Subu_get_subus(sqlite3 *db, char *masteru_name, Da *subus);
+  int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username);
+  #include <stdbool.h>
+  #include <errno.h>
+  #include <sqlite3.h>
+  char *useradd_mess(int err);
+  char *userdel_mess(int err);
+  #define SUBU_ERR_ARG_CNT 1
+  #define SUBU_ERR_SETUID_ROOT 2
+  #define SUBU_ERR_MALLOC 3
+  #define SUBU_ERR_MKDIR_SUBUHOME 4
+  #define SUBU_ERR_RMDIR_SUBUHOME 5
+  #define SUBU_ERR_SUBUNAME_MALFORMED 6
+  #define SUBU_ERR_HOMELESS 7
+  #define SUBU_ERR_DB_FILE 8
+  #define SUBU_ERR_SUBUHOME_EXISTS 9
+  #define SUBU_ERR_BUG_SSS 10
+  #define SUBU_ERR_FAILED_USERADD 11
+  #define SUBU_ERR_FAILED_USERDEL 12
+  #define SUBU_ERR_SUBU_NOT_FOUND 13
+  #define SUBU_ERR_N 14
+  #define SUBU_ERR_BIND 15
+  void subu_err(char *fname, int err, char *mess);
+  int subu_mk_0(char **mess, sqlite3 *db, char *subuname);
+  int subu_rm_0(char **mess, sqlite3 *db, char *subuname);
+  int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome);
+  int subu_bind_all(char **mess, sqlite3 *db);
diff --git a/module/subu-0/lib/libsubu-0.a b/module/subu-0/lib/libsubu-0.a
new file mode 100644 (file)
index 0000000..e678762
Binary files /dev/null and b/module/subu-0/lib/libsubu-0.a differ
index ab3ffe5..dacec61 100644 (file)
@@ -2,17 +2,16 @@
 
 SHELL=/bin/bash
 MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tool/lib/makefile-cc
-#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tool/lib/makefile-cc
 
 -include makefile-flags
 
-
 .PHONY: all 
 all: version
 
 .PHONY: info
 info:
        @echo "TRCDIR: " $(TRCDIR)
+       @echo "SHAREDIR: " $(SHAREDIR)
        $(MAKE) $@
 
 .PHONY: setup
@@ -23,21 +22,25 @@ setup:
 .PHONY: dep
 dep:
        if [ -e $(DEPFILE) ]; then rm $(DEPFILE); fi
-       @trcsources=$(wildcard $(TRCDIR)/*.trc.c)$(wildcard $(TRCDIR)/*.trc.cc);\
+       trcsources=($(wildcard $(TRCDIR)/*.trc.c)$(wildcard $(TRCDIR)/*.trc.cc));\
        if [ ! -z "$$trcsources" ]; then\
-         trctargets=$$(tranche-target $$trcsources -sep " " -tdir $(SRCDIR) );\
-         $(ECHO) $$trcsources;\
-         tranche-make $$trcsources -tdir $(SRCDIR) -mfile $(DEPFILE);\
+         trctargets=$$(tranche-target $${trcsources[@]} -sep " " -tdir $(SRCDIR) );\
+         $(ECHO) "trcsources: " $${trcsources[@]};\
+         $(ECHO) "trctargets: " $$trctargets;\
+         tranche-make $${trcsources[@]} -tdir $(SRCDIR) -mfile $(DEPFILE);\
          $(MAKE) $$trctargets;\
        fi
        $(MAKE) $@
 
 .PHONY: lib
 lib:
+       cp $(SRCDIR)/common.lib.h $(INCDIR)/subu.h
+       cat $(SRCDIR)/subudb.lib.h >> $(INCDIR)/subu.h
+       cat $(SRCDIR)/subu.lib.h >> $(INCDIR)/subu.h
        $(MAKE) $@
-       cp $(SRCDIR)/dispatch.lib.h $(INCDIR)/dispatch.h
 
 %::
+       @echo default target
        $(MAKE) $@
 
 
index 854b84f..f373601 100644 (file)
@@ -1,12 +1,12 @@
 
-MODULE=dispatch
+MODULE=subu-0
 
 DEPRDIR=deprecated
 DOCDIR=doc
 EXECDIR=exec
 INCDIR=include
 LIBDIR=lib
-SHAREDIR=../share
+SHAREDIR=$(realpath $(PROJECT_SUBU)/module/share)
 SRCDIR=tmp
 TESTDIR=test
 TMPDIR=tmp
@@ -24,10 +24,8 @@ ECHO= echo
 
 # compiler and flags
 C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -Werror
-
-LINKFLAGS=-L1_lib -lda 
+CFLAGS=-std=gnu11 -fPIC -I$(SRCDIR) -I$(INCDIR) -I$(SHAREDIR)/include -ggdb -Werror -DDEBUG -DDEBUGDB 
+LINKFLAGS=-L$(LIBDIR) -L$(SHAREDIR)/lib/ -l$(MODULE) -lda -ltranche -ldispatch
 
 
 
diff --git a/module/subu-0/trc/common.lib.c b/module/subu-0/trc/common.lib.c
deleted file mode 100644 (file)
index fec4853..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#tranche common.lib.c
-#include "common.lib.h"
-
-#tranche common.lib.h
-  typedef unsigned int uint;
-  /*
-    Fedora 29's sss_cache is checking the inherited uid instead of the effective
-    uid, so setuid root scripts will fail when calling sss_cache.
-
-    Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root 
-    program subu-mk-0.
-  */
-  #define BUG_SSS_CACHE_RUID 1
-#tranche-end
-
-#tranche common.lib.h
-  // extern char *DB_File;
-  extern char DB_File[];
-  extern uint Subuhome_Perms;
-  extern uint First_Max_Subunumber;
-  extern char Subuland_Extension[];
-#tranche-end
-// char *DB_File = "/etc/subudb";
-char DB_File[] = "subudb";
-uint Subuhome_Perms = 0700;
-uint First_Max_Subunumber = 114;
-char Subuland_Extension[] = "/subuland/";
-
-#tranche-end
diff --git a/module/subu-0/trc/common.trc.c b/module/subu-0/trc/common.trc.c
new file mode 100644 (file)
index 0000000..fec4853
--- /dev/null
@@ -0,0 +1,29 @@
+#tranche common.lib.c
+#include "common.lib.h"
+
+#tranche common.lib.h
+  typedef unsigned int uint;
+  /*
+    Fedora 29's sss_cache is checking the inherited uid instead of the effective
+    uid, so setuid root scripts will fail when calling sss_cache.
+
+    Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root 
+    program subu-mk-0.
+  */
+  #define BUG_SSS_CACHE_RUID 1
+#tranche-end
+
+#tranche common.lib.h
+  // extern char *DB_File;
+  extern char DB_File[];
+  extern uint Subuhome_Perms;
+  extern uint First_Max_Subunumber;
+  extern char Subuland_Extension[];
+#tranche-end
+// char *DB_File = "/etc/subudb";
+char DB_File[] = "subudb";
+uint Subuhome_Perms = 0700;
+uint First_Max_Subunumber = 114;
+char Subuland_Extension[] = "/subuland/";
+
+#tranche-end
diff --git a/module/subu-0/trc/db.lib.c b/module/subu-0/trc/db.lib.c
deleted file mode 100644 (file)
index 17a5419..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-The db file is maintained in SQLite
-
-Because user names of are of limited length, subu user names are always named _s<number>.
-A separate table translates the numbers into the subu names.
-
-The first argument is the biggest subu number in the system, or one minus an 
-starting point for subu numbering.
-
-currently a unit converted to base 10 will always fit in a 21 bit buffer.
-
-Each of these returns SQLITE_OK upon success
-*/
-#include "subudb.lib.h"
-
-#if INTERFACE
-#include <sqlite3.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-//--------------------------------------------------------------------------------
-// sqlite transactions don't nest.  There is a way to use save points, but still
-// we can't just nest transactions.  Instead use these wrappers around the whole
-// of something that needs to be in a transaction.
-int db_begin(sqlite3 *db){
-  return sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
-}
-int db_commit(sqlite3 *db){
-  return sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
-}
-int db_rollback(sqlite3 *db){
-  return sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
-}
-
-//--------------------------------------------------------------------------------
-int subudb_schema(sqlite3 *db){
-  int rc;
-
-  { // build tables
-    char sql[] = 
-      "CREATE TABLE Masteru_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT);"
-      "CREATE TABLE Attribute_Int(attribute TEXT, value INT);"
-      ;
-    rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
-    if(rc != SQLITE_OK) return rc;
-  }
-
-  { // data initialization
-    char *sql = "INSERT INTO Attribute_Int (attribute, value) VALUES ('Max_Subunumber', ?1);";
-    sqlite3_stmt *stmt;
-    sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-    sqlite3_bind_int(stmt, 1, First_Max_Subunumber);
-    rc = sqlite3_step(stmt);
-    sqlite3_finalize(stmt);
-    if( rc != SQLITE_DONE ) return rc;
-  }
-
-  return SQLITE_OK;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_number_get(sqlite3 *db, int *n){
-  char *sql = "SELECT value FROM Attribute_Int WHERE attribute = 'Max_Subunumber';";
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-  int rc = sqlite3_step(stmt);
-  if( rc == SQLITE_ROW ){
-    *n = sqlite3_column_int(stmt,0);
-    rc = sqlite3_step(stmt);
-    sqlite3_finalize(stmt);
-    if( rc != SQLITE_DONE ) return rc;
-    return SQLITE_OK;
-  }
-  // should have a message return, suppose
-  sqlite3_finalize(stmt);
-  return SQLITE_NOTFOUND; 
-}
-
-int subudb_number_set(sqlite3 *db, int n){
-  int rc;
-  char *sql = "UPDATE Attribute_Int SET value = ?1 WHERE attribute = 'Max_Subunumber';";
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-  sqlite3_bind_int(stmt, 1, n);
-  rc = sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
-
-//--------------------------------------------------------------------------------
-// put relation into Masteru_Subu table
-int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
-  char *sql = "INSERT INTO Masteru_Subu VALUES (?1, ?2, ?3);";
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
-  int rc = sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username){
-  char *sql = "SELECT subu_username FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2;";
-  size_t sql_len = strlen(sql);
-  sqlite3_stmt *stmt;
-  int rc;
-  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
-  if( rc != SQLITE_OK ) return rc;
-  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC);
-  rc = sqlite3_step(stmt);
-  if( rc == SQLITE_ROW ){
-    const char *username = sqlite3_column_text(stmt, 0);
-    *subu_username = strdup(username);
-  }else{
-    sqlite3_finalize(stmt);
-    return rc; // woops this needs to return an error!,  be sure it is not SQLITE_DONE
-  }
-  rc = sqlite3_step(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
-
-//--------------------------------------------------------------------------------
-
-// we return and array of subudb_subu_info
-#if INTERFACE
-struct subudb_subu_element{
-  char *subuname;
-  char *subu_username;
-};
-#endif
-
-int subudb_Masteru_Subu_get_subus
-(
- sqlite3 *db,
- char *masteru_name,
- da *subus
-){
-  char *sql = "SELECT subuname, subu_username"
-              " FROM Masteru_Subu"
-              " WHERE masteru_name = ?1;";
-  size_t sql_len = strlen(sql);
-  sqlite3_stmt *stmt;
-  int rc;
-  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
-  if( rc != SQLITE_OK ) return rc;
-  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
-
-  da_alloc(subus, sizeof(subudb_subu_element));
-  subudb_subu_element *pt = (subudb_subu_element *)subus->base;
-  rc = sqlite3_step(stmt);
-  while( rc == SQLITE_ROW ){
-    if( da_boundq(subus, pt) ){
-      char *old_base = da_expand(subus);
-      da_rebase(subus, old_base, pt);
-    }
-    pt->subuname = strdup(sqlite3_column_text(stmt, 0));
-    pt->subu_username = strdup(sqlite3_column_text(stmt, 1));
-  rc = sqlite3_step(stmt);
-  pt++;
-  }
-  sqlite3_finalize(stmt);
-  if( rc != SQLITE_DONE ) return rc;
-  return SQLITE_OK;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
-  char *sql = "DELETE FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2 AND subu_username = ?3;";
-  size_t sql_len = strlen(sql);
-  sqlite3_stmt *stmt;
-  int rc;
-  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
-  if( rc != SQLITE_OK ) return rc;
-  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
-  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
-  rc = sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-  if( rc == SQLITE_DONE ) return SQLITE_OK;
-  return rc;
-}
diff --git a/module/subu-0/trc/subu-bind-all.cli.c b/module/subu-0/trc/subu-bind-all.cli.c
deleted file mode 100644 (file)
index e942909..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-mount all the subu user directories into master's subuland
-uses unmount to undo this
-
-*/
-#include "subu-bind-all.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-  if( argc != 1){
-    fprintf(stderr, "%s does not take arguments\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  char *mess;
-  rc = subu_bind_all(&mess, db);
-  if(rc != 0){
-    fprintf(stderr, "subu-bind: %s\n", mess);
-    return rc;
-  }
-  return 0;
-}
diff --git a/module/subu-0/trc/subu-bind-all.trc.c b/module/subu-0/trc/subu-bind-all.trc.c
new file mode 100644 (file)
index 0000000..7674927
--- /dev/null
@@ -0,0 +1,32 @@
+#tranche subu-bind-all.cli.c
+/*
+mount all the subu user directories into master's subuland
+uses unmount to undo this
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+  if( argc != 1){
+    fprintf(stderr, "%s does not take arguments\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  char *mess;
+  rc = subu_bind_all(&mess, db);
+  if(rc != 0){
+    fprintf(stderr, "subu-bind: %s\n", mess);
+    return rc;
+  }
+  return 0;
+}
+#tranche-end
diff --git a/module/subu-0/trc/subu-bind.cli.c b/module/subu-0/trc/subu-bind.cli.c
deleted file mode 100644 (file)
index f315823..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-mount a subu user directory into master's subuland
-uses unmount to undo this
-
-*/
-#include "subu-bind.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if( argc != 4){
-    fprintf(stderr, "usage: %s masteru subu_username subuhome\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  char *mess;
-  rc = subu_bind(&mess, argv[1], argv[2], argv[3]);
-  if(rc != 0){
-    fprintf(stderr, "subu-bind: %s\n", mess);
-    return rc;
-  }
-  return 0;
-}
diff --git a/module/subu-0/trc/subu-bind.trc.c b/module/subu-0/trc/subu-bind.trc.c
new file mode 100644 (file)
index 0000000..0510d55
--- /dev/null
@@ -0,0 +1,26 @@
+#tranche subu-bind.cli.c
+/*
+mount a subu user directory into master's subuland
+uses unmount to undo this
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if( argc != 4){
+    fprintf(stderr, "usage: %s masteru subu_username subuhome\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  char *mess;
+  rc = subu_bind(&mess, argv[1], argv[2], argv[3]);
+  if(rc != 0){
+    fprintf(stderr, "subu-bind: %s\n", mess);
+    return rc;
+  }
+  return 0;
+}
+#tranche-end
diff --git a/module/subu-0/trc/subu-mk-0.cli.c b/module/subu-0/trc/subu-mk-0.cli.c
deleted file mode 100644 (file)
index af0888b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-  subu-mk-0 command
-
-*/
-#include "subu-mk-0.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-  char *command = argv[0];
-  if( argc != 2 ){
-    fprintf(stderr, "usage: %s subu", command);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *subuname = argv[1];
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "error when opening db, %s\n", DB_File);
-    fprintf(stderr, "sqlite3 says: %s\n", sqlite3_errmsg(db));
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  char *mess;
-  rc = subu_mk_0(&mess, db, subuname);
-  if( rc ){
-    subu_err("subu_mk_0", rc, mess);
-    free(mess);
-    sqlite3_close(db);
-    return rc;
-  }
-
-  rc = sqlite3_close(db);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-
-}
diff --git a/module/subu-0/trc/subu-mk-0.trc.c b/module/subu-0/trc/subu-mk-0.trc.c
new file mode 100644 (file)
index 0000000..f0a7b5a
--- /dev/null
@@ -0,0 +1,44 @@
+#tranche subu-mk-0.cli.c
+/*
+  subu-mk-0 command
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+  char *command = argv[0];
+  if( argc != 2 ){
+    fprintf(stderr, "usage: %s subu", command);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *subuname = argv[1];
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "error when opening db, %s\n", DB_File);
+    fprintf(stderr, "sqlite3 says: %s\n", sqlite3_errmsg(db));
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  char *mess;
+  rc = subu_mk_0(&mess, db, subuname);
+  if( rc ){
+    subu_err("subu_mk_0", rc, mess);
+    free(mess);
+    sqlite3_close(db);
+    return rc;
+  }
+
+  rc = sqlite3_close(db);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+
+}
+#tranche-end
diff --git a/module/subu-0/trc/subu-rm-0.cli.c b/module/subu-0/trc/subu-rm-0.cli.c
deleted file mode 100644 (file)
index a7e5926..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-  subu-mk-0 command
-
-*/
-#include "subu-rm-0.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-  char *command = argv[0];
-  if( argc != 2 ){
-    fprintf(stderr, "usage: %s subu", command);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *subuname = argv[1];
-
-  sqlite3 *db;
-  {
-    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-    if( ret != SQLITE_OK ){
-      fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
-      return SUBU_ERR_DB_FILE;
-    }}
-
-  {
-    char *mess=0;
-    int ret = subu_rm_0(&mess, db, subuname);
-    subu_err("subu_rm_0", ret, mess);
-    free(mess);
-    return ret;
-  }
-}
diff --git a/module/subu-0/trc/subu-rm-0.trc.c b/module/subu-0/trc/subu-rm-0.trc.c
new file mode 100644 (file)
index 0000000..e49e611
--- /dev/null
@@ -0,0 +1,33 @@
+#tranche subu-rm-0.cli.c
+/*
+  subu-mk-0 command
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+  char *command = argv[0];
+  if( argc != 2 ){
+    fprintf(stderr, "usage: %s subu", command);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *subuname = argv[1];
+
+  sqlite3 *db;
+  {
+    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+    if( ret != SQLITE_OK ){
+      fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
+      return SUBU_ERR_DB_FILE;
+    }}
+
+  {
+    char *mess=0;
+    int ret = subu_rm_0(&mess, db, subuname);
+    subu_err("subu_rm_0", ret, mess);
+    free(mess);
+    return ret;
+  }
+}
+#tranche-end
diff --git a/module/subu-0/trc/subu.lib.c b/module/subu-0/trc/subu.lib.c
deleted file mode 100644 (file)
index cd6bc2f..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
-  sqllite3 is used to maintain the db file, which is currently compiled
-  in as /etc/subu.db, (or just subu.db for testing).
-
-  masteru is the user who ran this script. The masteru name comes from getuid
-  and /etc/passwd. 
-
-  subu is a subservient user.  The subuname is passed in as an argument.
-
-  subu-mk-0 synthesizes a new user user name s<number>, calls useradd to creat
-  the new uswer account, and enters the relationship between masteru, subu, and
-  s<number> in the db file.  It is this relation in the db file that
-  associates the subuname with the s<number> user.
-
-  subu-rm-0 uses userdel to delete the related s<number> user account.  It
-  then removes the relaton from the db file.
-
-  subu-mk-0 and subu-rm-0 are setuid root scripts.  
-
-*/
-#include "subu.lib.h"
-
-// without this #define we get the warning: implicit declaration of function â€˜seteuid’/‘setegid’
-#define _GNU_SOURCE   
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#if INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-#endif
-
-//--------------------------------------------------------------------------------
-// dispatched command errors  .. should add mkdir and rmdir ...
-//
-char *useradd_mess(int err){
-  if(err <= 0) return NULL;
-  char *mess;
-  switch(err){
-  case 1: mess = "can't update password file"; break;
-  case 2: mess = "invalid command syntax"; break;
-  case 3: mess = "invalid argument to option"; break;
-  case 4: mess = "UID already in use (and no -o)"; break;
-  case 5: mess = "undefined"; break;
-  case 6: mess = "specified group doesn't exist"; break;
-  case 7:
-  case 8: mess = "undefined"; break;
-  case 9: mess = "username already in use"; break;
-  case 10: mess = "can't update group file:"; break;
-  case 11: mess = "undefined"; break;
-  case 12: mess = "can't create home directory"; break;
-  case 13: mess = "undefined"; break;
-  case 14: mess = "can't update SELinux user mapping"; break;
-  default: mess = "undefined"; break;
-  }
-  return strdup(mess);
-}
-char *userdel_mess(int err){
-  if(err <= 0) return NULL;
-  char *mess;
-  switch(err){
-  case 1: mess = "can't update password file"; break;
-  case 2: mess = "invalid command syntax"; break;
-  case 3:
-  case 4:
-  case 5: mess = "undefined"; break;
-  case 6: mess = "specified user doesn't exist"; break;
-  case 7:
-  case 8: 
-  case 9: mess = "undefined"; break;
-  case 10: mess = "can't update group file:"; break;
-  case 11: mess = "undefined"; break;
-  case 12: mess = "can't remove home directory"; break;
-  default: mess = "undefined"; break;
-  }
-  return strdup(mess);
-}
-
-
-//--------------------------------------------------------------------------------
-//
-#if INTERFACE
-#define SUBU_ERR_ARG_CNT 1
-#define SUBU_ERR_SETUID_ROOT 2
-#define SUBU_ERR_MALLOC 3
-#define SUBU_ERR_MKDIR_SUBUHOME 4
-#define SUBU_ERR_RMDIR_SUBUHOME 5
-#define SUBU_ERR_SUBUNAME_MALFORMED 6
-#define SUBU_ERR_HOMELESS 7
-#define SUBU_ERR_DB_FILE 8
-#define SUBU_ERR_SUBUHOME_EXISTS 9
-#define SUBU_ERR_BUG_SSS 10
-#define SUBU_ERR_FAILED_USERADD 11
-#define SUBU_ERR_FAILED_USERDEL 12
-#define SUBU_ERR_SUBU_NOT_FOUND 13
-#define SUBU_ERR_N 14
-#define SUBU_ERR_BIND 15
-#endif
-
-void subu_err(char *fname, int err, char *mess){
-  if(!mess) mess = "";
-  switch(err){
-  case 0: return;
-  case SUBU_ERR_ARG_CNT:
-    if(mess[0])
-      fprintf(stderr, "Incorrect number of arguments, %s", mess);
-    else
-      fprintf(stderr, "Incorrect number of arguments.", mess);
-    break;
-  case SUBU_ERR_SETUID_ROOT:
-    fprintf(stderr, "This program must be run setuid root from a user account.");
-    break;
-  case SUBU_ERR_MALLOC:
-    perror(fname);
-    break;
-  case SUBU_ERR_DB_FILE:
-    fprintf(stderr, "error on %s", DB_File); // DB_File is in common
-    fprintf(stderr, ": %s", mess);
-    break;
-  case SUBU_ERR_HOMELESS:
-    fprintf(stderr,"Masteru, \"%s\", has no home directory", mess);
-    break;
-  case SUBU_ERR_SUBUNAME_MALFORMED:
-    fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", mess);
-    break;
-  case SUBU_ERR_SUBUHOME_EXISTS:
-    fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", mess);
-    break;
-  case SUBU_ERR_MKDIR_SUBUHOME:
-    fprintf(stderr, "masteru could not make subuhome, \"%s\"", mess);
-    break;
-  case SUBU_ERR_BUG_SSS:
-    perror(fname);
-  break;
-  case SUBU_ERR_FAILED_USERADD:
-    fprintf(stderr, "%s useradd failed\n", mess);
-  break;
-  default:
-    fprintf(stderr, "unknown error code %d\n", err);
-  }
-  fputc('\n', stderr);
-}
-
-
-//--------------------------------------------------------------------------------
-// a well formed subuname
-// returns the length of the subuname, or -1
-//
-static int allowed_subuname(char **mess, char *subuname, size_t *subuname_len){
-  char *ch = subuname;
-  size_t i = 0;
-  while(
-        *ch
-        &&
-        ( *ch >= 'a' && *ch <= 'z'
-          ||
-          *ch >= 'A' && *ch <= 'Z'
-          ||
-          *ch >= '0' && *ch <= '9'
-          ||
-          *ch == '-'
-          ||
-          *ch == '_'
-          ||
-          *ch == '.'
-          ||
-          *ch == ' '
-          )
-        ){
-    ch++;
-    i++;
-  }
-  if( !*ch ){
-    *subuname_len = i;
-    return 0;
-  }else{
-    if(mess) *mess = strdup(subuname);
-    return SUBU_ERR_SUBUNAME_MALFORMED;
-  }
-}
-
-//--------------------------------------------------------------------------------
-// dispatched functions
-//
-static int masteru_mkdir_subuhome(void *arg){
-  char *subuhome = (char *) arg;
-  if( mkdir( subuhome, Subuhome_Perms ) == -1 ){ // find subuhome perms in common
-    perror("masteru_mkdir_subuhome");
-    return SUBU_ERR_MKDIR_SUBUHOME;
-  }
-  return 0;
-}
-static int masteru_rmdir_subuhome(void *arg){
-  char *subuhome = (char *) arg;
-  if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
-    perror("masteru_rmdir_subuhome");
-    return SUBU_ERR_RMDIR_SUBUHOME;
-  }
-  return 0;
-}
-
-//--------------------------------------------------------------------------------
-// build strings 
-//
-static int mk_subu_username(char **mess, sqlite3 *db, char **subu_username){
-  int rc,n;
-  db_begin(db);
-  if(
-    (rc = subudb_number_get(db, &n))
-    ||
-    (rc = subudb_number_set(db, ++n))
-     ){
-    db_rollback(db);
-    return SUBU_ERR_DB_FILE;
-  }
-  db_commit(db);
-
-  size_t len = 0;
-  FILE* name_stream = open_memstream(subu_username, &len);
-  fprintf(name_stream, "s%d", n);
-  fclose(name_stream);
-  return 0;
-}
-
-// man page says that getpwuid strings may not be freed, I don't know how long until they
-// are overwritten, so I just make my own copies that can be freed
-static int uid_to_name_and_home(uid_t uid, char **name, char **home ){
-  struct passwd *pw_record_pt = getpwuid(uid); // reading /etc/passwd
-  *name = strdup(pw_record_pt->pw_name);
-  *home = strdup(pw_record_pt->pw_dir);
-  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
-  return 0;
-}
-
-static int username_to_home(char *name, char **home ){
-  struct passwd *pw_record_pt = getpwnam(name); // reading /etc/passwd
-  *home = strdup(pw_record_pt->pw_dir);
-  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
-  return 0;
-}
-
-static int mk_subuland(char *masteru_home, char **subuland){
-  size_t masteru_home_len = strlen(masteru_home);
-  char *Subuland_Extension = "/subuland/";
-  size_t Subuland_Extension_len = strlen(Subuland_Extension);
-  *subuland = (char *)malloc( masteru_home_len + Subuland_Extension_len + 1 );
-  if(!*subuland) SUBU_ERR_MALLOC; 
-  strcpy(*subuland, masteru_home);
-  strcpy(*subuland + masteru_home_len, Subuland_Extension);
-  return 0;
-}
-
-static int mk_subuhome(char *subuland, char *subuname, char **subuhome){
-  size_t subuland_len = strlen(subuland);
-  size_t subuhome_len = subuland_len + strlen(subuname); // subuland has a trailing '/'
-  *subuhome = (char *)malloc(subuhome_len + 1);
-  if(!*subuhome) return SUBU_ERR_MALLOC;
-  strcpy (*subuhome, subuland);
-  strcpy (*subuhome + subuland_len, subuname);
-  return 0;
-}
-
-
-
-//===============================================================================
-int subu_mk_0(char **mess, sqlite3 *db, char *subuname){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  //--------------------------------------------------------------------------------
-  size_t subuname_len;
-  rc = allowed_subuname(mess, subuname, &subuname_len);
-  if(rc) return rc;
-  #ifdef DEBUG
-  debug_printf("subuname is well formed\n");
-  #endif
-
-  //--------------------------------------------------------------------------------
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    debug_printf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
-  }
-
-  //--------------------------------------------------------------------------------
-  char *masteru_name = 0;
-  char *masteru_home = 0;
-  char *subu_username = 0;
-  char *subuland = 0;
-  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
-  da_push(&resources, masteru_name);
-  da_push(&resources, masteru_home);
-  da_push(&resources, subu_username);
-  da_push(&resources, subuland);
-  da_push(&resources, subuhome);
-  rc =
-    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
-    ||
-    mk_subu_username(mess, db, &subu_username)
-    ||
-    mk_subuland(masteru_home, &subuland)
-    ||
-    mk_subuhome(subuland, subuname, &subuhome)
-    ;
-  if(rc) RETURN(&resources, rc);
-  #ifdef DEBUG
-  debug_printf("subu_username, subuland, subuhome: \"%s\"\"%s\"\"%s\"\n", subu_username, subuland, subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  // By having masteru create the subuhome, we know that masteru has rights to 
-  // to access this directory. This will be the mount point for bindfs
-  {
-    struct stat st;
-    if( stat(subuhome, &st) != -1 ){
-      if(mess)*mess = strdup(subuhome);
-      RETURN(&resources, SUBU_ERR_SUBUHOME_EXISTS);
-    }
-    int dispatch_err = dispatch_f_euid_egid
-      (
-       "masteru_mkdir_subuhome", 
-       masteru_mkdir_subuhome, 
-       (void *)subuhome,
-       masteru_uid, 
-       masteru_gid
-       );
-    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_MKDIR_SUBUHOME ){
-      #ifdef DEBUG
-      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_mkdir_subuhome");
-      #endif
-      if(mess)*mess = strdup(subuhome);
-      RETURN(&resources, SUBU_ERR_MKDIR_SUBUHOME);
-    }
-  }
-  #ifdef DEBUG
-  debug_printf("made directory \"%s\"\n", subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  //  Make the subservient user account, i.e. the subu
-  {
-    #ifdef DEBUG
-      debug_printf("making subu \"%s\" as user \"%s\"\n", subuname, subu_username);
-    #endif
-    #if BUG_SSS_CACHE_RUID
-      #ifdef DEBUG
-        debug_printf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
-      #endif
-      if( setuid(0) == -1 ) RETURN(&resources, SUBU_ERR_BUG_SSS);
-    #endif
-    char *command = "/usr/sbin/useradd";
-    char *argv[3];
-    argv[0] = command;
-    argv[1] = subu_username;
-    argv[2] = (char *) NULL;
-    char *envp[1];
-    envp[0] = (char *) NULL;
-    int dispatch_err = dispatch_exec(argv, envp);
-    if( dispatch_err != 0 ){
-      #ifdef DEBUG 
-      dispatch_f_mess("dispatch_exec", dispatch_err, command);
-      #endif
-      // go back and remove the directory we made in subuland
-      int dispatch_err_rmdir = dispatch_f_euid_egid
-        (
-         "masteru_rmdir_subuhome", 
-         masteru_rmdir_subuhome, 
-         (void *)subuhome,
-         masteru_uid, 
-         masteru_gid
-         );
-      #ifdef DEBUG
-      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err_rmdir, "masteru_rmdir_subuhome");
-      #endif
-      if(mess)*mess = useradd_mess(dispatch_err);
-      RETURN(&resources, SUBU_ERR_FAILED_USERADD);
-    }
-    #ifdef DEBUG
-    debug_printf("added user \"%s\"\n", subu_username);
-    #endif
-  }  
-  
-  //--------------------------------------------------------------------------------
-  #ifdef DEBUG
-  debug_printf("setting the masteru_name, subuname, subu_username relation\n");
-  #endif
-  {
-    int rc = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
-    if( rc != SQLITE_OK ){
-      if(mess)*mess = strdup("insert of masteru subu relation failed");
-      RETURN(&resources, SUBU_ERR_DB_FILE);
-    }
-  }
-  #ifdef DEBUG
-  debug_printf("finished subu-mk-0(%s)\n", subuname);
-  #endif
-  RETURN(&resources, 0);
-}
-
-//================================================================================
-int subu_rm_0(char **mess, sqlite3 *db, char *subuname){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  //--------------------------------------------------------------------------------
-  size_t subuname_len;
-  rc = allowed_subuname(mess, subuname, &subuname_len);
-  if(rc) return rc;
-  #ifdef DEBUG
-  debug_printf("subuname is well formed\n");
-  #endif
-  
-  //--------------------------------------------------------------------------------
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    debug_printf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
-  }
-
-  //--------------------------------------------------------------------------------
-  // various strings that we will need
-  char *masteru_name = 0;
-  char *masteru_home = 0;
-  char *subuland = 0;
-  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
-  da_push(&resources, masteru_name);
-  da_push(&resources, masteru_home);
-  da_push(&resources, subuland);
-  da_push(&resources, subuhome);
-  rc =
-    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
-    ||
-    mk_subuland(masteru_home, &subuland)
-    ||
-    mk_subuhome(subuland, subuname, &subuhome)
-    ;
-  if(rc) RETURN(&resources, rc);
-  #ifdef DEBUG
-  debug_printf("masteru_home, subuhome: \"%s\", \"%s\"\n", masteru_home, subuhome);
-  #endif
-
-  //--------------------------------------------------------------------------------
-  // removal from db
-  char *subu_username = 0;
-  da_push(&resources, subu_username);
-
-  db_begin(db);
-
-  rc = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
-  if( rc != SQLITE_OK ){
-    if(mess) *mess = strdup("subu requested for removal not found under this masteru in db file");
-    rc = SUBU_ERR_SUBU_NOT_FOUND;
-    db_rollback(db);
-    RETURN(&resources, rc);
-  }
-  #ifdef DEBUG
-  printf("subu_username: \"%s\"\n", subu_username);  
-  #endif
-
-  rc = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
-  if( rc != SQLITE_OK ){
-    if(mess)*mess = strdup("removal of masteru subu relation failed");
-    db_rollback(db);
-    RETURN(&resources, SUBU_ERR_DB_FILE);
-  }
-  #ifdef DEBUG
-  debug_printf("removed the masteru_name, subuname, subu_username relation\n");
-  #endif
-  
-  rc = db_commit(db);
-  if( rc != SQLITE_OK ){
-    if(mess)*mess = strdup("removal of masteru subu relation in unknown state, exiting");
-    RETURN(&resources, SUBU_ERR_DB_FILE);
-  }
-  
-  // even after removing the last masteru subu relation, we still do not remove
-  // the max subu count. Hence, a masteru will keep such for a life time.
-
-
-  //--------------------------------------------------------------------------------
-  // Only masteru can remove directories from masteru/subuland, so we switch to 
-  // masteru's uid to perform the rmdir.
-  //
-  {
-    #ifdef DEBUG
-    debug_printf("as masteru, removing the directory \"%s\"\n", subuhome);
-    #endif
-    int dispatch_err = dispatch_f_euid_egid
-      (
-       "masteru_rmdir_subuhome", 
-       masteru_rmdir_subuhome, 
-       (void *)subuhome,
-       masteru_uid, 
-       masteru_gid
-       );
-    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_RMDIR_SUBUHOME ){
-      #ifdef DEBUG
-      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_rmdir_subuhome");
-      #endif
-      if(mess)*mess = strdup(subuhome);
-      RETURN(&resources, SUBU_ERR_RMDIR_SUBUHOME);
-    }
-  }
-
-  //--------------------------------------------------------------------------------
-  //  Delete the subservient user account
-  {
-    #ifdef DEBUG
-    debug_printf("deleting user \"%s\"\n", subu_username);
-    #endif
-    #if BUG_SSS_CACHE_RUID
-      #ifdef DEBUG
-        debug_printf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
-      #endif
-      if( setuid(0) == -1 ){
-        RETURN(&resources, SUBU_ERR_BUG_SSS);
-      }
-    #endif
-    char *command = "/usr/sbin/userdel";
-    char *argv[4];
-    argv[0] = command;
-    argv[1] = subu_username;
-    argv[2] = "-r";  
-    argv[3] = (char *) NULL;
-    char *envp[1];
-    envp[0] = (char *) NULL;
-    int dispatch_err = dispatch_exec(argv, envp);
-    if( dispatch_err != 0 ){
-      #ifdef DEBUG 
-      dispatch_f_mess("dispatch_exec", dispatch_err, command);
-      #endif
-      if(mess)*mess = userdel_mess(dispatch_err);
-      RETURN(&resources, SUBU_ERR_FAILED_USERDEL);
-    }
-    #ifdef DEBUG
-    debug_printf("deleted user \"%s\"\n", subu_username);
-    #endif
-  }  
-
-  #ifdef DEBUG
-  debug_printf("finished subu-rm-0(%s)\n", subuname);
-  #endif
-  RETURN(&resources, 0);
-}
-
-//================================================================================
-// identifies masteru, the bindfs maps each subu_user's home to its mount point
-// in subuland.
-int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  // lookup the subu_user_home
-  char *subu_user_home = 0;
-  da_push(&resources, subu_user_home);
-
-  rc = username_to_home(subu_username, &subu_user_home);
-  if( rc ){
-    if(mess) *mess = strdup("in subu_bind, subu user home directory lookup in /etc/passwd failed.");
-    RETURN(&resources, rc);
-  }
-
-  size_t len = 0;
-  char *map = 0;
-  da_push(&resources, map);
-
-  FILE* map_stream = open_memstream(&map, &len);
-  fprintf(map_stream, "--map=%s/%s:@%s/@%s", subu_username, masteru_name, subu_username, masteru_name);
-  fclose(map_stream);
-  
-  char *command = "/usr/bin/bindfs";
-  char *argv[5];
-  argv[0] = command;
-  argv[1] = map;
-  argv[2] = subu_user_home;
-  argv[3] = subuhome;
-  argv[4] = (char *) NULL;
-  char *envp[1];
-  envp[0] = (char *) NULL;
-  int dispatch_err = dispatch_exec(argv, envp);
-  if( dispatch_err != 0 ){
-    #ifdef DEBUG 
-    dispatch_f_mess(command, dispatch_err, "dispatch_exec");
-    #endif
-    if(mess)*mess = strdup("bind failed");
-    RETURN(&resources, SUBU_ERR_BIND);
-  }
-  #ifdef DEBUG
-  debug_printf("mapped \"%s\" as \"%s\"\n", subu_user_home, subuhome);
-  #endif
-  RETURN(&resources, 0);
-}
-
-int subu_bind_all(char **mess, sqlite3 *db){
-
-  int rc;
-  if(mess)*mess = 0;
-  da resources;
-  da_alloc(&resources, sizeof(char *));
-
-  //--------------------------------------------------------------------------------
-  uid_t masteru_uid;
-  gid_t masteru_gid;
-  uid_t set_euid;
-  gid_t set_egid;
-  {
-    masteru_uid = getuid();
-    masteru_gid = getgid();
-    set_euid = geteuid();
-    set_egid = getegid();
-    #ifdef DEBUG
-    debug_printf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
-    #endif
-    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
-  }
-
-  //--------------------------------------------------------------------------------
-  // various strings that we will need
-  char *masteru_name = 0;
-  char *masteru_home = 0;
-  char *subuland = 0;
-  da_push(&resources, masteru_name);
-  da_push(&resources, masteru_home);
-  da_push(&resources, subuland);
-  rc =
-    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
-    ||
-    mk_subuland(masteru_home, &subuland)
-    ;
-  if(rc) RETURN(&resources, rc);
-  #ifdef DEBUG
-  if(masteru_name)  
-    debug_printf("masteru_name: \"%s\"", masteru_name);
-  else
-    debug_printf("masteru_name unknown");
-  if(subuland)
-    debug_printf("subuland: \"%s\"", subuland);
-  else
-    debug_printf("subuland unknown");
-  debug_printf("\n");
-  #endif
-
-  //--------------------------------------------------------------------------------
-  da subus;
-  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &subus);
-  if( rc != SQLITE_OK ){
-    if(mess)*mess = strdup("db access failed when fetching a list of subus");
-    return rc;
-  }
-  // a limitation of our error reporting approach is that we can only 
-  // return one error, but here is a loop that might generate many
-  rc = 0; 
-  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
-  uint err_cnt = 0;
-  subudb_subu_element *pt = (subudb_subu_element *)(subus.base);
-  while( !da_endq(&subus,pt) ){
-    rc = mk_subuhome(subuland, pt->subuname, &subuhome);
-    #ifdef DEBUG
-    if(subuhome)
-      debug_printf("subuhome: \"%s\"\n", subuhome);
-    else
-      debug_printf("subuhome unknown \n");
-    #endif
-    if(!rc) rc = subu_bind(NULL, masteru_name, pt->subu_username, subuhome);
-    if(rc) err_cnt++;
-    free(subuhome);
-    subuhome=0;
-  pt++;
-  }
-  if(err_cnt==1){
-    RETURN(&resources, rc);
-  }
-  if(err_cnt > 1){
-    *mess = strdup("multiple errors occured while binding subus");
-    RETURN(&resources, SUBU_ERR_BIND);
-  }
-  RETURN(&resources, 0);
-}
diff --git a/module/subu-0/trc/subu.trc.c b/module/subu-0/trc/subu.trc.c
new file mode 100644 (file)
index 0000000..6ce4625
--- /dev/null
@@ -0,0 +1,742 @@
+#tranche subu.lib.c
+/*
+  sqllite3 is used to maintain the db file, which is currently compiled
+  in as /etc/subu.db, (or just subu.db for testing).
+
+  masteru is the user who ran this script. The masteru name comes from getuid
+  and /etc/passwd. 
+
+  subu is a subservient user.  The subuname is passed in as an argument.
+
+  subu-mk-0 synthesizes a new user user name s<number>, calls useradd to creat
+  the new uswer account, and enters the relationship between masteru, subu, and
+  s<number> in the db file.  It is this relation in the db file that
+  associates the subuname with the s<number> user.
+
+  subu-rm-0 uses userdel to delete the related s<number> user account.  It
+  then removes the relaton from the db file.
+
+  subu-mk-0 and subu-rm-0 are setuid root scripts.  
+
+*/
+#include <da.h>
+#include <debug.h>
+#include <dispatch.h>
+#include "common.lib.h"
+#include "subudb.lib.h"
+#include "subu.lib.h"
+
+// without this #define we get the warning: implicit declaration of function â€˜seteuid’/‘setegid’
+#define _GNU_SOURCE   
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#tranche subu.lib.h
+  #include <stdbool.h>
+  #include <errno.h>
+  #include <sqlite3.h>
+#tranche-end
+
+//--------------------------------------------------------------------------------
+// dispatched command errors  .. should add mkdir and rmdir ...
+//
+#tranche subu.lib.h
+  char *useradd_mess(int err);
+#tranche-end
+char *useradd_mess(int err){
+  if(err <= 0) return NULL;
+  char *mess;
+  switch(err){
+  case 1: mess = "can't update password file"; break;
+  case 2: mess = "invalid command syntax"; break;
+  case 3: mess = "invalid argument to option"; break;
+  case 4: mess = "UID already in use (and no -o)"; break;
+  case 5: mess = "undefined"; break;
+  case 6: mess = "specified group doesn't exist"; break;
+  case 7:
+  case 8: mess = "undefined"; break;
+  case 9: mess = "username already in use"; break;
+  case 10: mess = "can't update group file:"; break;
+  case 11: mess = "undefined"; break;
+  case 12: mess = "can't create home directory"; break;
+  case 13: mess = "undefined"; break;
+  case 14: mess = "can't update SELinux user mapping"; break;
+  default: mess = "undefined"; break;
+  }
+  return strdup(mess);
+}
+#tranche subu.lib.h
+  char *userdel_mess(int err);
+#tranche-end
+char *userdel_mess(int err){
+  if(err <= 0) return NULL;
+  char *mess;
+  switch(err){
+  case 1: mess = "can't update password file"; break;
+  case 2: mess = "invalid command syntax"; break;
+  case 3:
+  case 4:
+  case 5: mess = "undefined"; break;
+  case 6: mess = "specified user doesn't exist"; break;
+  case 7:
+  case 8: 
+  case 9: mess = "undefined"; break;
+  case 10: mess = "can't update group file:"; break;
+  case 11: mess = "undefined"; break;
+  case 12: mess = "can't remove home directory"; break;
+  default: mess = "undefined"; break;
+  }
+  return strdup(mess);
+}
+
+
+//--------------------------------------------------------------------------------
+//
+#tranche subu.lib.h
+  #define SUBU_ERR_ARG_CNT 1
+  #define SUBU_ERR_SETUID_ROOT 2
+  #define SUBU_ERR_MALLOC 3
+  #define SUBU_ERR_MKDIR_SUBUHOME 4
+  #define SUBU_ERR_RMDIR_SUBUHOME 5
+  #define SUBU_ERR_SUBUNAME_MALFORMED 6
+  #define SUBU_ERR_HOMELESS 7
+  #define SUBU_ERR_DB_FILE 8
+  #define SUBU_ERR_SUBUHOME_EXISTS 9
+  #define SUBU_ERR_BUG_SSS 10
+  #define SUBU_ERR_FAILED_USERADD 11
+  #define SUBU_ERR_FAILED_USERDEL 12
+  #define SUBU_ERR_SUBU_NOT_FOUND 13
+  #define SUBU_ERR_N 14
+  #define SUBU_ERR_BIND 15
+#tranche-end
+#tranche subu.lib.h
+  void subu_err(char *fname, int err, char *mess);
+#tranche-end
+void subu_err(char *fname, int err, char *mess){
+  if(!mess) mess = "";
+  switch(err){
+  case 0: return;
+  case SUBU_ERR_ARG_CNT:
+    if(mess[0])
+      fprintf(stderr, "Incorrect number of arguments, %s", mess);
+    else
+      fprintf(stderr, "Incorrect number of arguments.", mess);
+    break;
+  case SUBU_ERR_SETUID_ROOT:
+    fprintf(stderr, "This program must be run setuid root from a user account.");
+    break;
+  case SUBU_ERR_MALLOC:
+    perror(fname);
+    break;
+  case SUBU_ERR_DB_FILE:
+    fprintf(stderr, "error on %s", DB_File); // DB_File is in common
+    fprintf(stderr, ": %s", mess);
+    break;
+  case SUBU_ERR_HOMELESS:
+    fprintf(stderr,"Masteru, \"%s\", has no home directory", mess);
+    break;
+  case SUBU_ERR_SUBUNAME_MALFORMED:
+    fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", mess);
+    break;
+  case SUBU_ERR_SUBUHOME_EXISTS:
+    fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", mess);
+    break;
+  case SUBU_ERR_MKDIR_SUBUHOME:
+    fprintf(stderr, "masteru could not make subuhome, \"%s\"", mess);
+    break;
+  case SUBU_ERR_BUG_SSS:
+    perror(fname);
+  break;
+  case SUBU_ERR_FAILED_USERADD:
+    fprintf(stderr, "%s useradd failed\n", mess);
+  break;
+  default:
+    fprintf(stderr, "unknown error code %d\n", err);
+  }
+  fputc('\n', stderr);
+}
+
+
+//--------------------------------------------------------------------------------
+// a well formed subuname
+// returns the length of the subuname, or -1
+//
+static int allowed_subuname(char **mess, char *subuname, size_t *subuname_len){
+  char *ch = subuname;
+  size_t i = 0;
+  while(
+        *ch
+        &&
+        ( *ch >= 'a' && *ch <= 'z'
+          ||
+          *ch >= 'A' && *ch <= 'Z'
+          ||
+          *ch >= '0' && *ch <= '9'
+          ||
+          *ch == '-'
+          ||
+          *ch == '_'
+          ||
+          *ch == '.'
+          ||
+          *ch == ' '
+          )
+        ){
+    ch++;
+    i++;
+  }
+  if( !*ch ){
+    *subuname_len = i;
+    return 0;
+  }else{
+    if(mess) *mess = strdup(subuname);
+    return SUBU_ERR_SUBUNAME_MALFORMED;
+  }
+}
+
+//--------------------------------------------------------------------------------
+// dispatched functions
+//
+static int masteru_mkdir_subuhome(void *arg){
+  char *subuhome = (char *) arg;
+  if( mkdir( subuhome, Subuhome_Perms ) == -1 ){ // find subuhome perms in common
+    perror("masteru_mkdir_subuhome");
+    return SUBU_ERR_MKDIR_SUBUHOME;
+  }
+  return 0;
+}
+static int masteru_rmdir_subuhome(void *arg){
+  char *subuhome = (char *) arg;
+  if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
+    perror("masteru_rmdir_subuhome");
+    return SUBU_ERR_RMDIR_SUBUHOME;
+  }
+  return 0;
+}
+
+//--------------------------------------------------------------------------------
+// build strings 
+//
+static int mk_subu_username(char **mess, sqlite3 *db, char **subu_username){
+  int rc,n;
+  db_begin(db);
+  if(
+    (rc = subudb_number_get(db, &n))
+    ||
+    (rc = subudb_number_set(db, ++n))
+     ){
+    db_rollback(db);
+    return SUBU_ERR_DB_FILE;
+  }
+  db_commit(db);
+
+  size_t len = 0;
+  FILE* name_stream = open_memstream(subu_username, &len);
+  fprintf(name_stream, "s%d", n);
+  fclose(name_stream);
+  return 0;
+}
+
+// man page says that getpwuid strings may not be freed, I don't know how long until they
+// are overwritten, so I just make my own copies that can be freed
+static int uid_to_name_and_home(uid_t uid, char **name, char **home ){
+  struct passwd *pw_record_pt = getpwuid(uid); // reading /etc/passwd
+  *name = strdup(pw_record_pt->pw_name);
+  *home = strdup(pw_record_pt->pw_dir);
+  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
+  return 0;
+}
+
+static int username_to_home(char *name, char **home ){
+  struct passwd *pw_record_pt = getpwnam(name); // reading /etc/passwd
+  *home = strdup(pw_record_pt->pw_dir);
+  if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
+  return 0;
+}
+
+static int mk_subuland(char *masteru_home, char **subuland){
+  size_t masteru_home_len = strlen(masteru_home);
+  char *Subuland_Extension = "/subuland/";
+  size_t Subuland_Extension_len = strlen(Subuland_Extension);
+  *subuland = (char *)malloc( masteru_home_len + Subuland_Extension_len + 1 );
+  if(!*subuland) SUBU_ERR_MALLOC; 
+  strcpy(*subuland, masteru_home);
+  strcpy(*subuland + masteru_home_len, Subuland_Extension);
+  return 0;
+}
+
+static int mk_subuhome(char *subuland, char *subuname, char **subuhome){
+  size_t subuland_len = strlen(subuland);
+  size_t subuhome_len = subuland_len + strlen(subuname); // subuland has a trailing '/'
+  *subuhome = (char *)malloc(subuhome_len + 1);
+  if(!*subuhome) return SUBU_ERR_MALLOC;
+  strcpy (*subuhome, subuland);
+  strcpy (*subuhome + subuland_len, subuname);
+  return 0;
+}
+
+
+
+//===============================================================================
+#tranche subu.lib.h
+  int subu_mk_0(char **mess, sqlite3 *db, char *subuname);
+#tranche-end
+int subu_mk_0(char **mess, sqlite3 *db, char *subuname){
+
+  int rc;
+  if(mess)*mess = 0;
+  Da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  //--------------------------------------------------------------------------------
+  size_t subuname_len;
+  rc = allowed_subuname(mess, subuname, &subuname_len);
+  if(rc) return rc;
+  #ifdef DEBUG
+  debug_printf("subuname is well formed\n");
+  #endif
+
+  //--------------------------------------------------------------------------------
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    debug_printf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
+  }
+
+  //--------------------------------------------------------------------------------
+  char *masteru_name = 0;
+  char *masteru_home = 0;
+  char *subu_username = 0;
+  char *subuland = 0;
+  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+  da_push(&resources, masteru_name);
+  da_push(&resources, masteru_home);
+  da_push(&resources, subu_username);
+  da_push(&resources, subuland);
+  da_push(&resources, subuhome);
+  rc =
+    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+    ||
+    mk_subu_username(mess, db, &subu_username)
+    ||
+    mk_subuland(masteru_home, &subuland)
+    ||
+    mk_subuhome(subuland, subuname, &subuhome)
+    ;
+  if(rc) RETURN(&resources, rc);
+  #ifdef DEBUG
+  debug_printf("subu_username, subuland, subuhome: \"%s\"\"%s\"\"%s\"\n", subu_username, subuland, subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  // By having masteru create the subuhome, we know that masteru has rights to 
+  // to access this directory. This will be the mount point for bindfs
+  {
+    struct stat st;
+    if( stat(subuhome, &st) != -1 ){
+      if(mess)*mess = strdup(subuhome);
+      RETURN(&resources, SUBU_ERR_SUBUHOME_EXISTS);
+    }
+    int dispatch_err = dispatch_f_euid_egid
+      (
+       "masteru_mkdir_subuhome", 
+       masteru_mkdir_subuhome, 
+       (void *)subuhome,
+       masteru_uid, 
+       masteru_gid
+       );
+    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_MKDIR_SUBUHOME ){
+      #ifdef DEBUG
+      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_mkdir_subuhome");
+      #endif
+      if(mess)*mess = strdup(subuhome);
+      RETURN(&resources, SUBU_ERR_MKDIR_SUBUHOME);
+    }
+  }
+  #ifdef DEBUG
+  debug_printf("made directory \"%s\"\n", subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  //  Make the subservient user account, i.e. the subu
+  {
+    #ifdef DEBUG
+      debug_printf("making subu \"%s\" as user \"%s\"\n", subuname, subu_username);
+    #endif
+    #if BUG_SSS_CACHE_RUID
+      #ifdef DEBUG
+        debug_printf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
+      #endif
+      if( setuid(0) == -1 ) RETURN(&resources, SUBU_ERR_BUG_SSS);
+    #endif
+    char *command = "/usr/sbin/useradd";
+    char *argv[3];
+    argv[0] = command;
+    argv[1] = subu_username;
+    argv[2] = (char *) NULL;
+    char *envp[1];
+    envp[0] = (char *) NULL;
+    int dispatch_err = dispatch_exec(argv, envp);
+    if( dispatch_err != 0 ){
+      #ifdef DEBUG 
+      dispatch_f_mess("dispatch_exec", dispatch_err, command);
+      #endif
+      // go back and remove the directory we made in subuland
+      int dispatch_err_rmdir = dispatch_f_euid_egid
+        (
+         "masteru_rmdir_subuhome", 
+         masteru_rmdir_subuhome, 
+         (void *)subuhome,
+         masteru_uid, 
+         masteru_gid
+         );
+      #ifdef DEBUG
+      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err_rmdir, "masteru_rmdir_subuhome");
+      #endif
+      if(mess)*mess = useradd_mess(dispatch_err);
+      RETURN(&resources, SUBU_ERR_FAILED_USERADD);
+    }
+    #ifdef DEBUG
+    debug_printf("added user \"%s\"\n", subu_username);
+    #endif
+  }  
+  
+  //--------------------------------------------------------------------------------
+  #ifdef DEBUG
+  debug_printf("setting the masteru_name, subuname, subu_username relation\n");
+  #endif
+  {
+    int rc = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
+    if( rc != SQLITE_OK ){
+      if(mess)*mess = strdup("insert of masteru subu relation failed");
+      RETURN(&resources, SUBU_ERR_DB_FILE);
+    }
+  }
+  #ifdef DEBUG
+  debug_printf("finished subu-mk-0(%s)\n", subuname);
+  #endif
+  RETURN(&resources, 0);
+}
+
+//================================================================================
+#tranche subu.lib.h
+  int subu_rm_0(char **mess, sqlite3 *db, char *subuname);
+#tranche-end
+int subu_rm_0(char **mess, sqlite3 *db, char *subuname){
+
+  int rc;
+  if(mess)*mess = 0;
+  Da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  //--------------------------------------------------------------------------------
+  size_t subuname_len;
+  rc = allowed_subuname(mess, subuname, &subuname_len);
+  if(rc) return rc;
+  #ifdef DEBUG
+  debug_printf("subuname is well formed\n");
+  #endif
+  
+  //--------------------------------------------------------------------------------
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    debug_printf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
+  }
+
+  //--------------------------------------------------------------------------------
+  // various strings that we will need
+  char *masteru_name = 0;
+  char *masteru_home = 0;
+  char *subuland = 0;
+  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+  da_push(&resources, masteru_name);
+  da_push(&resources, masteru_home);
+  da_push(&resources, subuland);
+  da_push(&resources, subuhome);
+  rc =
+    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+    ||
+    mk_subuland(masteru_home, &subuland)
+    ||
+    mk_subuhome(subuland, subuname, &subuhome)
+    ;
+  if(rc) RETURN(&resources, rc);
+  #ifdef DEBUG
+  debug_printf("masteru_home, subuhome: \"%s\", \"%s\"\n", masteru_home, subuhome);
+  #endif
+
+  //--------------------------------------------------------------------------------
+  // removal from db
+  char *subu_username = 0;
+  da_push(&resources, subu_username);
+
+  db_begin(db);
+
+  rc = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
+  if( rc != SQLITE_OK ){
+    if(mess) *mess = strdup("subu requested for removal not found under this masteru in db file");
+    rc = SUBU_ERR_SUBU_NOT_FOUND;
+    db_rollback(db);
+    RETURN(&resources, rc);
+  }
+  #ifdef DEBUG
+  printf("subu_username: \"%s\"\n", subu_username);  
+  #endif
+
+  rc = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
+  if( rc != SQLITE_OK ){
+    if(mess)*mess = strdup("removal of masteru subu relation failed");
+    db_rollback(db);
+    RETURN(&resources, SUBU_ERR_DB_FILE);
+  }
+  #ifdef DEBUG
+  debug_printf("removed the masteru_name, subuname, subu_username relation\n");
+  #endif
+  
+  rc = db_commit(db);
+  if( rc != SQLITE_OK ){
+    if(mess)*mess = strdup("removal of masteru subu relation in unknown state, exiting");
+    RETURN(&resources, SUBU_ERR_DB_FILE);
+  }
+  
+  // even after removing the last masteru subu relation, we still do not remove
+  // the max subu count. Hence, a masteru will keep such for a life time.
+
+
+  //--------------------------------------------------------------------------------
+  // Only masteru can remove directories from masteru/subuland, so we switch to 
+  // masteru's uid to perform the rmdir.
+  //
+  {
+    #ifdef DEBUG
+    debug_printf("as masteru, removing the directory \"%s\"\n", subuhome);
+    #endif
+    int dispatch_err = dispatch_f_euid_egid
+      (
+       "masteru_rmdir_subuhome", 
+       masteru_rmdir_subuhome, 
+       (void *)subuhome,
+       masteru_uid, 
+       masteru_gid
+       );
+    if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_RMDIR_SUBUHOME ){
+      #ifdef DEBUG
+      dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_rmdir_subuhome");
+      #endif
+      if(mess)*mess = strdup(subuhome);
+      RETURN(&resources, SUBU_ERR_RMDIR_SUBUHOME);
+    }
+  }
+
+  //--------------------------------------------------------------------------------
+  //  Delete the subservient user account
+  {
+    #ifdef DEBUG
+    debug_printf("deleting user \"%s\"\n", subu_username);
+    #endif
+    #if BUG_SSS_CACHE_RUID
+      #ifdef DEBUG
+        debug_printf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n");
+      #endif
+      if( setuid(0) == -1 ){
+        RETURN(&resources, SUBU_ERR_BUG_SSS);
+      }
+    #endif
+    char *command = "/usr/sbin/userdel";
+    char *argv[4];
+    argv[0] = command;
+    argv[1] = subu_username;
+    argv[2] = "-r";  
+    argv[3] = (char *) NULL;
+    char *envp[1];
+    envp[0] = (char *) NULL;
+    int dispatch_err = dispatch_exec(argv, envp);
+    if( dispatch_err != 0 ){
+      #ifdef DEBUG 
+      dispatch_f_mess("dispatch_exec", dispatch_err, command);
+      #endif
+      if(mess)*mess = userdel_mess(dispatch_err);
+      RETURN(&resources, SUBU_ERR_FAILED_USERDEL);
+    }
+    #ifdef DEBUG
+    debug_printf("deleted user \"%s\"\n", subu_username);
+    #endif
+  }  
+
+  #ifdef DEBUG
+  debug_printf("finished subu-rm-0(%s)\n", subuname);
+  #endif
+  RETURN(&resources, 0);
+}
+
+//================================================================================
+// identifies masteru, the bindfs maps each subu_user's home to its mount point
+// in subuland.
+#tranche subu.lib.h
+  int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome);
+#tranche-end
+int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome){
+
+  int rc;
+  if(mess)*mess = 0;
+  Da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  // lookup the subu_user_home
+  char *subu_user_home = 0;
+  da_push(&resources, subu_user_home);
+
+  rc = username_to_home(subu_username, &subu_user_home);
+  if( rc ){
+    if(mess) *mess = strdup("in subu_bind, subu user home directory lookup in /etc/passwd failed.");
+    RETURN(&resources, rc);
+  }
+
+  size_t len = 0;
+  char *map = 0;
+  da_push(&resources, map);
+
+  FILE* map_stream = open_memstream(&map, &len);
+  fprintf(map_stream, "--map=%s/%s:@%s/@%s", subu_username, masteru_name, subu_username, masteru_name);
+  fclose(map_stream);
+  
+  char *command = "/usr/bin/bindfs";
+  char *argv[5];
+  argv[0] = command;
+  argv[1] = map;
+  argv[2] = subu_user_home;
+  argv[3] = subuhome;
+  argv[4] = (char *) NULL;
+  char *envp[1];
+  envp[0] = (char *) NULL;
+  int dispatch_err = dispatch_exec(argv, envp);
+  if( dispatch_err != 0 ){
+    #ifdef DEBUG 
+    dispatch_f_mess(command, dispatch_err, "dispatch_exec");
+    #endif
+    if(mess)*mess = strdup("bind failed");
+    RETURN(&resources, SUBU_ERR_BIND);
+  }
+  #ifdef DEBUG
+  debug_printf("mapped \"%s\" as \"%s\"\n", subu_user_home, subuhome);
+  #endif
+  RETURN(&resources, 0);
+}
+
+#tranche subu.lib.h
+  int subu_bind_all(char **mess, sqlite3 *db);
+#tranche-end
+int subu_bind_all(char **mess, sqlite3 *db){
+
+  int rc;
+  if(mess)*mess = 0;
+  Da resources;
+  da_alloc(&resources, sizeof(char *));
+
+  //--------------------------------------------------------------------------------
+  uid_t masteru_uid;
+  gid_t masteru_gid;
+  uid_t set_euid;
+  gid_t set_egid;
+  {
+    masteru_uid = getuid();
+    masteru_gid = getgid();
+    set_euid = geteuid();
+    set_egid = getegid();
+    #ifdef DEBUG
+    debug_printf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid);
+    #endif
+    if( masteru_uid == 0 || set_euid != 0 ) return SUBU_ERR_SETUID_ROOT;
+  }
+
+  //--------------------------------------------------------------------------------
+  // various strings that we will need
+  char *masteru_name = 0;
+  char *masteru_home = 0;
+  char *subuland = 0;
+  da_push(&resources, masteru_name);
+  da_push(&resources, masteru_home);
+  da_push(&resources, subuland);
+  rc =
+    uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+    ||
+    mk_subuland(masteru_home, &subuland)
+    ;
+  if(rc) RETURN(&resources, rc);
+  #ifdef DEBUG
+  if(masteru_name)  
+    debug_printf("masteru_name: \"%s\"", masteru_name);
+  else
+    debug_printf("masteru_name unknown");
+  if(subuland)
+    debug_printf("subuland: \"%s\"", subuland);
+  else
+    debug_printf("subuland unknown");
+  debug_printf("\n");
+  #endif
+
+  //--------------------------------------------------------------------------------
+  Da subus;
+  Da *subusp = &subus;
+  da_alloc(subusp, sizeof(subudb_subu_element));
+  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, subusp);
+  if( rc != SQLITE_OK ){
+    if(mess)*mess = strdup("db access failed when fetching a list of subus");
+    return rc;
+  }
+  // a limitation of our error reporting approach is that we can only 
+  // return one error, but here is a loop that might generate many
+  rc = 0; 
+  char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+  uint err_cnt = 0;
+  subudb_subu_element *pt = (subudb_subu_element *)(subusp->base);
+  while( !da_endq(subusp,pt) ){
+    rc = mk_subuhome(subuland, pt->subuname, &subuhome);
+    #ifdef DEBUG
+    if(subuhome)
+      debug_printf("subuhome: \"%s\"\n", subuhome);
+    else
+      debug_printf("subuhome unknown \n");
+    #endif
+    if(!rc) rc = subu_bind(NULL, masteru_name, pt->subu_username, subuhome);
+    if(rc) err_cnt++;
+    free(subuhome);
+    subuhome=0;
+  pt++;
+  }
+  if(err_cnt==1){
+    RETURN(&resources, rc);
+  }
+  if(err_cnt > 1){
+    *mess = strdup("multiple errors occured while binding subus");
+    RETURN(&resources, SUBU_ERR_BIND);
+  }
+  RETURN(&resources, 0);
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb-init.cli.c b/module/subu-0/trc/subudb-init.cli.c
deleted file mode 100644 (file)
index 714c7e4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-This command initializes the db file.
-
-*/
-#include "subudb-init.cli.h"
-#include <stdio.h>
-
-int main(){
-  sqlite3 *db;
-  if( sqlite3_open(DB_File, &db) != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
-    return SUBU_ERR_DB_FILE;
-  }
-  db_begin(db);
-  if( subudb_schema(db) != SQLITE_OK ){
-    db_rollback(db);
-    fprintf(stderr, "error exit, opened db file but could not build schema\n");
-    return SUBU_ERR_DB_FILE;
-  }
-  db_commit(db);
-  if( sqlite3_close(db) != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not close the db\n");
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/module/subu-0/trc/subudb-init.trc.c b/module/subu-0/trc/subudb-init.trc.c
new file mode 100644 (file)
index 0000000..794644d
--- /dev/null
@@ -0,0 +1,27 @@
+#tranche subudb-init.cli.c
+/*
+This command initializes the db file.
+
+*/
+#include <stdio.h>
+
+int main(){
+  sqlite3 *db;
+  if( sqlite3_open(DB_File, &db) != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
+    return SUBU_ERR_DB_FILE;
+  }
+  db_begin(db);
+  if( subudb_schema(db) != SQLITE_OK ){
+    db_rollback(db);
+    fprintf(stderr, "error exit, opened db file but could not build schema\n");
+    return SUBU_ERR_DB_FILE;
+  }
+  db_commit(db);
+  if( sqlite3_close(db) != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not close the db\n");
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb-number.cli.c b/module/subu-0/trc/subudb-number.cli.c
deleted file mode 100644 (file)
index 60304e3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-number.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
-  if( argc < 1 || argc > 2){
-    fprintf(stderr, "usage: %s [n]\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not open db file\n");
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  // then arg[1] holds a number to set the max to
-  if(argc == 2){ 
-    long int i = strtol(argv[1], NULL, 10);
-    if( i < 0 ){
-      fprintf(stderr, "n must be positive\n");
-      sqlite3_close(db);
-      return SUBU_ERR_N;
-    }
-    if( i > INT_MAX ){
-      fprintf(stderr, "n is too big, max supported by this program is %d\n", INT_MAX);
-      sqlite3_close(db);
-      return SUBU_ERR_N;
-    }
-    rc = subudb_number_set(db, i);
-    if( rc != SQLITE_OK ){
-      fprintf(stderr, "couldn't set Max_Subunumber: %s\n", sqlite3_errmsg(db));
-      return SUBU_ERR_N;
-    }
-  }
-
-  // read and print the current max
-  int n;
-  rc = subudb_number_get(db, &n);
-  if( rc == SQLITE_OK ){
-    printf("%d\n", n);
-  }else{
-    fprintf(stderr, "couldn't get Max_Subunumber: %s\n", sqlite3_errmsg(db));
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-  rc = sqlite3_close(db);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-
-}
diff --git a/module/subu-0/trc/subudb-number.trc.c b/module/subu-0/trc/subudb-number.trc.c
new file mode 100644 (file)
index 0000000..183aec0
--- /dev/null
@@ -0,0 +1,64 @@
+#tranche subudb-number.cli.c
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+  if( argc < 1 || argc > 2){
+    fprintf(stderr, "usage: %s [n]\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not open db file\n");
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  // then arg[1] holds a number to set the max to
+  if(argc == 2){ 
+    long int i = strtol(argv[1], NULL, 10);
+    if( i < 0 ){
+      fprintf(stderr, "n must be positive\n");
+      sqlite3_close(db);
+      return SUBU_ERR_N;
+    }
+    if( i > INT_MAX ){
+      fprintf(stderr, "n is too big, max supported by this program is %d\n", INT_MAX);
+      sqlite3_close(db);
+      return SUBU_ERR_N;
+    }
+    rc = subudb_number_set(db, i);
+    if( rc != SQLITE_OK ){
+      fprintf(stderr, "couldn't set Max_Subunumber: %s\n", sqlite3_errmsg(db));
+      return SUBU_ERR_N;
+    }
+  }
+
+  // read and print the current max
+  int n;
+  rc = subudb_number_get(db, &n);
+  if( rc == SQLITE_OK ){
+    printf("%d\n", n);
+  }else{
+    fprintf(stderr, "couldn't get Max_Subunumber: %s\n", sqlite3_errmsg(db));
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+  rc = sqlite3_close(db);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb-rel-get.cli.c b/module/subu-0/trc/subudb-rel-get.cli.c
deleted file mode 100644 (file)
index 9828b15..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-get the username from the db file
-for testing subudb_Masteru_Subu_get_subu_username
-
-*/
-#include "subudb-rel-get.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if(argc != 3){
-    fprintf(stderr, "usage: %s masteru_name subuname\n", argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  char *masteru_name = argv[1];
-  char *subuname = argv[2];
-  char *subu_username;
-
-  int ret = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
-  if( ret != SQLITE_DONE ){
-    fprintf(stderr, "subudb_Masteru_Subu_get_subu_username indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }
-  ret = sqlite3_close(db);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/module/subu-0/trc/subudb-rel-get.trc.c b/module/subu-0/trc/subudb-rel-get.trc.c
new file mode 100644 (file)
index 0000000..e64331a
--- /dev/null
@@ -0,0 +1,43 @@
+#tranche subudb-rel-get.cli.c
+/*
+get the username from the db file
+for testing subudb_Masteru_Subu_get_subu_username
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if(argc != 3){
+    fprintf(stderr, "usage: %s masteru_name subuname\n", argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  char *masteru_name = argv[1];
+  char *subuname = argv[2];
+  char *subu_username;
+
+  int ret = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
+  if( ret != SQLITE_DONE ){
+    fprintf(stderr, "subudb_Masteru_Subu_get_subu_username indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }
+  ret = sqlite3_close(db);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb-rel-put.cli.c b/module/subu-0/trc/subudb-rel-put.cli.c
deleted file mode 100644 (file)
index b19896e..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-puts a relation in the masteru/subu table
-
-*/
-#include "subudb-rel-put.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if(argc != 4){
-    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
-    return 1;
-  }
-  char *masteru_name = argv[1];
-  char *subuname = argv[2];
-  char *subu_username = argv[3];
-
-  sqlite3 *db;
-  {
-    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-    if( ret != SQLITE_OK ){
-      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-      return SUBU_ERR_DB_FILE;
-    }}
-
-  int ret = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "subudb_Masteru_Subu_put indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }
-  ret = sqlite3_close(db);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/module/subu-0/trc/subudb-rel-put.trc.c b/module/subu-0/trc/subudb-rel-put.trc.c
new file mode 100644 (file)
index 0000000..5352700
--- /dev/null
@@ -0,0 +1,41 @@
+#tranche subudb-rel-put.cli.c
+/*
+puts a relation in the masteru/subu table
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if(argc != 4){
+    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
+    return 1;
+  }
+  char *masteru_name = argv[1];
+  char *subuname = argv[2];
+  char *subu_username = argv[3];
+
+  sqlite3 *db;
+  {
+    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+    if( ret != SQLITE_OK ){
+      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+      return SUBU_ERR_DB_FILE;
+    }}
+
+  int ret = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "subudb_Masteru_Subu_put indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }
+  ret = sqlite3_close(db);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb-rel-rm.cli.c b/module/subu-0/trc/subudb-rel-rm.cli.c
deleted file mode 100644 (file)
index 3d15ca9..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-puts a relation in the masteru/subu table
-
-*/
-#include "subudb-rel-rm.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
-  if(argc != 4){
-    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
-    return 1;
-  }
-  char *masteru_name = argv[1];
-  char *subuname = argv[2];
-  char *subu_username = argv[3];
-
-  sqlite3 *db;
-  {
-    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-    if( ret != SQLITE_OK ){
-      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
-      return SUBU_ERR_DB_FILE;
-    }}
-
-  int ret = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
-  if( ret != SQLITE_DONE ){
-    fprintf(stderr, "subudb_Masteru_Subu_rm indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
-    printf("put failed\n");
-    return 2;
-  }
-  ret = sqlite3_close(db);
-  if( ret != SQLITE_OK ){
-    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
-    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
-    return SUBU_ERR_DB_FILE;
-  }    
-  return 0;
-}
diff --git a/module/subu-0/trc/subudb-rel-rm.trc.c b/module/subu-0/trc/subudb-rel-rm.trc.c
new file mode 100644 (file)
index 0000000..6008c70
--- /dev/null
@@ -0,0 +1,42 @@
+#tranche subudb-rel-rm.cli.c
+/*
+puts a relation in the masteru/subu table
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+  if(argc != 4){
+    fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
+    return 1;
+  }
+  char *masteru_name = argv[1];
+  char *subuname = argv[2];
+  char *subu_username = argv[3];
+
+  sqlite3 *db;
+  {
+    int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+    if( ret != SQLITE_OK ){
+      fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+      return SUBU_ERR_DB_FILE;
+    }}
+
+  int ret = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
+  if( ret != SQLITE_DONE ){
+    fprintf(stderr, "subudb_Masteru_Subu_rm indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+    printf("put failed\n");
+    return 2;
+  }
+  ret = sqlite3_close(db);
+  if( ret != SQLITE_OK ){
+    fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+    fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+    return SUBU_ERR_DB_FILE;
+  }    
+  return 0;
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb-subus.cli.c b/module/subu-0/trc/subudb-subus.cli.c
deleted file mode 100644 (file)
index be3af20..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-subus.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
-  if( argc != 2){
-    fprintf(stderr, "usage: %s masteru_name\n",argv[0]);
-    return SUBU_ERR_ARG_CNT;
-  }
-  char *masteru_name = argv[1];
-
-  int rc;
-  sqlite3 *db;
-  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
-  if( rc != SQLITE_OK ){
-    fprintf(stderr, "error exit, could not open db file\n");
-    sqlite3_close(db);
-    return SUBU_ERR_DB_FILE;
-  }
-
-  subudb_subu_element *sa;
-  subudb_subu_element *sa_end;
-  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
-  if( rc == SQLITE_OK ){
-    subudb_subu_element *pt = sa;
-    while( pt != sa_end ){
-      printf("%s %s\n", pt->subuname, pt->subu_username);
-    pt++;
-    }
-    rc = sqlite3_close(db);
-    if( rc != SQLITE_OK ){
-      fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
-      return SUBU_ERR_DB_FILE;
-    }    
-    return 0;
-  }
-  fprintf(stderr, "lookup failed %s\n", sqlite3_errmsg(db));
-  sqlite3_close(db);
-  return SUBU_ERR_DB_FILE;
-
-}
diff --git a/module/subu-0/trc/subudb-subus.trc.c b/module/subu-0/trc/subudb-subus.trc.c
new file mode 100644 (file)
index 0000000..4871967
--- /dev/null
@@ -0,0 +1,48 @@
+#tranche subudb-subus.cli.c
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+  if( argc != 2){
+    fprintf(stderr, "usage: %s masteru_name\n",argv[0]);
+    return SUBU_ERR_ARG_CNT;
+  }
+  char *masteru_name = argv[1];
+
+  int rc;
+  sqlite3 *db;
+  rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+  if( rc != SQLITE_OK ){
+    fprintf(stderr, "error exit, could not open db file\n");
+    sqlite3_close(db);
+    return SUBU_ERR_DB_FILE;
+  }
+
+  subudb_subu_element *sa;
+  subudb_subu_element *sa_end;
+  rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
+  if( rc == SQLITE_OK ){
+    subudb_subu_element *pt = sa;
+    while( pt != sa_end ){
+      printf("%s %s\n", pt->subuname, pt->subu_username);
+    pt++;
+    }
+    rc = sqlite3_close(db);
+    if( rc != SQLITE_OK ){
+      fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+      return SUBU_ERR_DB_FILE;
+    }    
+    return 0;
+  }
+  fprintf(stderr, "lookup failed %s\n", sqlite3_errmsg(db));
+  sqlite3_close(db);
+  return SUBU_ERR_DB_FILE;
+
+}
+#tranche-end
diff --git a/module/subu-0/trc/subudb.trc.c b/module/subu-0/trc/subudb.trc.c
new file mode 100644 (file)
index 0000000..27d5639
--- /dev/null
@@ -0,0 +1,201 @@
+#tranche subudb.lib.c
+#tranche subudb.lib.h
+  /*
+  The db file is maintained in SQLite
+
+  Because linux user names are limited length, subu user names are of a compact
+  form: _s<number>.  A separate table translates the numbers into the subu names.
+
+  Each of these returns SQLITE_OK upon success
+  */
+  #include <sqlite3.h>
+#tranche-end
+
+#include <da.h>
+#include "common.lib.h"
+#include "subudb.lib.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+//--------------------------------------------------------------------------------
+// sqlite transactions don't nest.  There is a way to use save points, but still
+// we can't just nest transactions.  Instead use these wrappers around the whole
+// of something that needs to be in a transaction.
+#tranche subudb.lib.h
+  int db_begin(sqlite3 *db);
+  int db_commit(sqlite3 *db);
+  int db_rollback(sqlite3 *db);
+#tranche-end
+int db_begin(sqlite3 *db){
+  return sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
+}
+int db_commit(sqlite3 *db){
+  return sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
+}
+int db_rollback(sqlite3 *db){
+  return sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
+}
+
+//--------------------------------------------------------------------------------
+#tranche subudb.lib.h
+  int subudb_schema(sqlite3 *db);
+#tranche-end
+int subudb_schema(sqlite3 *db){
+  int rc;
+
+  { // build tables
+    char sql[] = 
+      "CREATE TABLE Masteru_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT);"
+      "CREATE TABLE Attribute_Int(attribute TEXT, value INT);"
+      ;
+    rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+    if(rc != SQLITE_OK) return rc;
+  }
+
+  { // data initialization
+    char *sql = "INSERT INTO Attribute_Int (attribute, value) VALUES ('Max_Subunumber', ?1);";
+    sqlite3_stmt *stmt;
+    sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+    sqlite3_bind_int(stmt, 1, First_Max_Subunumber);
+    rc = sqlite3_step(stmt);
+    sqlite3_finalize(stmt);
+    if( rc != SQLITE_DONE ) return rc;
+  }
+
+  return SQLITE_OK;
+}
+
+//--------------------------------------------------------------------------------
+#tranche subudb.lib.h
+  int subudb_number_get(sqlite3 *db, int *n);
+#tranche-end
+int subudb_number_get(sqlite3 *db, int *n){
+  char *sql = "SELECT value FROM Attribute_Int WHERE attribute = 'Max_Subunumber';";
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+  int rc = sqlite3_step(stmt);
+  if( rc == SQLITE_ROW ){
+    *n = sqlite3_column_int(stmt,0);
+    rc = sqlite3_step(stmt);
+    sqlite3_finalize(stmt);
+    if( rc != SQLITE_DONE ) return rc;
+    return SQLITE_OK;
+  }
+  // should have a message return, suppose
+  sqlite3_finalize(stmt);
+  return SQLITE_NOTFOUND; 
+}
+
+#tranche subudb.lib.h
+  int subudb_number_set(sqlite3 *db, int n);
+#tranche-end
+int subudb_number_set(sqlite3 *db, int n){
+  int rc;
+  char *sql = "UPDATE Attribute_Int SET value = ?1 WHERE attribute = 'Max_Subunumber';";
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+  sqlite3_bind_int(stmt, 1, n);
+  rc = sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
+
+//--------------------------------------------------------------------------------
+// put relation into Masteru_Subu table
+#tranche subudb.lib.h
+  int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username);
+#tranche-end
+int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
+  char *sql = "INSERT INTO Masteru_Subu VALUES (?1, ?2, ?3);";
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
+  int rc = sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
+
+//--------------------------------------------------------------------------------
+#tranche subudb.lib.h
+  int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username);
+#tranche-end
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username){
+  char *sql = "SELECT subu_username FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2;";
+  size_t sql_len = strlen(sql);
+  sqlite3_stmt *stmt;
+  int rc;
+  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
+  if( rc != SQLITE_OK ) return rc;
+  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC);
+  rc = sqlite3_step(stmt);
+  if( rc == SQLITE_ROW ){
+    const char *username = sqlite3_column_text(stmt, 0);
+    *subu_username = strdup(username);
+  }else{
+    sqlite3_finalize(stmt);
+    return rc; // woops this needs to return an error!,  be sure it is not SQLITE_DONE
+  }
+  rc = sqlite3_step(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
+
+//--------------------------------------------------------------------------------
+#tranche subudb.lib.h
+  typedef struct{
+    char *subuname; // the name that masteru chose for his or her subu
+    char *subu_username;  // the adduser name we gave it, typically of the s<number>
+  } subudb_subu_element;
+  int subudb_Masteru_Subu_get_subus(sqlite3 *db, char *masteru_name, Da *subus);
+#tranche-end
+//returns an array of subudb_subu_elements that correspond to the masteru_name
+int subudb_Masteru_Subu_get_subus(sqlite3 *db, char *masteru_name, Da *subusp){
+  char *sql = "SELECT subuname, subu_username"
+              " FROM Masteru_Subu"
+              " WHERE masteru_name = ?1;";
+  size_t sql_len = strlen(sql);
+  sqlite3_stmt *stmt;
+  int rc;
+  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
+  if( rc != SQLITE_OK ) return rc;
+  sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
+
+  subudb_subu_element *pt;
+  rc = sqlite3_step(stmt);
+  while( rc == SQLITE_ROW ){
+    pt = (subudb_subu_element *)da_push_alloc(subusp);
+    pt->subuname = strdup(sqlite3_column_text(stmt, 0));
+    pt->subu_username = strdup(sqlite3_column_text(stmt, 1));
+  rc = sqlite3_step(stmt);
+  }
+  sqlite3_finalize(stmt);
+  if( rc != SQLITE_DONE ) return rc;
+  return SQLITE_OK;
+}
+
+//--------------------------------------------------------------------------------
+#tranche subudb.lib.h
+  int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username);
+#tranche-end
+int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
+  char *sql = "DELETE FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2 AND subu_username = ?3;";
+  size_t sql_len = strlen(sql);
+  sqlite3_stmt *stmt;
+  int rc;
+  rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); 
+  if( rc != SQLITE_OK ) return rc;
+  sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
+  sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
+  rc = sqlite3_step(stmt);
+  sqlite3_finalize(stmt);
+  if( rc == SQLITE_DONE ) return SQLITE_OK;
+  return rc;
+}
diff --git a/module/subu-0/try/makefile b/module/subu-0/try/makefile
new file mode 100644 (file)
index 0000000..400ec02
--- /dev/null
@@ -0,0 +1,11 @@
+
+
+a b c:
+       echo $@
+
+x y z:
+       echo $@
+
+e f g: x y z
+       echo $^
+
diff --git a/module/tranche/exec/tranche b/module/tranche/exec/tranche
new file mode 100755 (executable)
index 0000000..886b915
Binary files /dev/null and b/module/tranche/exec/tranche differ
diff --git a/module/tranche/exec/tranche-make b/module/tranche/exec/tranche-make
new file mode 100755 (executable)
index 0000000..d2f5d91
Binary files /dev/null and b/module/tranche/exec/tranche-make differ
diff --git a/module/tranche/exec/tranche-target b/module/tranche/exec/tranche-target
new file mode 100755 (executable)
index 0000000..8ef74f3
Binary files /dev/null and b/module/tranche/exec/tranche-target differ
diff --git a/module/tranche/include/tranche.h b/module/tranche/include/tranche.h
new file mode 100644 (file)
index 0000000..575c97f
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef TRANCHE_LIB_H
+#define TRANCHE_LIB_H
+
+#define TRANCHE_ERR_ARG_PARSE 1
+#define TRANCHE_ERR_SRC_OPEN 2
+#define TRANCHE_ERR_DST_OPEN 4
+#define TRANCHE_ERR_FCLOSE 8
+#define TRANCHE_ERR_HELP 16
+#define TRANCHE_ERR_SNAME 32
+
+void path_trim_slashes(char *path);
+int tranche_send(FILE *src, Da *arg_fds, char *tdir);
+int tranche_target(FILE *src, Da *targets, char *tdir);
+void tranche_make(FILE *src_file, char *src_name, int mfile_fd, char *tdir);
+
+#endif
diff --git a/module/tranche/lib/libtranche.a b/module/tranche/lib/libtranche.a
new file mode 100644 (file)
index 0000000..407c21b
Binary files /dev/null and b/module/tranche/lib/libtranche.a differ
index 2c21909..e80a0d9 100644 (file)
@@ -16,8 +16,8 @@ dep:
 
 .PHONY: lib
 lib:
-       $(MAKE) $@
        cp $(SRCDIR)/tranche.lib.h include/tranche.h
+       $(MAKE) $@
 
 .PHONY: exec
 exec:
index 076600d..46febb1 100644 (file)
@@ -5,7 +5,7 @@ DOCDIR=doc
 EXECDIR=exec
 INCDIR=include
 LIBDIR=lib
-SHAREDIR=../share
+SHAREDIR=$(realpath $(PROJECT_SUBU)/module/share)
 SRCDIR=src
 TESTDIR=
 TMPDIR=tmp
@@ -21,7 +21,6 @@ ECHO= echo
 #ECHO= echo -e
 
 C=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -ggdb -Werror -DDEBUG -DDEBUGDB 
-#CFLAGS=-std=gnu11 -fPIC -I. -I../share/include -Werror
-LINKFLAGS=-Llib -L../share/lib/ -lda -ltranche
+CFLAGS=-std=gnu11 -fPIC -I$(SRCDIR) -I$(INCDIR) -I$(SHAREDIR)/include -ggdb -Werror -DDEBUG -DDEBUGDB 
+LINKFLAGS=-L$(LIBDIR) -L$(SHAREDIR)/lib/ -l$(MODULE) -lda 
 
index 65e66c1..9c154ce 100644 (file)
@@ -179,48 +179,60 @@ void path_trim_slashes(char *path){
 // write a make file rule for making the tranche targets
 void tranche_make(FILE *src_file, char *src_name, int mfile_fd, char *tdir){
 
-  // target list
-  Da ta;
-  Da *tap=&ta; // target array pointer
-  da_alloc(tap, sizeof(char *));
-  tranche_target(src_file, tap, tdir);
+  // array of the target file names -----------------------------------------
+  Da target_arr;
+  Da *target_arrp=&target_arr; // target array pointer
+  da_alloc(target_arrp, sizeof(char *));
+  tranche_target(src_file, target_arrp, tdir);
+
+  // a space separated list of the target file names
+  Da target_arr_as_string;
+  Da *taasp = &target_arr_as_string;
+  da_alloc(taasp, sizeof(char));
+  char *pt = target_arrp->base; // char * because it points to a byte in the array
+  if( pt < target_arrp->end ){
+    da_string_push(taasp, *(char **)pt);
+  pt += target_arrp->element_size;
+  }
+  while( pt < target_arrp->end ){
+    da_push(taasp, &sp);
+    da_string_push(taasp, *(char **)pt);
+  pt += target_arrp->element_size;
+  }
+  da_free_elements(target_arrp);
+  da_free(target_arrp);
 
   // construct then output the dependency line ----------------------------------------
-  Da dla;
-  Da *dlap=&dla; // dependency line array pointer
-  da_alloc(dlap, sizeof(char));
-  char *pt = tap->base; // char * because it points to a byte in the array
-  while( pt < tap->end ){
-    da_string_push(dlap, *(char **)pt);
-    da_push(dlap, &sp);
-  pt += tap->element_size;
-  }
-  da_push(dlap, &colon);
-  da_push(dlap, &sp);
-  da_string_push(dlap, src_name);
-  da_push(dlap, &newline);
-  write(mfile_fd, dlap->base, dlap->end - dlap->base);
-  da_free_elements(tap);
-  da_free(tap);
+  Da make_line_string;
+  Da *mlsp = &make_line_string;
+  da_alloc(mlsp, sizeof(char));
+  da_cat(mlsp, taasp);
+  da_push(mlsp, &colon);
+  da_push(mlsp, &sp);
+  da_string_push(mlsp, src_name);
+  da_push(mlsp, &newline);
+  write(mfile_fd, mlsp->base, mlsp->end - mlsp->base);
   
   // output action lines ----------------------------------------
-  da_rewind(dlap); // reuse the line buffer
-  da_push(dlap, &tab);
-  da_string_push(dlap, "for i in $@; do rm $$i || true; done");
-  da_push(dlap, &newline);
-  write(mfile_fd, dlap->base, dlap->end - dlap->base);
-
-  da_rewind(dlap); // reuse the line buffer
-  da_push(dlap, &tab);
-  da_string_push(dlap, "tranche $<");
+  da_rewind(mlsp); // reuse make line buffer
+  da_push(mlsp, &tab);
+  da_string_push(mlsp, "rm -f ");
+  da_cat(mlsp, taasp);
+  da_push(mlsp, &newline);
+  write(mfile_fd, mlsp->base, mlsp->end - mlsp->base);
+
+  da_rewind(mlsp); // reuse the line buffer
+  da_push(mlsp, &tab);
+  da_string_push(mlsp, "tranche $<");
   if(tdir){
-    da_string_push(dlap, " -tdir ");
-    da_string_push(dlap, tdir);
+    da_string_push(mlsp, " -tdir ");
+    da_string_push(mlsp, tdir);
   }
-  da_push(dlap, &newline);
-  da_push(dlap, &newline);
-  write(mfile_fd, dlap->base, dlap->end - dlap->base);
+  da_push(mlsp, &newline);
+  da_push(mlsp, &newline);
+  write(mfile_fd, mlsp->base, mlsp->end - mlsp->base);
 
-  da_free(dlap);
+  da_free(taasp);
+  da_free(mlsp);
   return;
 }
index 31fdc5d..886b915 100755 (executable)
Binary files a/tool/bin/tranche and b/tool/bin/tranche differ
index ae00d98..d2f5d91 100755 (executable)
Binary files a/tool/bin/tranche-make and b/tool/bin/tranche-make differ
index 4415c1a..8ef74f3 100755 (executable)
Binary files a/tool/bin/tranche-target and b/tool/bin/tranche-target differ
index 4d548e9..71f1a05 100755 (executable)
@@ -36,7 +36,7 @@ DOCDIR=doc
 EXECDIR=exec
 INCDIR=include
 LIBDIR=lib
-SHAREDIR=../share
+SHAREDIR=$(realpath $(PROJECT_SUBU)/module/share)
 SRCDIR=src
 TESTDIR=test
 TMPDIR=tmp
@@ -47,7 +47,6 @@ DEPFILE=$(TMPDIR)/makefile-cc.deps
 LIBFILE=$(LIBDIR)/lib$(MODULE).a
 INCFILE=$(INCDIR)/$(MODULE).h
 
-
 # a single space literal, for example if you wanted to subsitute commas to
 # spaces: $(subst $(space),;,$(string))
 blank :=
@@ -61,7 +60,8 @@ CC=
 # local customization
 #  user must define things needed by the local makefile, the compiler, and flags
 
--include makefile-flags
+include makefile-flags
+-include $(DEPFILE)
 
 #--------------------------------------------------------------------------------
 # targets
@@ -183,11 +183,10 @@ dist-clean: clean
        rm $(LIBFILE) || true
 
 # recipes
--include $(DEPFILE)
-
-$(TMPDIR)/%.o : $(SRCDIR)/%.c
+ $(TMPDIR)/%.o : $(SRCDIR)/%.c
        $(C) $(CFLAGS) -o $@ -c $<
 
-$(TMPDIR)/%.o : $(SRCDIR)/%.cc
+ $(TMPDIR)/%.o : $(SRCDIR)/%.cc
        $(CC) $(CCFLAGS) -o $@ -c $<
 
+