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

« back to all changes in this revision

Viewing changes to models/upscommon.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Quette
  • Date: 2004-05-28 13:10:01 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040528131001-yj2m9qcez4ya2w14
Tags: upstream-1.4.2
ImportĀ upstreamĀ versionĀ 1.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* upscommon.c - functions used in more than one model support module
2
 
 
3
 
   Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
4
 
 
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.
9
 
 
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.
14
 
 
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
18
 
*/
19
 
 
20
 
#include "upscommon.h"
21
 
#include "common.h"
22
 
 
23
 
#include <pwd.h>
24
 
#include <ctype.h>
25
 
#include <sys/file.h>
26
 
#include <sys/ioctl.h>
27
 
#include "timehead.h"
28
 
#include <sys/socket.h>
29
 
#include <sys/un.h>
30
 
 
31
 
#ifdef HAVE_SYS_SHM_H
32
 
#include <sys/ipc.h>
33
 
#include <sys/shm.h>
34
 
#else
35
 
#define shmget(a,b,c) (-1)
36
 
#define shmctl(a,b,c) /* nop */
37
 
struct shmid_ds {
38
 
        void *junk;
39
 
};
40
 
#endif
41
 
 
42
 
#ifdef HAVE_UU_LOCK
43
 
#include <libutil.h>
44
 
#endif
45
 
 
46
 
        int     upsfd, shmid = -1, upsc_debug = 0;
47
 
static  int statefd = -1;
48
 
        char    statefn[SIZE_OF_STATEFN], *upsport, *pidfn = NULL;
49
 
        char    initfn[SIZE_OF_STATEFN];
50
 
 
51
 
static  char    sock_fn[SIZE_OF_STATEFN];
52
 
static  int     sock_fd = -1;
53
 
static  fd_set  sock_rfds;
54
 
static  int     sock_maxfd;
55
 
 
56
 
        itype   *info = NULL;
57
 
static  itype   *shared_info = NULL;
58
 
static  size_t info_size = 0;
59
 
static  itype *info_mtime = NULL;
60
 
        int     infoused = 0, infomax = 0;
61
 
 
62
 
        struct  ups_handler     upsh;
63
 
 
64
 
        int     do_lock_port = 1;
65
 
 
66
 
        /* main sets this, and nobody else does */
67
 
        /* TODO: remove when all old style drivers are dead */
68
 
        int     use_init_fn = 0;
69
 
 
70
 
/* need to pick a sane default.  maybe this should be set by open_serial */
71
 
        unsigned int upssend_delay = 0;
72
 
        char    upssend_endchar = '\0';
73
 
        
74
 
        int     flag_timeoutfailure = 0;
75
 
 
76
 
/* signal handler for SIGALRM when opening a serial port */
77
 
void openfail(int sig)
78
 
{
79
 
        fatal("Fatal error: serial port open timed out");
80
 
}
81
 
 
82
 
/* try whatever method(s) are available to lock the port for our use */
83
 
void lockport (int upsfd, const char *port)
84
 
{
85
 
        if (do_lock_port == 0) {
86
 
                upslogx(LOG_INFO, "Serial port locking disabled.");
87
 
                return;
88
 
        }
89
 
 
90
 
#ifdef HAVE_UU_LOCK
91
 
        if (upsport)            /* already locked? */
92
 
                return;
93
 
 
94
 
        /* save for later in case we need it at shutdown */
95
 
        upsport = xstrdup(xbasename(port));
96
 
 
97
 
        {
98
 
                int res = uu_lock(upsport);
99
 
 
100
 
                if (res != 0)
101
 
                        fatalx("Can't uu_lock %s: %s", upsport,
102
 
                               uu_lockerr(res));
103
 
        }
104
 
#elif defined(HAVE_FLOCK)
105
 
        if (flock(upsfd, LOCK_EX | LOCK_NB) != 0)
106
 
                fatalx("%s is locked by another process", port);
107
 
#elif defined(HAVE_LOCKF)
108
 
        lseek(upsfd, 0L, SEEK_SET);
109
 
        if (lockf(upsfd, F_TLOCK, 0L))
110
 
                fatalx("%s is locked by another process", port);
111
 
#endif
112
 
}
113
 
 
114
 
/* explain in full detail what's wrong when the open fails */
115
 
static void open_error(const char *port)
116
 
{
117
 
        struct  passwd  *user;
118
 
        struct  stat    fs;
119
 
 
120
 
        /* see if port even exists first - typo check */
121
 
        if (stat(port, &fs)) {
122
 
                upslogx(LOG_NOTICE, "Can't stat() %s - did you specify a nonexistent /dev file?",
123
 
                       port);
124
 
                fatal("Unable to open %s", port);
125
 
        }
126
 
 
127
 
        user = getpwuid(getuid());
128
 
        if (user)
129
 
                upslogx(LOG_NOTICE, "This program is currently running as %s (UID %d)",
130
 
                       user->pw_name, (int)user->pw_uid);
131
 
 
132
 
        user = getpwuid(fs.st_uid);
133
 
        if (user)
134
 
                upslogx(LOG_NOTICE, "%s is owned by user %s (UID %d), mode %04o", port, 
135
 
                       user->pw_name, (int)user->pw_uid,
136
 
                       (int)(fs.st_mode & 07777));
137
 
 
138
 
        upslogx(LOG_NOTICE, "Change the port name, or fix the permissions or ownership"
139
 
               " of %s and try again.", port);
140
 
 
141
 
        fatal("Unable to open %s", port);
142
 
}
143
 
 
144
 
