#include #include #include #include #include #include #include "config.h" #include "scode.h" #include "log.h" /* command line options for UPIWIN */ static const struct option long_options[] = { {"framebuffer", required_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"touchscreen", required_argument, 0, 'T'}, { NULL, 0, 0, 0 } }; static const char *short_options = "F:hT:"; /* printed to stdout when upiwin is executed with -h/--help option */ static const char *helptext = "UPIWIN - Micro Pi Windows server program\n\n" "Usage: upiwin [options] scriptname [scriptargs]\n\n" "Available options:\n" " -F,--framebuffer [devname] - Specifies the framebuffer device name\n" " -h,--help - Displays this help message.\n" " -T,--touchscreen - Specifies the touchscreen device name\n" ""; #define EXITFUNCBLOCK_FUNCCOUNT 64 /* number of exit functions per function block */ /* exit functions are stored in these data blocks */ typedef struct tagEXITFUNCBLOCK { struct tagEXITFUNCBLOCK *next; /* chained in single linked list */ int num_funcs; /* number of functions this block contains */ PEXITFUNC funcs[EXITFUNCBLOCK_FUNCCOUNT]; /* pointers to functions */ } EXITFUNCBLOCK, *PEXITFUNCBLOCK; /* The global configuration data */ GLOBAL_CONFIG Gconfig; static PEXITFUNCBLOCK exitfuncs = NULL; /* pointer to head of exit function chain */ static void run_exit_funcs(void) { int i; PEXITFUNCBLOCK p; while (exitfuncs) { p = exitfuncs; exitfuncs = p->next; for (i = p->num_funcs - 1; i >= 0; i--) { /* execute functions in LIFO order */ ASSERT(p->funcs[i]); (*(p->funcs[i]))(); } free(p); } } static void init_defaults(void) { memset(&Gconfig, 0, sizeof(GLOBAL_CONFIG)); Gconfig.framebuffer_device = "/dev/fb1"; Gconfig.touchscreen_device = "/dev/input/touchscreen"; Gconfig.python_loc = "/usr/bin/python3"; Gconfig.button_debounce = 100; Gconfig.sys_mq_length = 64; Gconfig.click_time = 500; Gconfig.click_radius = 2; } static HRESULT parse_cmdline(int argc, char *argv[], GLOBAL_CONFIG *parsed) { int c; PSTR pstr; PPCSTR pargs; BOOL help = FALSE; memset(parsed, 0, sizeof(GLOBAL_CONFIG)); for (;;) { c = getopt_long(argc, argv, short_options, long_options, NULL); if (c==-1) break; switch (c) { case 'F': /* frame buffer device name */ pstr = strdup(optarg); if (!pstr) { Log(LERROR, "Out of memory in parse_cmdline"); return E_OUTOFMEMORY; } if (parsed->framebuffer_device) free((PVOID)(parsed->framebuffer_device)); parsed->framebuffer_device = pstr; break; case 'h': /* show help */ help = TRUE; break; case 'T': /* touchscreen device name */ pstr = strdup(optarg); if (!pstr) { Log(LERROR, "Out of memory in parse_cmdline"); return E_OUTOFMEMORY; } if (parsed->touchscreen_device) free((PVOID)(parsed->touchscreen_device)); parsed->touchscreen_device = pstr; break; default: fprintf(stderr, "%s: unexpected option -%c\n", argv[0], c); return E_UNEXPECTED; } } if (help) { fputs(helptext, stdout); return S_FALSE; } if (optind < argc) { pstr = realpath(argv[optind], NULL); /* implicit strdup */ if (!pstr) { Log(LERROR, "Out of memory in parse_cmdline"); return E_OUTOFMEMORY; } if (access(pstr, R_OK)) { fprintf(stderr, "%s: script %s not found\n", argv[0], pstr); return UPIWIN_E_INVALIDSCRIPT; } parsed->script_name = pstr; if (++optind < argc) { parsed->script_arg_count = argc - optind; pargs = (PPCSTR)malloc(sizeof(PCSTR) * parsed->script_arg_count); if (!pargs) { Log(LERROR, "Out of memory in parse_cmdline"); return E_OUTOFMEMORY; } for (c = 0; c < parsed->script_arg_count; c++) { pargs[c] = strdup(argv[optind++]); if (!(pargs[c])) { Log(LERROR, "Out of memory in parse_cmdline"); return E_OUTOFMEMORY; } } parsed->script_args = pargs; } } else { fprintf(stderr, "%s: no script specified\n", argv[0]); return UPIWIN_E_NOSCRIPT; } return S_OK; } static void overlay_config(GLOBAL_CONFIG *p) { if (p->framebuffer_device) Gconfig.framebuffer_device = p->framebuffer_device; if (p->touchscreen_device) Gconfig.touchscreen_device = p->touchscreen_device; /* always overlay the script name and arguments */ Gconfig.script_name = p->script_name; Gconfig.script_arg_count = p->script_arg_count; Gconfig.script_args = p->script_args; } HRESULT Config_setup(int argc, char *argv[]) { HRESULT hr; GLOBAL_CONFIG from_commandline; if (geteuid() != 0) { Log(LFATAL, "upiwin must be run with root privileges"); return E_ACCESSDENIED; } if (atexit(run_exit_funcs)) { Log(LFATAL, "Unable to set up exit function mechanism"); return E_FAIL; } /* set defaults */ init_defaults(); /* evaluate command line */ hr = parse_cmdline(argc, argv, &from_commandline); if (hr != S_OK) return hr; /* command line overrides everything */ overlay_config(&from_commandline); return S_OK; } HRESULT Config_exitfunc(PEXITFUNC pfn) { PEXITFUNCBLOCK p; if (!exitfuncs || (exitfuncs->num_funcs == EXITFUNCBLOCK_FUNCCOUNT)) { p = (PEXITFUNCBLOCK)malloc(sizeof(EXITFUNCBLOCK)); if (!p) { Log(LERROR, "unable to allocate another exit function block"); return E_OUTOFMEMORY; } p->next = exitfuncs; p->num_funcs = 0; exitfuncs = p; } exitfuncs->funcs[exitfuncs->num_funcs++] = pfn; return S_OK; }