2019-12-06 22:45:01 -07:00
|
|
|
#include <stdio.h>
|
2019-12-06 22:06:05 -07:00
|
|
|
#include <stdlib.h>
|
2019-12-07 22:05:31 -07:00
|
|
|
#include <limits.h>
|
2019-12-06 22:37:20 -07:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2019-12-06 22:45:01 -07:00
|
|
|
#include <getopt.h>
|
2019-12-06 22:06:05 -07:00
|
|
|
#include "config.h"
|
2019-12-06 22:45:01 -07:00
|
|
|
#include "scode.h"
|
2019-12-06 22:06:05 -07:00
|
|
|
#include "log.h"
|
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
/* command line options for UPIWIN */
|
2019-12-06 22:37:20 -07:00
|
|
|
static const struct option long_options[] = {
|
|
|
|
{"framebuffer", required_argument, 0, 'F'},
|
|
|
|
{"help", no_argument, 0, 'h'},
|
2019-12-07 00:46:27 -07:00
|
|
|
{"touchscreen", required_argument, 0, 'T'},
|
2019-12-06 22:37:20 -07:00
|
|
|
{ NULL, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
2019-12-07 00:46:27 -07:00
|
|
|
static const char *short_options = "F:hT:";
|
2019-12-06 22:37:20 -07:00
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
/* printed to stdout when upiwin is executed with -h/--help option */
|
2019-12-06 22:37:20 -07:00
|
|
|
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"
|
2019-12-07 00:46:27 -07:00
|
|
|
" -T,--touchscreen - Specifies the touchscreen device name\n"
|
2019-12-06 22:37:20 -07:00
|
|
|
"";
|
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
#define EXITFUNCBLOCK_FUNCCOUNT 64 /* number of exit functions per function block */
|
2019-12-06 22:06:05 -07:00
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
/* exit functions are stored in these data blocks */
|
2019-12-06 22:06:05 -07:00
|
|
|
typedef struct tagEXITFUNCBLOCK
|
|
|
|
{
|
2019-12-07 13:07:59 -07:00
|
|
|
struct tagEXITFUNCBLOCK *next; /* chained in single linked list */
|
|
|
|
int num_funcs; /* number of functions this block contains */
|
|
|
|
PEXITFUNC funcs[EXITFUNCBLOCK_FUNCCOUNT]; /* pointers to functions */
|
2019-12-06 22:06:05 -07:00
|
|
|
} EXITFUNCBLOCK, *PEXITFUNCBLOCK;
|
|
|
|
|
|
|
|
/* The global configuration data */
|
|
|
|
GLOBAL_CONFIG Gconfig;
|
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
static PEXITFUNCBLOCK exitfuncs = NULL; /* pointer to head of exit function chain */
|
2019-12-06 22:06:05 -07:00
|
|
|
|
|
|
|
static void run_exit_funcs(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
PEXITFUNCBLOCK p;
|
|
|
|
|
|
|
|
while (exitfuncs)
|
|
|
|
{
|
|
|
|
p = exitfuncs;
|
|
|
|
exitfuncs = p->next;
|
2019-12-06 23:34:34 -07:00
|
|
|
for (i = p->num_funcs - 1; i >= 0; i--)
|
2019-12-06 23:46:21 -07:00
|
|
|
{
|
2019-12-07 13:07:59 -07:00
|
|
|
/* execute functions in LIFO order */
|
2019-12-06 23:46:21 -07:00
|
|
|
ASSERT(p->funcs[i]);
|
|
|
|
(*(p->funcs[i]))();
|
|
|
|
}
|
2019-12-06 22:06:05 -07:00
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_defaults(void)
|
|
|
|
{
|
2019-12-07 13:07:59 -07:00
|
|
|
memset(&Gconfig, 0, sizeof(GLOBAL_CONFIG));
|
2019-12-06 22:06:05 -07:00
|
|
|
Gconfig.framebuffer_device = "/dev/fb1";
|
2019-12-07 00:46:27 -07:00
|
|
|
Gconfig.touchscreen_device = "/dev/input/touchscreen";
|
2019-12-07 19:43:45 -07:00
|
|
|
Gconfig.python_loc = "/usr/bin/python3";
|
2019-12-06 22:06:05 -07:00
|
|
|
Gconfig.button_debounce = 100;
|
|
|
|
Gconfig.sys_mq_length = 64;
|
|
|
|
}
|
|
|
|
|
2019-12-06 22:37:20 -07:00
|
|
|
static HRESULT parse_cmdline(int argc, char *argv[], GLOBAL_CONFIG *parsed)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
PSTR pstr;
|
2019-12-07 22:05:31 -07:00
|
|
|
PPCSTR pargs;
|
2019-12-06 22:37:20 -07:00
|
|
|
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)
|
|
|
|
{
|
2019-12-07 13:07:59 -07:00
|
|
|
case 'F': /* frame buffer device name */
|
2019-12-06 22:37:20 -07:00
|
|
|
pstr = strdup(optarg);
|
|
|
|
if (!pstr)
|
|
|
|
{
|
|
|
|
Log(LERROR, "Out of memory in parse_cmdline");
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
if (parsed->framebuffer_device)
|
2019-12-06 22:45:01 -07:00
|
|
|
free((PVOID)(parsed->framebuffer_device));
|
2019-12-06 22:37:20 -07:00
|
|
|
parsed->framebuffer_device = pstr;
|
|
|
|
break;
|
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
case 'h': /* show help */
|
2019-12-06 22:37:20 -07:00
|
|
|
help = TRUE;
|
|
|
|
break;
|
|
|
|
|
2019-12-07 13:07:59 -07:00
|
|
|
case 'T': /* touchscreen device name */
|
2019-12-07 00:46:27 -07:00
|
|
|
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;
|
|
|
|
|
2019-12-06 22:37:20 -07:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s: unexpected option -%c\n", argv[0], c);
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (help)
|
|
|
|
{
|
|
|
|
fputs(helptext, stdout);
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
2019-12-07 22:05:31 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2019-12-07 22:09:27 -07:00
|
|
|
fprintf(stderr, "%s: no script specified\n", argv[0]);
|
2019-12-07 22:05:31 -07:00
|
|
|
return UPIWIN_E_NOSCRIPT;
|
|
|
|
}
|
|
|
|
|
2019-12-06 22:37:20 -07:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void overlay_config(GLOBAL_CONFIG *p)
|
2019-12-06 22:06:05 -07:00
|
|
|
{
|
2019-12-06 22:37:20 -07:00
|
|
|
if (p->framebuffer_device)
|
|
|
|
Gconfig.framebuffer_device = p->framebuffer_device;
|
2019-12-07 00:46:27 -07:00
|
|
|
if (p->touchscreen_device)
|
|
|
|
Gconfig.touchscreen_device = p->touchscreen_device;
|
2019-12-07 22:05:31 -07:00
|
|
|
/* 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;
|
2019-12-06 22:37:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT Config_setup(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
GLOBAL_CONFIG from_commandline;
|
|
|
|
|
2019-12-09 10:14:20 -07:00
|
|
|
if (geteuid() != 0)
|
|
|
|
{
|
|
|
|
Log(LFATAL, "upiwin must be run with root privileges");
|
|
|
|
return E_ACCESSDENIED;
|
|
|
|
}
|
|
|
|
|
2019-12-06 22:06:05 -07:00
|
|
|
if (atexit(run_exit_funcs))
|
|
|
|
{
|
|
|
|
Log(LFATAL, "Unable to set up exit function mechanism");
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
2019-12-07 13:07:59 -07:00
|
|
|
|
|
|
|
/* set defaults */
|
2019-12-06 22:06:05 -07:00
|
|
|
init_defaults();
|
2019-12-07 13:07:59 -07:00
|
|
|
|
|
|
|
/* evaluate command line */
|
2019-12-06 22:37:20 -07:00
|
|
|
hr = parse_cmdline(argc, argv, &from_commandline);
|
|
|
|
if (hr != S_OK)
|
|
|
|
return hr;
|
2019-12-07 13:07:59 -07:00
|
|
|
|
|
|
|
/* command line overrides everything */
|
2019-12-06 22:45:01 -07:00
|
|
|
overlay_config(&from_commandline);
|
2019-12-06 22:06:05 -07:00
|
|
|
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;
|
|
|
|
}
|