/* open the port, but don't touch the tty details (except CLOCAL and speed) */
145
 
void open_serial_simple(const char *port, speed_t speed, int flags)
146
 
{
147
 
        struct  termios tio;
148
 
 
149
 
        signal(SIGALRM, openfail);
150
 
        alarm(3);
151
 
 
152
 
        if ((upsfd = open(port, O_RDWR | O_NONBLOCK)) == -1)
153
 
                open_error(port);
154
 
 
155
 
        alarm(0);
156
 
 
157
 
        lockport(upsfd, port);
158
 
 
159
 
        tcgetattr(upsfd, &tio);
160
 
        tio.c_cflag |= CLOCAL;
161
 
        if (speed) {
162
 
#ifndef HAVE_CFSETISPEED
163
 
#error This system lacks cfsetispeed() and has no other means to set the speed
164
 
#endif
165
 
                cfsetispeed(&tio, speed);
166
 
                cfsetospeed(&tio, speed);
167
 
        }
168
 
        tcsetattr(upsfd, TCSANOW, &tio);
169
 
 
170
 
        /* set "normal" flags - cable power, or whatever */
171
 
        if (ioctl(upsfd, TIOCMSET, &flags))
172
 
                fatal("ioctl");
173
 
}
174
 
 
175
 
/* open a serial port and setup the flags properly at a given speed */
176
 
void open_serial(const char *port, speed_t speed)
177
 
{
178
 
        struct  termios tio;
179
 
        int     fcarg;
180
 
 
181
 
        /* open port for normal use */
182
 
 
183
 
        signal (SIGALRM, openfail);
184
 
        alarm (3);
185
 
 
186
 
        upsfd = open (port, O_RDWR | O_NOCTTY | O_EXCL | O_NONBLOCK);
187
 
        alarm (0);
188
 
 
189
 
        if (upsfd < 0)
190
 
                open_error(port);
191
 
 
192
 
        fcarg = fcntl(upsfd, F_GETFL, 0);
193
 
        if (fcarg < 0 || fcntl(upsfd, F_SETFL, fcarg & ~O_NONBLOCK) < 0)
194
 
                fatal("Unable to clear O_NONBLOCK 2 %s", port);
195
 
 
196
 
        signal (SIGALRM, SIG_IGN);
197
 
 
198
 
        lockport (upsfd, port);
199
 
 
200
 
        tcgetattr (upsfd, &tio);
201
 
        tio.c_cflag = CS8 | CLOCAL | CREAD;
202
 
        tio.c_iflag = IGNPAR;
203
 
        tio.c_oflag = 0;
204
 
        tio.c_lflag = 0;
205
 
        tio.c_cc[VMIN] = 1;
206
 
        tio.c_cc[VTIME] = 0;
207
 
 
208
 
#ifdef HAVE_CFSETISPEED
209
 
        cfsetispeed (&tio, speed);
210
 
        cfsetospeed (&tio, speed);
211
 
#else
212
 
#error This system lacks cfsetispeed() and has no other means to set the speed
213
 
#endif
214
 
 
215
 
        tcflush (upsfd, TCIFLUSH);
216
 
        tcsetattr (upsfd, TCSANOW, &tio);
217
 
}
218
 
 
219
 
/* put a notice in the syslog */
220
 
void notice (const char *msg)
221
 
{
222
 
        upslogx(LOG_NOTICE, "Notice: %s", msg);
223
 
}
224
 
 
225
 
/* function for erasing "timeout"-conditions */
226
 
void nolongertimeout(void)
227
 
{
228
 
        /* if override enabled, then return without changing anything */
229
 
        if (flag_timeoutfailure == -1)
230
 
                return;
231
 
 
232
 
        if (flag_timeoutfailure == 1)
233
 
                upslogx(LOG_NOTICE, "Serial port read ok again");
234
 
        
235
 
        flag_timeoutfailure = 0;
236
 
        return;
237
 
}
238
 
 
239
 
/* signal handler for SIGALRM when trying to read */
240
 
void timeout(int sig)
241
 
{
242
 
        struct sigaction sa;
243
 
        sigset_t sigmask;
244
 
 
245
 
        sa.sa_handler = SIG_DFL;
246
 
        sigemptyset (&sigmask);
247
 
        sa.sa_mask = sigmask;
248
 
        sa.sa_flags = 0;
249
 
        sigaction (SIGALRM, &sa, NULL);
250
 
 
251
 
        /* if override enabled, then return without changing anything */
252
 
        if (flag_timeoutfailure == -1)
253
 
                return;
254
 
 
255
 
        if (flag_timeoutfailure == 0)
256
 
                upslogx(LOG_NOTICE, "Serial port read timed out");
257
 
        
258
 
        flag_timeoutfailure = 1;
259
 
        return;
260
 
}
261
 
 
262
 
/* wait for an answer in the form <data><endchar> and store in buf */
263
 
int upsrecv (char *buf, int buflen, char endchar, const char *ignchars)
264
 
