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