~ubuntu-branches/ubuntu/saucy/nut/saucy

« back to all changes in this revision

Viewing changes to drivers/upsdrvctl.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2005-07-20 19:48:50 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050720194850-oo61wjr33rrx2mre
Tags: upstream-2.0.2
ImportĀ upstreamĀ versionĀ 2.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <sys/wait.h>
26
26
 
27
27
#include "config.h"
28
 
#include "shared.h"
29
28
#include "proto.h"
30
29
#include "version.h"
31
30
#include "common.h"
40
39
        void    *next;
41
40
}       ups_t;
42
41
 
43
 
        ups_t   *upstable = NULL;
 
42
static  ups_t   *upstable = NULL;
44
43
 
45
 
        int     execwait, verbose = 0, maxsdorder = 0, testmode = 0;
 
44
static  int     verbose = 0, maxsdorder = 0, testmode = 0, exec_error = 0;
46
45
 
47
46
        /* timer - keeps us from getting stuck if a driver hangs */
48
 
        int     maxstartdelay = 45;
 
47
static  int     maxstartdelay = 45;
49
48
 
50
49
        /* Directory where driver executables live */
51
 
        const char * driverpath;
 
50
static  char    *driverpath = NULL;
52
51
 
53
52
        /* passthrough to the drivers: chroot path and new user name */
54
 
        char    *pt_root = NULL, *pt_user = NULL;
 
53
static  char    *pt_root = NULL, *pt_user = NULL;
 
54
 
 
55
static  sigset_t        nut_upsdrvctl_sigmask;
 
56
static  struct  sigaction       sa;
55
57
 
56
58
void do_upsconf_args(char *upsname, char *var, char *val)
57
59
{
58
60
        ups_t   *tmp, *last;
59
61
 
 
62
        /* handle global declarations */
60
63
        if (!upsname) {
61
64
                if (!strcmp(var, "maxstartdelay"))
62
65
                        maxstartdelay = atoi(val);
63
66
 
64
 
                if (!strcmp(var, "driverpath"))
 
67
                if (!strcmp(var, "driverpath")) {
 
68
                        if (driverpath)
 
69
                                free(driverpath);
 
70
 
65
71
                        driverpath = xstrdup(val);
 
72
                }
 
73
 
 
74
                /* ignore anything else - it's probably for main */
66
75
 
67
76
                return;
68
77
        }
128
137
 
129
138
        if (ret != 0) {
130
139
                upslog(LOG_ERR, "Can't open %s", pidfn);
 
140
                exec_error++;
131
141
                return;
132
142
        }
133
143
 
135
145
 
136
146
        if (!pidf) {
137
147
                upslog(LOG_ERR, "Can't open %s", pidfn);
 
148
                exec_error++;
138
149
                return;
139
150
        }
140
151
 
146
157
        if (pid < 2) {
147
158
                upslogx(LOG_NOTICE, "Ignoring invalid pid %d in %s",
148
159
                        pid, pidfn);
 
160
                exec_error++;
149
161
                return;
150
162
        }
151
163
 
159
171
 
160
172
        if (ret < 0) {
161
173
                upslog(LOG_ERR, "kill pid %d failed", pid);
 
174
                exec_error++;
162
175
                return;
163
176
        }
164
177
}
196
209
 
197
210
                tmp = tmp->next;
198
211
        }
199
 
 
200
 
        exit(0);
201
 
}
202
 
 
203
 
/* reap exiting children */
204
 
static void sigchld(int sig)
205
 
{
206
 
        execwait = 0;
207
 
}
208
 
 
209
 
/* break free of drivers that don't start up quickly */
210
 
static void sigalrm(int sig)
211
 
{
212
 
        upslogx(LOG_NOTICE, "Startup timer elapsed, continuing...");
213
 
        execwait = 0;
214
 
}
215
 
 
216
 
static void forkexec(const char *prog, ups_t *ups)
217
 
{
 
212
}
 
213
 
 
214
static void waitpid_timeout(int sig)
 
215
{
 
216
        /* do nothing */
 
217
        return;
 
218
}
 
219
 
 
220
static void forkexec(const char *prog, char **argv, ups_t *ups)
 