{
265
 
        char    recvbuf[512], *ptr, in;
266
 
        int     ret, cnt;
267
 
        struct  sigaction sa;
268
 
        sigset_t sigmask;
269
 
 
270
 
        strcpy (recvbuf, "");
271
 
 
272
 
        sa.sa_handler = timeout;
273
 
        sigemptyset (&sigmask);
274
 
        sa.sa_mask = sigmask;
275
 
        sa.sa_flags = 0;
276
 
        sigaction (SIGALRM, &sa, NULL);
277
 
 
278
 
        alarm (3);
279
 
 
280
 
        ptr = recvbuf;
281
 
        *ptr = 0;
282
 
        cnt = 0;
283
 
        for (;;) {
284
 
                ret = read (upsfd, &in, 1);
285
 
                if (ret > 0) {
286
 
 
287
 
                        if (in == endchar) {
288
 
                                alarm (0);
289
 
                                signal (SIGALRM, SIG_IGN);
290
 
                                strlcpy (buf, recvbuf, buflen);
291
 
                                if (upsc_debug > 0) {
292
 
                                        int i;
293
 
                                        printf("upsrecv: read %d bytes [", cnt);
294
 
                                        for (i = 0; i < cnt; ++i)
295
 
                                                printf(isprint((unsigned char)buf[i]) ? "%c" : "\\%03o",
296
 
                                                           buf[i]);
297
 
                                        printf ("]\n");
298
 
                                }
299
 
                                return (buflen);
300
 
                        }
301
 
 
302
 
                        if (strchr(ignchars, in) == NULL) {
303
 
                                *ptr++ = in;
304
 
                                *ptr = 0; /* tie off end */
305
 
                                cnt++;
306
 
                        }
307
 
                        
308
 
                        nolongertimeout();
309
 
                }
310
 
                else {
311
 
                        alarm (0);
312
 
                        signal (SIGALRM, SIG_IGN);
313
 
                        strlcpy (buf, recvbuf, buflen);
314
 
                        return (-1);
315
 
                }
316
 
 
317
 
                /* keep from overrunning the buffer - lame hack */
318
 
                if (cnt > (sizeof(recvbuf) - 4)) {
319
 
                        notice ("UPS is spewing wildly");
320
 
                        return(-1);
321
 
                }
322
 
        }
323
 
 
324
 
        return (-1);    /* not reached */
325
 
}
326
 
 
327
 
/* read buflen chars and store in buf */
328
 
int upsrecvchars (char *buf, int buflen)
329
 
{
330
 
        int ret,count;
331
 
        char* bufptr;
332
 
        struct  sigaction sa;
333
 
        sigset_t sigmask;
334
 
 
335
 
        sa.sa_handler = timeout;
336
 
        sigemptyset (&sigmask);
337
 
        sa.sa_mask = sigmask;
338
 
        sa.sa_flags = 0;
339
 
        sigaction (SIGALRM, &sa, NULL);
340
 
 
341
 
        alarm (3);
342
 
        
343
 
        bufptr=buf;
344
 
        count=buflen;
345
 
        while (count>0) {
346
 
                ret=read(upsfd,bufptr,count);
347
 
                if (ret>0) {
348
 
                        bufptr+=ret;
349
 
                        count-=ret;
350
 
                } else {
351
 
                        alarm (0);
352
 
                        signal (SIGALRM, SIG_IGN);
353
 
                        return (-1);
354
 
                }
355
 
        }
356
 
        alarm (0);
357
 
        signal (SIGALRM, SIG_IGN);
358
 
        return buflen;
359
 
}
360
 
 
361
 
/* send a single byte to the UPS */
362
 
int upssendchar (char data)
363
 
{
364
 
        if (upsc_debug > 0) {
365
 
                printf ("upssendchar: sending [");
366
 
                printf (isprint((unsigned char)data) ? "%c" : "\\%03o", data);
367
 
                printf ("]\n");
368
 
        }
369
 
 
370
 
        tcflush (upsfd, TCIFLUSH);
371
 
        return (write (upsfd, &data, 1));
372
 
}
373
 
 
374
 
int upssend(const char *fmt, ...)
375
 
{
376
 
        char buf[1024], *p;
377
 
        int bytes_sent = 0;
378
 
        va_list ap;
379
 
 
380
 
        va_start(ap, fmt);
381
 
 
382
 
        if (vsnprintf(buf, sizeof(buf), fmt, ap) >= sizeof(buf))
383
 
                ; /* truncated */
384
 
 
385
 
        va_end(ap);
386
 
 
387
 
        tcflush(upsfd, TCIFLUSH);
388
 
 
389
 
        for (p = buf; *p; p++) {
390
 
                if (upsc_debug > 0) {
391
 
/*                      printf ("upssendchar: sending [");
392
 
 *                      printf (isprint(data) ? "%c" : "\\%03o", data);
393
 
 *                      printf ("]\n");
394
 
 */             }
395
 
 
396
 
                if (write(upsfd, p, 1) != 1)
397
 
                        return -1;
398
 
                bytes_sent++;
399
 
                usleep(upssend_delay);
400
 
        }
401
 
 
402
 
        if (upssend_endchar) {
403
 
                if (write(upsfd, &upssend_endchar, 1) != 1)
404
 
                        return -1;
405
 
                bytes_sent++;
406
 
                usleep(upssend_delay);
407
 
        }
408
 
 
409
 
        return bytes_sent;
410
 
}
411
 
 
412
 
 
413
 
/* read in any pending characters.  If expected is set then
414
 
 * just drop them, otherwise log an error unles they are
415
 
 * in ignore chars
416
 
 */
417
 
void upsflushin (int expected, int debugit, const char *ignchars)
418
 
