1 /*
2  *  ser2net - A program for allowing telnet connection to serial ports
3  *  Copyright (C) 2001  Corey Minyard <minyard@acm.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 /* This code handles generating the configuration for the serial port. */
21 #include <unistd.h>
22 #include <termios.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <syslog.h>
33 
34 #include "ser2net.h"
35 #include "selector.h"
36 #include "utils.h"
37 #include "dataxfer.h"
38 #include "devio.h"
39 
40 #include <assert.h>
41 
42 struct devcfg_data {
43     /* Information about the terminal device. */
44     char           *devname;		/* The full path to the device */
45     int            devfd;		/* The file descriptor for the
46                                            device, only valid if the
47                                            TCP port is open. */
48     struct termios termctl;
49 
50     void (*shutdown_done)(struct devio *);
51 
52     int default_bps;
53     int default_data_size;
54     int default_stop_bits;
55     int default_parity_on;
56     int current_bps;
57     int current_data_size;
58     int current_stop_bits;
59     int current_parity_on;
60 
61     /* Holds whether break is on or not. */
62     int break_set;
63 
64     /* Disable break-commands */
65     int disablebreak;
66 
67 #if HAVE_DECL_TIOCSRS485
68     struct serial_rs485 *conf;
69 #endif
70 };
71 
72 static struct baud_rates_s {
73     int real_rate;
74     int val;
75     int cisco_ios_val;
76 } baud_rates[] =
77 {
78     { 50, B50, -1 },
79     { 75, B75, -1 },
80     { 110, B110, -1 },
81     { 134, B134, -1 },
82     { 150, B150, -1 },
83     { 200, B200, -1 },
84     { 300, B300, 3 },
85     { 600, B600 , 4},
86     { 1200, B1200, 5 },
87     { 1800, B1800, -1 },
88     { 2400, B2400, 6 },
89     { 4800, B4800, 7 },
90     { 9600, B9600, 8 },
91     /* We don't support 14400 baud */
92     { 19200, B19200, 10 },
93     /* We don't support 28800 baud */
94     { 38400, B38400, 12 },
95     { 57600, B57600, 13 },
96     { 115200, B115200, 14 },
97     { 230400, B230400, 15 },
98     /* We don't support 460800 baud */
99 };
100 #define BAUD_RATES_LEN ((sizeof(baud_rates) / sizeof(struct baud_rates_s)))
101 
102 static int
get_baud_rate(int rate,int * val,int cisco,int * bps)103 get_baud_rate(int rate, int *val, int cisco, int *bps)
104 {
105     unsigned int i;
106     for (i = 0; i < BAUD_RATES_LEN; i++) {
107 	if (cisco) {
108 	    if (rate == baud_rates[i].cisco_ios_val) {
109 		*val = baud_rates[i].val;
110 		*bps = baud_rates[i].real_rate;
111 		return 1;
112 	    }
113 	} else {
114 	    if (rate == baud_rates[i].real_rate) {
115 		*val = baud_rates[i].val;
116 		*bps = baud_rates[i].real_rate;
117 		return 1;
118 	    }
119 	}
120     }
121 
122     return 0;
123 }
124 
125 static void
get_rate_from_baud_rate(int baud_rate,int * val,int cisco)126 get_rate_from_baud_rate(int baud_rate, int *val, int cisco)
127 {
128     unsigned int i;
129     for (i = 0; i < BAUD_RATES_LEN; i++) {
130 	if (baud_rate == baud_rates[i].val) {
131 	    if (cisco) {
132 		if (baud_rates[i].cisco_ios_val < 0)
133 		    /* We are at a baud rate unsupported by the
134 		       enumeration, just return zero. */
135 		    *val = 0;
136 		else
137 		    *val = baud_rates[i].cisco_ios_val;
138 	    } else {
139 		*val = baud_rates[i].real_rate;
140 	    }
141 	    return;
142 	}
143     }
144 }
145 
146 #ifdef USE_UUCP_LOCKING
147 static char *uucp_lck_dir = "/var/spool/lock/";
148 static char *dev_prefix = "/dev/";
149 
150 static int
uucp_fname_lock_size(char * devname)151 uucp_fname_lock_size(char *devname)
152 {
153     int dev_prefix_len = strlen(dev_prefix);
154 
155     if (strncmp(dev_prefix, devname, dev_prefix_len) == 0)
156 	devname += dev_prefix_len;
157 
158     /*
159      * Format is "/var/lock/LCK..<devname>".  The 6 is for
160      * the "LCK.." and the final nil char.
161      */
162     return 6 + strlen(uucp_lck_dir) + strlen(devname);
163 }
164 
165 static void
uucp_fname_lock(char * buf,char * devname)166 uucp_fname_lock(char *buf, char *devname)
167 {
168     int i, dev_prefix_len = strlen(dev_prefix);
169 
170     if (strncmp(dev_prefix, devname, dev_prefix_len) == 0)
171 	devname += dev_prefix_len;
172 
173     sprintf(buf, "%sLCK..%s", uucp_lck_dir, devname);
174     for (i = strlen(uucp_lck_dir); buf[i]; i++) {
175 	if (buf[i] == '/')
176 	    buf[i] = '_';
177     }
178 }
179 
180 static void
uucp_rm_lock(char * devname)181 uucp_rm_lock(char *devname)
182 {
183     char *lck_file;
184 
185     if (!uucp_locking_enabled) return;
186 
187     lck_file = malloc(uucp_fname_lock_size(devname));
188     if (lck_file == NULL) {
189 	return;
190     }
191     uucp_fname_lock(lck_file, devname);
192     unlink(lck_file);
193     free(lck_file);
194 }
195 
196 /* return 0=OK, -1=error, 1=locked by other proces */
197 static int
uucp_mk_lock(char * devname)198 uucp_mk_lock(char *devname)
199 {
200     struct stat stt;
201     int pid = -1;
202 
203     if (!uucp_locking_enabled)
204 	return 0;
205 
206     if (stat(uucp_lck_dir, &stt) == 0) { /* is lock file directory present? */
207 	char *lck_file;
208 	union {
209 	    uint32_t ival;
210 	    char     str[64];
211 	} buf;
212 	int fd;
213 
214 	lck_file = malloc(uucp_fname_lock_size(devname));
215 	if (lck_file == NULL)
216 	    return -1;
217 
218 	uucp_fname_lock(lck_file, devname);
219 
220 	pid = 0;
221 	if ((fd = open(lck_file, O_RDONLY)) >= 0) {
222 	    int n;
223 
224 	    n = read(fd, &buf, sizeof(buf) - 1);
225 	    close(fd);
226 	    if (n == 4) 		/* Kermit-style lockfile. */
227 		pid = buf.ival;
228 	    else if (n > 0) {		/* Ascii lockfile. */
229 		buf.str[n] = '\0';
230 		sscanf(buf.str, "%10d", &pid);
231 	    }
232 
233 	    if (pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH) {
234 		/* death lockfile - remove it */
235 		unlink(lck_file);
236 		pid = 0;
237 	    } else
238 		pid = 1;
239 
240 	}
241 
242 	if (pid == 0) {
243 	    int mask;
244 
245 	    mask = umask(022);
246 	    fd = open(lck_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
247 	    umask(mask);
248 	    if (fd >= 0) {
249 	        ssize_t rv;
250 
251 		snprintf(buf.str, sizeof(buf), "%10ld\n",
252 			 (long)getpid());
253 		rv = write_full(fd, buf.str, strlen(buf.str));
254 		close(fd);
255 		if (rv < 0) {
256 		    pid = -1;
257 		    unlink(lck_file);
258 		}
259 	    } else {
260 		pid = -1;
261 	    }
262 	}
263 
264 	free(lck_file);
265     }
266 
267     return pid;
268 }
269 #else
uucp_rm_lock(char * devname)270 static void uucp_rm_lock(char *devname) { }
uucp_mk_lock(char * devname)271 static int uucp_mk_lock(char *devname)
272 {
273     return 0;
274 }
275 #endif /* USE_UUCP_LOCKING */
276 
277 #ifdef __CYGWIN__
cfmakeraw(struct termios * termios_p)278 static void cfmakeraw(struct termios *termios_p) {
279     termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
280     termios_p->c_oflag &= ~OPOST;
281     termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
282     termios_p->c_cflag &= ~(CSIZE|PARENB);
283     termios_p->c_cflag |= CS8;
284 }
285 #endif
286 
287 static int
set_termios_from_speed(struct devcfg_data * d,struct termios * termctl,int speed)288 set_termios_from_speed(struct devcfg_data *d, struct termios *termctl,
289 		       int speed)
290 {
291     switch (speed) {
292     case 300:
293 	cfsetospeed(termctl, B300);
294 	cfsetispeed(termctl, B300);
295 	break;
296 
297     case 600:
298 	cfsetospeed(termctl, B600);
299 	cfsetispeed(termctl, B600);
300 	break;
301 
302     case 1200:
303 	cfsetospeed(termctl, B1200);
304 	cfsetispeed(termctl, B1200);
305 	break;
306 
307     case 2400:
308 	cfsetospeed(termctl, B2400);
309 	cfsetispeed(termctl, B2400);
310 	break;
311 
312     case 4800:
313 	cfsetospeed(termctl, B4800);
314 	cfsetispeed(termctl, B4800);
315 	break;
316 
317     case 9600:
318 	cfsetospeed(termctl, B9600);
319 	cfsetispeed(termctl, B9600);
320 	break;
321 
322     case 19200:
323 	cfsetospeed(termctl, B19200);
324 	cfsetispeed(termctl, B19200);
325 	break;
326 
327     case 38400:
328 	cfsetospeed(termctl, B38400);
329 	cfsetispeed(termctl, B38400);
330 	break;
331 
332     case 57600:
333 	cfsetospeed(termctl, B57600);
334 	cfsetispeed(termctl, B57600);
335 	break;
336 
337     case 115200:
338 	cfsetospeed(termctl, B115200);
339 	cfsetispeed(termctl, B115200);
340 	break;
341 
342 #ifdef B230400
343     case 230400:
344 	cfsetospeed(termctl, B230400);
345 	cfsetispeed(termctl, B230400);
346 	break;
347 #endif
348 #ifdef B460800
349     case 460800:
350 	cfsetospeed(termctl, B460800);
351 	cfsetispeed(termctl, B460800);
352 	break;
353 #endif
354 #ifdef B500000
355     case 500000:
356 	cfsetospeed(termctl, B500000);
357 	cfsetispeed(termctl, B500000);
358 	break;
359 #endif
360 #ifdef B576000
361     case 576000:
362 	cfsetospeed(termctl, B576000);
363 	cfsetispeed(termctl, B576000);
364 	break;
365 #endif
366 #ifdef B921600
367     case 921600:
368 	cfsetospeed(termctl, B921600);
369 	cfsetispeed(termctl, B921600);
370 	break;
371 #endif
372 #ifdef B1000000
373     case 1000000:
374 	cfsetospeed(termctl, B1000000);
375 	cfsetispeed(termctl, B1000000);
376 	break;
377 #endif
378 #ifdef B1152000
379     case 1152000:
380 	cfsetospeed(termctl, B1152000);
381 	cfsetispeed(termctl, B1152000);
382 	break;
383 #endif
384 #ifdef B1500000
385     case 1500000:
386 	cfsetospeed(termctl, B1500000);
387 	cfsetispeed(termctl, B1500000);
388 	break;
389 #endif
390 #ifdef B2000000
391     case 2000000:
392 	cfsetospeed(termctl, B2000000);
393 	cfsetispeed(termctl, B2000000);
394 	break;
395 #endif
396 #ifdef B2500000
397     case 2500000:
398 	cfsetospeed(termctl, B2500000);
399 	cfsetispeed(termctl, B2500000);
400 	break;
401 #endif
402 #ifdef B3000000
403     case 3000000:
404 	cfsetospeed(termctl, B3000000);
405 	cfsetispeed(termctl, B3000000);
406 	break;
407 #endif
408 #ifdef B3500000
409     case 3500000:
410 	cfsetospeed(termctl, B3500000);
411 	cfsetispeed(termctl, B3500000);
412 	break;
413 #endif
414 #ifdef B4000000
415     case 4000000:
416 	cfsetospeed(termctl, B4000000);
417 	cfsetispeed(termctl, B4000000);
418 	break;
419 #endif
420     default:
421 	return -1;
422     }
423 
424     d->default_bps = speed;
425     return 0;
426 }
427 
428 static void
set_termios_parity(struct devcfg_data * d,struct termios * termctl,enum parity_vals val)429 set_termios_parity(struct devcfg_data *d, struct termios *termctl,
430 		   enum parity_vals val)
431 {
432     switch (val) {
433     case PARITY_NONE:
434 	termctl->c_cflag &= ~(PARENB);
435 	break;
436     case PARITY_EVEN:
437     case PARITY_SPACE:
438 	termctl->c_cflag |= PARENB;
439 	termctl->c_cflag &= ~(PARODD);
440 #ifdef CMSPAR
441 	if (val == PARITY_SPACE)
442 	    termctl->c_cflag |= CMSPAR;
443 #endif
444 	break;
445     case PARITY_ODD:
446     case PARITY_MARK:
447 	termctl->c_cflag |= PARENB | PARODD;
448 #ifdef CMSPAR
449 	if (val == PARITY_MARK)
450 	    termctl->c_cflag |= CMSPAR;
451 #endif
452 	break;
453     }
454     d->default_parity_on = val != PARITY_NONE;
455 }
456 
457 static void
set_termios_xonoff(struct termios * termctl,int enabled)458 set_termios_xonoff(struct termios *termctl, int enabled)
459 {
460     if (enabled) {
461 	termctl->c_iflag |= (IXON | IXOFF | IXANY);
462 	termctl->c_cc[VSTART] = 17;
463 	termctl->c_cc[VSTOP] = 19;
464     } else {
465 	termctl->c_iflag &= ~(IXON | IXOFF | IXANY);
466     }
467 }
468 
469 static void
set_termios_rtscts(struct termios * termctl,int enabled)470 set_termios_rtscts(struct termios *termctl, int enabled)
471 {
472     if (enabled)
473 	termctl->c_cflag |= CRTSCTS;
474     else
475 	termctl->c_cflag &= ~CRTSCTS;
476 }
477 
478 static void
set_termios_datasize(struct devcfg_data * d,struct termios * termctl,int size)479 set_termios_datasize(struct devcfg_data *d, struct termios *termctl, int size)
480 {
481     termctl->c_cflag &= ~CSIZE;
482     switch (size) {
483     case 5: termctl->c_cflag |= CS5; break;
484     case 6: termctl->c_cflag |= CS6; break;
485     case 7: termctl->c_cflag |= CS7; break;
486     case 8: termctl->c_cflag |= CS8; break;
487     }
488     d->default_data_size = size;
489 }
490 
491 /* Initialize a serial port control structure for the first time.
492    This should only be called when the port is created.  It sets the
493    port to the default 9600N81. */
494 static void
devinit(struct devcfg_data * d,struct termios * termctl)495 devinit(struct devcfg_data *d, struct termios *termctl)
496 {
497     cfmakeraw(termctl);
498 
499     set_termios_from_speed(d, termctl, find_default_int("speed"));
500     set_termios_datasize(d, termctl, find_default_int("databits"));
501     d->default_stop_bits = find_default_int("stopbits");
502     if (d->default_stop_bits == 1)
503 	termctl->c_cflag &= ~(CSTOPB);
504     else
505 	termctl->c_cflag |= CSTOPB;
506 
507     set_termios_parity(d, termctl, find_default_int("parity"));
508     set_termios_xonoff(termctl, find_default_int("xonxoff"));
509     set_termios_rtscts(termctl, find_default_int("rtscts"));
510 
511     if (find_default_int("local"))
512 	termctl->c_cflag |= CLOCAL;
513     else
514 	termctl->c_cflag &= ~CLOCAL;
515 
516     if (find_default_int("hangup_when_done"))
517 	termctl->c_cflag &= HUPCL;
518     else
519 	termctl->c_cflag &= ~HUPCL;
520 
521     d->disablebreak = find_default_int("nobreak");
522 
523     termctl->c_cflag |= CREAD;
524     termctl->c_iflag |= IGNBRK;
525 }
526 
527 /* Configure a serial port control structure based upon input strings
528    in instr.  These strings are described in the man page for this
529    program. */
530 static int
devconfig(struct devcfg_data * d,struct absout * eout,const char * instr,int (* otherconfig)(void * data,struct absout * eout,const char * item),void * data)531 devconfig(struct devcfg_data *d, struct absout *eout, const char *instr,
532 	  int (*otherconfig)(void *data, struct absout *eout, const char *item),
533 	  void *data)
534 {
535     struct termios *termctl = &d->termctl;
536     char *str;
537     char *pos;
538     char *strtok_data;
539     int  rv = 0, val;
540 
541     devinit(d, termctl);
542 
543     str = strdup(instr);
544     if (str == NULL) {
545 	return -1;
546     }
547 
548     pos = strtok_r(str, " \t", &strtok_data);
549     while (pos != NULL) {
550 	if ((val = speedstr_to_speed(pos)) != -1) {
551 	    rv = set_termios_from_speed(d, termctl, val);
552 	    if (rv) {
553 		eout->out(eout, "Invalid baud rate: %d\n", d->default_bps);
554 		goto out;
555 	    }
556 	} else if (strcmp(pos, "1STOPBIT") == 0) {
557 	    termctl->c_cflag &= ~(CSTOPB);
558 	    d->default_stop_bits = 1;
559 	} else if (strcmp(pos, "2STOPBITS") == 0) {
560 	    termctl->c_cflag |= CSTOPB;
561 	    d->default_stop_bits = 2;
562 	} else if (strcmp(pos, "5DATABITS") == 0) {
563 	    set_termios_datasize(d, termctl, 5);
564 	} else if (strcmp(pos, "6DATABITS") == 0) {
565 	    set_termios_datasize(d, termctl, 6);
566 	} else if (strcmp(pos, "7DATABITS") == 0) {
567 	    set_termios_datasize(d, termctl, 7);
568 	} else if (strcmp(pos, "8DATABITS") == 0) {
569 	    set_termios_datasize(d, termctl, 8);
570 	} else if ((val = lookup_parity(pos)) != -1) {
571 	    set_termios_parity(d, termctl, val);
572         } else if (strcmp(pos, "XONXOFF") == 0) {
573 	    set_termios_xonoff(termctl, 1);
574         } else if (strcmp(pos, "-XONXOFF") == 0) {
575 	    set_termios_xonoff(termctl, 0);
576         } else if (strcmp(pos, "RTSCTS") == 0) {
577 	    set_termios_rtscts(termctl, 1);
578         } else if (strcmp(pos, "-RTSCTS") == 0) {
579 	    set_termios_rtscts(termctl, 0);
580         } else if (strcmp(pos, "LOCAL") == 0) {
581             termctl->c_cflag |= CLOCAL;
582         } else if (strcmp(pos, "-LOCAL") == 0) {
583             termctl->c_cflag &= ~CLOCAL;
584         } else if (strcmp(pos, "HANGUP_WHEN_DONE") == 0) {
585             termctl->c_cflag |= HUPCL;
586         } else if (strcmp(pos, "-HANGUP_WHEN_DONE") == 0) {
587             termctl->c_cflag &= ~HUPCL;
588 	} else if (strcmp(pos, "NOBREAK") == 0) {
589 	    d->disablebreak = 1;
590 	} else if (strcmp(pos, "-NOBREAK") == 0) {
591 	    d->disablebreak = 0;
592 	} else {
593 	    if (otherconfig(data, eout, pos) == -1)
594 		goto out;
595 	}
596 
597 	pos = strtok_r(NULL, " \t", &strtok_data);
598     }
599 
600 #if HAVE_DECL_TIOCSRS485
601     d->conf = get_rs485_conf(data);
602 #endif
603  out:
604     free(str);
605     return rv;
606 }
607 
608 static char *
baud_string(int speed)609 baud_string(int speed)
610 {
611     char *str;
612     switch (speed) {
613     case B300: str = "300"; break;
614     case B600: str = "600"; break;
615     case B1200: str = "1200"; break;
616     case B2400: str = "2400"; break;
617     case B4800: str = "4800"; break;
618     case B9600: str = "9600"; break;
619     case B19200: str = "19200"; break;
620     case B38400: str = "38400"; break;
621     case B57600: str = "57600"; break;
622     case B115200: str = "115200"; break;
623 #ifdef B230400
624     case B230400: str = "230400"; break;
625 #endif
626 #ifdef B460800
627     case B460800: str = "460800"; break;
628 #endif
629 #ifdef B500000
630     case B500000: str = "500000"; break;
631 #endif
632 #ifdef B576000
633     case B576000: str = "576000"; break;
634 #endif
635 #ifdef B921600
636     case B921600: str = "921600"; break;
637 #endif
638 #ifdef B1000000
639     case B1000000: str = "1000000"; break;
640 #endif
641 #ifdef B1152000
642     case B1152000: str = "1152000"; break;
643 #endif
644 #ifdef B1500000
645     case B1500000: str = "1500000"; break;
646 #endif
647 #ifdef B2000000
648     case B2000000: str = "2000000"; break;
649 #endif
650 #ifdef B2500000
651     case B2500000: str = "2500000"; break;
652 #endif
653 #ifdef B3000000
654     case B3000000: str = "3000000"; break;
655 #endif
656 #ifdef B3500000
657     case B3500000: str = "3500000"; break;
658 #endif
659 #ifdef B4000000
660     case B4000000: str = "4000000"; break;
661 #endif
662     default: str = "unknown speed";
663     }
664     return str;
665 }
666 
667 static void
devcfg_serparm_to_str(struct devio * io,char * str,int strlen)668 devcfg_serparm_to_str(struct devio *io, char *str, int strlen)
669 {
670     struct devcfg_data *d = io->my_data;
671     struct termios *termctl = &d->termctl;
672     speed_t speed = cfgetospeed(termctl);
673     int     stopbits = termctl->c_cflag & CSTOPB;
674     int     databits = termctl->c_cflag & CSIZE;
675     int     parity_enabled = termctl->c_cflag & PARENB;
676     int     parity = termctl->c_cflag & PARODD;
677     char    *sstr;
678     char    pchar, schar, dchar;
679 
680     sstr = baud_string(speed);
681 
682     if (stopbits)
683 	schar = '2';
684     else
685 	schar = '1';
686 
687     switch (databits) {
688     case CS7: dchar = '7'; break;
689     case CS8: dchar = '8'; break;
690     default: dchar = '?';
691     }
692 
693     if (parity_enabled) {
694 	if (parity) {
695 	    pchar = 'O';
696 	} else {
697 	    pchar = 'E';
698 	}
699     } else {
700 	pchar = 'N';
701     }
702 
703     snprintf(str, strlen, "%s %c%c%c", sstr, pchar, dchar, schar);
704 }
705 
706 /* Send the serial port device configuration to the control port. */
707 static void
devcfg_show_devcfg(struct devio * io,struct absout * out)708 devcfg_show_devcfg(struct devio *io, struct absout *out)
709 {
710     struct devcfg_data *d = io->my_data;
711     struct termios *termctl = &d->termctl;
712 
713     speed_t speed = cfgetospeed(termctl);
714     int     stopbits = termctl->c_cflag & CSTOPB;
715     int     databits = termctl->c_cflag & CSIZE;
716     int     parity_enabled = termctl->c_cflag & PARENB;
717     int     parity = termctl->c_cflag & PARODD;
718     int     xon = termctl->c_iflag & IXON;
719     int     xoff = termctl->c_iflag & IXOFF;
720     int     xany = termctl->c_iflag & IXANY;
721     int     flow_rtscts = termctl->c_cflag & CRTSCTS;
722     int     clocal = termctl->c_cflag & CLOCAL;
723     int     hangup_when_done = termctl->c_cflag & HUPCL;
724     char    *str;
725 
726     out->out(out, "%s ", baud_string(speed));
727 
728     if (xon && xoff && xany) {
729       out->out(out, "XONXOFF ");
730     }
731 
732     if (flow_rtscts) {
733       out->out(out, "RTSCTS ");
734     }
735 
736     if (clocal) {
737       out->out(out, "LOCAL ");
738     }
739 
740     if (hangup_when_done) {
741       out->out(out, "HANGUP_WHEN_DONE ");
742     }
743 
744     if (stopbits) {
745 	str = "2STOPBITS";
746     } else {
747 	str = "1STOPBIT";
748     }
749     out->out(out, "%s ", str);
750 
751     switch (databits) {
752     case CS7: str = "7DATABITS"; break;
753     case CS8: str = "8DATABITS"; break;
754     default: str = "unknown databits";
755     }
756     out->out(out, "%s ", str);
757 
758     if (parity_enabled) {
759 	if (parity) {
760 	    str = "ODD";
761 	} else {
762 	    str = "EVEN";
763 	}
764     } else {
765 	str = "NONE";
766     }
767     out->out(out, "%s", str);
768 }
769 
770 static int
devcfg_set_devcontrol(struct devio * io,const char * instr)771 devcfg_set_devcontrol(struct devio *io, const char *instr)
772 {
773     struct devcfg_data *d = io->my_data;
774     int fd = d->devfd;
775     int rv = 0;
776     char *str;
777     char *pos;
778     int status;
779     char *strtok_data;
780 
781     str = malloc(strlen(instr) + 1);
782     if (str == NULL) {
783 	return -1;
784     }
785 
786     strcpy(str, instr);
787 
788     pos = strtok_r(str, " \t", &strtok_data);
789     while (pos != NULL) {
790        if (strcmp(pos, "RTSHI") == 0) {
791            ioctl(fd, TIOCMGET, &status);
792            status |= TIOCM_RTS;
793            ioctl(fd, TIOCMSET, &status);
794        } else if (strcmp(pos, "RTSLO") == 0) {
795            ioctl(fd, TIOCMGET, &status);
796            status &= ~TIOCM_RTS;
797            ioctl(fd, TIOCMSET, &status);
798        } else if (strcmp(pos, "DTRHI") == 0) {
799            ioctl(fd, TIOCMGET, &status);
800            status |= TIOCM_DTR;
801            ioctl(fd, TIOCMSET, &status);
802        } else if (strcmp(pos, "DTRLO") == 0) {
803            ioctl(fd, TIOCMGET, &status);
804            status &= ~TIOCM_DTR;               /* AKA drop DTR */
805            ioctl(fd, TIOCMSET, &status);
806 	} else {
807 	    rv = -1;
808 	    goto out;
809 	}
810 
811 	pos = strtok_r(NULL, " \t", &strtok_data);
812     }
813 
814 out:
815     free(str);
816     return rv;
817 }
818 
819 static void
devcfg_show_devcontrol(struct devio * io,struct absout * out)820 devcfg_show_devcontrol(struct devio *io, struct absout *out)
821 {
822     struct devcfg_data *d = io->my_data;
823     char *str;
824     int  status;
825 
826     ioctl(d->devfd, TIOCMGET, &status);
827 
828     if (status & TIOCM_RTS) {
829 	str = "RTSHI";
830     } else {
831 	str = "RTSLO";
832     }
833     out->out(out, "%s ", str);
834 
835     if (status & TIOCM_DTR) {
836 	str = "DTRHI";
837     } else {
838 	str = "DTRLO";
839     }
840     out->out(out, "%s ", str);
841 }
842 
843 static void
do_read(int fd,void * data)844 do_read(int fd, void *data)
845 {
846     struct devio *io = data;
847     io->read_handler(io);
848 }
849 
850 static void
do_write(int fd,void * data)851 do_write(int fd, void *data)
852 {
853     struct devio *io = data;
854     io->write_handler(io);
855 }
856 
857 static void
do_except(int fd,void * data)858 do_except(int fd, void *data)
859 {
860     struct devio *io = data;
861     io->except_handler(io);
862 }
863 
calc_bpc(struct devcfg_data * d)864 static int calc_bpc(struct devcfg_data *d)
865 {
866     return d->current_data_size + d->current_stop_bits +
867 	d->current_parity_on + 1;
868 }
869 
870 static void
devfd_fd_cleared(int fd,void * cb_data)871 devfd_fd_cleared(int fd, void *cb_data)
872 {
873     struct devio *io = cb_data;
874     struct devcfg_data *d = io->my_data;
875     void (*shutdown_done)(struct devio *) = d->shutdown_done;
876     struct termios termio;
877 
878     /* Disable flow control to avoid a long shutdown. */
879     if (tcgetattr(d->devfd, &termio) != -1) {
880 	termio.c_iflag &= ~(IXON | IXOFF);
881 	termio.c_cflag &= ~CRTSCTS;
882 	tcsetattr(d->devfd, TCSANOW, &termio);
883     }
884     tcflush(d->devfd, TCOFLUSH);
885     close(d->devfd);
886     d->devfd = -1;
887     uucp_rm_lock(io->devname);
888     shutdown_done(io);
889 }
890 
devcfg_setup(struct devio * io,const char * name,const char ** errstr,int * bps,int * bpc)891 static int devcfg_setup(struct devio *io, const char *name, const char **errstr,
892 			int *bps, int *bpc)
893 {
894     struct devcfg_data *d = io->my_data;
895     int options;
896     int rv;
897 
898     rv = uucp_mk_lock(io->devname);
899     if (rv > 0 ) {
900 	*errstr = "Port already in use by another process\r\n";
901 	return -1;
902     } else if (rv < 0) {
903 	*errstr = "Error creating port lock file\r\n";
904 	return -1;
905     }
906 
907     *bps = d->current_bps = d->default_bps;
908     d->current_data_size = d->default_data_size;
909     d->current_stop_bits = d->default_stop_bits;
910     d->current_parity_on = d->default_parity_on;
911     *bpc = calc_bpc(d);
912 
913     /* Oct 05 2001 druzus: NOCTTY - don't make
914        device control tty for our process */
915     options = O_NONBLOCK | O_NOCTTY;
916     if (io->read_disabled) {
917 	options |= O_WRONLY;
918     } else {
919 	options |= O_RDWR;
920     }
921     d->devfd = open(io->devname, options);
922     if (d->devfd == -1) {
923 	syslog(LOG_ERR, "Could not open device %s for port %s: %m",
924 	       io->devname,
925 	       name);
926 	uucp_rm_lock(io->devname);
927 	return -1;
928     }
929 
930     if (!io->read_disabled && tcsetattr(d->devfd, TCSANOW, &d->termctl) == -1)
931     {
932 	close(d->devfd);
933 	d->devfd = -1;
934 	syslog(LOG_ERR, "Could not set up device %s for port %s: %m",
935 	       io->devname,
936 	       name);
937 	uucp_rm_lock(io->devname);
938 	return -1;
939     }
940 
941     /* Turn off BREAK. */
942     if (!io->read_disabled && !d->disablebreak
943 	&& ioctl(d->devfd, TIOCCBRK) == -1) {
944 	/* Probably not critical, but we should at least log something. */
945 	syslog(LOG_ERR, "Could not turn off break for device %s port %s: %m",
946 	       io->devname,
947 	       name);
948     }
949 
950 #if HAVE_DECL_TIOCSRS485
951     if (d->conf) {
952         if (d->conf->flags & SER_RS485_ENABLED) {
953             if (ioctl(d->devfd , TIOCSRS485, d->conf ) < 0) {
954                 syslog(LOG_ERR, "Could not set RS485 config for device %s port %s: %m",
955                        io->devname,
956                        name);
957                 return -1;
958             }
959         }
960     }
961 #endif
962 
963     sel_set_fd_handlers(ser2net_sel, d->devfd, io,
964 			io->read_disabled ? NULL : do_read,
965 			do_write, do_except, devfd_fd_cleared);
966     return 0;
967 }
968 
devcfg_shutdown(struct devio * io,void (* shutdown_done)(struct devio *))969 static void devcfg_shutdown(struct devio *io,
970 			    void (*shutdown_done)(struct devio *))
971 {
972     struct devcfg_data *d = io->my_data;
973 
974     /* To avoid blocking on close if we have written bytes and are in
975        flow-control, we flush the output queue. */
976     if (d->devfd != -1) {
977 	d->shutdown_done = shutdown_done;
978 	sel_clear_fd_handlers(ser2net_sel, d->devfd);
979     } else {
980 	shutdown_done(io);
981     }
982 }
983 
devcfg_read(struct devio * io,void * buf,size_t size)984 static int devcfg_read(struct devio *io, void *buf, size_t size)
985 {
986     struct devcfg_data *d = io->my_data;
987 
988     return read(d->devfd, buf, size);
989 }
990 
devcfg_write(struct devio * io,void * buf,size_t size)991 static int devcfg_write(struct devio *io, void *buf, size_t size)
992 {
993     struct devcfg_data *d = io->my_data;
994 
995     return write(d->devfd, buf, size);
996 }
997 
devcfg_read_handler_enable(struct devio * io,int enabled)998 static void devcfg_read_handler_enable(struct devio *io, int enabled)
999 {
1000     struct devcfg_data *d = io->my_data;
1001 
1002     sel_set_fd_read_handler(ser2net_sel, d->devfd,
1003 			    enabled ? SEL_FD_HANDLER_ENABLED :
1004 			    SEL_FD_HANDLER_DISABLED);
1005 }
1006 
devcfg_write_handler_enable(struct devio * io,int enabled)1007 static void devcfg_write_handler_enable(struct devio *io, int enabled)
1008 {
1009     struct devcfg_data *d = io->my_data;
1010 
1011     sel_set_fd_write_handler(ser2net_sel, d->devfd,
1012 			     enabled ? SEL_FD_HANDLER_ENABLED :
1013 			     SEL_FD_HANDLER_DISABLED);
1014 }
1015 
devcfg_except_handler_enable(struct devio * io,int enabled)1016 static void devcfg_except_handler_enable(struct devio *io, int enabled)
1017 {
1018     struct devcfg_data *d = io->my_data;
1019 
1020     sel_set_fd_except_handler(ser2net_sel, d->devfd,
1021 			      enabled ? SEL_FD_HANDLER_ENABLED :
1022 			      SEL_FD_HANDLER_DISABLED);
1023 }
1024 
devcfg_send_break(struct devio * io)1025 static int devcfg_send_break(struct devio *io)
1026 {
1027     struct devcfg_data *d = io->my_data;
1028 
1029     tcsendbreak(d->devfd, 0);
1030     return 0;
1031 }
1032 
devcfg_get_modem_state(struct devio * io,unsigned char * modemstate)1033 static int devcfg_get_modem_state(struct devio *io, unsigned char *modemstate)
1034 {
1035     struct devcfg_data *d = io->my_data;
1036     int val;
1037 
1038     if (ioctl(d->devfd, TIOCMGET, &val) != 0)
1039 	return -1;
1040 
1041     *modemstate = 0;
1042     if (val & TIOCM_CD)
1043 	*modemstate |= 0x80;
1044     if (val & TIOCM_RI)
1045 	*modemstate |= 0x40;
1046     if (val & TIOCM_DSR)
1047 	*modemstate |= 0x20;
1048     if (val & TIOCM_CTS)
1049 	*modemstate |= 0x10;
1050     return 0;
1051 }
1052 
devcfg_baud_rate(struct devio * io,int * val,int cisco,int * bps)1053 static int devcfg_baud_rate(struct devio *io, int *val, int cisco, int *bps)
1054 {
1055     struct devcfg_data *d = io->my_data;
1056     struct termios termio;
1057 
1058     if (tcgetattr(d->devfd, &termio) == -1) {
1059 	*val = 0;
1060 	return -1;
1061     }
1062 
1063     if ((*val != 0) && (get_baud_rate(*val, val, cisco, bps))) {
1064 	/* We have a valid baud rate. */
1065 	cfsetispeed(&termio, *val);
1066 	cfsetospeed(&termio, *val);
1067 	tcsetattr(d->devfd, TCSANOW, &termio);
1068     }
1069 
1070     tcgetattr(d->devfd, &termio);
1071     *val = cfgetispeed(&termio);
1072     get_rate_from_baud_rate(*val, val, cisco);
1073 
1074     return 0;
1075 }
1076 
devcfg_data_size(struct devio * io,unsigned char * val,int * bpc)1077 static int devcfg_data_size(struct devio *io, unsigned char *val, int *bpc)
1078 {
1079     struct devcfg_data *d = io->my_data;
1080     struct termios termio;
1081 
1082     if (tcgetattr(d->devfd, &termio) == -1) {
1083 	*val = 0;
1084 	return -1;
1085     }
1086 
1087     if ((*val >= 5) && (*val <= 8)) {
1088 	termio.c_cflag &= ~CSIZE;
1089 	switch (*val) {
1090 	case 5: termio.c_cflag |= CS5; d->current_data_size = 5; break;
1091 	case 6: termio.c_cflag |= CS6; d->current_data_size = 6; break;
1092 	case 7: termio.c_cflag |= CS7; d->current_data_size = 7; break;
1093 	case 8: termio.c_cflag |= CS8; d->current_data_size = 8; break;
1094 	}
1095 	tcsetattr(d->devfd, TCSANOW, &termio);
1096     }
1097 
1098     switch (termio.c_cflag & CSIZE) {
1099     case CS5: *val = 5; break;
1100     case CS6: *val = 6; break;
1101     case CS7: *val = 7; break;
1102     case CS8: *val = 8; break;
1103     default:  *val = 0;
1104     }
1105 
1106     *bpc = calc_bpc(d);
1107 
1108     return 0;
1109 }
1110 
devcfg_parity(struct devio * io,unsigned char * val,int * bpc)1111 static int devcfg_parity(struct devio *io, unsigned char *val, int *bpc)
1112 {
1113     struct devcfg_data *d = io->my_data;
1114     struct termios termio;
1115 
1116     if (tcgetattr(d->devfd, &termio) == -1) {
1117 	*val = 0;
1118 	return -1;
1119     }
1120 
1121     /* We don't support MARK or SPACE parity. */
1122     if ((*val >= 1) && (*val <= 3)) {
1123 	termio.c_cflag &= ~(PARENB | PARODD);
1124 	switch (*val) {
1125 	case 1: d->current_parity_on = 0; break; /* NONE */
1126 	case 2: termio.c_cflag |= PARENB | PARODD; /* ODD */
1127 	    d->current_parity_on = 1;
1128 	    break;
1129 	case 3: termio.c_cflag |= PARENB; /* EVEN */
1130 	    d->current_parity_on = 1;
1131 	    break;
1132 	}
1133 	tcsetattr(d->devfd, TCSANOW, &termio);
1134     }
1135 
1136     if (termio.c_cflag & PARENB) {
1137 	if (termio.c_cflag & PARODD)
1138 	    *val = 2; /* ODD */
1139 	else
1140 	    *val = 3; /* EVEN */
1141     } else
1142 	*val = 1; /* NONE */
1143 
1144     *bpc = calc_bpc(d);
1145 
1146     return 0;
1147 }
1148 
devcfg_stop_size(struct devio * io,unsigned char * val,int * bpc)1149 static int devcfg_stop_size(struct devio *io, unsigned char *val, int *bpc)
1150 {
1151     struct devcfg_data *d = io->my_data;
1152     struct termios termio;
1153 
1154     if (tcgetattr(d->devfd, &termio) == -1) {
1155 	*val = 0;
1156 	return -1;
1157     }
1158 
1159     if ((*val >= 1) && (*val <= 2)) {
1160 	termio.c_cflag &= ~CSTOPB;
1161 	switch (*val) {
1162 	case 1: d->current_stop_bits = 1; break; /* 1 stop bit */
1163 	case 2: d->current_stop_bits = 2; /* 2 stop bits */
1164 	    termio.c_cflag |= CSTOPB;
1165 	    break;
1166 	}
1167 	tcsetattr(d->devfd, TCSANOW, &termio);
1168     }
1169 
1170     if (termio.c_cflag & CSTOPB)
1171 	*val = 2; /* 2 stop bits. */
1172     else
1173 	*val = 1; /* 1 stop bit. */
1174 
1175     *bpc = calc_bpc(d);
1176 
1177     return 0;
1178 }
1179 
devcfg_flow_control(struct devio * io,unsigned char val)1180 static int devcfg_flow_control(struct devio *io, unsigned char val)
1181 {
1182     struct devcfg_data *d = io->my_data;
1183 
1184     tcflow(d->devfd, val ? TCIOFF : TCION);
1185     return 0;
1186 }
1187 
devcfg_control(struct devio * io,unsigned char * val)1188 static int devcfg_control(struct devio *io, unsigned char *val)
1189 {
1190     struct devcfg_data *d = io->my_data;
1191     struct termios termio;
1192     int ival;
1193 
1194     if (tcgetattr(d->devfd, &termio) == -1) {
1195 	*val = 0;
1196 	return -1;
1197     }
1198 
1199     switch (*val) {
1200     case 0:
1201     case 1:
1202     case 2:
1203     case 3:
1204 	/* Outbound/both flow control */
1205 	if (tcgetattr(d->devfd, &termio) != -1) {
1206 	    if (*val != 0) {
1207 		termio.c_iflag &= ~(IXON | IXOFF);
1208 		termio.c_cflag &= ~CRTSCTS;
1209 		switch (*val) {
1210 		case 1: break; /* NONE */
1211 		case 2: termio.c_iflag |= IXON | IXOFF; break;
1212 		case 3: termio.c_cflag |= CRTSCTS; break;
1213 		}
1214 		tcsetattr(d->devfd, TCSANOW, &termio);
1215 	    }
1216 	    if (termio.c_cflag & CRTSCTS)
1217 		*val = 3;
1218 	    else if (termio.c_iflag & IXON)
1219 		*val = 2;
1220 	    else
1221 		*val = 1;
1222 	}
1223 	break;
1224 
1225     case 13:
1226     case 14:
1227     case 15:
1228     case 16:
1229     case 17:
1230     case 18:
1231     case 19:
1232 	/* Inbound flow-control */
1233 	if (tcgetattr(d->devfd, &termio) != -1) {
1234 	    if (*val == 15) {
1235 		/* We can only set XON/XOFF independently */
1236 		termio.c_iflag |= IXOFF;
1237 		tcsetattr(d->devfd, TCSANOW, &termio);
1238 	    }
1239 	    if (termio.c_cflag & CRTSCTS)
1240 		*val = 16;
1241 	    else if (termio.c_iflag & IXOFF)
1242 		*val = 15;
1243 	    else
1244 		*val = 14;
1245 	}
1246 	break;
1247 
1248 	/* Handle BREAK stuff. */
1249     case 6:
1250 	if (ioctl(d->devfd, TIOCCBRK) != -1)
1251 	    d->break_set = 0;
1252 	goto read_break_val;
1253 
1254     case 5:
1255 	if (ioctl(d->devfd, TIOCSBRK) != -1)
1256 	    d->break_set = 1;
1257 	goto read_break_val;
1258 
1259     case 4:
1260     read_break_val:
1261 	if (d->break_set)
1262 	    *val = 5;
1263 	else
1264 	    *val = 6;
1265 	break;
1266 
1267     /* DTR handling */
1268     case 8:
1269 #ifndef __CYGWIN__
1270 	ival = TIOCM_DTR;
1271 	ioctl(d->devfd, TIOCMBIS, &ival);
1272 #else
1273 	ioctl(d->devfd, TIOCMGET, &ival);
1274 	ival |= TIOCM_DTR;
1275 	ioctl(d->devfd, TIOCMSET, &ival);
1276 #endif
1277 	    goto read_dtr_val;
1278 
1279     case 9:
1280 #ifndef __CYGWIN__
1281 	ival = TIOCM_DTR;
1282 	ioctl(d->devfd, TIOCMBIC, &ival);
1283 #else
1284 	ioctl(d->devfd, TIOCMGET, &ival);
1285 	ival &= ~TIOCM_DTR;
1286 	ioctl(d->devfd, TIOCMSET, &ival);
1287 #endif
1288 	goto read_dtr_val;
1289 
1290     case 7:
1291     read_dtr_val:
1292 	if (ioctl(d->devfd, TIOCMGET, &ival) == -1)
1293 	    *val = 7;
1294 	else if (ival & TIOCM_DTR)
1295 	    *val = 8;
1296 	else
1297 	    *val = 9;
1298 	break;
1299 
1300     /* RTS handling */
1301     case 11:
1302 #ifndef __CYGWIN__
1303 	ival = TIOCM_RTS;
1304 	ioctl(d->devfd, TIOCMBIS, &ival);
1305 #else
1306 	ioctl(d->devfd, TIOCMGET, &ival);
1307 	ival |= TIOCM_RTS;
1308 	ioctl(d->devfd, TIOCMSET, &ival);
1309 #endif
1310 	goto read_rts_val;
1311 
1312     case 12:
1313 #ifndef __CYGWIN__
1314 	ival = TIOCM_RTS;
1315 	ioctl(d->devfd, TIOCMBIC, &ival);
1316 #else
1317 	ioctl(d->devfd, TIOCMGET, &ival);
1318 	ival &= ~TIOCM_RTS;
1319 	ioctl(d->devfd, TIOCMSET, &ival);
1320 #endif
1321 	goto read_rts_val;
1322 
1323     case 10:
1324     read_rts_val:
1325 	if (ioctl(d->devfd, TIOCMGET, &ival) == -1)
1326 	    *val = 10;
1327 	else if (ival & TIOCM_RTS)
1328 	    *val = 11;
1329 	else
1330 	    *val = 12;
1331 	break;
1332 
1333     default:
1334 	*val = 0;
1335 	return -1;
1336     }
1337 
1338     return 0;
1339 }
1340 
devcfg_flush(struct devio * io,int * val)1341 static int devcfg_flush(struct devio *io, int *val)
1342 {
1343     struct devcfg_data *d = io->my_data;
1344     int ival;
1345 
1346     switch (*val) {
1347     case DEVIO_FLUSH_INPUT: ival = TCIFLUSH; goto purge_found;
1348     case DEVIO_FLUSH_OUTPUT: ival = TCOFLUSH; goto purge_found;
1349     case DEVIO_FLUSH_INPUT | DEVIO_FLUSH_OUTPUT:
1350 	ival = TCIOFLUSH; goto purge_found;
1351     }
1352     *val = 0;
1353     return -1;
1354  purge_found:
1355     tcflush(d->devfd, ival);
1356     return 0;
1357 }
1358 
devcfg_free(struct devio * io)1359 static void devcfg_free(struct devio *io)
1360 {
1361     struct devcfg_data *d = io->my_data;
1362 
1363     if (d->devfd != -1)
1364 	close(d->devfd);
1365     io->my_data = NULL;
1366     free(d);
1367 }
1368 
1369 static int
devcfg_reconfig(struct devio * io,struct absout * eout,const char * instr,int (* otherconfig)(void * data,struct absout * eout,const char * item),void * data)1370 devcfg_reconfig(struct devio *io, struct absout *eout, const char *instr,
1371 		int (*otherconfig)(void *data, struct absout *eout,
1372 				   const char *item),
1373 		void *data)
1374 {
1375     struct devcfg_data *d = io->my_data;
1376 
1377     return devconfig(d, eout, instr, otherconfig, data);
1378 }
1379 
1380 static struct devio_f devcfg_io_f = {
1381     .setup = devcfg_setup,
1382     .shutdown = devcfg_shutdown,
1383     .reconfig = devcfg_reconfig,
1384     .read = devcfg_read,
1385     .write = devcfg_write,
1386     .read_handler_enable = devcfg_read_handler_enable,
1387     .write_handler_enable = devcfg_write_handler_enable,
1388     .except_handler_enable = devcfg_except_handler_enable,
1389     .send_break = devcfg_send_break,
1390     .get_modem_state = devcfg_get_modem_state,
1391     .set_devcontrol = devcfg_set_devcontrol,
1392     .show_devcontrol = devcfg_show_devcontrol,
1393     .show_devcfg = devcfg_show_devcfg,
1394     .baud_rate = devcfg_baud_rate,
1395     .data_size = devcfg_data_size,
1396     .parity = devcfg_parity,
1397     .stop_size = devcfg_stop_size,
1398     .control = devcfg_control,
1399     .flow_control = devcfg_flow_control,
1400     .flush = devcfg_flush,
1401     .free = devcfg_free,
1402     .serparm_to_str = devcfg_serparm_to_str
1403 };
1404 
1405 int
devcfg_init(struct devio * io,struct absout * eout,const char * instr,int (* otherconfig)(void * data,struct absout * eout,const char * item),void * data)1406 devcfg_init(struct devio *io, struct absout *eout, const char *instr,
1407 	    int (*otherconfig)(void *data, struct absout *eout,
1408 			       const char *item),
1409 	    void *data)
1410 {
1411     struct devcfg_data *d;
1412 
1413     d = malloc(sizeof(*d));
1414     if (!d)
1415 	return -1;
1416     memset(d, 0, sizeof(*d));
1417     d->devfd = -1;
1418 
1419     if (devconfig(d, eout, instr, otherconfig, data) == -1) {
1420 	free(d);
1421 	return -1;
1422     }
1423 
1424     io->my_data = d;
1425     io->f = &devcfg_io_f;
1426     return 0;
1427 }
1428 
1429