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