{
419
 
        fd_set readfds;
420
 
        struct timeval timeout;
421
 
        char logstr[256];
422
 
        char * ptr;
423
 
        int left, rc;
424
 
 
425
 
        ptr = logstr;
426
 
        *ptr = 0;
427
 
        left = 250;             /* somewhat smaller than buffer */
428
 
 
429
 
        FD_ZERO(&readfds);
430
 
        FD_SET(upsfd, &readfds);
431
 
 
432
 
        timeout.tv_usec = 0;
433
 
        timeout.tv_sec = 0;
434
 
 
435
 
        while ((rc = select(upsfd+1,
436
 
                            &readfds,
437
 
                            NULL,
438
 
                            NULL,
439
 
                            &timeout)) > 0) {
440
 
                char in;
441
 
 
442
 
                read(upsfd, &in, 1);
443
 
                if (debugit) {
444
 
                        printf ("upsflushin: read char ");
445
 
                        printf(isprint(in) ? "%c" : "\\%03o",
446
 
                               in);
447
 
                }
448
 
                if ((!expected) &&
449
 
                    (strchr(ignchars, in) == NULL)) {
450
 
                        /* log the excess characters */
451
 
                        if (isprint(in)) {
452
 
                                *ptr++ = in;
453
 
                                *ptr = 0; /* tie of string */
454
 
                                left--;
455
 
                        } else {
456
 
                                sprintf(ptr, "\\%03o", in);
457
 
                                ptr += 4;
458
 
                                left--;
459
 
                        }
460
 
                        /* check if buffer full - if so moan */
461
 
                        if (left <= 0) {
462
 
                                upslogx(LOG_INFO,
463
 
                                        "Unexpected UPS jabber [%s]",
464
 
                                        logstr);
465
 
                                ptr = logstr;
466
 
                                left = 250;
467
 
                        }
468
 
                }
469
 
        }
470
 
 
471
 
        /* check for error returns from select */
472
 
        if (rc != 0) {
473
 
                upslogx(LOG_NOTICE, "select() on input flush returned error");
474
 
        }
475
 
 
476
 
        if (ptr != logstr) {
477
 
                upslogx(LOG_INFO,
478
 
                        "Unexpected UPS output [%s]",
479
 
                        logstr);
480
 
        }
481
 
 
482
 
        return;
483
 
}
484
 
 
485
 
/* get data from the UPS and install it in the data array */
486
 
void installinfo (int infotype, char reqchar, char endchar, const char *ignchars)
487
 
{
488
 
        int     pos;
489
 
 
490
 
        pos = findinfo(info, infomax, 0, infotype);
491
 
 
492
 
        if (pos == -1)          /* not found, probably not supported */
493
 
                return;
494
 
 
495
 
        upssendchar (reqchar);
496
 
        upsrecv (info[pos].value, sizeof(info[pos].value), endchar, ignchars);
497
 
}
498
 
 
499
 
/* store data into the array */
500
 
void setinfo(int infotype, const char *fmt, ...)
501
 
{
502
 
        int     pos;
503
 
        va_list ap;
504
 
 
505
 
        pos = findinfo(info, infomax, 0, infotype);
506
 
 
507
 
        if (pos == -1) {        /* not found, probably debugging? */
508
 
                upslogx(LOG_ERR, "setinfo: can't find type %i", infotype);
509
 
                return;
510
 
        }
511
 
 
512
 
        va_start(ap, fmt);
513
 
        if (vsnprintf(info[pos].value, sizeof(info[pos].value), fmt, ap) >= sizeof(info[pos].value))
514
 
                ; /* truncated */
515
 
        va_end(ap);
516
 
}
517
 
 
518
 
/* set a flag on an existing member of the array */
519
 
void setflag (int infotype, int newflags)
520
 
{
521
 
        int     pos;
522
 
 
523
 
        pos = findinfo(info, infomax, 0, infotype);
524
 
 
525
 
        if (pos == -1) {        /* not found, probably debugging? */
526
 
                upslogx(LOG_ERR, "setflag: can't find type %i", infotype);
527
 
                return;
528
 
        }
529
 
 
530
 
        info[pos].flags = newflags;
531
 
}
532
 
 
533
 
/* find data of a given type in the info array */
534
 
char *getdata (int infotype)
535
 
{
536
 
        int     i;
537
 
 
538
 
        for (i = 0; i < infomax; i++)
539
 
                if (info[i].type == infotype)
540
 
                        return (info[i].value);
541
 
        
542
 
        return (NULL);
543
 
}
544
 
 
545
 
#ifdef HAVE_SHMAT
546
 
 
547
 
/* create state file with a pointer to the SHM struct */
548
 
static void writeshminfo(itype *writeinfo)
549
 
{
550
 
        if (writeinfo[0].type != INFO_SHMID)
551
 
                fatalx("shouldn't be here");
552
 
 
553
 
        if (statefd >= 0) {
554
 
                int ret = write(statefd, writeinfo, sizeof(itype));
555
 
                if (ret == sizeof(itype))
556
 
                        return;
557
 
        }
558
 
 
559
 
        /* ssfd < 0 || ret < 0 */
560
 
        fatal("Can't write shminfo to %s", statefn);
561
 
}
562
 
#endif  /* HAVE_SHMAT */
563
 
 
564
 
void writeinfo(void)
565
 
