1
/* main.c - Network UPS Tools driver core
3
Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
unsigned int sddelay = 90; /* wait 90 seconds for shutdown */
23
const char *progname = NULL, *upsname = NULL;
24
const char *device_name = NULL, *device_path = NULL;
25
const char *statepath = NULL;
26
int do_forceshutdown = 0;
27
vartab_t *vartab_h = NULL;
28
int experimental_driver = 0;
30
/* stuff from upscommon */
31
extern int do_lock_port;
33
extern int use_init_fn; /* TODO: remove in the future */
35
/* stuff from common */
36
extern int upslog_flags;
38
/* power down the attached load immediately */
39
static void forceshutdown(void)
41
upslogx(LOG_NOTICE, "Initiating UPS shutdown");
42
printf("Initiating forced UPS shutdown!\n");
48
printf("Waiting for poweroff...\n");
50
printf("Hmm, did the shutdown fail? Oh well...\n");
58
printf ("usage: %s [-h] [-a <id>] [-d <num>] [-k] [-x <var>=<val>] [<device>]\n",
61
printf("Examples:\n");
62
printf(" %s -a myups - new method: use ups.conf section myups\n",
64
printf(" %s /dev/ttyS0 - old method: start up on port /dev/ttyS0\n",
73
printf ("usage: %s [-h] [-a <id>] [-d <num>] [-k] [-x <var>=<val>] [<device>]\n",
77
" -a <id> - autoconfig using ups.conf section <id>\n"
78
" - note: -x options after -a override ups.conf settings\n"
79
" -d <num> - wait <num> seconds after sending shutdown command\n"
80
" -k - force shutdown\n"
81
" -h - display this help\n"
82
" -x <var>=<val> - set driver variable <var> to <val>\n"
83
" - example: -x cable=940-0095B\n"
85
" <device> - /dev entry corresponding to UPS port\n"
86
" - Only optional when using -a!\n"
92
printf ("Acceptable values for -x in this driver:\n\n");
95
if (tmp->vartype == VAR_VALUE)
96
printf("%40s : -x %s=<value>\n",
99
printf("%40s : -x %s\n", tmp->desc, tmp->var);
108
/* cram var [= <val>] data into storage */
109
static void storeval(const char *var, char *val)
111
vartab_t *tmp, *last;
113
tmp = last = vartab_h;
124
/* later definitions overwrite earlier ones */
125
if (!strcasecmp(tmp->var, var)) {
130
tmp->val = xstrdup(val);
139
printf("Error: -x %s is not valid for this driver.\n\n", var);
143
/* retrieve the value of variable <var> if possible */
144
char *getval(const char *var)
146
vartab_t *tmp = vartab_h;
149
if (!strcasecmp(tmp->var, var))
157
/* see if <var> has been defined, even if no value has been given to it */
158
int testvar(const char *var)
160
vartab_t *tmp = vartab_h;
163
if (!strcasecmp(tmp->var, var))
168
return 0; /* not found */
171
/* callback from driver - create the table for -x/conf entries */
172
void addvar(int vartype, const char *name, const char *desc)
174
vartab_t *tmp, *last;
176
tmp = last = vartab_h;
183
tmp = xmalloc(sizeof(vartab_t));
185
tmp->vartype = vartype;
186
tmp->var = xstrdup(name);
188
tmp->desc = xstrdup(desc);
198
/* handle -x / ups.conf config details that are for this part of the code */
199
static int main_arg(char *var, char *val)
201
/* flags for main: just 'nolock' for now */
203
if (!strcmp(var, "nolock")) {
205
return 1; /* handled */
208
/* any other flags are for the driver code */
212
/* variables for main: port and sddelay */
214
if (!strcmp(var, "port")) {
215
device_path = xstrdup(val);
216
device_name = xbasename(device_path);
217
return 1; /* handled */
220
if (!strcmp(var, "sddelay")) {
222
return 1; /* handled */
225
/* only for upsdrvctl - ignored here */
226
if (!strcmp(var, "sdorder"))
227
return 1; /* handled */
229
return 0; /* unhandled, pass it through to the driver */
232
void do_upsconf_args(char *confupsname, char *var, char *val)
234
/* ignore global stuff in here */
238
/* no match = not for us */
239
if (strcmp(confupsname, upsname) != 0)
242
if (main_arg(var, val))
245
/* flags (no =) now get passed to the driver-level stuff */
251
/* don't let the user shoot themselves in the foot */
252
if (!strcmp(var, "driver")) {
253
if (strcmp(val, progname) != 0)
254
fatalx("Error: UPS [%s] is for driver %s, but I'm %s!\n",
255
confupsname, val, progname);
259
/* everything else must be for the driver */
264
/* split -x foo=bar into 'foo' and 'bar' */
265
static void splitxarg(char *inbuf)
267
char *eqptr, *val, *buf;
269
/* make our own copy - avoid changing argv */
270
buf = xstrdup(inbuf);
272
eqptr = strchr(buf, '=');
281
/* see if main handles this first */
282
if (main_arg(buf, val))
285
/* otherwise store it for later */
289
/* two pipes for two different sync points during startup */
291
#define SERIALIZE_INIT 1
292
#define SERIALIZE_SETM1 2
293
#define SERIALIZE_SETM2 3
294
#define SERIALIZE_WAITM1 4
295
#define SERIALIZE_WAITM2 5
297
void serialize(int op)
299
static int pipe1[2], pipe2[2];
309
fatal("serialize: pipe");
316
fatal("serialize: pipe");
322
case SERIALIZE_SETM1:
327
case SERIALIZE_WAITM1:
329
ret = read(pipe1[0], &ch, 1);
333
case SERIALIZE_SETM2:
338
case SERIALIZE_WAITM2:
340
ret = read(pipe2[0], &ch, 1);
346
static void runparent(void)
350
/* allow the client to exit from its WAITM1 call */
351
serialize(SERIALIZE_SETM1);
353
/* wait for the client to call info_ready() and set M2 */
354
serialize(SERIALIZE_WAITM2);
360
/* special version to deal with the nasty sync issues in here */
361
static void main_background(void)
365
if ((pid = fork()) < 0)
366
fatal("Unable to enter background");
368
xbit_set(&upslog_flags, UPSLOG_SYSLOG);
369
xbit_clear(&upslog_flags, UPSLOG_STDERR);
380
/* make fds 0-2 point somewhere defined */
381
if (open("/dev/null", O_RDWR) != 0)
382
fatal("open /dev/null");
387
setsid(); /* make a new session to dodge signals */
390
/* wait until after parent closes the statefd */
391
serialize(SERIALIZE_WAITM1);
393
/* load up info with a full set of data */
396
/* put the state file where it's supposed to be */
399
/* let the parent exit now that we're ready to roll */
400
serialize(SERIALIZE_SETM2);
402
upslogx(LOG_INFO, "Startup successful");
405
int main(int argc, char **argv)
418
if (experimental_driver) {
419
printf("Warning: This is an experimental driver.\n");
420
printf("Some features may not function correctly.\n\n");
423
progname = xbasename(argv[0]);
424
openlog(progname, LOG_PID, LOG_FACILITY);
426
if ((statepath = getenv("NUT_STATEPATH")) == NULL)
427
statepath = STATEPATH;
429
/* build the driver's extra (-x) variable table */
430
upsdrv_makevartable();
432
while ((i = getopt(argc, argv, "+a:d:kDhx:")) != EOF) {
439
sddelay = atoi(optarg);
442
do_forceshutdown = 1;
448
printf("Network UPS Tools (%s)\n", UPS_VERSION);
466
/* we need to get the port from somewhere */
469
fprintf(stderr, "Error: You must specify a port name in ups.conf or on the command line.\n");
474
/* allow argv to override the ups.conf entry if specified */
476
device_path = argv[0];
477
device_name = xbasename(device_path);
480
snprintf(statefn, sizeof(statefn), "%s/%s-%s",
481
statepath, progname, device_name);
483
pidfn = xmalloc(SMALLBUF);
484
snprintf(pidfn, SMALLBUF, "%s/%s-%s.pid",
485
ALTPIDPATH, progname, device_name);
487
upsdebugx(1, "debug level is '%d'", nut_debug_level);
491
if (do_forceshutdown)
494
if (chdir(statepath))
495
fatal("Can't chdir to %s", statepath);
497
/* TODO: remove when all old drivers are dead */
500
create_info(upsdrv_infomax(), shmok);
505
if (nut_debug_level == 0) {
506
serialize(SERIALIZE_INIT);
511
/* no sync to worry about, so rename it and get going */
520
upslogx(LOG_DEBUG, "Received a message from upsd");