-include makefile-flags
.PHONY: all
-all: version dep lib exec
+all: version
.PHONY: lib
lib:
--- /dev/null
+
+
+#include "dispatch.h"
+
+// we need the declaration for uid_t etc.
+// without this #define execvpe is undefined
+#define _GNU_SOURCE
+
+#include <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+void dispatch_f_mess(char *fname, int err, char *dispatchee){
+ if(err == 0) return;
+ fprintf(stderr, "%s: ", fname); // if fprintf gets an error, errno will be overwritten
+ if(err > ERR_DISPATCH){
+ fprintf(stderr, "dispatchee \"%s\" returned the error %d\n", dispatchee, err);
+ return;
+ }
+ switch(err){
+ case ERR_DISPATCH_NEGATIVE_RETURN_STATUS:
+ fprintf(stderr, " dispatchee \"%s\" returned a negative status.", dispatchee);
+ break;
+ case ERR_DISPATCH_F_FORK:
+ case ERR_DISPATCH_F_SETEUID:
+ case ERR_DISPATCH_F_SETEGID:
+ fputc(' ', stderr);
+ perror(dispatchee);
+ break;
+ case ERR_DISPATCH_NULL_EXECUTABLE:
+ fprintf(stderr, " executable was not specified");
+ break;
+ case ERR_DISPATCH_EXEC:
+ // exec is running in another process when it fails, so we can't see the errno value it set
+ fprintf(stderr, " exec of \"%s\" failed", dispatchee);
+ break;
+ default:
+ fprintf(stderr, " returned undefined status when dispatching \"%s\"", dispatchee);
+ }
+ fputc('\n', stderr);
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a function
+int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
+ #ifdef DEBUG
+ dbprintf("%s %s\n", "dispatch_f", fname);
+ #endif
+ pid_t pid = fork();
+ if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
+ if( pid == 0 ){ // we are the child
+ int status = (*f)(f_arg); // we require that f return a zero or positive value
+ if( status < ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS;
+ exit(status);
+ }else{ // we are the parent
+ int err;
+ waitpid(pid, &err, 0);
+ return err;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a function with a given euid/egid
+// of course this will only work if our euid is root in the first place
+int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
+ #ifdef DEBUG
+ dbprintf("%s %s as euid:%u egid:%u\n", "dispatch_f_euid_egid", fname, euid, egid);
+ #endif
+ pid_t pid = fork();
+ if( pid == -1 ) return ERR_DISPATCH_F_FORK;
+ if( pid == 0 ){ // we are the child
+ int status;
+ if( seteuid(euid) == -1 )
+ status = ERR_DISPATCH_F_SETEUID;
+ else if( setegid(egid) == -1 )
+ status = ERR_DISPATCH_F_SETEGID;
+ else{
+ status = (*f)(f_arg);
+ if( status <= ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS;
+ exit(status);
+ }
+ }else{ // we are the parent
+ uint err;
+ waitpid(pid, &err, 0);
+ return err;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a executable
+int dispatch_exec(char **argv, char **envp){
+ char *command;
+ {
+ if( !argv || !argv[0] ) return ERR_DISPATCH_NULL_EXECUTABLE;
+ #ifdef DEBUG
+ dbprintf("dispatch_exec:");
+ char **apt = argv;
+ while( *apt ){
+ dbprintf(" %s",*apt);
+ apt++;
+ }
+ dbprintf("\n");
+ #endif
+ command = argv[0];
+ }
+ pid_t pid = fork();
+ if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
+ if( pid == 0 ){ // we are the child
+ execvpe(command, argv, envp); // exec will only return if it has an error
+ #ifdef DEBUG
+ dbprintf("dispatch_exec: exec returned, perror message:");
+ perror("dispatch_exec"); // our only chance to print this message, as this is the child process
+ #endif
+ fflush(stdout);
+ exit(ERR_DISPATCH_EXEC);
+ }else{ // we are the parent
+ int err;
+ waitpid(pid, &err, 0);
+ return err;
+ }
+}
+
--- /dev/null
+/*
+ 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);
int err = 0;
char *sep = 0;
+ char *tdir = 0;
Da args; // we will queue the non option args here
Da *argsp = &args; // collection of the non-option non-option-value args
da_alloc(argsp, sizeof(char *));
sep = value;
goto endif;
}
+ if( !strcmp(option, "tdir") ){
+ tdir = value;
+ path_trim_slashes(tdir);
+ goto endif;
+ }
fprintf(stderr, "Unrecognized option %s.", option);
err |= TRANCHE_ERR_ARG_PARSE;
goto endif;
char *src_file_path;
FILE *src_file;
if(da_emptyq(src_arrp))
- tranche_target(stdin, target_arrp);
+ tranche_target(stdin, target_arrp, tdir);
else{
char *pt = src_arrp->base;
while( pt < src_arrp->end ){
fprintf(stderr,"Could not open source file %s.\n", src_file_path);
err |= TRANCHE_ERR_SRC_OPEN;
}else{
- tranche_target(src_file, target_arrp);
+ tranche_target(src_file, target_arrp, tdir);
if( fclose(src_file) == -1 ){perror(NULL); err |= TRANCHE_ERR_FCLOSE;}
}
pt += src_arrp->element_size;
//--------------------------------------------------------------------------------
// parsing
+char sp = ' ';
+char colon = ':';
+char slash = '/';
char newline = '\n';
+char tab = '\t';
char terminator = 0;
+
char tranche_begin_tag[] = "#tranche";
size_t tranche_begin_tag_len = 8;
return pt + tranche_end_tag_len;
}
-static bool parse_file_list(Da *file_names, char *pt0){
- char *pt1;
+static void parse_file_list(Da *file_names, char *pt0, char *tdir){
+ Da filename_arr;
+ Da *fn_arrp = &filename_arr;
+ da_alloc(fn_arrp,sizeof(char));
+
while( *pt0 && isspace(*pt0) ) pt0++;
- pt1 = pt0;
- while( *pt0 ){
- while( *pt1 && !isspace(*pt1) ) pt1++;
- char *file_name = strndup(pt0, pt1 - pt0);
- da_push(file_names, &file_name);
- while( *pt1 && isspace(*pt1) ) pt1++;
- pt0 = pt1;
+ if(tdir){
+ da_string_push(fn_arrp, tdir);
+ da_push(fn_arrp, &slash);
}
+ while( *pt0 && !isspace(*pt0) ){
+ da_push(fn_arrp, *pt0);
+ }
+ da_push(fn_arrp, &terminator);
+
+ char *file_name = strdup(*(char **)fn_arrp->base);
+ da_push(file_names, &file_name);
}
//--------------------------------------------------------------------------------
if( is_tranche_end(line.base) ) break;
pt = is_tranche_begin(line.base);
if(pt){ // then this line is the start of a nested tranche block
- parse_file_list(&file_name_arr, pt);
+ parse_file_list(&file_name_arr, pt, NULL);
tranche_open_fds(&file_name_arr, &fda);
da_free_elements(&file_name_arr);
tranche_send(src, &fda);
// returns a list of unique target file names from a tranche source
// make a list of the unique tranche target files found in src
-int tranche_target(FILE *src, Da *target_arrp){
+int tranche_target(FILE *src, Da *target_arrp, char *tdir){
char *pt;
Da line; // buffer holding the characters from a line
Da file_name_arr;// an array of file name parameters parsed from a #tranche line
if( is_tranche_end(line.base) ) break;
pt = is_tranche_begin(line.base);
if(pt){ // then this line is the start of a nested tranche block
- parse_file_list(&file_name_arr, pt);
+ parse_file_list(&file_name_arr, pt, tdir);
da_strings_set_union(target_arrp, &file_name_arr, free);
da_rewind(&file_name_arr);
tranche_target(src, target_arrp);
da_alloc(tap, sizeof(char *));
tranche_target(src_file, tap);
- char sp = ' ';
- char colon = ':';
- char slash = '/';
- char newline = '\n';
- char tab = '\t';
- char terminator = 0;
-
// construct then output the dependency line ----------------------------------------
Da dla;
Da *dlap=&dla; // dependency line array pointer
void path_trim_slashes(char *path);
int tranche_send(FILE *src, Da *arg_fds);
-int tranche_target(FILE *src, Da *targets);
+int tranche_target(FILE *src, Da *targets, char *tdir);
void tranche_make(FILE *src_file, char *src_name, int mfile_fd, char *tdir);
#endif
# when local customizations set a TRCDIR, then these are the actual sources
ifneq ($TRCDIR,)
- TRCFILES= $(wildcard $(TRCDIR)/*.trc.c) $(wildcard $(TRCDIR)/*.trc.cc)
+ TRCSOURCES=$(wildcard $(TRCDIR)/*.trc.c)$(wildcard $(TRCDIR)/*.trc.cc)
+ TRCTARGETS=
else
- TRCFILES=
+ TRCSOURCES=
+ TRCTARGETS=
endif
@echo "DEPFILE: " $(DEPFILE)
@echo "LIBFILE: " $(LIBFILE)
@echo "INCFILE: " $(INCFILE)
- @echo "TRCFILES: " $(TRCFILES)
+ @echo "TRCSOURCES: " $(TRCSOURCES)
@echo "C_SOURCE_LIB: " $(C_SOURCE_LIB)
@echo "C_SOURCE_LIB: " $(C_SOURCE_LIB)
@echo "C_SOURCE_CLI: " $(C_SOURCE_CLI)
# gee this script could be better, particlarly in gathering the targets
# it would be simplified if the tranche commands took multiple source arguments
# if [ -e $(DEPFILE) ]; then rm $(DEPFILE); fi
-# if [ ! -z "$(TRCFILES)" ]; then\
+# if [ ! -z "$(TRCSOURCES)" ]; then\
# targets="";\
-# for i in $(TRCFILES); do\
+# for i in $(TRCSOURCES); do\
# tranche-make $$i -tdir $(SRCDIR) -mfile $(DEPFILE);\
# targets+=$$(tranche-target $$i);\
# targets+=" ";\
.PHONY: dep
dep:
if [ -e $(DEPFILE) ]; then rm $(DEPFILE); fi
- if [ ! -z "$(TRCFILES)" ]; then\
- tranche-make $(TRCFILES) -mfile $(DEPFILE);\
- $(MAKE) $(shell tranche-targets $(TRCFILES) -sep " ");\
- fi
- if [ -z "$(CC)" ]; then\
+ifneq ($(TRCDIR),)
+ $(ECHO) TRC deps
+ @trcsources=$(wildcard $(TRCDIR)/*.trc.c)$(wildcard $(TRCDIR)/*.trc.cc);\
+ $(ECHO) $$trcsources;\
+ if [ ! -z "$$trcsources" ]; then\
+ trctargets=$$(tranche-target $$trcsources -sep " ");\
+ echo $$trctargets;\
+ tranche-make $$trcsources -tdir $(SRCDIR) -mfile $(DEPFILE);\
+ $(MAKE) $$trctargets;\
+ fi
+endif
+ @if [ -z "$(CC)" ]; then\
if [ -z "$C()" ]; then\
- echo "No compiler specified";\
+ $(ECHO) "No compiler specified";\
exit 1;\
else\
echo "C compiler only deps" ;\