{
566
 
        int     ret, tries = 0;
567
 
        struct  flock   lock;
568
 
 
569
 
        /* if data is stale, don't write it so the information ages */
570
 
        if (flag_timeoutfailure == 1)
571
 
                return;
572
 
 
573
 
        if (info[0].type == INFO_SHMID)
574
 
                fatalx("info[0].type == INFO_SHMID in a shm segment");
575
 
 
576
 
        snprintf(info_mtime->value, VALSIZE, "%ld", time(NULL));
577
 
 
578
 
        lock.l_start = 0;
579
 
        lock.l_len = 0;
580
 
        lock.l_type = F_WRLCK;
581
 
        lock.l_whence = SEEK_SET;
582
 
 
583
 
        /* try to get the lock for up to 250 ms */
584
 
        while (fcntl(statefd, F_SETLK, &lock) == -1) {
585
 
                tries++;
586
 
 
587
 
                if (tries == 10) {
588
 
                        upslogx(LOG_WARNING, "Could not lock data for writing");
589
 
                        return;
590
 
                }
591
 
 
592
 
                usleep(25000);
593
 
        }
594
 
 
595
 
        memcpy(shared_info, info, info_size);
596
 
 
597
 
        if (shmid >= 0) {
598
 
                struct  shmid_ds shmbuf;
599
 
 
600
 
                /* this updates the ctime that upsd wants to see */
601
 
                shmctl (shmid, IPC_STAT, &shmbuf);
602
 
                shmctl (shmid, IPC_SET, &shmbuf);
603
 
        } else {
604
 
#ifndef HAVE_MMAP
605
 
                if (lseek(statefd, 0, SEEK_SET))
606
 
                        fatal("lseek statefd");
607
 
                if (write(statefd, info, info_size) != info_size)
608
 
                        fatal("Can't write to %s", statefn);
609
 
#endif /* HAVE_MMAP */
610
 
        }
611
 
 
612
 
        lock.l_start = 0;
613
 
        lock.l_len = 0;
614
 
        lock.l_type = F_UNLCK;
615
 
        lock.l_whence = SEEK_SET;
616
 
 
617
 
        ret = fcntl(statefd, F_SETLK, &lock);
618
 
 
619
 
        if (ret == -1)
620
 
                upslog(LOG_INFO, "Error while unlocking UPS data");
621
 
}
622
 
 
623
 
static void create_socket(void)
624
 
{
625
 
        struct sockaddr_un sa;
626
 
        int ret;
627
 
 
628
 
        snprintf(sock_fn, sizeof(sock_fn), "%s.sock", statefn);
629
 
 
630
 
        memset(&sa, '\0', sizeof(sa));
631
 
        sa.sun_family = AF_UNIX;
632
 
        if (strlcpy(sa.sun_path, sock_fn, sizeof(sa.sun_path)) >= sizeof(sa.sun_path))
633
 
                fatalx("sockfile path too long: %s", sock_fn);
634
 
 
635
 
        /*      sa.sun_len = strlen(sock_fn); */        /* not portable */
636
 
 
637
 
        if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
638
 
                fatal("socket");
639
 
        if (bind(sock_fd, (struct sockaddr *) &sa, sizeof(sa)))
640
 
                fatal("bind %s", sock_fn);
641
 
        if (listen(sock_fd, 5))
642
 
                fatal("listen %s", sock_fn);
643
 
 
644
 
        if ((ret = fcntl(sock_fd, F_GETFL, 0)) == -1)
645
 
                fatal("fcntl(get)");
646
 
        if (fcntl(sock_fd, F_SETFL, ret | O_NDELAY) == -1)
647
 
                fatal("fcntl(set)");
648
 
 
649
 
        FD_ZERO(&sock_rfds);
650
 
        FD_SET(sock_fd, &sock_rfds);
651
 
        sock_maxfd = sock_fd + 1;
652
 
}
653
 
 
654
 
/* try to create the state file before entering the background */
655
 
static void test_writeinfo(void) 
656
 
{
657
 
        int     mode;
658
 
        char    *fn;
659
 
 
660
 
        /* upsd needs to be able to write to the file in mmap mode */
661
 
#ifdef HAVE_MMAP
662
 
        mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
663
 
        umask(0117);
664
 
#else
665
 
        mode = S_IRUSR | S_IWUSR | S_IRGRP;
666
 
#endif
667
 
 
668
 
        /* TODO: remove when all old style drivers are dead */
669
 
        /* for now - instead of adding info_ready to all the old drivers */
670
 
 
671
 
        if (use_init_fn) {
672
 
                snprintf(initfn, sizeof(initfn), "%s.init", statefn);
673
 
                unlink(initfn);
674
 
                fn = initfn;
675
 
        } else {
676
 
 
677
 
                /* OK, this is the end of the line for the old drivers...
678
 
                 *
679
 
                 * this is a place only old drivers get to, so it's the
680
 
                 * perfect place to warn the user of the impending doom
681
 
                 */
682
 
 
683
 
                upslogx(LOG_WARNING, "*** Warning: old style driver detected                            ***");
684
 
                upslogx(LOG_WARNING, "*** This driver will be removed from the tree in the next version ***");
685
 
                upslogx(LOG_WARNING, "*** See the FAQ for more information                              ***");          
686
 
 
687
 
                unlink(statefn);
688
 
                fn = statefn;
689
 
        }
690
 
 
691
 
        statefd = open(fn, O_RDWR | O_CREAT | O_NOCTTY, mode);
692
 
 
693
 
        if (statefd < 0) {
694
 
                int tmperr = errno;
695
 
                upslog(LOG_NOTICE, "Can't open %s", fn);
696
 
 
697
 
                if (tmperr == EACCES) {
698
 
                        struct  passwd  *user;
699
 
                        user = getpwuid(getuid());
700
 
 
701
 
                        if (user)
702
 
                                upslogx(LOG_NOTICE, "This program is currently running as %s (UID %d)",
703
 
                                         user ? user->pw_name : "(UNKNOWN)", user->pw_uid);
704
 
                }
705
 
                exit (1);
706
 
        }
707
 
}
708
 
 
709
 
/* rename from <fn>.init to <fn> when it's ready to be used */
710
 
void info_ready(void)
711
 
