1
/* serial.c - common serial port functions for Network UPS Tools drivers
3
Copyright (C) 2003 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
27
#include <sys/types.h>
29
#include <sys/termios.h>
37
extern int do_lock_port, exit_flag;
39
static unsigned int comm_failures = 0;
41
static void ser_open_error(const char *port)
49
printf("Unable to open %s: %s\n\n", port, strerror(errno));
51
/* check for bad port definitions first */
52
if (stat(port, &fs)) {
53
printf("Things to try:\n\n");
54
printf(" - Check 'port=' in ups.conf\n\n");
55
printf(" - Check owner/permissions of all parts of path\n\n");
56
fatalx("Fatal error: unusable configuration");
59
user = getpwuid(getuid());
62
printf(" Current user id: %s (%d)\n",
63
user->pw_name, (int) user->pw_uid);
65
user = getpwuid(fs.st_uid);
68
printf("Serial port owner: %s (%d)\n",
69
user->pw_name, (int) fs.st_uid);
71
group = getgrgid(fs.st_gid);
74
printf("Serial port group: %s (%d)\n",
75
group->gr_name, (int) fs.st_gid);
77
printf(" Mode of port: %04o\n\n", (int) fs.st_mode & 07777);
79
printf("Things to try:\n\n");
80
printf(" - Use another port (with the right permissions)\n\n");
81
printf(" - Fix the port owner/group or permissions on this port\n\n");
82
printf(" - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n");
83
printf(" See upsdrvctl(8) and ups.conf(5).\n\n");
85
fatalx("Fatal error: unusable configuration");
88
static void lock_set(int fd, const char *port)
93
fatal("lock_set: programming error: fd = %d", fd);
95
if (do_lock_port == 0)
99
ret = uu_lock(xbasename(port));
102
fatalx("Can't uu_lock %s: %s", xbasename(port),
107
#elif defined(HAVE_FLOCK)
109
ret = flock(fd, LOCK_EX | LOCK_NB);
112
fatalx("%s is locked by another process", port);
116
#elif defined(HAVE_LOCKF)
118
lseek(fd, 0L, SEEK_SET);
120
ret = lockf(fd, F_TLOCK, 0L);
123
fatalx("%s is locked by another process", port);
129
upslog(LOG_WARNING, "Warning: no locking method is available");
132
int ser_open(const char *port)
136
fd = open(port, O_RDWR | O_NOCTTY | O_EXCL | O_NONBLOCK);
139
ser_open_error(port);
146
int ser_set_speed(int fd, const char *port, speed_t speed)
150
if (tcgetattr(fd, &tio) != 0)
151
fatal("tcgetattr(%s)", port);
153
tio.c_cflag = CS8 | CLOCAL | CREAD;
154
tio.c_iflag = IGNPAR;
160
#ifdef HAVE_CFSETISPEED
161
cfsetispeed(&tio, speed);
162
cfsetospeed(&tio, speed);
164
#error This system lacks cfsetispeed() and has no other means to set the speed
167
tcflush(fd, TCIFLUSH);
168
tcsetattr(fd, TCSANOW, &tio);
173
int ser_close(int fd, const char *port)
176
fatal("ser_close: programming error: fd=%d port=%s", fd, port);
183
uu_unlock(xbasename(port));
189
int ser_send_char(int fd, char ch)
191
return write(fd, &ch, 1);
194
/* send the results of the format string with d_usec delay after each char */
195
unsigned int ser_send_pace(int fd, unsigned long d_usec, const char *fmt, ...)
200
unsigned int sent = 0;
204
ret = vsnprintf(buf, sizeof(buf), fmt, ap);
208
if ((ret < 1) || (ret >= (int) sizeof(buf)))
209
upslogx(LOG_WARNING, "ser_send_pace: vsnprintf needed more "
210
"than %d bytes", sizeof(buf));
212
for (p = buf; *p; p++) {
213
if (write(fd, p, 1) != 1)
225
/* send the results of the format string with no delay */
226
unsigned int ser_send(int fd, const char *fmt, ...)
234
ret = vsnprintf(buf, sizeof(buf), fmt, ap);
238
if ((ret < 1) || (ret >= (int) sizeof(buf)))
239
upslogx(LOG_WARNING, "ser_send: vsnprintf needed more "
240
"than %d bytes", sizeof(buf));
242
ret = write(fd, buf, strlen(buf));
247
/* send buflen bytes from buf with no delay */
248
int ser_send_buf(int fd, const char *buf, size_t buflen)
250
return (write(fd, buf, buflen));
253
/* send buflen bytes from buf with d_usec delay after each char */
254
int ser_send_buf_pace(int fd, unsigned long d_usec, const char *buf,
260
for (i = 0; i < buflen; i++) {
261
ret = ser_send_char(fd, buf[i]);
272
static int get_buf(int fd, char *buf, size_t buflen, long d_sec, long d_usec)
284
ret = select(fd + 1, &rfds, NULL, NULL, &tv);
288
upslog(LOG_ERR, "select fd %d", fd);
294
return -1; /* timeout */
296
ret = read(fd, buf, buflen);
299
return -1; /* read error */
304
int ser_get_char(int fd, char *ch, long d_sec, long d_usec)
306
return get_buf(fd, ch, 1, d_sec, d_usec);
309
/* keep reading until buflen bytes are received or a timeout occurs */
310
int ser_get_buf_len(int fd, char *buf, size_t buflen, long d_sec, long d_usec)
314
size_t count = 0, tmplen;
316
memset(buf, '\0', buflen);
318
/* don't use all of tmp if the caller has a small buffer */
319
tmplen = sizeof(tmp);
324
while (count < buflen) {
325
ret = get_buf(fd, tmp, tmplen, d_sec, d_usec);
330
for (i = 0; i < ret; i++) {
334
buf[count++] = tmp[i];
337
/* make sure we don't read too much next time */
338
tmplen = sizeof(tmp);
340
if ((buflen - count) < tmplen)
341
tmplen = buflen - count;
348
/* reads a line up to <endchar>, discarding anything else that may follow,
349
with callouts to the handler if anything matches the alertset */
350
int ser_get_line_alert(int fd, char *buf, size_t buflen, char endchar,
351
const char *ignset, const char *alertset, void handler(char ch),
352
long d_sec, long d_usec)
356
size_t count = 0, maxcount;
358
memset(buf, '\0', buflen);
360
maxcount = buflen - 1; /* for trailing \0 */
362
while (count < maxcount) {
363
ret = get_buf(fd, tmp, sizeof(tmp), d_sec, d_usec);
368
for (i = 0; i < ret; i++) {
370
if ((count == maxcount) || (tmp[i] == endchar)) {
375
if (strchr(ignset, tmp[i]))
378
if (strchr(alertset, tmp[i])) {
385
buf[count++] = tmp[i];
394
/* as above, only with no alertset handling (just a wrapper) */
395
int ser_get_line(int fd, char *buf, size_t buflen, char endchar,
396
const char *ignset, long d_sec, long d_usec)
398
return ser_get_line_alert(fd, buf, buflen, endchar, ignset, "", NULL,
402
int ser_flush_in(int fd, const char *ignset, int verbose)
407
while ((ret = ser_get_char(fd, &ch, 0, 0)) > 0) {
409
if (strchr(ignset, ch))
417
if (isprint(ch & 0xFF))
418
upslogx(LOG_INFO, "ser_flush_in: read char %c", ch);
420
upslogx(LOG_INFO, "ser_flush_in: read char 0x%02x", ch);
426
void ser_comm_fail(const char *fmt, ...)
432
/* this means we're probably here because select was interrupted */
434
return; /* ignored, since we're about to exit anyway */
438
if ((comm_failures == SER_ERR_LIMIT) ||
439
((comm_failures % SER_ERR_RATE) == 0)) {
440
upslogx(LOG_WARNING, "Warning: excessive comm failures, "
441
"limiting error reporting");
444
/* once it's past the limit, only log once every SER_ERR_LIMIT calls */
445
if ((comm_failures > SER_ERR_LIMIT) &&
446
((comm_failures % SER_ERR_LIMIT) != 0))
449
/* generic message if the caller hasn't elaborated */
451
upslogx(LOG_WARNING, "Communications with UPS lost"
457
ret = vsnprintf(why, sizeof(why), fmt, ap);
460
if ((ret < 1) || (ret >= (int) sizeof(why)))
461
upslogx(LOG_WARNING, "ser_comm_fail: vsnprintf needed "
462
"more than %d bytes", sizeof(why));
464
upslogx(LOG_WARNING, "Communications with UPS lost: %s", why);
467
void ser_comm_good(void)
469
if (comm_failures == 0)
472
upslogx(LOG_NOTICE, "Communications with UPS re-established");