1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <unistd.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <regex.h> 31 #include <sac.h> 32 #include <errno.h> 33 #include <dirent.h> 34 #include <limits.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/wait.h> 38 #include <fcntl.h> 39 #include <devfsadm.h> 40 #include <syslog.h> 41 42 /* 43 * sacadm output parsing 44 */ 45 #define PMTAB_MAXLINE 512 46 #define PMTAB_SEPR ':' 47 #define PMTAB_DEVNAME_FIELD 7 /* field containing /dev/term/n */ 48 #define DIALOUT_SUFFIX ",cu" 49 #define DEVNAME_SEPR '/' 50 #define MN_SEPR ',' 51 #define MN_NULLCHAR '\0' 52 53 /* 54 * sacadm/pmadm exit codes (see /usr/include/sac.h) 55 */ 56 static char *sacerrs[] = { 57 "UNKNOWN", "Unknown exit code", 58 "E_BADARGS", "Invalid arguments", 59 "E_NOPRIV", "Not privileged", 60 "E_SAFERR", "SAF error", 61 "E_SYSERR", "System error", 62 "E_NOEXIST", "Entry does not exist", 63 "E_DUP", "Entry already exists", 64 "E_PMRUN", "Port monitor already running", 65 "E_PMNOTRUN", "Port monitor not running", 66 "E_RECOVER", "In recovery", 67 "E_SACNOTRUN", "SAC daemon not running", 68 }; 69 70 #define SAC_EXITVAL(x) ((x) >> 8) 71 #define SAC_EID(x) \ 72 (sacerrs[((uint_t)(x) > E_SACNOTRUN ? 0 : ((x)<<1))]) 73 #define SAC_EMSG(x) \ 74 (sacerrs[((uint_t)(x) > E_SACNOTRUN ? 1 : (((x)<<1) + 1))]) 75 76 77 78 /* 79 * create port monitors for each group of PM_GRPSZ port devices. 80 */ 81 #define PM_GRPSZ 64 82 83 /* 84 * compute port monitor # and base index 85 */ 86 #define PM_NUM(p) ((p) / PM_GRPSZ) 87 #define PM_SLOT(p) (PM_NUM(p) * PM_GRPSZ) 88 89 90 /* 91 * default maxports value 92 * override by setting SUNW_port_link.maxports in default/devfsadm 93 */ 94 #define MAXPORTS_DEFAULT 2048 95 96 /* 97 * command line buffer size for sacadm 98 */ 99 #define CMDLEN 1024 100 101 struct pm_alloc { 102 uint_t flags; 103 char *pm_tag; 104 }; 105 106 /* port monitor entry flags */ 107 #define PM_HAS_ENTRY 0x1 /* pm entry for this port */ 108 #define HAS_PORT_DEVICE 0x2 /* device exists */ 109 #define PORT_REMOVED 0x4 /* dangling port */ 110 #define HAS_PORT_MON 0x8 /* port monitor active */ 111 #define PM_NEEDED 0x10 /* port monitor needed */ 112 113 static int maxports; 114 static struct pm_alloc *pma; 115 static char *modname = "SUNW_port_link"; 116 117 /* 118 * devfsadm_print message id 119 */ 120 #define PORT_MID "SUNW_port_link" 121 122 /* 123 * enumeration regular expressions, port and onboard port devices 124 * On x86, /dev/term|cua/[a..z] namespace is split into 2: 125 * a-d are assigned based on minor name. e-z are 126 * assigned via enumeration. 127 */ 128 static devfsadm_enumerate_t port_rules[] = 129 {"^(term|cua)$/^([0-9]+)$", 1, MATCH_MINOR, "1"}; 130 131 #ifdef __i386 132 static devfsadm_enumerate_t obport_rules[] = 133 {"^(term|cua)$/^([e-z])$", 1, MATCH_MINOR, "1"}; 134 static char start_id[] = "e"; 135 #else 136 static devfsadm_enumerate_t obport_rules[] = 137 {"^(term|cua)$/^([a-z])$", 1, MATCH_MINOR, "1"}; 138 static char start_id[] = "a"; 139 #endif 140 141 static int serial_port_create(di_minor_t minor, di_node_t node); 142 static int onbrd_port_create(di_minor_t minor, di_node_t node); 143 static int dialout_create(di_minor_t minor, di_node_t node); 144 static int onbrd_dialout_create(di_minor_t minor, di_node_t node); 145 static int rsc_port_create(di_minor_t minor, di_node_t node); 146 static int lom_port_create(di_minor_t minor, di_node_t node); 147 static int pcmcia_port_create(di_minor_t minor, di_node_t node); 148 static int pcmcia_dialout_create(di_minor_t minor, di_node_t node); 149 static void rm_dangling_port(char *devname); 150 static void update_sacadm_db(void); 151 static int parse_portno(char *dname); 152 static int is_dialout(char *dname); 153 static int load_ttymondb(void); 154 static void remove_pm_entry(char *pmtag, int port); 155 static void add_pm_entry(int port); 156 static void delete_port_monitor(int port); 157 static void add_port_monitor(int port); 158 static int execute(const char *s); 159 static char *pmtab_parse_portname(char *cmdbuf); 160 static void *pma_alloc(void); 161 static void pma_free(void); 162 extern char *defread(char *varname); 163 extern int defopen(char *fname); 164 165 /* 166 * devfs create callback register 167 */ 168 static devfsadm_create_t ports_cbt[] = { 169 {"pseudo", "ddi_pseudo", "su", 170 TYPE_EXACT | DRV_EXACT, ILEVEL_1, rsc_port_create}, 171 {"port", "ddi_serial:lomcon", "su", 172 TYPE_EXACT | DRV_EXACT, ILEVEL_1, lom_port_create}, 173 {"port", "ddi_serial", "pcser", 174 TYPE_EXACT | DRV_EXACT, ILEVEL_1, pcmcia_port_create}, 175 {"port", "ddi_serial:dialout", "pcser", 176 TYPE_EXACT | DRV_EXACT, ILEVEL_1, pcmcia_dialout_create}, 177 {"port", "ddi_serial", NULL, 178 TYPE_EXACT, ILEVEL_0, serial_port_create}, 179 {"port", "ddi_serial:mb", NULL, 180 TYPE_EXACT, ILEVEL_0, onbrd_port_create}, 181 {"port", "ddi_serial:dialout", NULL, 182 TYPE_EXACT, ILEVEL_0, dialout_create}, 183 {"port", "ddi_serial:dialout,mb", NULL, 184 TYPE_EXACT, ILEVEL_0, onbrd_dialout_create}, 185 }; 186 DEVFSADM_CREATE_INIT_V0(ports_cbt); 187 188 /* 189 * devfs cleanup register 190 * no cleanup rules for PCMCIA port devices 191 */ 192 static devfsadm_remove_t ports_remove_cbt[] = { 193 {"port", "^term/[0-9]+$", RM_PRE | RM_ALWAYS | RM_HOT, ILEVEL_0, 194 rm_dangling_port}, 195 {"port", "^cua/[0-9]+$", RM_PRE | RM_ALWAYS | RM_HOT, ILEVEL_0, 196 devfsadm_rm_all}, 197 {"port", "^(term|cua)/[a-z]$", 198 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all}, 199 }; 200 DEVFSADM_REMOVE_INIT_V0(ports_remove_cbt); 201 202 int 203 minor_init() 204 { 205 char *maxport_str; 206 207 if (defopen("/etc/default/devfsadm") == 0) { 208 maxport_str = defread("SUNW_port_link.maxports"); 209 if ((maxport_str == NULL) || 210 (sscanf(maxport_str, "%d", &maxports) != 1)) { 211 maxports = MAXPORTS_DEFAULT; 212 } 213 /* close defaults file */ 214 (void) defopen(NULL); 215 } else { 216 maxports = MAXPORTS_DEFAULT; 217 } 218 219 devfsadm_print(CHATTY_MID, "%s: maximum number of port devices (%d)\n", 220 modname, maxports); 221 222 if (pma_alloc() == NULL) 223 return (DEVFSADM_FAILURE); 224 225 return (DEVFSADM_SUCCESS); 226 } 227 228 int 229 minor_fini() 230 { 231 /* 232 * update the sacadm database only if we are updating 233 * this platform (no -r option) 234 */ 235 if (strcmp(devfsadm_root_path(), "/") == 0) 236 update_sacadm_db(); 237 238 pma_free(); 239 240 return (DEVFSADM_SUCCESS); 241 } 242 243 /* 244 * Called for all serial devices that are NOT onboard 245 * Creates links of the form "/dev/term/[0..n]" 246 * Schedules an update the sacadm (portmon). 247 */ 248 static int 249 serial_port_create(di_minor_t minor, di_node_t node) 250 { 251 char l_path[MAXPATHLEN], p_path[MAXPATHLEN]; 252 char *devfspath, *buf, *minor_name; 253 int port_num; 254 255 devfspath = di_devfs_path(node); 256 if (devfspath == NULL) { 257 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 258 return (DEVFSADM_CONTINUE); 259 } 260 261 if ((minor_name = di_minor_name(minor)) == NULL) { 262 devfsadm_errprint("%s: NULL minor name\n\t%s\n", modname, 263 devfspath); 264 di_devfs_path_free(devfspath); 265 return (DEVFSADM_CONTINUE); 266 } 267 268 /* 269 * verify dialout ports do not come in on this nodetype 270 */ 271 if (is_dialout(minor_name)) { 272 devfsadm_errprint("%s: dialout device\n\t%s:%s\n", 273 modname, devfspath, minor_name); 274 di_devfs_path_free(devfspath); 275 return (DEVFSADM_CONTINUE); 276 } 277 278 /* 279 * add the minor name to the physical path so we can 280 * enum the port# and create the link. 281 */ 282 (void) strcpy(p_path, devfspath); 283 (void) strcat(p_path, ":"); 284 (void) strcat(p_path, minor_name); 285 di_devfs_path_free(devfspath); 286 287 if (devfsadm_enumerate_int(p_path, 0, &buf, port_rules, 1)) { 288 devfsadm_errprint("%s:serial_port_create:" 289 " enumerate_int() failed\n\t%s\n", 290 modname, p_path); 291 return (DEVFSADM_CONTINUE); 292 } 293 294 (void) strcpy(l_path, "term/"); 295 (void) strcat(l_path, buf); 296 (void) devfsadm_mklink(l_path, node, minor, 0); 297 298 /* 299 * This is probably a USB serial port coming into the system 300 * because someone just plugged one in. Log an indication of 301 * this to syslog just in case someone wants to know what the 302 * name of the new serial device is .. 303 */ 304 (void) syslog(LOG_INFO, "serial device /dev/%s present", l_path); 305 306 /* 307 * update the portmon database if this port falls within 308 * the valid range of ports. 309 */ 310 if ((port_num = parse_portno(buf)) != -1) { 311 pma[port_num].flags |= HAS_PORT_DEVICE; 312 } 313 314 free(buf); 315 return (DEVFSADM_CONTINUE); 316 } 317 318 /* 319 * Called for all dialout devices that are NOT onboard 320 * Creates links of the form "/dev/cua/[0..n]" 321 */ 322 static int 323 dialout_create(di_minor_t minor, di_node_t node) 324 { 325 char l_path[MAXPATHLEN], p_path[MAXPATHLEN]; 326 char *devfspath, *buf, *mn; 327 328 devfspath = di_devfs_path(node); 329 if (devfspath == NULL) { 330 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 331 return (DEVFSADM_CONTINUE); 332 } 333 334 if ((mn = di_minor_name(minor)) == NULL) { 335 devfsadm_errprint("%s: NULL minorname\n\t%s\n", 336 modname, devfspath); 337 di_devfs_path_free(devfspath); 338 return (DEVFSADM_CONTINUE); 339 } 340 341 if (!is_dialout(mn)) { 342 devfsadm_errprint("%s: invalid minor name\n\t%s:%s\n", 343 modname, devfspath, mn); 344 di_devfs_path_free(devfspath); 345 return (DEVFSADM_CONTINUE); 346 } 347 348 (void) strcpy(p_path, devfspath); 349 (void) strcat(p_path, ":"); 350 (void) strcat(p_path, mn); 351 di_devfs_path_free(devfspath); 352 353 if (devfsadm_enumerate_int(p_path, 0, &buf, port_rules, 1)) { 354 devfsadm_errprint("%s:dialout_create:" 355 " enumerate_int() failed\n\t%s\n", 356 modname, p_path); 357 return (DEVFSADM_CONTINUE); 358 } 359 (void) strcpy(l_path, "cua/"); 360 (void) strcat(l_path, buf); 361 362 /* 363 * add the minor name to the physical path so we can create 364 * the link. 365 */ 366 (void) devfsadm_mklink(l_path, node, minor, 0); 367 368 free(buf); 369 return (DEVFSADM_CONTINUE); 370 } 371 372 #ifdef __i386 373 374 static int 375 portcmp(char *devfs_path, char *phys_path) 376 { 377 char *p1, *p2; 378 int rv; 379 380 p2 = NULL; 381 382 p1 = strrchr(devfs_path, ':'); 383 if (p1 == NULL) 384 return (1); 385 386 p1 = strchr(p1, ','); 387 if (p1) 388 *p1 = '\0'; 389 390 p2 = strrchr(phys_path, ':'); 391 if (p2 == NULL) { 392 rv = -1; 393 goto out; 394 } 395 396 p2 = strchr(p2, ','); 397 if (p2) 398 *p2 = '\0'; 399 400 rv = strcmp(devfs_path, phys_path); 401 402 out: 403 if (p1) 404 *p1 = ','; 405 if (p2) 406 *p2 = ','; 407 408 return (rv); 409 } 410 411 /* 412 * If the minor name begins with [a-d] and the 413 * links in /dev/term/<char> and /dev/cua/<char> 414 * don't point at a different minor, then we can 415 * create compatibility links for this minor. 416 * Returns: 417 * port id if a compatibility link can be created. 418 * NULL otherwise 419 */ 420 static char * 421 check_compat_ports(di_node_t node, char *phys_path, char *minor) 422 { 423 char portid = *minor; 424 char port[PATH_MAX]; 425 char *devfs_path; 426 427 if (portid < 'a' || portid > 'd') 428 return (NULL); 429 430 (void) snprintf(port, sizeof (port), "term/%c", portid); 431 if (devfsadm_read_link(node, port, &devfs_path) == DEVFSADM_SUCCESS && 432 portcmp(devfs_path, phys_path) != 0) { 433 free(devfs_path); 434 return (NULL); 435 } 436 437 free(devfs_path); 438 439 (void) snprintf(port, sizeof (port), "cua/%c", portid); 440 if (devfsadm_read_link(node, port, &devfs_path) == DEVFSADM_SUCCESS && 441 portcmp(devfs_path, phys_path) != 0) { 442 free(devfs_path); 443 return (NULL); 444 } 445 446 free(devfs_path); 447 448 /* 449 * Neither link exists or both links point at "phys_path" 450 * We can safely create compatibility links. 451 */ 452 port[0] = portid; 453 port[1] = '\0'; 454 455 return (s_strdup(port)); 456 } 457 458 #endif 459 460 /* 461 * Called for all Onboard serial devices 462 * Creates links of the form "/dev/term/[a..z]" 463 */ 464 static int 465 onbrd_port_create(di_minor_t minor, di_node_t node) 466 { 467 char l_path[MAXPATHLEN], p_path[MAXPATHLEN]; 468 char *devfspath, *buf, *minor_name; 469 470 devfspath = di_devfs_path(node); 471 if (devfspath == NULL) { 472 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 473 return (DEVFSADM_CONTINUE); 474 } 475 476 if ((minor_name = di_minor_name(minor)) == NULL) { 477 devfsadm_errprint("%s: NULL minor name\n\t%s\n", 478 modname, devfspath); 479 di_devfs_path_free(devfspath); 480 return (DEVFSADM_CONTINUE); 481 } 482 483 /* 484 * verify dialout ports do not come in on this nodetype 485 */ 486 if (is_dialout(minor_name)) { 487 devfsadm_errprint("%s: dialout device\n\t%s:%s\n", modname, 488 devfspath, minor_name); 489 di_devfs_path_free(devfspath); 490 return (DEVFSADM_CONTINUE); 491 } 492 493 (void) strcpy(p_path, devfspath); 494 (void) strcat(p_path, ":"); 495 (void) strcat(p_path, minor_name); 496 di_devfs_path_free(devfspath); 497 498 499 buf = NULL; 500 501 #ifdef __i386 502 buf = check_compat_ports(node, p_path, minor_name); 503 #endif 504 505 /* 506 * devfsadm_enumerate_char_start() is a private interface for use by the 507 * ports module only 508 */ 509 if (!buf && devfsadm_enumerate_char_start(p_path, 0, &buf, obport_rules, 510 1, start_id)) { 511 devfsadm_errprint("%s: devfsadm_enumerate_char_start() failed" 512 "\n\t%s\n", modname, p_path); 513 return (DEVFSADM_CONTINUE); 514 } 515 516 (void) strcpy(l_path, "term/"); 517 (void) strcat(l_path, buf); 518 (void) devfsadm_mklink(l_path, node, minor, 0); 519 free(buf); 520 return (DEVFSADM_CONTINUE); 521 } 522 523 /* 524 * Onboard dialout devices 525 * Creates links of the form "/dev/cua/[a..z]" 526 */ 527 static int 528 onbrd_dialout_create(di_minor_t minor, di_node_t node) 529 { 530 char l_path[MAXPATHLEN], p_path[MAXPATHLEN]; 531 char *devfspath, *buf, *mn; 532 533 devfspath = di_devfs_path(node); 534 if (devfspath == NULL) { 535 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 536 return (DEVFSADM_CONTINUE); 537 } 538 539 if ((mn = di_minor_name(minor)) == NULL) { 540 devfsadm_errprint("%s: NULL minor name\n\t%s\n", 541 modname, devfspath); 542 di_devfs_path_free(devfspath); 543 return (DEVFSADM_CONTINUE); 544 } 545 546 /* 547 * verify this is a dialout port 548 */ 549 if (!is_dialout(mn)) { 550 devfsadm_errprint("%s: not a dialout device\n\t%s:%s\n", 551 modname, devfspath, mn); 552 di_devfs_path_free(devfspath); 553 return (DEVFSADM_CONTINUE); 554 } 555 556 (void) strcpy(p_path, devfspath); 557 (void) strcat(p_path, ":"); 558 (void) strcat(p_path, mn); 559 di_devfs_path_free(devfspath); 560 561 buf = NULL; 562 563 #ifdef __i386 564 buf = check_compat_ports(node, p_path, mn); 565 #endif 566 567 /* 568 * devfsadm_enumerate_char_start() is a private interface 569 * for use by the ports module only. 570 */ 571 if (!buf && devfsadm_enumerate_char_start(p_path, 0, &buf, obport_rules, 572 1, start_id)) { 573 devfsadm_errprint("%s: devfsadm_enumerate_char_start() failed" 574 "\n\t%s\n", modname, p_path); 575 return (DEVFSADM_CONTINUE); 576 } 577 578 /* 579 * create the logical link 580 */ 581 (void) strcpy(l_path, "cua/"); 582 (void) strcat(l_path, buf); 583 (void) devfsadm_mklink(l_path, node, minor, 0); 584 free(buf); 585 return (DEVFSADM_CONTINUE); 586 } 587 588 589 /* 590 * Remote System Controller (RSC) serial ports 591 * Creates links of the form "/dev/rsc-control" | "/dev/term/rsc-console". 592 */ 593 static int 594 rsc_port_create(di_minor_t minor, di_node_t node) 595 { 596 char *devfspath; 597 char *minor_name; 598 599 600 devfspath = di_devfs_path(node); 601 if (devfspath == NULL) { 602 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 603 return (DEVFSADM_CONTINUE); 604 } 605 606 if ((minor_name = di_minor_name(minor)) == NULL) { 607 devfsadm_errprint("%s: NULL minor name\n\t%s\n", 608 modname, devfspath); 609 di_devfs_path_free(devfspath); 610 return (DEVFSADM_CONTINUE); 611 } 612 613 /* 614 * if this is the RSC console serial port (i.e. the minor name == ssp), 615 * create /dev/term/rsc-console link and then we are done with this 616 * node. 617 */ 618 if (strcmp(minor_name, "ssp") == 0) { 619 (void) devfsadm_mklink("term/rsc-console", node, minor, 0); 620 di_devfs_path_free(devfspath); 621 return (DEVFSADM_TERMINATE); 622 623 /* 624 * else if this is the RSC control serial port (i.e. the minor name == 625 * sspctl), create /dev/rsc-control link and then we are done with this 626 * node. 627 */ 628 } else if (strcmp(minor_name, "sspctl") == 0) { 629 (void) devfsadm_mklink("rsc-control", node, minor, 0); 630 di_devfs_path_free(devfspath); 631 return (DEVFSADM_TERMINATE); 632 } 633 634 /* This is not an RSC node, continue... */ 635 di_devfs_path_free(devfspath); 636 return (DEVFSADM_CONTINUE); 637 } 638 639 /* 640 * Lights Out Management (LOM) serial ports 641 * Creates links of the form "/dev/term/lom-console". 642 */ 643 static int 644 lom_port_create(di_minor_t minor, di_node_t node) 645 { 646 char *devfspath; 647 char *minor_name; 648 649 devfspath = di_devfs_path(node); 650 if (devfspath == NULL) { 651 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 652 return (DEVFSADM_CONTINUE); 653 } 654 655 if ((minor_name = di_minor_name(minor)) == NULL) { 656 devfsadm_errprint("%s: NULL minor name\n\t%s\n", 657 modname, devfspath); 658 di_devfs_path_free(devfspath); 659 return (DEVFSADM_CONTINUE); 660 } 661 662 /* 663 * if this is the LOM console serial port (i.e. the minor 664 * name == lom-console ), create /dev/term/lom-console link and 665 * then we are done with this node. 666 */ 667 if (strcmp(minor_name, "lom-console") == 0) { 668 (void) devfsadm_mklink("term/lom-console", node, minor, 0); 669 di_devfs_path_free(devfspath); 670 return (DEVFSADM_TERMINATE); 671 } 672 673 /* This is not a LOM node, continue... */ 674 di_devfs_path_free(devfspath); 675 return (DEVFSADM_CONTINUE); 676 } 677 678 /* 679 * PCMCIA serial ports 680 * Creates links of the form "/dev/term/pcN", where N is the PCMCIA 681 * socket # the device is plugged into. 682 */ 683 #define PCMCIA_MAX_SOCKETS 64 684 #define PCMCIA_SOCKETNO(x) ((x) & (PCMCIA_MAX_SOCKETS - 1)) 685 686 static int 687 pcmcia_port_create(di_minor_t minor, di_node_t node) 688 { 689 char l_path[MAXPATHLEN]; 690 char *devfspath; 691 int socket, *intp; 692 693 devfspath = di_devfs_path(node); 694 if (devfspath == NULL) { 695 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 696 return (DEVFSADM_TERMINATE); 697 } 698 699 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "socket", &intp) <= 0) { 700 devfsadm_errprint("%s: failed pcmcia socket lookup\n\t%s\n", 701 modname, devfspath); 702 di_devfs_path_free(devfspath); 703 return (DEVFSADM_TERMINATE); 704 } 705 706 socket = PCMCIA_SOCKETNO(*intp); 707 708 di_devfs_path_free(devfspath); 709 710 (void) sprintf(l_path, "term/pc%d", socket); 711 (void) devfsadm_mklink(l_path, node, minor, 0); 712 713 return (DEVFSADM_TERMINATE); 714 } 715 716 /* 717 * PCMCIA dialout serial ports 718 * Creates links of the form "/dev/cua/pcN", where N is the PCMCIA 719 * socket number the device is plugged into. 720 */ 721 static int 722 pcmcia_dialout_create(di_minor_t minor, di_node_t node) 723 { 724 char l_path[MAXPATHLEN]; 725 char *devfspath; 726 int socket, *intp; 727 728 devfspath = di_devfs_path(node); 729 if (devfspath == NULL) { 730 devfsadm_errprint("%s: di_devfs_path() failed\n", modname); 731 return (DEVFSADM_TERMINATE); 732 } 733 734 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "socket", &intp) <= 0) { 735 devfsadm_errprint("%s: failed socket lookup\n\t%s\n", 736 modname, devfspath); 737 di_devfs_path_free(devfspath); 738 return (DEVFSADM_TERMINATE); 739 } 740 741 socket = PCMCIA_SOCKETNO(*intp); 742 743 di_devfs_path_free(devfspath); 744 (void) sprintf(l_path, "cua/pc%d", socket); 745 (void) devfsadm_mklink(l_path, node, minor, 0); 746 747 return (DEVFSADM_TERMINATE); 748 } 749 750 751 /* 752 * Removes port entries that no longer have devices 753 * backing them 754 * Schedules an update the sacadm (portmon) database 755 */ 756 static void 757 rm_dangling_port(char *devname) 758 { 759 char *portstr; 760 int portnum; 761 762 devfsadm_print(PORT_MID, "%s:rm_stale_port: %s\n", 763 modname, devname); 764 765 if ((portstr = strrchr(devname, (int)'/')) == NULL) { 766 devfsadm_errprint("%s: invalid name: %s\n", 767 modname, devname); 768 return; 769 } 770 portstr++; 771 772 /* 773 * mark for removal from sacadm database 774 */ 775 if ((portnum = parse_portno(portstr)) != -1) 776 pma[portnum].flags |= PORT_REMOVED; 777 778 devfsadm_rm_all(devname); 779 } 780 781 /* 782 * Algorithm is to step through ports; checking for unneeded PM entries 783 * entries that should be there but are not. Every PM_GRPSZ entries 784 * check to see if there are any entries for the port monitor group; 785 * if not, delete the group. 786 */ 787 static void 788 update_sacadm_db(void) 789 { 790 int i; 791 792 if (load_ttymondb() != DEVFSADM_SUCCESS) 793 return; 794 795 for (i = 0; i < maxports; i++) { 796 /* 797 * if this port was removed and has a port 798 * monitor entry, remove the entry from the sacadm db 799 */ 800 if ((pma[i].flags & PORT_REMOVED) != 0) { 801 if ((pma[i].flags & PM_HAS_ENTRY) != 0) 802 remove_pm_entry(pma[i].pm_tag, i); 803 } 804 805 /* 806 * if this port is present and lacks a port monitor 807 * add an entry to the sacadm db 808 */ 809 if (pma[i].flags & HAS_PORT_DEVICE) { 810 if (!(pma[i].flags & PM_HAS_ENTRY)) 811 add_pm_entry(i); 812 } 813 814 /* 815 * if this port has a pm entry, mark as needing 816 * a port monitor within this range of ports 817 */ 818 if ((pma[i].flags & PM_HAS_ENTRY)) 819 pma[PM_SLOT(i)].flags |= PM_NEEDED; 820 821 /* 822 * continue for the range of ports per-portmon 823 */ 824 if (((i + 1) % PM_GRPSZ) != 0) 825 continue; 826 827 /* 828 * if there are no ports active on the range we have 829 * just completed, remove the port monitor entry if 830 * it exists 831 */ 832 if ((pma[PM_SLOT(i)].flags & (PM_NEEDED | HAS_PORT_MON)) == 833 HAS_PORT_MON) { 834 delete_port_monitor(i); 835 } 836 837 } 838 839 /* 840 * cleanup remaining port monitor, if active 841 */ 842 if ((i % PM_GRPSZ != 0) && 843 ((pma[PM_SLOT(i)].flags & (PM_NEEDED | HAS_PORT_MON)) == 844 HAS_PORT_MON)) { 845 delete_port_monitor(i); 846 } 847 } 848 849 /* 850 * Determine which port monitor entries already exist by invoking pmadm(1m) 851 * to list all configured 'ttymon' port monitor entries. 852 * Do not explicitly report errors from executing pmadm(1m) or sacadm(1m) 853 * commands to remain compatible with the ports(1m) implementation. 854 */ 855 static int 856 load_ttymondb(void) 857 { 858 char cmdline[CMDLEN]; 859 char cmdbuf[PMTAB_MAXLINE+1]; 860 int sac_exitval; 861 FILE *fs_popen; 862 char *portname; /* pointer to a tty name */ 863 int portnum; 864 char *ptr; 865 char *error_msg = "%s: failed to load port monitor database\n"; 866 867 (void) strcpy(cmdline, "/usr/sbin/pmadm -L -t ttymon"); 868 fs_popen = popen(cmdline, "r"); 869 if (fs_popen == NULL) { 870 devfsadm_print(VERBOSE_MID, error_msg, modname); 871 return (DEVFSADM_FAILURE); 872 } 873 874 while (fgets(cmdbuf, PMTAB_MAXLINE, fs_popen) != NULL) { 875 if ((portname = pmtab_parse_portname(cmdbuf)) == NULL) { 876 devfsadm_print(VERBOSE_MID, 877 "load_ttymondb: failed to parse portname\n"); 878 devfsadm_print(VERBOSE_MID, 879 "load_ttymondb: buffer \"%s\"\n", cmdbuf); 880 goto load_failed; 881 } 882 883 devfsadm_print(PORT_MID, "%s:load_ttymondb: port %s ", 884 modname, portname); 885 886 /* 887 * skip onboard ports 888 * There is no reliable way to determine if we 889 * should start a port monitor on these lines. 890 */ 891 if ((portnum = parse_portno(portname)) == -1) { 892 devfsadm_print(PORT_MID, "ignored\n"); 893 continue; 894 } 895 896 /* 897 * the first field of the pmadm output is 898 * the port monitor name for this entry 899 */ 900 if ((ptr = strchr(cmdbuf, PMTAB_SEPR)) == NULL) { 901 devfsadm_print(VERBOSE_MID, 902 "load_ttymondb: no portmon tag\n"); 903 goto load_failed; 904 } 905 906 *ptr = MN_NULLCHAR; 907 if ((pma[portnum].pm_tag = strdup(cmdbuf)) == NULL) { 908 devfsadm_errprint("load_ttymondb: failed strdup\n"); 909 goto load_failed; 910 } 911 pma[portnum].flags |= PM_HAS_ENTRY; 912 pma[PM_SLOT(portnum)].flags |= HAS_PORT_MON; 913 devfsadm_print(PORT_MID, "present\n"); 914 } 915 (void) pclose(fs_popen); 916 return (DEVFSADM_SUCCESS); 917 918 load_failed: 919 920 /* 921 * failed to load the port monitor database 922 */ 923 devfsadm_print(VERBOSE_MID, error_msg, modname); 924 sac_exitval = SAC_EXITVAL(pclose(fs_popen)); 925 if (sac_exitval != 0) { 926 devfsadm_print(VERBOSE_MID, 927 "pmadm: (%s) %s\n", SAC_EID(sac_exitval), 928 SAC_EMSG(sac_exitval)); 929 } 930 return (DEVFSADM_FAILURE); 931 } 932 933 /* 934 * add a port monitor entry for device /dev/term/"port" 935 */ 936 static void 937 add_pm_entry(int port) 938 { 939 char cmdline[CMDLEN]; 940 int sac_exitval; 941 942 add_port_monitor(port); 943 (void) sprintf(cmdline, 944 "/usr/sbin/pmadm -a -p ttymon%d -s %d -i root" 945 " -v `/usr/sbin/ttyadm -V` -fux -y\"/dev/term/%d\"" 946 " -m \"`/usr/sbin/ttyadm -d /dev/term/%d -s /usr/bin/login" 947 " -l 9600 -p \\\"login: \\\"`\"", PM_NUM(port), port, port, port); 948 949 if (devfsadm_noupdate() == DEVFSADM_FALSE) { 950 sac_exitval = execute(cmdline); 951 if ((sac_exitval != 0) && (sac_exitval != E_SACNOTRUN)) { 952 devfsadm_print(VERBOSE_MID, 953 "failed to add port monitor entry" 954 " for /dev/term/%d\n", port); 955 devfsadm_print(VERBOSE_MID, "pmadm: (%s) %s\n", 956 SAC_EID(sac_exitval), SAC_EMSG(sac_exitval)); 957 } 958 } 959 pma[port].flags |= PM_HAS_ENTRY; 960 devfsadm_print(VERBOSE_MID, "%s: /dev/term/%d added to sacadm\n", 961 modname, port); 962 } 963 964 static void 965 remove_pm_entry(char *pmtag, int port) 966 { 967 968 char cmdline[CMDLEN]; 969 int sac_exitval; 970 971 if (devfsadm_noupdate() == DEVFSADM_FALSE) { 972 (void) snprintf(cmdline, sizeof (cmdline), 973 "/usr/sbin/pmadm -r -p %s -s %d", pmtag, port); 974 sac_exitval = execute(cmdline); 975 if ((sac_exitval != 0) && (sac_exitval != E_SACNOTRUN)) { 976 devfsadm_print(VERBOSE_MID, 977 "failed to remove port monitor entry" 978 " for /dev/term/%d\n", port); 979 devfsadm_print(VERBOSE_MID, "pmadm: (%s) %s\n", 980 SAC_EID(sac_exitval), SAC_EMSG(sac_exitval)); 981 } 982 } 983 pma[port].flags &= ~PM_HAS_ENTRY; 984 devfsadm_print(VERBOSE_MID, "%s: /dev/term/%d removed from sacadm\n", 985 modname, port); 986 } 987 988 989 /* 990 * delete_port_monitor() 991 * Check for the existence of a port monitor for "port" and remove it if 992 * one exists 993 */ 994 static void 995 delete_port_monitor(int port) 996 { 997 char cmdline[CMDLEN]; 998 int sac_exitval; 999 1000 (void) sprintf(cmdline, "/usr/sbin/sacadm -L -p ttymon%d", 1001 PM_NUM(port)); 1002 sac_exitval = execute(cmdline); 1003 1004 /* clear the PM tag and return if the port monitor is not active */ 1005 if (sac_exitval == E_NOEXIST) { 1006 pma[PM_SLOT(port)].flags &= ~HAS_PORT_MON; 1007 return; 1008 } 1009 1010 /* some other sacadm(1m) error, log and return */ 1011 if (sac_exitval != 0) { 1012 devfsadm_print(VERBOSE_MID, "sacadm: (%s) %s\n", 1013 SAC_EID(sac_exitval), SAC_EMSG(sac_exitval)); 1014 return; 1015 } 1016 1017 if (devfsadm_noupdate() == DEVFSADM_FALSE) { 1018 (void) sprintf(cmdline, 1019 "/usr/sbin/sacadm -r -p ttymon%d", PM_NUM(port)); 1020 if (sac_exitval = execute(cmdline)) { 1021 devfsadm_print(VERBOSE_MID, 1022 "failed to remove port monitor ttymon%d\n", 1023 PM_NUM(port)); 1024 devfsadm_print(VERBOSE_MID, "sacadm: (%s) %s\n", 1025 SAC_EID(sac_exitval), SAC_EMSG(sac_exitval)); 1026 } 1027 } 1028 devfsadm_print(VERBOSE_MID, "%s: port monitor ttymon%d removed\n", 1029 modname, PM_NUM(port)); 1030 pma[PM_SLOT(port)].flags &= ~HAS_PORT_MON; 1031 } 1032 1033 static void 1034 add_port_monitor(int port) 1035 { 1036 char cmdline[CMDLEN]; 1037 int sac_exitval; 1038 1039 if ((pma[PM_SLOT(port)].flags & HAS_PORT_MON) != 0) { 1040 return; 1041 } 1042 1043 (void) sprintf(cmdline, 1044 "/usr/sbin/sacadm -l -p ttymon%d", PM_NUM(port)); 1045 sac_exitval = execute(cmdline); 1046 if (sac_exitval == E_NOEXIST) { 1047 (void) sprintf(cmdline, 1048 "/usr/sbin/sacadm -a -n 2 -p ttymon%d -t ttymon" 1049 " -c /usr/lib/saf/ttymon -v \"`/usr/sbin/ttyadm" 1050 " -V`\" -y \"Ports %d-%d\"", PM_NUM(port), PM_SLOT(port), 1051 PM_SLOT(port) + (PM_GRPSZ - 1)); 1052 if (devfsadm_noupdate() == DEVFSADM_FALSE) { 1053 if (sac_exitval = execute(cmdline)) { 1054 devfsadm_print(VERBOSE_MID, 1055 "failed to add port monitor ttymon%d\n", 1056 PM_NUM(port)); 1057 devfsadm_print(VERBOSE_MID, "sacadm: (%s) %s\n", 1058 SAC_EID(sac_exitval), 1059 SAC_EMSG(sac_exitval)); 1060 } 1061 } 1062 devfsadm_print(VERBOSE_MID, "%s: port monitor ttymon%d added\n", 1063 modname, PM_NUM(port)); 1064 } 1065 pma[PM_SLOT(port)].flags |= HAS_PORT_MON; 1066 } 1067 1068 /* 1069 * parse port number from string 1070 * returns port number if in range [0..maxports] 1071 */ 1072 static int 1073 parse_portno(char *dname) 1074 { 1075 int pn; 1076 1077 if (sscanf(dname, "%d", &pn) != 1) 1078 return (-1); 1079 1080 if ((pn < 0) || (pn > maxports)) { 1081 devfsadm_print(VERBOSE_MID, 1082 "%s:parse_portno: %d not in range (0..%d)\n", 1083 modname, pn, maxports); 1084 return (-1); 1085 } 1086 1087 return (pn); 1088 } 1089 1090 1091 /* 1092 * fork and exec a command, waiting for the command to 1093 * complete and return it's status 1094 */ 1095 static int 1096 execute(const char *s) 1097 { 1098 int status; 1099 int fd; 1100 pid_t pid; 1101 pid_t w; 1102 1103 /* 1104 * fork a single threaded child proc to execute the 1105 * sacadm command string 1106 */ 1107 devfsadm_print(PORT_MID, "%s: execute:\n\t%s\n", modname, s); 1108 if ((pid = fork1()) == 0) { 1109 (void) close(0); 1110 (void) close(1); 1111 (void) close(2); 1112 fd = open("/dev/null", O_RDWR); 1113 (void) dup(fd); 1114 (void) dup(fd); 1115 (void) execl("/sbin/sh", "sh", "-c", s, 0); 1116 /* 1117 * return the sacadm exit status (see _exit(2)) 1118 */ 1119 _exit(127); 1120 } 1121 1122 /* 1123 * wait for child process to terminate 1124 */ 1125 for (;;) { 1126 w = wait(&status); 1127 if (w == pid) { 1128 devfsadm_print(PORT_MID, "%s:exit status (%d)\n", 1129 modname, SAC_EXITVAL(status)); 1130 return (SAC_EXITVAL(status)); 1131 } 1132 if (w == (pid_t)-1) { 1133 devfsadm_print(VERBOSE_MID, "%s: exec failed\n", 1134 modname); 1135 return (-1); 1136 } 1137 } 1138 1139 /* NOTREACHED */ 1140 } 1141 1142 1143 /* 1144 * check if the minor name is suffixed with ",cu" 1145 */ 1146 static int 1147 is_dialout(char *name) 1148 { 1149 char *s_chr; 1150 1151 if ((name == NULL) || (s_chr = strrchr(name, MN_SEPR)) == NULL) 1152 return (0); 1153 1154 if (strcmp(s_chr, DIALOUT_SUFFIX) == 0) { 1155 return (1); 1156 } else { 1157 return (0); 1158 } 1159 } 1160 1161 1162 /* 1163 * Get the name of the port device from a pmtab entry. 1164 * Note the /dev/term/ part is taken off. 1165 */ 1166 static char * 1167 pmtab_parse_portname(char *buffer) 1168 { 1169 int i; 1170 char *bufp, *devnamep, *portnamep; 1171 1172 /* 1173 * position to the device name (field 8) 1174 */ 1175 bufp = strchr(buffer, PMTAB_SEPR); 1176 for (i = 0; i < PMTAB_DEVNAME_FIELD; i++) { 1177 if (bufp == NULL) 1178 return (NULL); 1179 bufp = strchr(++bufp, PMTAB_SEPR); 1180 } 1181 1182 /* move past the ':' and locate the end of the devname */ 1183 devnamep = bufp++; 1184 if ((bufp = strchr(bufp, PMTAB_SEPR)) == NULL) 1185 return (NULL); 1186 1187 *bufp = MN_NULLCHAR; 1188 if ((portnamep = strrchr(devnamep, DEVNAME_SEPR)) == NULL) { 1189 *bufp = PMTAB_SEPR; 1190 return (NULL); 1191 } 1192 1193 /* return with "buffer" chopped after the /dev/term entry */ 1194 1195 return (++portnamep); 1196 } 1197 1198 /* 1199 * port monitor array mgmt 1200 */ 1201 static void * 1202 pma_alloc(void) 1203 { 1204 1205 if (pma != NULL) { 1206 devfsadm_errprint("%s:pma_alloc:pma != NULL\n", modname); 1207 return (NULL); 1208 } 1209 1210 if ((pma = calloc(maxports + 1, sizeof (*pma))) == NULL) { 1211 devfsadm_errprint("%s:pma_alloc:pma alloc failure\n", modname); 1212 return (NULL); 1213 } 1214 1215 return ((void *)pma); 1216 } 1217 1218 static void 1219 pma_free(void) 1220 { 1221 1222 int i; 1223 1224 if (pma == NULL) 1225 return; 1226 1227 /* 1228 * free any strings we had allocated 1229 */ 1230 for (i = 0; i <= maxports; i++) { 1231 if (pma[i].pm_tag != NULL) 1232 free(pma[i].pm_tag); 1233 } 1234 1235 free(pma); 1236 pma = NULL; 1237 } 1238