{
712
 
        int     ret;
713
 
 
714
 
        if (use_init_fn != 1) {
715
 
                upslogx(LOG_ERR, "Programming error: info_ready() called without use_init_fn set");
716
 
                return;
717
 
        }
718
 
 
719
 
        ret = rename(initfn, statefn);
720
 
 
721
 
        if (ret != 0)
722
 
                fatal("rename %s to %s", initfn, statefn);
723
 
}
724
 
 
725
 
static void cleanup(void)
726
 
{
727
 
        if (pidfn)
728
 
                unlink(pidfn);
729
 
 
730
 
        unlink(statefn);
731
 
 
732
 
        /* just in case this lingers... */
733
 
        unlink(initfn);
734
 
 
735
 
        if (sock_fd != -1) {
736
 
                close(sock_fd);
737
 
                unlink(sock_fn);
738
 
        }
739
 
 
740
 
        if (statefd != -1)
741
 
                close(statefd);
742
 
 
743
 
#ifdef HAVE_SHMAT
744
 
        /* mark for deletion after total detachment */
745
 
        if (shmid != -1) {
746
 
                shmctl (shmid, IPC_RMID, NULL);                
747
 
                shmdt ((char *) info);  /* detach */
748
 
        }
749
 
#endif  /* HAVE_SHMAT */
750
 
 
751
 
#ifdef HAVE_UU_LOCK
752
 
        uu_unlock (upsport);
753
 
#endif
754
 
}
755
 
 
756
 
void sigdie(int sig)
757
 
{
758
 
        upslogx(LOG_INFO, "Signal %d: Shutting down", sig);
759
 
        exit (0);
760
 
}
761
 
 
762
 
/* install handler for sigterm */
763
 
void catch_sigterm(void)
764
 
{
765
 
        struct sigaction sa;
766
 
        sigset_t sigmask;
767
 
 
768
 
        sa.sa_handler = sigdie;
769
 
        sigemptyset (&sigmask);
770
 
        sa.sa_mask = sigmask;
771
 
        sa.sa_flags = 0;
772
 
        sigaction (SIGTERM, &sa, NULL);
773
 
}
774
 
 
775
 
/* clean up the local info storage for future use */
776
 
static void info_init()
777
 
{
778
 
        int     i;
779
 
 
780
 
        /* initialize the array */
781
 
        for (i = 0; i < infomax; i++)
782
 
                info[i].type = INFO_UNUSED;
783
 
 
784
 
        info[0].type = INFO_MEMBERS;
785
 
        snprintf(info[0].value, VALSIZE, "%i", infomax);
786
 
        infoused++;
787
 
 
788
 
        info[1].type = INFO_MTIME;
789
 
        snprintf(info[1].value, VALSIZE, "%ld", time(NULL));
790
 
        infoused++;
791
 
 
792
 
        info_mtime = &info[1];
793
 
 
794
 
        writeinfo();
795
 
}
796
 
 
797
 
#ifdef HAVE_SHMAT
798
 
 
799
 
/* create a shared memory struct for our info */
800
 
static int shm_create(void)
801
 
{
802
 
        key_t   shmkey = IPC_PRIVATE;
803
 
        itype   shminfo;
804
 
 
805
 
        /* get some shared memory */
806
 
        shmid = shmget(shmkey, sizeof(itype) * infomax, IPC_MODE);
807
 
 
808
 
        if (shmid == -1) {
809
 
                upslog(LOG_ERR, "shmget");
810
 
                shmid = -1;
811
 
                return 0;       /* failed */
812
 
        }
813
 
 
814
 
        /* got a good ID, so attach to it */
815
 
        shared_info = (itype *) shmat(shmid, 0, 0);
816
 
 
817
 
        if (shared_info == (itype *) (-1)) {
818
 
                upslog(LOG_ERR, "shmat");
819
 
                shmid = -1;
820
 
                return 0;       /* failed */
821
 
        }
822
 
 
823
 
        shminfo.type = INFO_SHMID;
824
 
        snprintf(shminfo.value, sizeof(shminfo.value), "%d", shmid);
825
 
 
826
 
        /* create state file with pointer to shm struct */
827
 
        writeshminfo(&shminfo);
828
 
 
829
 
        /* use the same mtime number in both places */
830
 
        info_init();
831
 
 
832
 
        return 1;       /* OK */
833
 
}       
834
 
 
835
 
#endif  /* HAVE_SHMAT */
836
 
 
837
 
/* start the state file, and possibly the shared memory struct too */
838
 
void create_info(int numinfo, int shmok)
839
 
{
840
 
        infomax = numinfo;
841
 
        info_size = infomax * sizeof(itype);
842
 
 
843
 
        info = xcalloc(1, info_size);
844
 
 
845
 
        /* make sure we clean up when exiting */
846
 
        catch_sigterm();
847
 
        signal(SIGINT, sigdie);
848
 
        signal(SIGQUIT, sigdie);
849
 
        if (atexit(cleanup))
850
 
                fatal("atexit");
851
 
 
852
 
        /* see if the state file can be created */
853
 
        test_writeinfo();
854
 
 
855
 
#ifdef HAVE_SHMAT
856
 
 
857
 
        /* SHM failures fall through and try normal mode */
858
 
        if ((shmok) && (shm_create()))
859
 
                return;
860
 
 
861
 
#endif
862
 
 
863
 
#ifdef HAVE_MMAP
864
 
        if (ftruncate(statefd, info_size))
865
 
                fatal("ftruncate");
866
 
 
867
 
        if ((shared_info = (itype *) mmap(NULL, info_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NOSYNC, statefd, 0)) == MAP_FAILED)
868
 
                fatal("mmap fd=%d size=%u", statefd, info_size);
869
 
#else /* HAVE_MMAP */
870
 
 
871
 
        shared_info = xcalloc(1, info_size);
872
 
 
873
 
#endif /* HAVE_MMAP */
874
 
 
875
 
        /* clean out some space for later */
876
 
        info_init();
877
 
}
878
 
 
879
 