221
{
 
222
        int     ret;
 
223
        pid_t   pid;
 
224
 
 
225
        pid = fork();
 
226
 
 
227
        if (pid < 0)
 
228
                fatal("fork");
 
229
 
 
230
        if (pid != 0) {                 /* parent */
 
231
                int     wstat;
 
232
 
 
233
                sigemptyset(&nut_upsdrvctl_sigmask);
 
234
                sa.sa_mask = nut_upsdrvctl_sigmask;
 
235
                sa.sa_flags = 0;
 
236
                sa.sa_handler = waitpid_timeout;
 
237
                sigaction(SIGALRM, &sa, NULL);
 
238
 
 
239
                if (ups->maxstartdelay != -1)
 
240
                        alarm(ups->maxstartdelay);
 
241
                else
 
242
                        alarm(maxstartdelay);
 
243
 
 
244
                ret = waitpid(pid, &wstat, 0);
 
245
 
 
246
                signal(SIGALRM, SIG_IGN);
 
247
                alarm(0);
 
248
 
 
249
                if (ret == -1) {
 
250
                        upslogx(LOG_WARNING, "Startup timer elapsed, continuing...");
 
251
                        exec_error++;
 
252
                        return;
 
253
                }
 
254
 
 
255
                if (WIFEXITED(wstat) == 0) {
 
256
                        upslogx(LOG_WARNING, "Driver exited abnormally");
 
257
                        exec_error++;
 
258
                        return;
 
259
                }
 
260
 
 
261
                if (WEXITSTATUS(wstat) != 0) {
 
262
                        upslogx(LOG_WARNING, "Driver failed to start"
 
263
                        " (exit status=%d)", WEXITSTATUS(wstat));
 
264
                        exec_error++;
 
265
                        return;
 
266
                }
 
267
 
 
268
                /* the rest only work when WIFEXITED is nonzero */
 
269
 
 
270
                if (WIFSIGNALED(wstat)) {
 
271
                        upslog(LOG_WARNING, "Driver died after signal %d",
 
272
                                WTERMSIG(wstat));
 
273
                        exec_error++;
 
274
                }
 
275
 
 
276
                return;
 
277
        }
 
278
 
 
279
        /* child */
 
280
 
 
281
        ret = execv(prog, argv);
 
282
 
 
283
        /* shouldn't get here */
 
284
        fatal("execv");
 
285
}               
 
286
 
 
287
static void start_driver(ups_t *ups)
 
288
{
 
289
        char    dfn[SMALLBUF], *argv[8];
218
290
        int     ret, arg = 0;
219
 
        char    *argv[8];
220
 
 
221
 
        /* TODO: consider redoing this with wait() depending on portability */
222
 
 
223
 
        /* parent spins until the child exits */
224
 
        execwait = 1;
225
 
 
226
 
        ret = fork();
 
291
        struct  stat    fs;
 
292
 
 
293
        snprintf(dfn, sizeof(dfn), "%s/%s", driverpath, ups->driver);
 
294
        ret = stat(dfn, &fs);
227
295
 
228
296
        if (ret < 0)
229
 
                fatal("fork");
230
 
 
231
 
        /* parent */
232
 
        if (ret != 0) {
233
 
 
234
 
                /* catching this will unset execwait */
235
 
                signal(SIGCHLD, sigchld);
236
 
 
237
 
                /* give us a way out if the child gets stuck */
238
 
                signal(SIGALRM, sigalrm);
239
 
 
240
 
                if (ups->maxstartdelay != -1)
241
 
                        alarm(ups->maxstartdelay);
242
 
                else
243
 
                        alarm(maxstartdelay);
244
 
 
245
 
                /* spin until the child is done */
246
 
                while (execwait)
247
 
                        usleep(250000);
248
 
 
249
 
                alarm(0);
250
 
                signal(SIGALRM, SIG_IGN);
251
 
 
252
 
                return;
253
 
        }
 
297
                fatal("Can't start %s", dfn);
254
298
 
255
299
        if (verbose)
256
 
                printf("exec: %s -a %s", prog, ups->upsname);
257
 
 
258
 
        argv[arg++] = xstrdup(prog);
 
300
                printf("exec: %s -a %s", dfn, ups->upsname);
 
301
 
 
302
        argv[arg++] = xstrdup(dfn);
 
303
 
259
304
        argv[arg++] = "-a";
260
305
        argv[arg++] = ups->upsname;
261
306
 
278
323
 
279
324
        if (verbose)
280
325
                printf("\n");
 
326
        if (testmode)
 
327
                return;
281
328
 
282
329
        /* tie it off */
283
330
        argv[arg++] = NULL;
284
331
 
285
 
        /* child */
286
 
 
287
 
        if (testmode)
288
 
                exit(0);
289
 
 
290
 
        ret = execv(prog, argv);
291
 
 
292
 
        /* should not be reached */
293
 
        fatal("execv");
294
 
}
295
 
 
296
 
