1*a096f125Skrw /* $OpenBSD: cu.c,v 1.32 2024/10/24 22:42:08 krw 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 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 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 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 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 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 289f391cec5Snicm restore_termios(void) 290f391cec5Snicm { 29111403328Snicm if (isatty(STDIN_FILENO)) 29211403328Snicm tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tio); 293f391cec5Snicm } 294f391cec5Snicm 295909d4fcfSnicm int 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 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 354f391cec5Snicm stream_error(struct bufferevent *bufev, short what, void *data) 355f391cec5Snicm { 356f391cec5Snicm event_loopexit(NULL); 357f391cec5Snicm } 358f391cec5Snicm 359f391cec5Snicm void 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 378f391cec5Snicm line_error(struct bufferevent *bufev, short what, void *data) 379f391cec5Snicm { 380f391cec5Snicm event_loopexit(NULL); 381f391cec5Snicm } 382f391cec5Snicm 383439243a3Snicm void 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 * 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 * 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) 491f928e069Sderaadt 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) 497f928e069Sderaadt return NULL; 4981835b44fSkrw } 4991835b44fSkrw return names; 5001835b44fSkrw } 5011835b44fSkrw 5021835b44fSkrw char * 5031835b44fSkrw find_ucom(const char *usbid, char *names) 5041835b44fSkrw { 505*a096f125Skrw const char *errstr; 506*a096f125Skrw const char *U; 5071835b44fSkrw char *cua, *id, *ucom; 508*a096f125Skrw uint32_t unit; 5091835b44fSkrw 5101835b44fSkrw if (names == NULL) 5111835b44fSkrw return NULL; 5121835b44fSkrw 513*a096f125Skrw /* The mapping of ucom[NN] to cuaU[C] is defined in MAKEDEV. */ 514*a096f125Skrw U ="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 515*a096f125Skrw 5165cc7c8afSjca /* names is a comma separated list of "ucom<unit#>:<usb id>". */ 5171835b44fSkrw cua = NULL; 5181835b44fSkrw for (ucom = strsep(&names, ","); ucom; ucom = strsep(&names, ",")) { 5191835b44fSkrw if (*ucom == '\0' || strncasecmp(ucom, "ucom", 4)) 5201835b44fSkrw continue; 5211835b44fSkrw ucom += 4; 5221835b44fSkrw id = strchr(ucom, ':'); 5231835b44fSkrw if (id == NULL) 5241835b44fSkrw continue; 5251835b44fSkrw *id++ = '\0'; 5261835b44fSkrw if (strcasecmp(id, usbid) == 0) { 527*a096f125Skrw unit = strtonum(ucom, 0, strlen(U) - 1, &errstr); 528*a096f125Skrw if (errstr != NULL) 529*a096f125Skrw continue; 530*a096f125Skrw if (asprintf(&cua, "cuaU%c", U[unit]) == -1) 5311835b44fSkrw err(1, NULL); 5321835b44fSkrw break; 5331835b44fSkrw } 5341835b44fSkrw } 5351835b44fSkrw return cua; 5361835b44fSkrw } 537