/* add a member to the info struct */
880
 
void addinfo (int type, const char *value, int flags, int auxdata)
881
 
{
882
 
        int     i;
883
 
 
884
 
        for (i = 0; i < infomax; i++) {
885
 
                if (info[i].type == INFO_UNUSED) {      /* found open spot */
886
 
                        infoused++;
887
 
                        info[i].type = type;
888
 
                        strlcpy(info[i].value, value, sizeof(info[i].value));
889
 
                        info[i].flags = flags;
890
 
                        info[i].auxdata = auxdata;
891
 
                        return;
892
 
                }
893
 
        }
894
 
 
895
 
        upslogx(LOG_ERR, "Unable to add new member to info array!");
896
 
 
897
 
        return;
898
 
}
899
 
 
900
 
/* add a new ENUM info entry and do other related housekeeping */
901
 
void addenum (int basetype, const char *value)
902
 
{
903
 
        int     i;
904
 
 
905
 
        /* first find the basetype in the struct */
906
 
        for (i = 0; i < infomax; i++)
907
 
                if (info[i].type == basetype) {
908
 
 
909
 
                        /* add the enum value, then increment the enum count */
910
 
                        addinfo (INFO_ENUM, value, 0, basetype);
911
 
                        info[i].auxdata++;
912
 
                        return;
913
 
                }
914
 
 
915
 
        upslogx(LOG_ERR, "Unable to add enumerated type for base 0x%04x", basetype);
916
 
 
917
 
        return;
918
 
}
919
 
 
920
 
void createmsgq(void)
921
 
{
922
 
        /* init handlers early */
923
 
        memset (&upsh, '\0', sizeof(upsh));
924
 
 
925
 
        create_socket();
926
 
}
927
 
 
928
 
struct client_conn {
929
 
        int fd;
930
 
        struct sockaddr_un sa;
931
 
        struct client_conn *next;
932
 
        msgtype msg;
933
 
        size_t msg_len;
934
 
};
935
 
 
936
 
static struct client_conn *client_conn = NULL;
937
 
 
938
 
void close_client_conn(struct client_conn *cc)
939
 
{
940
 
        struct client_conn *t1, *t2;
941
 
 
942
 
        upsdebugx(1, "closing client_conn %p fd=%d", cc, cc->fd);
943
 
 
944
 
        for (t1 = client_conn, t2 = NULL; t1; t2 = t1, t1 = t1->next)
945
 
                if (cc == t1)
946
 
                        break;
947
 
 
948
 
        assert(t1 != NULL);
949
 
 
950
 
        if (t2)
951
 
                t2->next = cc->next;
952
 
        if (cc == client_conn)
953
 
                client_conn = cc->next;
954
 
 
955
 
        close(cc->fd);
956
 
        FD_CLR(cc->fd, &sock_rfds);
957
 
 
958
 
        if (cc->fd + 1 == sock_maxfd) {
959
 
                int maxfd = sock_fd;
960
 
 
961
 
                for (t1 = client_conn; t1; t1 = t1->next) {
962
 
                        if (t1->fd > maxfd)
963
 
                                maxfd = t1->fd;
964
 
                }
965
 
 
966
 
                sock_maxfd = maxfd + 1;
967
 
        }
968
 
 
969
 
        free(cc);
970
 
}
971
 
 
972
 
/* get a message if one's waiting in the queue */
973
 
int getupsmsg(int wait)
974
 