static void start_driver(ups_t *ups)
297
 
{
298
 
        char    dfn[SMALLBUF];
299
 
        int     ret;
300
 
        struct  stat    fs;
301
 
 
302
 
        snprintf(dfn, sizeof(dfn), "%s/%s", driverpath, ups->driver);
303
 
        ret = stat(dfn, &fs);
304
 
 
305
 
        if (ret < 0)
306
 
                fatal("Can't start %s", dfn);
307
 
 
308
 
        forkexec(dfn, ups);
 
332
        forkexec(dfn, argv, ups);
309
333
}
310
334
 
311
335
/* start user-selected driver */
345
369
static void help(const char *progname)
346
370
{
347
371
        printf("Starts and stops UPS drivers via ups.conf.\n\n");
348
 
        printf("usage: %s [OPTIONS] (start | stop | shutdown [<ups>])\n\n", progname);
 
372
        printf("usage: %s [OPTIONS] (start | stop | shutdown) [<ups>]\n\n", progname);
349
373
 
350
374
        printf("  -h                    display this help\n");
351
375
        printf("  -r <path>             drivers will chroot to <path>\n");
358
382
        printf("  stop <ups>            only stop driver for UPS <ups>\n");
359
383
        printf("  shutdown              shutdown all UPS drivers in ups.conf\n");
360
384
        printf("  shutdown <ups>        only shutdown UPS <ups>\n");
361
 
        exit(0);
 
385
 
 
386
        exit(EXIT_SUCCESS);
362
387
}
363
388
 
364
389
static void shutdown_driver(ups_t *ups)
365
390
{
366
 
        int     ret;
367
391
        char    *argv[7], dfn[SMALLBUF];
368
392
 
369
 
        /* parent spins until the child exits */
370
 
        execwait = 1;
371
 
 
372
 
        ret = fork();
373
 
 
374
 
        if (ret < 0)
375
 
                fatal("fork");
376
 
 
377
 
        /* parent */
378
 
        if (ret != 0) {
379
 
 
380
 
                /* wait for child to return */
381
 
                signal(SIGCHLD, sigchld);
382
 
 
383
 
                /* give us a way out if the child gets stuck */
384
 
                signal(SIGALRM, sigalrm);
385
 
 
386
 
                if (ups->maxstartdelay != -1)
387
 
                        alarm(ups->maxstartdelay);
388
 
                else
389
 
                        alarm(maxstartdelay);
390
 
 
391
 
                while (execwait)
392
 
                        usleep(250000);
393
 
 
394
 
                alarm(0);
395
 
                signal(SIGALRM, SIG_IGN);
396
 
 
397
 
                return;
398
 
        }
399
 
 
400
 
        /* child */
401
 
 
402
393
        snprintf(dfn, sizeof(dfn), "%s/%s", driverpath, ups->driver);
403
394
 
404
395
        if (verbose)
405
 
                printf("exec: %s -a %s -d 0 -k\n", dfn, ups->upsname);
 
396
                printf("exec: %s -a %s -k\n", dfn, ups->upsname);
 
397
        if (testmode)
 
398
                return;
406
399
 
407
400
        argv[0] = dfn;
408
401
        argv[1] = "-a";
409
402
        argv[2] = xstrdup(ups->upsname);
410
 
        argv[3] = "-d";
411
 
        argv[4] = "0";
412
 
        argv[5] = "-k";
413
 
        argv[6] = NULL;
414
 
 
415
 
        if (testmode)
416
 
                exit(0);
417
 
 
418
 
        ret = execv(dfn, argv);
419
 
 
420
 
        /* should not be reached */
421
 
        fatal("execv");
 
403
        argv[3] = "-k";
 
404
        argv[4] = NULL;
 
405
 
 
406
        forkexec(dfn, argv, ups);
422
407
}
423
408
 
