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