1*f928e069Sderaadt /* $OpenBSD: cu.c,v 1.31 2024/02/10 15:29:04 deraadt Exp $ */
2f391cec5Snicm
3f391cec5Snicm /*
4f391cec5Snicm * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
5f391cec5Snicm *
6f391cec5Snicm * Permission to use, copy, modify, and distribute this software for any
7f391cec5Snicm * purpose with or without fee is hereby granted, provided that the above
8f391cec5Snicm * copyright notice and this permission notice appear in all copies.
9f391cec5Snicm *
10f391cec5Snicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f391cec5Snicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f391cec5Snicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f391cec5Snicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f391cec5Snicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15f391cec5Snicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16f391cec5Snicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f391cec5Snicm */
18f391cec5Snicm
191835b44fSkrw #include <sys/types.h>
20f391cec5Snicm #include <sys/ioctl.h>
211835b44fSkrw #include <sys/sysctl.h>
22f391cec5Snicm
23023045f1Shalex #include <ctype.h>
24f391cec5Snicm #include <err.h>
251835b44fSkrw #include <errno.h>
26f391cec5Snicm #include <event.h>
27f391cec5Snicm #include <fcntl.h>
28f391cec5Snicm #include <getopt.h>
29f391cec5Snicm #include <paths.h>
30f391cec5Snicm #include <pwd.h>
31f391cec5Snicm #include <signal.h>
32f391cec5Snicm #include <stdio.h>
33f391cec5Snicm #include <stdlib.h>
34f391cec5Snicm #include <string.h>
35f391cec5Snicm #include <termios.h>
36f391cec5Snicm #include <unistd.h>
37b9fc9a72Sderaadt #include <limits.h>
38f391cec5Snicm
39f391cec5Snicm #include "cu.h"
40f391cec5Snicm
41f391cec5Snicm extern char *__progname;
42f391cec5Snicm
4366d5e211Snicm FILE *record_file;
44f391cec5Snicm struct termios saved_tio;
45f391cec5Snicm struct bufferevent *input_ev;
46f391cec5Snicm struct bufferevent *output_ev;
47f3767adaSnicm int escape_char = '~';
4850866e70Snicm int is_direct = -1;
49087a5e3bSderaadt int restricted = 0;
50439243a3Snicm const char *line_path = NULL;
51439243a3Snicm int line_speed = -1;
52f391cec5Snicm int line_fd;
5389ee0e62Snicm struct termios line_tio;
54f391cec5Snicm struct bufferevent *line_ev;
55f391cec5Snicm struct event sigterm_ev;
56c30d1c6aSnicm struct event sighup_ev;
57f391cec5Snicm enum {
58f391cec5Snicm STATE_NONE,
59f391cec5Snicm STATE_NEWLINE,
60f3767adaSnicm STATE_ESCAPE
61f391cec5Snicm } last_state = STATE_NEWLINE;
62f391cec5Snicm
63f391cec5Snicm __dead void usage(void);
64f391cec5Snicm void signal_event(int, short, void *);
65f391cec5Snicm void stream_read(struct bufferevent *, void *);
66f391cec5Snicm void stream_error(struct bufferevent *, short, void *);
67f391cec5Snicm void line_read(struct bufferevent *, void *);
68f391cec5Snicm void line_error(struct bufferevent *, short, void *);
69a035d822Snicm void try_remote(const char *, const char *, const char *);
701835b44fSkrw char *get_ucomnames(void);
711835b44fSkrw char *find_ucom(const char *, char *);
72f391cec5Snicm
73f391cec5Snicm __dead void
usage(void)74f391cec5Snicm usage(void)
75f391cec5Snicm {
76f3767adaSnicm fprintf(stderr, "usage: %s [-dr] [-E escape_char] [-l line] "
77f3767adaSnicm "[-s speed | -speed]\n", __progname);
781a0917ceSnicm fprintf(stderr, " %s [host]\n", __progname);
79f391cec5Snicm exit(1);
80f391cec5Snicm }
81f391cec5Snicm
82f391cec5Snicm int
main(int argc,char ** argv)83f391cec5Snicm main(int argc, char **argv)
84f391cec5Snicm {
85439243a3Snicm const char *errstr;
861835b44fSkrw char *tmp, *s, *host, *ucomnames;
8750866e70Snicm int opt, i, flags;
88f391cec5Snicm
891835b44fSkrw ucomnames = get_ucomnames();
901835b44fSkrw
91758d4455Sderaadt if (pledge("stdio rpath wpath cpath getpw proc exec tty",
92758d4455Sderaadt NULL) == -1)
93758d4455Sderaadt err(1, "pledge");
94758d4455Sderaadt
95439243a3Snicm if (isatty(STDIN_FILENO) && tcgetattr(STDIN_FILENO, &saved_tio) != 0)
96439243a3Snicm err(1, "tcgetattr");
97f391cec5Snicm
98f391cec5Snicm /*
99f391cec5Snicm * Convert obsolescent -### speed to modern -s### syntax which getopt()
100f391cec5Snicm * can handle.
101f391cec5Snicm */
102f391cec5Snicm for (i = 1; i < argc; i++) {
1030630af0bSdlg if (strcmp("--", argv[i]) == 0)
104f391cec5Snicm break;
105f3767adaSnicm if (argv[i][0] != '-' || !isdigit((u_char)argv[i][1]))
1060630af0bSdlg continue;
1070630af0bSdlg
1080630af0bSdlg if (asprintf(&argv[i], "-s%s", &argv[i][1]) == -1)
1090630af0bSdlg errx(1, "speed asprintf");
110f391cec5Snicm }
111f391cec5Snicm
112f3767adaSnicm while ((opt = getopt(argc, argv, "drE:l:s:")) != -1) {
113f391cec5Snicm switch (opt) {
11450866e70Snicm case 'd':
11550866e70Snicm is_direct = 1;
11650866e70Snicm break;
117087a5e3bSderaadt case 'r':
118087a5e3bSderaadt if (pledge("stdio rpath wpath tty", NULL) == -1)
119087a5e3bSderaadt err(1, "pledge");
120087a5e3bSderaadt restricted = 1;
121087a5e3bSderaadt break;
122f3767adaSnicm case 'E':
123f3767adaSnicm if (optarg[0] == '^' && optarg[2] == '\0' &&
124f3767adaSnicm (u_char)optarg[1] >= 64 && (u_char)optarg[1] < 128)
125f3767adaSnicm escape_char = (u_char)optarg[1] & 31;
126f3767adaSnicm else if (strlen(optarg) == 1)
127f3767adaSnicm escape_char = (u_char)optarg[0];
128f3767adaSnicm else
129f3767adaSnicm errx(1, "invalid escape character: %s", optarg);
130f3767adaSnicm break;
131f391cec5Snicm case 'l':
132439243a3Snicm line_path = optarg;
133f391cec5Snicm break;
134f391cec5Snicm case 's':
135439243a3Snicm line_speed = strtonum(optarg, 0, INT_MAX, &errstr);
136f391cec5Snicm if (errstr != NULL)
137f391cec5Snicm errx(1, "speed is %s: %s", errstr, optarg);
138f391cec5Snicm break;
139f391cec5Snicm default:
140f391cec5Snicm usage();
141f391cec5Snicm }
142f391cec5Snicm }
143f391cec5Snicm argc -= optind;
144f391cec5Snicm argv += optind;
145439243a3Snicm if (argc != 0 && argc != 1)
146f391cec5Snicm usage();
147f391cec5Snicm
14850866e70Snicm if (line_path != NULL || line_speed != -1 || is_direct != -1) {
1491a0917ceSnicm if (argc != 0)
1501a0917ceSnicm usage();
1511a0917ceSnicm } else {
152a035d822Snicm if (argc == 1)
153a035d822Snicm host = argv[0];
154439243a3Snicm else
155a035d822Snicm host = getenv("HOST");
156a035d822Snicm if (host != NULL && *host != '\0') {
1571a0917ceSnicm if (*host == '/')
158290c3e61Snicm line_path = host;
1591a0917ceSnicm else {
160a035d822Snicm s = getenv("REMOTE");
161a035d822Snicm if (s != NULL && *s == '/')
162a035d822Snicm try_remote(host, s, NULL);
163a035d822Snicm else
164a035d822Snicm try_remote(host, NULL, s);
165a035d822Snicm }
166290c3e61Snicm }
1671a0917ceSnicm }
168439243a3Snicm
169439243a3Snicm if (line_path == NULL)
170439243a3Snicm line_path = "/dev/cua00";
171439243a3Snicm if (line_speed == -1)
172439243a3Snicm line_speed = 9600;
17350866e70Snicm if (is_direct == -1)
17450866e70Snicm is_direct = 0;
175439243a3Snicm
1761835b44fSkrw if (strncasecmp(line_path, "usb", 3) == 0) {
1771835b44fSkrw tmp = find_ucom(line_path, ucomnames);
1781835b44fSkrw if (tmp == NULL)
1791835b44fSkrw errx(1, "No ucom matched '%s'", line_path);
1801835b44fSkrw line_path = tmp;
1811835b44fSkrw }
182439243a3Snicm if (strchr(line_path, '/') == NULL) {
183439243a3Snicm if (asprintf(&tmp, "%s%s", _PATH_DEV, line_path) == -1)
184f391cec5Snicm err(1, "asprintf");
185439243a3Snicm line_path = tmp;
186f391cec5Snicm }
187f391cec5Snicm
18850866e70Snicm flags = O_RDWR;
18950866e70Snicm if (is_direct)
19050866e70Snicm flags |= O_NONBLOCK;
19150866e70Snicm line_fd = open(line_path, flags);
1923aaa63ebSderaadt if (line_fd == -1)
193439243a3Snicm err(1, "open(\"%s\")", line_path);
194087a5e3bSderaadt if (restricted && pledge("stdio tty", NULL) == -1)
195087a5e3bSderaadt err(1, "pledge");
1962db3b77dSmestre if (!isatty(line_fd))
1972db3b77dSmestre err(1, "%s", line_path);
198f391cec5Snicm if (ioctl(line_fd, TIOCEXCL) != 0)
199f391cec5Snicm err(1, "ioctl(TIOCEXCL)");
20089ee0e62Snicm if (tcgetattr(line_fd, &line_tio) != 0)
20189ee0e62Snicm err(1, "tcgetattr");
202439243a3Snicm if (set_line(line_speed) != 0)
20311403328Snicm err(1, "tcsetattr");
204f391cec5Snicm
205f391cec5Snicm event_init();
206ca5f2657Snicm
207f391cec5Snicm signal_set(&sigterm_ev, SIGTERM, signal_event, NULL);
208f391cec5Snicm signal_add(&sigterm_ev, NULL);
209c30d1c6aSnicm signal_set(&sighup_ev, SIGHUP, signal_event, NULL);
210c30d1c6aSnicm signal_add(&sighup_ev, NULL);
211ca5f2657Snicm if (signal(SIGINT, SIG_IGN) == SIG_ERR)
212ca5f2657Snicm err(1, "signal");
213ca5f2657Snicm if (signal(SIGQUIT, SIG_IGN) == SIG_ERR)
214ca5f2657Snicm err(1, "signal");
215f391cec5Snicm
21611403328Snicm set_termios(); /* after this use cu_err and friends */
217f391cec5Snicm
218f391cec5Snicm /* stdin and stdout get separate events */
219f391cec5Snicm input_ev = bufferevent_new(STDIN_FILENO, stream_read, NULL,
220f391cec5Snicm stream_error, NULL);
221f391cec5Snicm bufferevent_enable(input_ev, EV_READ);
222f391cec5Snicm output_ev = bufferevent_new(STDOUT_FILENO, NULL, NULL, stream_error,
223f391cec5Snicm NULL);
224f391cec5Snicm bufferevent_enable(output_ev, EV_WRITE);
225f391cec5Snicm
226668574b2Snicm set_blocking(line_fd, 0);
227f391cec5Snicm line_ev = bufferevent_new(line_fd, line_read, NULL, line_error,
228f391cec5Snicm NULL);
229f391cec5Snicm bufferevent_enable(line_ev, EV_READ|EV_WRITE);
230f391cec5Snicm
231439243a3Snicm printf("Connected to %s (speed %d)\r\n", line_path, line_speed);
232f391cec5Snicm event_dispatch();
233f391cec5Snicm
234654f0ea4Snicm restore_termios();
235f391cec5Snicm printf("\r\n[EOT]\n");
236f391cec5Snicm
237f391cec5Snicm exit(0);
238f391cec5Snicm }
239f391cec5Snicm
240f391cec5Snicm void
signal_event(int fd,short events,void * data)241f391cec5Snicm signal_event(int fd, short events, void *data)
242f391cec5Snicm {
243654f0ea4Snicm restore_termios();
244f391cec5Snicm printf("\r\n[SIG%s]\n", sys_signame[fd]);
245f391cec5Snicm
246f391cec5Snicm exit(0);
247f391cec5Snicm }
248f391cec5Snicm
249f391cec5Snicm void
set_blocking(int fd,int state)250668574b2Snicm set_blocking(int fd, int state)
251668574b2Snicm {
252668574b2Snicm int mode;
253668574b2Snicm
254668574b2Snicm state = state ? 0 : O_NONBLOCK;
255668574b2Snicm if ((mode = fcntl(fd, F_GETFL)) == -1)
256668574b2Snicm cu_err(1, "fcntl");
257668574b2Snicm if ((mode & O_NONBLOCK) != state) {
258668574b2Snicm mode = (mode & ~O_NONBLOCK) | state;
259668574b2Snicm if (fcntl(fd, F_SETFL, mode) == -1)
260668574b2Snicm cu_err(1, "fcntl");
261668574b2Snicm }
262668574b2Snicm }
263668574b2Snicm
264668574b2Snicm void
set_termios(void)265f391cec5Snicm set_termios(void)
266f391cec5Snicm {
267f391cec5Snicm struct termios tio;
268f391cec5Snicm
269f391cec5Snicm if (!isatty(STDIN_FILENO))
270f391cec5Snicm return;
271f391cec5Snicm
272f391cec5Snicm memcpy(&tio, &saved_tio, sizeof(tio));
273f391cec5Snicm tio.c_lflag &= ~(ICANON|IEXTEN|ECHO);
274f391cec5Snicm tio.c_iflag &= ~(INPCK|ICRNL);
275f391cec5Snicm tio.c_oflag &= ~OPOST;
276f391cec5Snicm tio.c_cc[VMIN] = 1;
277f391cec5Snicm tio.c_cc[VTIME] = 0;
278f391cec5Snicm tio.c_cc[VDISCARD] = _POSIX_VDISABLE;
279f391cec5Snicm tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
280f391cec5Snicm tio.c_cc[VINTR] = _POSIX_VDISABLE;
281f391cec5Snicm tio.c_cc[VLNEXT] = _POSIX_VDISABLE;
282f391cec5Snicm tio.c_cc[VQUIT] = _POSIX_VDISABLE;
283f391cec5Snicm tio.c_cc[VSUSP] = _POSIX_VDISABLE;
284f391cec5Snicm if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0)
28511403328Snicm cu_err(1, "tcsetattr");
286f391cec5Snicm }
287f391cec5Snicm
288f391cec5Snicm void
restore_termios(void)289f391cec5Snicm restore_termios(void)
290f391cec5Snicm {
29111403328Snicm if (isatty(STDIN_FILENO))
29211403328Snicm tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tio);
293f391cec5Snicm }
294f391cec5Snicm
295909d4fcfSnicm int
set_line(int speed)296909d4fcfSnicm set_line(int speed)
297909d4fcfSnicm {
298909d4fcfSnicm struct termios tio;
299909d4fcfSnicm
30089ee0e62Snicm memcpy(&tio, &line_tio, sizeof(tio));
30189ee0e62Snicm tio.c_iflag &= ~(ISTRIP|ICRNL);
30289ee0e62Snicm tio.c_oflag &= ~OPOST;
30389ee0e62Snicm tio.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
30489ee0e62Snicm tio.c_cflag &= ~(CSIZE|PARENB);
30589ee0e62Snicm tio.c_cflag |= CREAD|CS8|CLOCAL;
306909d4fcfSnicm tio.c_cc[VMIN] = 1;
307909d4fcfSnicm tio.c_cc[VTIME] = 0;
308909d4fcfSnicm cfsetspeed(&tio, speed);
30911403328Snicm if (tcsetattr(line_fd, TCSAFLUSH, &tio) != 0)
310909d4fcfSnicm return (-1);
311909d4fcfSnicm return (0);
312909d4fcfSnicm }
313909d4fcfSnicm
314f391cec5Snicm void
stream_read(struct bufferevent * bufev,void * data)315f391cec5Snicm stream_read(struct bufferevent *bufev, void *data)
316f391cec5Snicm {
317f391cec5Snicm char *new_data, *ptr;
318f391cec5Snicm size_t new_size;
319f391cec5Snicm int state_change;
320f391cec5Snicm
321f391cec5Snicm new_data = EVBUFFER_DATA(input_ev->input);
322f391cec5Snicm new_size = EVBUFFER_LENGTH(input_ev->input);
323f391cec5Snicm if (new_size == 0)
324f391cec5Snicm return;
325f391cec5Snicm
326f391cec5Snicm state_change = isatty(STDIN_FILENO);
327f391cec5Snicm for (ptr = new_data; ptr < new_data + new_size; ptr++) {
328f391cec5Snicm switch (last_state) {
329f391cec5Snicm case STATE_NONE:
330f391cec5Snicm if (state_change && *ptr == '\r')
331f391cec5Snicm last_state = STATE_NEWLINE;
332f391cec5Snicm break;
333f391cec5Snicm case STATE_NEWLINE:
334f3767adaSnicm if (state_change && (u_char)*ptr == escape_char) {
335f3767adaSnicm last_state = STATE_ESCAPE;
336f391cec5Snicm continue;
337f391cec5Snicm }
338f391cec5Snicm if (*ptr != '\r')
339f391cec5Snicm last_state = STATE_NONE;
340f391cec5Snicm break;
341f3767adaSnicm case STATE_ESCAPE:
342f391cec5Snicm do_command(*ptr);
343f391cec5Snicm last_state = STATE_NEWLINE;
344f391cec5Snicm continue;
345f391cec5Snicm }
346f391cec5Snicm
347f391cec5Snicm bufferevent_write(line_ev, ptr, 1);
348f391cec5Snicm }
349f391cec5Snicm
350f391cec5Snicm evbuffer_drain(input_ev->input, new_size);
351f391cec5Snicm }
352f391cec5Snicm
353f391cec5Snicm void
stream_error(struct bufferevent * bufev,short what,void * data)354f391cec5Snicm stream_error(struct bufferevent *bufev, short what, void *data)
355f391cec5Snicm {
356f391cec5Snicm event_loopexit(NULL);
357f391cec5Snicm }
358f391cec5Snicm
359f391cec5Snicm void
line_read(struct bufferevent * bufev,void * data)360f391cec5Snicm line_read(struct bufferevent *bufev, void *data)
361f391cec5Snicm {
362f391cec5Snicm char *new_data;
363f391cec5Snicm size_t new_size;
364f391cec5Snicm
365f391cec5Snicm new_data = EVBUFFER_DATA(line_ev->input);
366f391cec5Snicm new_size = EVBUFFER_LENGTH(line_ev->input);
367f391cec5Snicm if (new_size == 0)
368f391cec5Snicm return;
369f391cec5Snicm
37066d5e211Snicm if (record_file != NULL)
37166d5e211Snicm fwrite(new_data, 1, new_size, record_file);
372f391cec5Snicm bufferevent_write(output_ev, new_data, new_size);
373f391cec5Snicm
374f391cec5Snicm evbuffer_drain(line_ev->input, new_size);
375f391cec5Snicm }
376f391cec5Snicm
377f391cec5Snicm void
line_error(struct bufferevent * bufev,short what,void * data)378f391cec5Snicm line_error(struct bufferevent *bufev, short what, void *data)
379f391cec5Snicm {
380f391cec5Snicm event_loopexit(NULL);
381f391cec5Snicm }
382f391cec5Snicm
383439243a3Snicm void
try_remote(const char * host,const char * path,const char * entry)384a035d822Snicm try_remote(const char *host, const char *path, const char *entry)
385439243a3Snicm {
386439243a3Snicm const char *paths[] = { "/etc/remote", NULL, NULL };
387439243a3Snicm char *cp, *s;
388439243a3Snicm long l;
389439243a3Snicm int error;
390439243a3Snicm
391439243a3Snicm if (path != NULL) {
392439243a3Snicm paths[0] = path;
393439243a3Snicm paths[1] = "/etc/remote";
394439243a3Snicm }
395439243a3Snicm
396a035d822Snicm if (entry != NULL && cgetset(entry) != 0)
397a035d822Snicm cu_errx(1, "cgetset failed");
398439243a3Snicm error = cgetent(&cp, (char **)paths, (char *)host);
399439243a3Snicm if (error < 0) {
400439243a3Snicm switch (error) {
401439243a3Snicm case -1:
402439243a3Snicm cu_errx(1, "unknown host %s", host);
403439243a3Snicm case -2:
404439243a3Snicm cu_errx(1, "can't open remote file");
405439243a3Snicm case -3:
406439243a3Snicm cu_errx(1, "loop in remote file");
407439243a3Snicm default:
408439243a3Snicm cu_errx(1, "unknown error in remote file");
409439243a3Snicm }
410439243a3Snicm }
411439243a3Snicm
41250866e70Snicm if (is_direct == -1 && cgetcap(cp, "dc", ':') != NULL)
41350866e70Snicm is_direct = 1;
41450866e70Snicm
415439243a3Snicm if (line_path == NULL && cgetstr(cp, "dv", &s) >= 0)
416439243a3Snicm line_path = s;
417439243a3Snicm
418439243a3Snicm if (line_speed == -1 && cgetnum(cp, "br", &l) >= 0) {
419439243a3Snicm if (l < 0 || l > INT_MAX)
420439243a3Snicm cu_errx(1, "speed out of range");
421439243a3Snicm line_speed = l;
422439243a3Snicm }
423439243a3Snicm }
424439243a3Snicm
425f391cec5Snicm /* Expands tildes in the file name. Based on code from ssh/misc.c. */
426f391cec5Snicm char *
tilde_expand(const char * filename1)427f391cec5Snicm tilde_expand(const char *filename1)
428f391cec5Snicm {
42934574ca2Stedu const char *filename, *path, *sep;
43034574ca2Stedu char user[128], *out;
431f391cec5Snicm struct passwd *pw;
432f391cec5Snicm u_int len, slash;
43334574ca2Stedu int rv;
434f391cec5Snicm
435f391cec5Snicm if (*filename1 != '~')
436f391cec5Snicm goto no_change;
437f391cec5Snicm filename = filename1 + 1;
438f391cec5Snicm
439f391cec5Snicm path = strchr(filename, '/');
440f391cec5Snicm if (path != NULL && path > filename) { /* ~user/path */
441f391cec5Snicm slash = path - filename;
442f391cec5Snicm if (slash > sizeof(user) - 1)
443f391cec5Snicm goto no_change;
444f391cec5Snicm memcpy(user, filename, slash);
445f391cec5Snicm user[slash] = '\0';
446f391cec5Snicm if ((pw = getpwnam(user)) == NULL)
447f391cec5Snicm goto no_change;
448f391cec5Snicm } else if ((pw = getpwuid(getuid())) == NULL) /* ~/path */
449f391cec5Snicm goto no_change;
450f391cec5Snicm
451f391cec5Snicm /* Make sure directory has a trailing '/' */
452f391cec5Snicm len = strlen(pw->pw_dir);
45334574ca2Stedu if (len == 0 || pw->pw_dir[len - 1] != '/')
45434574ca2Stedu sep = "/";
45534574ca2Stedu else
45634574ca2Stedu sep = "";
457f391cec5Snicm
458f391cec5Snicm /* Skip leading '/' from specified path */
459f391cec5Snicm if (path != NULL)
460f391cec5Snicm filename = path + 1;
461f391cec5Snicm
46234574ca2Stedu if ((rv = asprintf(&out, "%s%s%s", pw->pw_dir, sep, filename)) == -1)
46334574ca2Stedu cu_err(1, "asprintf");
464b9fc9a72Sderaadt if (rv >= PATH_MAX) {
46534574ca2Stedu free(out);
46634574ca2Stedu goto no_change;
46734574ca2Stedu }
46834574ca2Stedu
469f391cec5Snicm return (out);
470f391cec5Snicm
471f391cec5Snicm no_change:
472f391cec5Snicm out = strdup(filename1);
473f391cec5Snicm if (out == NULL)
47411403328Snicm cu_err(1, "strdup");
475f391cec5Snicm return (out);
476f391cec5Snicm }
4771835b44fSkrw
4781835b44fSkrw char *
get_ucomnames(void)4791835b44fSkrw get_ucomnames(void)
4801835b44fSkrw {
4811835b44fSkrw char *names;
4821835b44fSkrw int mib[2];
4831835b44fSkrw size_t size;
4841835b44fSkrw
4851835b44fSkrw mib[0] = CTL_HW;
4861835b44fSkrw mib[1] = HW_UCOMNAMES;
4871835b44fSkrw names = NULL;
4881835b44fSkrw size = 0;
4891835b44fSkrw for (;;) {
4901835b44fSkrw if (sysctl(mib, 2, NULL, &size, NULL, 0) == -1 || size == 0)
491*f928e069Sderaadt return NULL;
4921835b44fSkrw if ((names = realloc(names, size)) == NULL)
4931835b44fSkrw err(1, NULL);
4941835b44fSkrw if (sysctl(mib, 2, names, &size, NULL, 0) != -1)
4951835b44fSkrw break;
4961835b44fSkrw if (errno != ENOMEM)
497*f928e069Sderaadt return NULL;
4981835b44fSkrw }
4991835b44fSkrw return names;
5001835b44fSkrw }
5011835b44fSkrw
5021835b44fSkrw char *
find_ucom(const char * usbid,char * names)5031835b44fSkrw find_ucom(const char *usbid, char *names)
5041835b44fSkrw {
5051835b44fSkrw char *cua, *id, *ucom;
5061835b44fSkrw
5071835b44fSkrw if (names == NULL)
5081835b44fSkrw return NULL;
5091835b44fSkrw
5105cc7c8afSjca /* names is a comma separated list of "ucom<unit#>:<usb id>". */
5111835b44fSkrw cua = NULL;
5121835b44fSkrw for (ucom = strsep(&names, ","); ucom; ucom = strsep(&names, ",")) {
5131835b44fSkrw if (*ucom == '\0' || strncasecmp(ucom, "ucom", 4))
5141835b44fSkrw continue;
5151835b44fSkrw ucom += 4;
5161835b44fSkrw id = strchr(ucom, ':');
5171835b44fSkrw if (id == NULL)
5181835b44fSkrw continue;
5191835b44fSkrw *id++ = '\0';
5201835b44fSkrw if (strcasecmp(id, usbid) == 0) {
5211835b44fSkrw if (asprintf(&cua, "cuaU%s", ucom) == -1)
5221835b44fSkrw err(1, NULL);
5231835b44fSkrw break;
5241835b44fSkrw }
5251835b44fSkrw }
5261835b44fSkrw return cua;
5271835b44fSkrw }
528