424
409
static void shutdown_one_driver(char *upsname)
459
444
                        tmp = tmp->next;
460
445
                }
461
446
        }
462
 
 
463
 
        exit(0);
 
447
}
 
448
 
 
449
static void exit_cleanup(void)
 
450
{
 
451
        ups_t   *tmp, *next;
 
452
 
 
453
        tmp = upstable;
 
454
 
 
455
        while (tmp) {
 
456
                next = tmp->next;
 
457
 
 
458
                if (tmp->driver)
 
459
                        free(tmp->driver);
 
460
                if (tmp->port)
 
461
                        free(tmp->port);
 
462
                if (tmp->upsname)
 
463
                        free(tmp->upsname);
 
464
                free(tmp);
 
465
 
 
466
                tmp = next;
 
467
        }
 
468
 
 
469
        if (driverpath)
 
470
                free(driverpath);
464
471
}
465
472
 
466
473
int main(int argc, char **argv)
474
481
        prog = argv[0];
475
482
        while ((i = getopt(argc, argv, "+htvu:r:V")) != EOF) {
476
483
                switch(i) {
477
 
                        case 'v':
478
 
                                verbose++;
 
484
                        case 'r':
 
485
                                pt_root = optarg;
479
486
                                break;
480
487
 
481
488
                        case 't':
491
498
                                pt_user = optarg;
492
499
                                break;
493
500
 
494
 
                        case 'r':
495
 
                                pt_root = optarg;
 
501
                        case 'v':
 
502
                                verbose++;
496
503
                                break;
497
504
 
498
505
                        case 'V':
499
 
                                exit(0);
 
506
                                exit(EXIT_SUCCESS);
500
507
 
501
508
                        case 'h':
502
509
                        default:
506
513
        }
507
514
 
508
515
        argc -= optind;
509
 
        argv += optind;
 
516
        argv += optind;
510
517
 
511
518
        if (argc < 1)
512
519
                help(prog);
514
521
        if (testmode)
515
522
                printf("*** Testing mode: not calling exec/kill\n");
516
523
 
517
 
    driverpath = xstrdup(DRVPATH);  /* set default */
 
524
        driverpath = xstrdup(DRVPATH);  /* set default */
 
525
 
 
526
        atexit(exit_cleanup);
518
527
 
519
528
        if (!strcmp(argv[0], "start")) {
520
 
                read_upsconf(1);
 
529
                read_upsconf();
521
530
 
522
531
                if (argc == 1)
523
532
                        start_all_drivers();
524
533
                else
525
534
                        start_one_driver(argv[1]);
526
535
 
527
 
                exit(0);
 
536
                if (exec_error)
 
537
                        exit(EXIT_FAILURE);
 
538
 
 
539
                exit(EXIT_SUCCESS);
528
540
        }
529
541
 
530
542
        if (!strcmp(argv[0], "stop")) {
531
 
                read_upsconf(1);
 
543
                read_upsconf();
532
544
 
533
545
                if (argc == 1)
534
546
                        stop_all_drivers();
535
547
                else
536
548
                        stop_one_driver(argv[1]);
537
549
 
538
 
                exit(0);
 
550
                if (exec_error)
 
551
                        exit(EXIT_FAILURE);
 
552
 
 
553
                exit(EXIT_SUCCESS);
539
554
        }
540
555
 
541
556
        if (!strcmp(argv[0], "shutdown")) {
542
 
                read_upsconf(1);
 
557
                read_upsconf();
543
558
 
544
559
                if (argc == 1)
545
560
                        shutdown_all_drivers();
546
561
                else
547
562
                        shutdown_one_driver(argv[1]);
548
563
 
549
 
                exit(0);
 
564
                if (exec_error)
 
565
                        exit(EXIT_FAILURE);
 
566
 
 
567
                exit(EXIT_SUCCESS);
550
568
        }
551
569
 
552
570
        fatalx("Error: unrecognized command [%s]\n", argv[0]);
553
571
 
554
572
        /* NOTREACHED */
555
 
        return 0;
 
573
        exit(EXIT_FAILURE);
556
574
}
557
 
 
558