{
975
 
        struct timeval tv;
976
 
        fd_set  rfds;
977
 
        time_t  start_time;
978
 
        int     ret;
979
 
        struct client_conn *cc;
980
 
 
981
 
        memcpy(&rfds, &sock_rfds, sizeof(rfds));
982
 
 
983
 
        start_time = time(NULL);
984
 
 
985
 
        do {
986
 
                upsdebugx(3, "select loop maxfd=%d", sock_maxfd);
987
 
 
988
 
                tv.tv_sec = wait;
989
 
                tv.tv_usec = 0;
990
 
                ret = select(sock_maxfd, &rfds, NULL, NULL, &tv);
991
 
 
992
 
                if (ret == 0)
993
 
                        break;
994
 
                if (ret == -1) {
995
 
                        if (errno == EINTR)
996
 
                                continue;
997
 
                        else
998
 
                                fatal("select");
999
 
                }
1000
 
 
1001
 
                for (cc = client_conn; cc; cc = cc->next) {
1002
 
                        if (FD_ISSET(cc->fd, &rfds)) {
1003
 
                                switch ((ret = read(cc->fd, (char *) &cc->msg, sizeof(cc->msg) - cc->msg_len))) {
1004
 
                                case 0:
1005
 
                                case -1:
1006
 
                                        if (errno == 0 || errno == EINTR || errno == EAGAIN) /* try again the next time around */
1007
 
                                                break;
1008
 
 
1009
 
                                        upsdebug(1, "read %d bytes from fd %d", ret, cc->fd);
1010
 
                                        close_client_conn(cc);
1011
 
                                        break;
1012
 
                                default:
1013
 
                                        upsdebugx(1, "read %d bytes from fd %d", ret, cc->fd);
1014
 
 
1015
 
                                        cc->msg_len += ret;
1016
 
                                        upsdebugx(1, "msg_len=%d", cc->msg_len);
1017
 
 
1018
 
                                        if (cc->msg_len != sizeof(cc->msg)) /* buffer not full yet */
1019
 
                                                break;
1020
 
 
1021
 
                                        if (cc->msg.dlen >= UPSMSG_MAXLEN) {
1022
 
                                                upslogx(LOG_ERR, "client sent bad data - possible buffer overflow");
1023
 
                                                close_client_conn(cc);
1024
 
                                                break;
1025
 
                                        }
1026
 
 
1027
 
                                        switch (cc->msg.cmdtype) {
1028
 
                                        case UPSMSG_CMDSET:
1029
 
                                                if (upsh.setvar)
1030
 
                                                        upsh.setvar(cc->msg.auxcmd, cc->msg.dlen, cc->msg.data);
1031
 
                                                else
1032
 
                                                        upslogx(LOG_INFO, "No handler for SET command");
1033
 
                                                break;
1034
 
                                        case UPSMSG_INSTCMD:
1035
 
                                                if (upsh.instcmd)
1036
 
                                                        upsh.instcmd(cc->msg.auxcmd, cc->msg.dlen, cc->msg.data);
1037
 
                                                else
1038
 
                                                        upslogx(LOG_INFO, "No handler for INSTCMD command");
1039
 
                                                break;
1040
 
                                        default: 
1041
 
                                                upslogx(LOG_INFO, "Unknown msgcmd 0x%04x", cc->msg.cmdtype);
1042
 
                                        }               
1043
 
 
1044
 
                                        cc->msg_len = 0;
1045
 
 
1046
 
                                        upsdebugx(1, "finished message");
1047
 
                                }
1048
 
                        }
1049
 
                }
1050
 
 
1051
 
                if (FD_ISSET(sock_fd, &rfds)) {
1052
 
                        int sa_len;
1053
 
 
1054
 
                        cc = xcalloc(1, sizeof(struct client_conn));
1055
 
                        sa_len = sizeof(cc->sa);
1056
 
 
1057
 
                        if ((cc->fd = accept(sock_fd, (struct sockaddr *) &cc->sa, &sa_len)) != -1) {
1058
 
                                upsdebugx(1, "accept sock_fd fd=%d", cc->fd);
1059
 
 
1060
 
                                cc->next = client_conn;
1061
 
                                client_conn = cc;
1062
 
 
1063
 
                                FD_SET(cc->fd, &sock_rfds);
1064
 
                                if (cc->fd >= sock_maxfd)
1065
 
                                        sock_maxfd = cc->fd + 1;
1066
 
                        } else {
1067
 
                                upslog(LOG_NOTICE, "accept sock_fd");
1068
 
                                free(cc);
1069
 
                        }
1070
 
                }
1071
 
        } while (start_time + wait < time(NULL));
1072
 
 
1073
 
        return 0;
1074
 
}
1075
 
 
1076
 
/* add these functions back when a driver is capable of testing them.
1077
 
void sendupsmsg(struct client_conn *cc, const msgtype *msg)
1078
 
{
1079
 
        if (write(cc->fd, msg, sizeof(msgtype)) != sizeof(msgtype)) {
1080
 
                upslog(LOG_NOTICE, "write failed");
1081
 
                close_client_conn(cc);
1082
 
        }
1083
 
}
1084
 
 
1085
 
void msgreply(struct client_conn *cc, int reptype)
1086
 
{
1087
 
        msgtype msg;
1088
 
 
1089
 
        msg.cmdtype = reptype;
1090
 
        msg.auxcmd = 0;
1091
 
        msg.dlen = 0;
1092
 
        msg.data[0] = '\0';
1093
 
 
1094
 
        sendupsmsg(cc, &msg);
1095
 
}
1096
 
*/
1097
 
 
1098
 
/* modify in - strip all trailing instances of <sep> */
1099
 
void rtrim(char *in, char sep)
1100
 
{
1101
 
        char    *p = NULL;
1102
 
 
1103
 
        p = &in[strlen(in) - 1];
1104
 
 
1105
 
        while (p >= in) {
1106
 
                if (*p != sep)
1107
 
                        return;
1108
 
 
1109
 
                *p-- = '\0';
1110
 
        }
1111
 
}
1112
 
 
1113
 
/* try to unlock the port using any methods that are available */
1114
 
void unlockport (int upsfd, const char *port)
1115
 
{
1116
 
#ifdef HAVE_UU_LOCK
1117
 
        int res;
1118
 
    
1119
 
        if (!upsport)           /* not already locked? */
1120
 
                return;
1121
 
 
1122
 
        res = uu_unlock(upsport);
1123
 
 
1124
 
        /* free up allocated memory */
1125
 
        free(upsport);
1126
 
 
1127
 
        if (res != 0)
1128
 
                fatalx("Can't uu_unlock %s: %s", upsport, uu_lockerr(res));
1129
 
 
1130
 
#elif defined(HAVE_FLOCK)
1131
 
        if (flock(upsfd, LOCK_UN) != 0)
1132
 
                fatalx("can't unlock %s!", port);
1133
 
#elif defined(HAVE_LOCKF)
1134
 
        lseek(upsfd, 0L, SEEK_SET);
1135
 
        if (lockf(upsfd, F_ULOCK, 0L))
1136
 
                fatalx("can't unlock %s!", port);
1137
 
#endif
1138
 
}
1139
 
 
1140
 
/* close the state fd - used by the exiting parent */
1141
 
void close_statefd(void)
1142
 
{
1143
 
        close(statefd);
1144
 
}