xref: /onnv-gate/usr/src/cmd/devfsadm/port_link.c (revision 12116:ea985fb42600)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59241SVikram.Hegde@Sun.COM  * Common Development and Distribution License (the "License").
69241SVikram.Hegde@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
219354STim.Marsland@Sun.COM 
220Sstevel@tonic-gate /*
23*12116SVikram.Hegde@Sun.COM  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <unistd.h>
270Sstevel@tonic-gate #include <stdio.h>
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <regex.h>
310Sstevel@tonic-gate #include <sac.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <dirent.h>
340Sstevel@tonic-gate #include <limits.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/wait.h>
380Sstevel@tonic-gate #include <fcntl.h>
390Sstevel@tonic-gate #include <devfsadm.h>
409354STim.Marsland@Sun.COM #include <syslog.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * sacadm output parsing
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate #define	PMTAB_MAXLINE		512
460Sstevel@tonic-gate #define	PMTAB_SEPR		':'
470Sstevel@tonic-gate #define	PMTAB_DEVNAME_FIELD	7	/* field containing /dev/term/n */
480Sstevel@tonic-gate #define	DIALOUT_SUFFIX		",cu"
490Sstevel@tonic-gate #define	DEVNAME_SEPR		'/'
500Sstevel@tonic-gate #define	MN_SEPR			','
510Sstevel@tonic-gate #define	MN_NULLCHAR		'\0'
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * sacadm/pmadm exit codes (see /usr/include/sac.h)
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate static char *sacerrs[] = {
570Sstevel@tonic-gate 	"UNKNOWN", "Unknown exit code",
580Sstevel@tonic-gate 	"E_BADARGS", "Invalid arguments",
590Sstevel@tonic-gate 	"E_NOPRIV", "Not privileged",
600Sstevel@tonic-gate 	"E_SAFERR", "SAF error",
610Sstevel@tonic-gate 	"E_SYSERR",  "System error",
620Sstevel@tonic-gate 	"E_NOEXIST", "Entry does not exist",
630Sstevel@tonic-gate 	"E_DUP", "Entry already exists",
640Sstevel@tonic-gate 	"E_PMRUN", "Port monitor already running",
650Sstevel@tonic-gate 	"E_PMNOTRUN", "Port monitor not running",
660Sstevel@tonic-gate 	"E_RECOVER", "In recovery",
670Sstevel@tonic-gate 	"E_SACNOTRUN", "SAC daemon not running",
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #define	SAC_EXITVAL(x)		((x) >> 8)
710Sstevel@tonic-gate #define	SAC_EID(x)	\
720Sstevel@tonic-gate 	(sacerrs[((uint_t)(x) > E_SACNOTRUN ? 0 : ((x)<<1))])
730Sstevel@tonic-gate #define	SAC_EMSG(x) \
740Sstevel@tonic-gate 	(sacerrs[((uint_t)(x) > E_SACNOTRUN ? 1 : (((x)<<1) + 1))])
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * create port monitors for each group of PM_GRPSZ port devices.
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate #define	PM_GRPSZ		64
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate  * compute port monitor # and base index
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate #define	PM_NUM(p)	((p) / PM_GRPSZ)
870Sstevel@tonic-gate #define	PM_SLOT(p)	(PM_NUM(p) * PM_GRPSZ)
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * default maxports value
920Sstevel@tonic-gate  * override by setting SUNW_port_link.maxports in default/devfsadm
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate #define	MAXPORTS_DEFAULT	2048
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate  * command line buffer size for sacadm
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate #define	CMDLEN			1024
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate struct pm_alloc {
1020Sstevel@tonic-gate 	uint_t	flags;
1030Sstevel@tonic-gate 	char	*pm_tag;
1040Sstevel@tonic-gate };
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate /* port monitor entry flags */
1070Sstevel@tonic-gate #define	PM_HAS_ENTRY	0x1		/* pm entry for this port */
1080Sstevel@tonic-gate #define	HAS_PORT_DEVICE	0x2		/* device exists */
1090Sstevel@tonic-gate #define	PORT_REMOVED	0x4		/* dangling port */
1100Sstevel@tonic-gate #define	HAS_PORT_MON	0x8		/* port monitor active */
1110Sstevel@tonic-gate #define	PM_NEEDED	0x10		/* port monitor needed */
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate static int maxports;
1140Sstevel@tonic-gate static struct pm_alloc *pma;
1150Sstevel@tonic-gate static char *modname = "SUNW_port_link";
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate  * devfsadm_print message id
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate #define	PORT_MID	"SUNW_port_link"
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate  * enumeration regular expressions, port and onboard port devices
1240Sstevel@tonic-gate  * On x86, /dev/term|cua/[a..z] namespace is split into 2:
1250Sstevel@tonic-gate  * a-d are assigned based on minor name. e-z are
1260Sstevel@tonic-gate  * assigned via enumeration.
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate static devfsadm_enumerate_t port_rules[] =
1290Sstevel@tonic-gate 	{"^(term|cua)$/^([0-9]+)$", 1, MATCH_MINOR, "1"};
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate #ifdef __i386
1320Sstevel@tonic-gate static devfsadm_enumerate_t obport_rules[] =
1330Sstevel@tonic-gate 	{"^(term|cua)$/^([e-z])$", 1, MATCH_MINOR, "1"};
1340Sstevel@tonic-gate static char start_id[] = "e";
1350Sstevel@tonic-gate #else
1360Sstevel@tonic-gate static devfsadm_enumerate_t obport_rules[] =
1370Sstevel@tonic-gate 	{"^(term|cua)$/^([a-z])$", 1, MATCH_MINOR, "1"};
1380Sstevel@tonic-gate static char start_id[] = "a";
1390Sstevel@tonic-gate #endif
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate static int serial_port_create(di_minor_t minor, di_node_t node);
1420Sstevel@tonic-gate static int onbrd_port_create(di_minor_t minor, di_node_t node);
1430Sstevel@tonic-gate static int dialout_create(di_minor_t minor, di_node_t node);
1440Sstevel@tonic-gate static int onbrd_dialout_create(di_minor_t minor, di_node_t node);
1450Sstevel@tonic-gate static int rsc_port_create(di_minor_t minor, di_node_t node);
1460Sstevel@tonic-gate static int lom_port_create(di_minor_t minor, di_node_t node);
1470Sstevel@tonic-gate static int pcmcia_port_create(di_minor_t minor, di_node_t node);
1480Sstevel@tonic-gate static int pcmcia_dialout_create(di_minor_t minor, di_node_t node);
1490Sstevel@tonic-gate static void rm_dangling_port(char *devname);
1500Sstevel@tonic-gate static void update_sacadm_db(void);
1510Sstevel@tonic-gate static int parse_portno(char *dname);
1520Sstevel@tonic-gate static int is_dialout(char *dname);
1530Sstevel@tonic-gate static int load_ttymondb(void);
1540Sstevel@tonic-gate static void remove_pm_entry(char *pmtag, int port);
1550Sstevel@tonic-gate static void add_pm_entry(int port);
1560Sstevel@tonic-gate static void delete_port_monitor(int port);
1570Sstevel@tonic-gate static void add_port_monitor(int port);
1580Sstevel@tonic-gate static int execute(const char *s);
1590Sstevel@tonic-gate static char *pmtab_parse_portname(char *cmdbuf);
1600Sstevel@tonic-gate static void *pma_alloc(void);
1610Sstevel@tonic-gate static void pma_free(void);
1620Sstevel@tonic-gate extern char *defread(char *varname);
1639241SVikram.Hegde@Sun.COM extern int defopen(char *fname);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * devfs create callback register
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate static devfsadm_create_t ports_cbt[] = {
1690Sstevel@tonic-gate 	{"pseudo", "ddi_pseudo", "su",
1700Sstevel@tonic-gate 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, rsc_port_create},
1710Sstevel@tonic-gate 	{"port", "ddi_serial:lomcon", "su",
1720Sstevel@tonic-gate 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, lom_port_create},
1730Sstevel@tonic-gate 	{"port", "ddi_serial", "pcser",
1740Sstevel@tonic-gate 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, pcmcia_port_create},
1750Sstevel@tonic-gate 	{"port", "ddi_serial:dialout", "pcser",
1760Sstevel@tonic-gate 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, pcmcia_dialout_create},
1770Sstevel@tonic-gate 	{"port", "ddi_serial", NULL,
1780Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, serial_port_create},
1790Sstevel@tonic-gate 	{"port", "ddi_serial:mb", NULL,
1800Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, onbrd_port_create},
1810Sstevel@tonic-gate 	{"port", "ddi_serial:dialout", NULL,
1820Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, dialout_create},
1830Sstevel@tonic-gate 	{"port", "ddi_serial:dialout,mb", NULL,
1840Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, onbrd_dialout_create},
1850Sstevel@tonic-gate };
1860Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(ports_cbt);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * devfs cleanup register
1900Sstevel@tonic-gate  * no cleanup rules for PCMCIA port devices
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate static devfsadm_remove_t ports_remove_cbt[] = {
19311615SJimmy.Vetayases@Sun.COM 	{"port", "^term/[0-9]+$", RM_PRE | RM_ALWAYS | RM_HOT, ILEVEL_0,
19411615SJimmy.Vetayases@Sun.COM 	    rm_dangling_port},
19511615SJimmy.Vetayases@Sun.COM 	{"port", "^cua/[0-9]+$", RM_PRE | RM_ALWAYS | RM_HOT, ILEVEL_0,
19611615SJimmy.Vetayases@Sun.COM 	    devfsadm_rm_all},
1970Sstevel@tonic-gate 	{"port", "^(term|cua)/[a-z]$",
19811615SJimmy.Vetayases@Sun.COM 	    RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all},
1990Sstevel@tonic-gate };
2000Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(ports_remove_cbt);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate int
minor_init()2030Sstevel@tonic-gate minor_init()
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	char *maxport_str;
2060Sstevel@tonic-gate 
2079241SVikram.Hegde@Sun.COM 	if (defopen("/etc/default/devfsadm") == 0) {
2089241SVikram.Hegde@Sun.COM 		maxport_str = defread("SUNW_port_link.maxports");
2099241SVikram.Hegde@Sun.COM 		if ((maxport_str == NULL) ||
2109241SVikram.Hegde@Sun.COM 		    (sscanf(maxport_str, "%d", &maxports) != 1)) {
2119241SVikram.Hegde@Sun.COM 			maxports = MAXPORTS_DEFAULT;
2129241SVikram.Hegde@Sun.COM 		}
2139241SVikram.Hegde@Sun.COM 		/* close defaults file */
2149241SVikram.Hegde@Sun.COM 		(void) defopen(NULL);
2159241SVikram.Hegde@Sun.COM 	} else {
2160Sstevel@tonic-gate 		maxports = MAXPORTS_DEFAULT;
2179241SVikram.Hegde@Sun.COM 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	devfsadm_print(CHATTY_MID, "%s: maximum number of port devices (%d)\n",
2200Sstevel@tonic-gate 	    modname, maxports);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	if (pma_alloc() == NULL)
2230Sstevel@tonic-gate 		return (DEVFSADM_FAILURE);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate int
minor_fini()2290Sstevel@tonic-gate minor_fini()
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * update the sacadm database only if we are updating
2330Sstevel@tonic-gate 	 * this platform (no -r option)
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 	if (strcmp(devfsadm_root_path(), "/") == 0)
2360Sstevel@tonic-gate 		update_sacadm_db();
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	pma_free();
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * Called for all serial devices that are NOT onboard
2450Sstevel@tonic-gate  * Creates links of the form "/dev/term/[0..n]"
2460Sstevel@tonic-gate  * Schedules an update the sacadm (portmon).
2470Sstevel@tonic-gate  */
2480Sstevel@tonic-gate static int
serial_port_create(di_minor_t minor,di_node_t node)2490Sstevel@tonic-gate serial_port_create(di_minor_t minor, di_node_t node)
2500Sstevel@tonic-gate {
2510Sstevel@tonic-gate 	char l_path[MAXPATHLEN], p_path[MAXPATHLEN];
2520Sstevel@tonic-gate 	char *devfspath, *buf, *minor_name;
2530Sstevel@tonic-gate 	int port_num;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
2560Sstevel@tonic-gate 	if (devfspath == NULL) {
2570Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
2580Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if ((minor_name = di_minor_name(minor)) == NULL) {
2620Sstevel@tonic-gate 		devfsadm_errprint("%s: NULL minor name\n\t%s\n", modname,
2630Sstevel@tonic-gate 		    devfspath);
2640Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
2650Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/*
2690Sstevel@tonic-gate 	 * verify dialout ports do not come in on this nodetype
2700Sstevel@tonic-gate 	 */
2710Sstevel@tonic-gate 	if (is_dialout(minor_name)) {
2720Sstevel@tonic-gate 		devfsadm_errprint("%s: dialout device\n\t%s:%s\n",
2730Sstevel@tonic-gate 		    modname, devfspath, minor_name);
2740Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
2750Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	/*
2799354STim.Marsland@Sun.COM 	 * add the minor name to the physical path so we can
2809354STim.Marsland@Sun.COM 	 * enum the port# and create the link.
2810Sstevel@tonic-gate 	 */
2820Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
2830Sstevel@tonic-gate 	(void) strcat(p_path, ":");
2840Sstevel@tonic-gate 	(void) strcat(p_path, minor_name);
2850Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, port_rules, 1)) {
2880Sstevel@tonic-gate 		devfsadm_errprint("%s:serial_port_create:"
2890Sstevel@tonic-gate 		    " enumerate_int() failed\n\t%s\n",
2900Sstevel@tonic-gate 		    modname, p_path);
2910Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	(void) strcpy(l_path, "term/");
2950Sstevel@tonic-gate 	(void) strcat(l_path, buf);
2960Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2999354STim.Marsland@Sun.COM 	 * This is probably a USB serial port coming into the system
3009354STim.Marsland@Sun.COM 	 * because someone just plugged one in.  Log an indication of
3019354STim.Marsland@Sun.COM 	 * this to syslog just in case someone wants to know what the
3029354STim.Marsland@Sun.COM 	 * name of the new serial device is ..
3039354STim.Marsland@Sun.COM 	 */
3049354STim.Marsland@Sun.COM 	(void) syslog(LOG_INFO, "serial device /dev/%s present", l_path);
3059354STim.Marsland@Sun.COM 
3069354STim.Marsland@Sun.COM 	/*
3070Sstevel@tonic-gate 	 * update the portmon database if this port falls within
3080Sstevel@tonic-gate 	 * the valid range of ports.
3090Sstevel@tonic-gate 	 */
3100Sstevel@tonic-gate 	if ((port_num = parse_portno(buf)) != -1) {
3110Sstevel@tonic-gate 		pma[port_num].flags |= HAS_PORT_DEVICE;
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	free(buf);
3150Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate  * Called for all dialout devices that are NOT onboard
3200Sstevel@tonic-gate  * Creates links of the form "/dev/cua/[0..n]"
3210Sstevel@tonic-gate  */
3220Sstevel@tonic-gate static int
dialout_create(di_minor_t minor,di_node_t node)3230Sstevel@tonic-gate dialout_create(di_minor_t minor, di_node_t node)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	char l_path[MAXPATHLEN], p_path[MAXPATHLEN];
3260Sstevel@tonic-gate 	char  *devfspath, *buf, *mn;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
3290Sstevel@tonic-gate 	if (devfspath == NULL) {
3300Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
3310Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if ((mn = di_minor_name(minor)) == NULL) {
3350Sstevel@tonic-gate 		devfsadm_errprint("%s: NULL minorname\n\t%s\n",
3360Sstevel@tonic-gate 		    modname, devfspath);
3370Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
3380Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (!is_dialout(mn)) {
3420Sstevel@tonic-gate 		devfsadm_errprint("%s: invalid minor name\n\t%s:%s\n",
3430Sstevel@tonic-gate 		    modname, devfspath, mn);
3440Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
3450Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
3490Sstevel@tonic-gate 	(void) strcat(p_path, ":");
3500Sstevel@tonic-gate 	(void) strcat(p_path, mn);
3510Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, port_rules, 1)) {
3540Sstevel@tonic-gate 		devfsadm_errprint("%s:dialout_create:"
3550Sstevel@tonic-gate 		    " enumerate_int() failed\n\t%s\n",
3560Sstevel@tonic-gate 		    modname, p_path);
3570Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 	(void) strcpy(l_path, "cua/");
3600Sstevel@tonic-gate 	(void) strcat(l_path, buf);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/*
3630Sstevel@tonic-gate 	 *  add the minor name to the physical path so we can create
3640Sstevel@tonic-gate 	 *  the link.
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	free(buf);
3690Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate #ifdef __i386
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate static int
portcmp(char * devfs_path,char * phys_path)3750Sstevel@tonic-gate portcmp(char *devfs_path, char *phys_path)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	char *p1, *p2;
3780Sstevel@tonic-gate 	int rv;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	p2 = NULL;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	p1 = strrchr(devfs_path, ':');
3830Sstevel@tonic-gate 	if (p1 == NULL)
3840Sstevel@tonic-gate 		return (1);
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	p1 = strchr(p1, ',');
3870Sstevel@tonic-gate 	if (p1)
3880Sstevel@tonic-gate 		*p1 = '\0';
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	p2 = strrchr(phys_path, ':');
3910Sstevel@tonic-gate 	if (p2 == NULL) {
3920Sstevel@tonic-gate 		rv = -1;
3930Sstevel@tonic-gate 		goto out;
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	p2 = strchr(p2, ',');
3970Sstevel@tonic-gate 	if (p2)
3980Sstevel@tonic-gate 		*p2 = '\0';
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	rv = strcmp(devfs_path, phys_path);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate out:
4030Sstevel@tonic-gate 	if (p1)
4040Sstevel@tonic-gate 		*p1 = ',';
4050Sstevel@tonic-gate 	if (p2)
4060Sstevel@tonic-gate 		*p2 = ',';
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	return (rv);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * If the minor name begins with [a-d] and the
4130Sstevel@tonic-gate  * links in /dev/term/<char> and /dev/cua/<char>
4140Sstevel@tonic-gate  * don't point at a different minor, then we can
4150Sstevel@tonic-gate  * create compatibility links for this minor.
4160Sstevel@tonic-gate  * Returns:
4170Sstevel@tonic-gate  *	port id if a compatibility link can be created.
4180Sstevel@tonic-gate  *	NULL otherwise
4190Sstevel@tonic-gate  */
4200Sstevel@tonic-gate static char *
check_compat_ports(di_node_t node,char * phys_path,char * minor)421*12116SVikram.Hegde@Sun.COM check_compat_ports(di_node_t node, char *phys_path, char *minor)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	char portid = *minor;
4240Sstevel@tonic-gate 	char port[PATH_MAX];
4250Sstevel@tonic-gate 	char *devfs_path;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (portid < 'a' || portid >  'd')
4280Sstevel@tonic-gate 		return (NULL);
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	(void) snprintf(port, sizeof (port), "term/%c", portid);
431*12116SVikram.Hegde@Sun.COM 	if (devfsadm_read_link(node, port, &devfs_path) == DEVFSADM_SUCCESS &&
4320Sstevel@tonic-gate 	    portcmp(devfs_path, phys_path) != 0) {
4330Sstevel@tonic-gate 		free(devfs_path);
4340Sstevel@tonic-gate 		return (NULL);
4350Sstevel@tonic-gate 	}
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	free(devfs_path);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	(void) snprintf(port, sizeof (port), "cua/%c", portid);
440*12116SVikram.Hegde@Sun.COM 	if (devfsadm_read_link(node, port, &devfs_path) == DEVFSADM_SUCCESS &&
4410Sstevel@tonic-gate 	    portcmp(devfs_path, phys_path) != 0) {
4420Sstevel@tonic-gate 		free(devfs_path);
4430Sstevel@tonic-gate 		return (NULL);
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	free(devfs_path);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * Neither link exists or both links point at "phys_path"
4500Sstevel@tonic-gate 	 * We can safely create compatibility links.
4510Sstevel@tonic-gate 	 */
4520Sstevel@tonic-gate 	port[0] = portid;
4530Sstevel@tonic-gate 	port[1] = '\0';
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	return (s_strdup(port));
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate #endif
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate  * Called for all Onboard serial devices
4620Sstevel@tonic-gate  * Creates links of the form "/dev/term/[a..z]"
4630Sstevel@tonic-gate  */
4640Sstevel@tonic-gate static int
onbrd_port_create(di_minor_t minor,di_node_t node)4650Sstevel@tonic-gate onbrd_port_create(di_minor_t minor, di_node_t node)
4660Sstevel@tonic-gate {
4670Sstevel@tonic-gate 	char l_path[MAXPATHLEN], p_path[MAXPATHLEN];
4680Sstevel@tonic-gate 	char  *devfspath, *buf, *minor_name;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
4710Sstevel@tonic-gate 	if (devfspath == NULL) {
4720Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
4730Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	if ((minor_name = di_minor_name(minor)) == NULL) {
4770Sstevel@tonic-gate 		devfsadm_errprint("%s: NULL minor name\n\t%s\n",
4780Sstevel@tonic-gate 		    modname, devfspath);
4790Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
4800Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	/*
4840Sstevel@tonic-gate 	 * verify dialout ports do not come in on this nodetype
4850Sstevel@tonic-gate 	 */
4860Sstevel@tonic-gate 	if (is_dialout(minor_name)) {
4870Sstevel@tonic-gate 		devfsadm_errprint("%s: dialout device\n\t%s:%s\n", modname,
4880Sstevel@tonic-gate 		    devfspath, minor_name);
4890Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
4900Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
4940Sstevel@tonic-gate 	(void) strcat(p_path, ":");
4950Sstevel@tonic-gate 	(void) strcat(p_path, minor_name);
4960Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	buf = NULL;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate #ifdef __i386
502*12116SVikram.Hegde@Sun.COM 	buf = check_compat_ports(node, p_path, minor_name);
5030Sstevel@tonic-gate #endif
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * devfsadm_enumerate_char_start() is a private interface for use by the
5070Sstevel@tonic-gate 	 * ports module only
5080Sstevel@tonic-gate 	 */
5090Sstevel@tonic-gate 	if (!buf && devfsadm_enumerate_char_start(p_path, 0, &buf, obport_rules,
5100Sstevel@tonic-gate 	    1, start_id)) {
5110Sstevel@tonic-gate 		devfsadm_errprint("%s: devfsadm_enumerate_char_start() failed"
5120Sstevel@tonic-gate 		    "\n\t%s\n", modname, p_path);
5130Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	(void) strcpy(l_path, "term/");
5170Sstevel@tonic-gate 	(void) strcat(l_path, buf);
5180Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
5190Sstevel@tonic-gate 	free(buf);
5200Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate  * Onboard dialout devices
5250Sstevel@tonic-gate  * Creates links of the form "/dev/cua/[a..z]"
5260Sstevel@tonic-gate  */
5270Sstevel@tonic-gate static int
onbrd_dialout_create(di_minor_t minor,di_node_t node)5280Sstevel@tonic-gate onbrd_dialout_create(di_minor_t minor, di_node_t node)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	char l_path[MAXPATHLEN], p_path[MAXPATHLEN];
5310Sstevel@tonic-gate 	char  *devfspath, *buf, *mn;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
5340Sstevel@tonic-gate 	if (devfspath == NULL) {
5350Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
5360Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if ((mn = di_minor_name(minor)) == NULL) {
5400Sstevel@tonic-gate 		devfsadm_errprint("%s: NULL minor name\n\t%s\n",
5410Sstevel@tonic-gate 		    modname, devfspath);
5420Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
5430Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	/*
5470Sstevel@tonic-gate 	 * verify this is a dialout port
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 	if (!is_dialout(mn)) {
5500Sstevel@tonic-gate 		devfsadm_errprint("%s: not a dialout device\n\t%s:%s\n",
5510Sstevel@tonic-gate 		    modname, devfspath, mn);
5520Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
5530Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
5540Sstevel@tonic-gate 	}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
5570Sstevel@tonic-gate 	(void) strcat(p_path, ":");
5580Sstevel@tonic-gate 	(void) strcat(p_path, mn);
5590Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	buf = NULL;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate #ifdef __i386
564*12116SVikram.Hegde@Sun.COM 	buf = check_compat_ports(node, p_path, mn);
5650Sstevel@tonic-gate #endif
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	/*
5680Sstevel@tonic-gate 	 * devfsadm_enumerate_char_start() is a private interface
5690Sstevel@tonic-gate 	 * for use by the ports module only.
5700Sstevel@tonic-gate 	 */
5710Sstevel@tonic-gate 	if (!buf && devfsadm_enumerate_char_start(p_path, 0, &buf, obport_rules,
5720Sstevel@tonic-gate 	    1, start_id)) {
5730Sstevel@tonic-gate 		devfsadm_errprint("%s: devfsadm_enumerate_char_start() failed"
5740Sstevel@tonic-gate 		    "\n\t%s\n", modname, p_path);
5750Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/*
5790Sstevel@tonic-gate 	 * create the logical link
5800Sstevel@tonic-gate 	 */
5810Sstevel@tonic-gate 	(void) strcpy(l_path, "cua/");
5820Sstevel@tonic-gate 	(void) strcat(l_path, buf);
5830Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
5840Sstevel@tonic-gate 	free(buf);
5850Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate  * Remote System Controller (RSC) serial ports
5910Sstevel@tonic-gate  * Creates links of the form "/dev/rsc-control" | "/dev/term/rsc-console".
5920Sstevel@tonic-gate  */
5930Sstevel@tonic-gate static int
rsc_port_create(di_minor_t minor,di_node_t node)5940Sstevel@tonic-gate rsc_port_create(di_minor_t minor, di_node_t node)
5950Sstevel@tonic-gate {
5960Sstevel@tonic-gate 	char  *devfspath;
5970Sstevel@tonic-gate 	char  *minor_name;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
6010Sstevel@tonic-gate 	if (devfspath == NULL) {
6020Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
6030Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	if ((minor_name = di_minor_name(minor)) == NULL) {
6070Sstevel@tonic-gate 		devfsadm_errprint("%s: NULL minor name\n\t%s\n",
6080Sstevel@tonic-gate 		    modname, devfspath);
6090Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
6100Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	/*
6140Sstevel@tonic-gate 	 * if this is the RSC console serial port (i.e. the minor name == ssp),
6150Sstevel@tonic-gate 	 * create /dev/term/rsc-console link and then we are done with this
6160Sstevel@tonic-gate 	 * node.
6170Sstevel@tonic-gate 	 */
6180Sstevel@tonic-gate 	if (strcmp(minor_name, "ssp") == 0) {
6190Sstevel@tonic-gate 		(void) devfsadm_mklink("term/rsc-console", node, minor, 0);
6200Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
6210Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	/*
6240Sstevel@tonic-gate 	 * else if this is the RSC control serial port (i.e. the minor name ==
6250Sstevel@tonic-gate 	 * sspctl), create /dev/rsc-control link and then we are done with this
6260Sstevel@tonic-gate 	 * node.
6270Sstevel@tonic-gate 	 */
6280Sstevel@tonic-gate 	} else if (strcmp(minor_name, "sspctl") == 0) {
6290Sstevel@tonic-gate 		(void) devfsadm_mklink("rsc-control", node, minor, 0);
6300Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
6310Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
6320Sstevel@tonic-gate 	}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	/* This is not an RSC node, continue... */
6350Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
6360Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate /*
6400Sstevel@tonic-gate  * Lights Out Management (LOM) serial ports
6410Sstevel@tonic-gate  * Creates links of the form "/dev/term/lom-console".
6420Sstevel@tonic-gate  */
6430Sstevel@tonic-gate static int
lom_port_create(di_minor_t minor,di_node_t node)6440Sstevel@tonic-gate lom_port_create(di_minor_t minor, di_node_t node)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	char  *devfspath;
6470Sstevel@tonic-gate 	char  *minor_name;
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
6500Sstevel@tonic-gate 	if (devfspath == NULL) {
6510Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
6520Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	if ((minor_name = di_minor_name(minor)) == NULL) {
6560Sstevel@tonic-gate 		devfsadm_errprint("%s: NULL minor name\n\t%s\n",
6570Sstevel@tonic-gate 		    modname, devfspath);
6580Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
6590Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	/*
6630Sstevel@tonic-gate 	 * if this is the LOM console serial port (i.e. the minor
6640Sstevel@tonic-gate 	 * name == lom-console ), create /dev/term/lom-console link and
6650Sstevel@tonic-gate 	 * then we are done with this node.
6660Sstevel@tonic-gate 	 */
6670Sstevel@tonic-gate 	if (strcmp(minor_name, "lom-console") == 0) {
6680Sstevel@tonic-gate 		(void) devfsadm_mklink("term/lom-console", node, minor, 0);
6690Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
6700Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/* This is not a LOM node, continue... */
6740Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
6750Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate /*
6790Sstevel@tonic-gate  * PCMCIA serial ports
6800Sstevel@tonic-gate  * Creates links of the form "/dev/term/pcN", where N is the PCMCIA
6810Sstevel@tonic-gate  * socket # the device is plugged into.
6820Sstevel@tonic-gate  */
6830Sstevel@tonic-gate #define	PCMCIA_MAX_SOCKETS	64
6840Sstevel@tonic-gate #define	PCMCIA_SOCKETNO(x)	((x) & (PCMCIA_MAX_SOCKETS - 1))
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate static int
pcmcia_port_create(di_minor_t minor,di_node_t node)6870Sstevel@tonic-gate pcmcia_port_create(di_minor_t minor, di_node_t node)
6880Sstevel@tonic-gate {
6890Sstevel@tonic-gate 	char l_path[MAXPATHLEN];
6900Sstevel@tonic-gate 	char  *devfspath;
6910Sstevel@tonic-gate 	int socket, *intp;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
6940Sstevel@tonic-gate 	if (devfspath == NULL) {
6950Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
6960Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "socket", &intp) <= 0) {
7000Sstevel@tonic-gate 		devfsadm_errprint("%s: failed pcmcia socket lookup\n\t%s\n",
7010Sstevel@tonic-gate 		    modname, devfspath);
7020Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
7030Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	socket = PCMCIA_SOCKETNO(*intp);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	(void) sprintf(l_path, "term/pc%d", socket);
7110Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	return (DEVFSADM_TERMINATE);
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate /*
7170Sstevel@tonic-gate  * PCMCIA dialout serial ports
7180Sstevel@tonic-gate  * Creates links of the form "/dev/cua/pcN", where N is the PCMCIA
7190Sstevel@tonic-gate  * socket number the device is plugged into.
7200Sstevel@tonic-gate  */
7210Sstevel@tonic-gate static int
pcmcia_dialout_create(di_minor_t minor,di_node_t node)7220Sstevel@tonic-gate pcmcia_dialout_create(di_minor_t minor, di_node_t node)
7230Sstevel@tonic-gate {
7240Sstevel@tonic-gate 	char l_path[MAXPATHLEN];
7250Sstevel@tonic-gate 	char  *devfspath;
7260Sstevel@tonic-gate 	int socket, *intp;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
7290Sstevel@tonic-gate 	if (devfspath == NULL) {
7300Sstevel@tonic-gate 		devfsadm_errprint("%s: di_devfs_path() failed\n", modname);
7310Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "socket", &intp) <= 0) {
7350Sstevel@tonic-gate 		devfsadm_errprint("%s: failed socket lookup\n\t%s\n",
7360Sstevel@tonic-gate 		    modname, devfspath);
7370Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
7380Sstevel@tonic-gate 		return (DEVFSADM_TERMINATE);
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	socket = PCMCIA_SOCKETNO(*intp);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
7440Sstevel@tonic-gate 	(void) sprintf(l_path, "cua/pc%d", socket);
7450Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	return (DEVFSADM_TERMINATE);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate /*
7520Sstevel@tonic-gate  * Removes port entries that no longer have devices
7530Sstevel@tonic-gate  * backing them
7540Sstevel@tonic-gate  * Schedules an update the sacadm (portmon) database
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate static void
rm_dangling_port(char * devname)7570Sstevel@tonic-gate rm_dangling_port(char *devname)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate 	char *portstr;
7600Sstevel@tonic-gate 	int  portnum;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	devfsadm_print(PORT_MID, "%s:rm_stale_port: %s\n",
7630Sstevel@tonic-gate 	    modname, devname);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if ((portstr = strrchr(devname, (int)'/')) == NULL) {
7660Sstevel@tonic-gate 		devfsadm_errprint("%s: invalid name: %s\n",
7670Sstevel@tonic-gate 		    modname, devname);
7680Sstevel@tonic-gate 		return;
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	portstr++;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	/*
7730Sstevel@tonic-gate 	 * mark for removal from sacadm database
7740Sstevel@tonic-gate 	 */
7750Sstevel@tonic-gate 	if ((portnum = parse_portno(portstr)) != -1)
7760Sstevel@tonic-gate 		pma[portnum].flags |= PORT_REMOVED;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	devfsadm_rm_all(devname);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate  * Algorithm is to step through ports; checking for unneeded PM entries
7830Sstevel@tonic-gate  * entries that should be there but are not.  Every PM_GRPSZ entries
7840Sstevel@tonic-gate  * check to see if there are any entries for the port monitor group;
7850Sstevel@tonic-gate  * if not, delete the group.
7860Sstevel@tonic-gate  */
7870Sstevel@tonic-gate static void
update_sacadm_db(void)7880Sstevel@tonic-gate update_sacadm_db(void)
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate 	int i;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if (load_ttymondb() != DEVFSADM_SUCCESS)
7930Sstevel@tonic-gate 		return;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	for (i = 0; i < maxports; i++) {
7960Sstevel@tonic-gate 		/*
7970Sstevel@tonic-gate 		 * if this port was removed and has a port
7980Sstevel@tonic-gate 		 * monitor entry, remove the entry from the sacadm db
7990Sstevel@tonic-gate 		 */
8000Sstevel@tonic-gate 		if ((pma[i].flags & PORT_REMOVED) != 0) {
8010Sstevel@tonic-gate 			if ((pma[i].flags & PM_HAS_ENTRY) != 0)
8020Sstevel@tonic-gate 				remove_pm_entry(pma[i].pm_tag, i);
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 		/*
8060Sstevel@tonic-gate 		 * if this port is present and lacks a port monitor
8070Sstevel@tonic-gate 		 * add an entry to the sacadm db
8080Sstevel@tonic-gate 		 */
8090Sstevel@tonic-gate 		if (pma[i].flags & HAS_PORT_DEVICE) {
8100Sstevel@tonic-gate 			if (!(pma[i].flags & PM_HAS_ENTRY))
8110Sstevel@tonic-gate 				add_pm_entry(i);
8120Sstevel@tonic-gate 		}
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 		/*
8150Sstevel@tonic-gate 		 * if this port has a pm entry, mark as needing
8160Sstevel@tonic-gate 		 * a port monitor within this range of ports
8170Sstevel@tonic-gate 		 */
8180Sstevel@tonic-gate 		if ((pma[i].flags & PM_HAS_ENTRY))
8190Sstevel@tonic-gate 			pma[PM_SLOT(i)].flags |= PM_NEEDED;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 		/*
8220Sstevel@tonic-gate 		 * continue for the range of ports per-portmon
8230Sstevel@tonic-gate 		 */
8240Sstevel@tonic-gate 		if (((i + 1) % PM_GRPSZ) != 0)
8250Sstevel@tonic-gate 			continue;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		/*
8280Sstevel@tonic-gate 		 * if there are no ports active on the range we have
8290Sstevel@tonic-gate 		 * just completed, remove the port monitor entry if
8300Sstevel@tonic-gate 		 * it exists
8310Sstevel@tonic-gate 		 */
8320Sstevel@tonic-gate 		if ((pma[PM_SLOT(i)].flags & (PM_NEEDED | HAS_PORT_MON)) ==
8339241SVikram.Hegde@Sun.COM 		    HAS_PORT_MON) {
8340Sstevel@tonic-gate 			delete_port_monitor(i);
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	}
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	/*
8400Sstevel@tonic-gate 	 * cleanup remaining port monitor, if active
8410Sstevel@tonic-gate 	 */
8420Sstevel@tonic-gate 	if ((i % PM_GRPSZ != 0) &&
8430Sstevel@tonic-gate 	    ((pma[PM_SLOT(i)].flags & (PM_NEEDED | HAS_PORT_MON)) ==
8440Sstevel@tonic-gate 	    HAS_PORT_MON)) {
8450Sstevel@tonic-gate 		delete_port_monitor(i);
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate /*
8500Sstevel@tonic-gate  * Determine which port monitor entries already exist by invoking pmadm(1m)
8510Sstevel@tonic-gate  * to list all configured 'ttymon' port monitor entries.
8520Sstevel@tonic-gate  * Do not explicitly report errors from executing pmadm(1m) or sacadm(1m)
8530Sstevel@tonic-gate  * commands to remain compatible with the ports(1m) implementation.
8540Sstevel@tonic-gate  */
8550Sstevel@tonic-gate static int
load_ttymondb(void)8560Sstevel@tonic-gate load_ttymondb(void)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate 	char	cmdline[CMDLEN];
8590Sstevel@tonic-gate 	char	cmdbuf[PMTAB_MAXLINE+1];
8600Sstevel@tonic-gate 	int	sac_exitval;
8610Sstevel@tonic-gate 	FILE	*fs_popen;
8620Sstevel@tonic-gate 	char	*portname;	/* pointer to a tty name */
8630Sstevel@tonic-gate 	int	portnum;
8640Sstevel@tonic-gate 	char	*ptr;
8650Sstevel@tonic-gate 	char	*error_msg = "%s: failed to load port monitor database\n";
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	(void) strcpy(cmdline, "/usr/sbin/pmadm -L -t ttymon");
8680Sstevel@tonic-gate 	fs_popen = popen(cmdline, "r");
8690Sstevel@tonic-gate 	if (fs_popen == NULL) {
8700Sstevel@tonic-gate 		devfsadm_print(VERBOSE_MID, error_msg, modname);
8710Sstevel@tonic-gate 		return (DEVFSADM_FAILURE);
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	while (fgets(cmdbuf, PMTAB_MAXLINE, fs_popen) != NULL) {
8750Sstevel@tonic-gate 		if ((portname = pmtab_parse_portname(cmdbuf)) == NULL) {
8760Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID,
8770Sstevel@tonic-gate 			    "load_ttymondb: failed to parse portname\n");
8780Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID,
8790Sstevel@tonic-gate 			    "load_ttymondb: buffer \"%s\"\n", cmdbuf);
8800Sstevel@tonic-gate 			goto load_failed;
8810Sstevel@tonic-gate 		}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 		devfsadm_print(PORT_MID, "%s:load_ttymondb: port %s ",
8840Sstevel@tonic-gate 		    modname, portname);
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 		/*
8870Sstevel@tonic-gate 		 * skip onboard ports
8880Sstevel@tonic-gate 		 * There is no reliable way to determine if we
8890Sstevel@tonic-gate 		 * should start a port monitor on these lines.
8900Sstevel@tonic-gate 		 */
8910Sstevel@tonic-gate 		if ((portnum = parse_portno(portname)) == -1) {
8920Sstevel@tonic-gate 			devfsadm_print(PORT_MID, "ignored\n");
8930Sstevel@tonic-gate 			continue;
8940Sstevel@tonic-gate 		}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		/*
8970Sstevel@tonic-gate 		 * the first field of the pmadm output is
8980Sstevel@tonic-gate 		 * the port monitor name for this entry
8990Sstevel@tonic-gate 		 */
9000Sstevel@tonic-gate 		if ((ptr = strchr(cmdbuf, PMTAB_SEPR)) == NULL) {
9010Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID,
9020Sstevel@tonic-gate 			    "load_ttymondb: no portmon tag\n");
9030Sstevel@tonic-gate 			goto load_failed;
9040Sstevel@tonic-gate 		}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 		*ptr = MN_NULLCHAR;
9070Sstevel@tonic-gate 		if ((pma[portnum].pm_tag = strdup(cmdbuf)) == NULL) {
9080Sstevel@tonic-gate 			devfsadm_errprint("load_ttymondb: failed strdup\n");
9090Sstevel@tonic-gate 			goto load_failed;
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 		pma[portnum].flags |= PM_HAS_ENTRY;
9120Sstevel@tonic-gate 		pma[PM_SLOT(portnum)].flags |= HAS_PORT_MON;
9130Sstevel@tonic-gate 		devfsadm_print(PORT_MID, "present\n");
9140Sstevel@tonic-gate 	}
9150Sstevel@tonic-gate 	(void) pclose(fs_popen);
9160Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate load_failed:
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	/*
9210Sstevel@tonic-gate 	 * failed to load the port monitor database
9220Sstevel@tonic-gate 	 */
9230Sstevel@tonic-gate 	devfsadm_print(VERBOSE_MID, error_msg, modname);
9240Sstevel@tonic-gate 	sac_exitval = SAC_EXITVAL(pclose(fs_popen));
9250Sstevel@tonic-gate 	if (sac_exitval != 0) {
9260Sstevel@tonic-gate 		devfsadm_print(VERBOSE_MID,
9270Sstevel@tonic-gate 		    "pmadm: (%s) %s\n", SAC_EID(sac_exitval),
9280Sstevel@tonic-gate 		    SAC_EMSG(sac_exitval));
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 	return (DEVFSADM_FAILURE);
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate  * add a port monitor entry for device /dev/term/"port"
9350Sstevel@tonic-gate  */
9360Sstevel@tonic-gate static void
add_pm_entry(int port)9370Sstevel@tonic-gate add_pm_entry(int port)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate 	char cmdline[CMDLEN];
9400Sstevel@tonic-gate 	int sac_exitval;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	add_port_monitor(port);
9430Sstevel@tonic-gate 	(void) sprintf(cmdline,
9440Sstevel@tonic-gate 	    "/usr/sbin/pmadm -a -p ttymon%d -s %d -i root"
9450Sstevel@tonic-gate 	    " -v `/usr/sbin/ttyadm -V` -fux -y\"/dev/term/%d\""
9460Sstevel@tonic-gate 	    " -m \"`/usr/sbin/ttyadm -d /dev/term/%d -s /usr/bin/login"
9470Sstevel@tonic-gate 	    " -l 9600 -p \\\"login: \\\"`\"", PM_NUM(port), port, port, port);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	if (devfsadm_noupdate() == DEVFSADM_FALSE) {
9500Sstevel@tonic-gate 		sac_exitval = execute(cmdline);
9510Sstevel@tonic-gate 		if ((sac_exitval != 0) && (sac_exitval != E_SACNOTRUN)) {
9520Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID,
9530Sstevel@tonic-gate 			    "failed to add port monitor entry"
9540Sstevel@tonic-gate 			    " for /dev/term/%d\n", port);
9550Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID, "pmadm: (%s) %s\n",
9560Sstevel@tonic-gate 			    SAC_EID(sac_exitval), SAC_EMSG(sac_exitval));
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate 	pma[port].flags |= PM_HAS_ENTRY;
9600Sstevel@tonic-gate 	devfsadm_print(VERBOSE_MID, "%s: /dev/term/%d added to sacadm\n",
9610Sstevel@tonic-gate 	    modname, port);
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate static void
remove_pm_entry(char * pmtag,int port)9650Sstevel@tonic-gate remove_pm_entry(char *pmtag, int port)
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	char cmdline[CMDLEN];
9690Sstevel@tonic-gate 	int sac_exitval;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if (devfsadm_noupdate() == DEVFSADM_FALSE) {
9720Sstevel@tonic-gate 		(void) snprintf(cmdline, sizeof (cmdline),
9730Sstevel@tonic-gate 		    "/usr/sbin/pmadm -r -p %s -s %d", pmtag, port);
9740Sstevel@tonic-gate 		sac_exitval = execute(cmdline);
9750Sstevel@tonic-gate 		if ((sac_exitval != 0) && (sac_exitval != E_SACNOTRUN)) {
9760Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID,
9770Sstevel@tonic-gate 			    "failed to remove port monitor entry"
9780Sstevel@tonic-gate 			    " for /dev/term/%d\n", port);
9790Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID, "pmadm: (%s) %s\n",
9800Sstevel@tonic-gate 			    SAC_EID(sac_exitval), SAC_EMSG(sac_exitval));
9810Sstevel@tonic-gate 		}
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 	pma[port].flags &= ~PM_HAS_ENTRY;
9840Sstevel@tonic-gate 	devfsadm_print(VERBOSE_MID, "%s: /dev/term/%d removed from sacadm\n",
9850Sstevel@tonic-gate 	    modname, port);
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate /*
9900Sstevel@tonic-gate  * delete_port_monitor()
9910Sstevel@tonic-gate  * Check for the existence of a port monitor for "port" and remove it if
9920Sstevel@tonic-gate  * one exists
9930Sstevel@tonic-gate  */
9940Sstevel@tonic-gate static void
delete_port_monitor(int port)9950Sstevel@tonic-gate delete_port_monitor(int port)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate 	char	cmdline[CMDLEN];
9980Sstevel@tonic-gate 	int	sac_exitval;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	(void) sprintf(cmdline, "/usr/sbin/sacadm -L -p ttymon%d",
10010Sstevel@tonic-gate 	    PM_NUM(port));
10020Sstevel@tonic-gate 	sac_exitval = execute(cmdline);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/* clear the PM tag and return if the port monitor is not active */
10050Sstevel@tonic-gate 	if (sac_exitval == E_NOEXIST) {
10060Sstevel@tonic-gate 		pma[PM_SLOT(port)].flags &= ~HAS_PORT_MON;
10070Sstevel@tonic-gate 		return;
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	/* some other sacadm(1m) error, log and return */
10110Sstevel@tonic-gate 	if (sac_exitval != 0) {
10120Sstevel@tonic-gate 		devfsadm_print(VERBOSE_MID, "sacadm: (%s) %s\n",
10130Sstevel@tonic-gate 		    SAC_EID(sac_exitval), SAC_EMSG(sac_exitval));
10140Sstevel@tonic-gate 		return;
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	if (devfsadm_noupdate() == DEVFSADM_FALSE) {
10180Sstevel@tonic-gate 		(void) sprintf(cmdline,
10190Sstevel@tonic-gate 		    "/usr/sbin/sacadm -r -p ttymon%d", PM_NUM(port));
10200Sstevel@tonic-gate 		if (sac_exitval = execute(cmdline)) {
10210Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID,
10220Sstevel@tonic-gate 			    "failed to remove port monitor ttymon%d\n",
10230Sstevel@tonic-gate 			    PM_NUM(port));
10240Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID, "sacadm: (%s) %s\n",
10250Sstevel@tonic-gate 			    SAC_EID(sac_exitval), SAC_EMSG(sac_exitval));
10260Sstevel@tonic-gate 		}
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate 	devfsadm_print(VERBOSE_MID, "%s: port monitor ttymon%d removed\n",
10290Sstevel@tonic-gate 	    modname, PM_NUM(port));
10300Sstevel@tonic-gate 	pma[PM_SLOT(port)].flags &= ~HAS_PORT_MON;
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate static void
add_port_monitor(int port)10340Sstevel@tonic-gate add_port_monitor(int port)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	char cmdline[CMDLEN];
10370Sstevel@tonic-gate 	int sac_exitval;
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	if ((pma[PM_SLOT(port)].flags & HAS_PORT_MON) != 0) {
10400Sstevel@tonic-gate 		return;
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	(void) sprintf(cmdline,
10440Sstevel@tonic-gate 	    "/usr/sbin/sacadm -l -p ttymon%d", PM_NUM(port));
10450Sstevel@tonic-gate 	sac_exitval = execute(cmdline);
10460Sstevel@tonic-gate 	if (sac_exitval == E_NOEXIST) {
10470Sstevel@tonic-gate 		(void) sprintf(cmdline,
10480Sstevel@tonic-gate 		    "/usr/sbin/sacadm -a -n 2 -p ttymon%d -t ttymon"
10490Sstevel@tonic-gate 		    " -c /usr/lib/saf/ttymon -v \"`/usr/sbin/ttyadm"
10500Sstevel@tonic-gate 		    " -V`\" -y \"Ports %d-%d\"", PM_NUM(port), PM_SLOT(port),
10510Sstevel@tonic-gate 		    PM_SLOT(port) + (PM_GRPSZ - 1));
10520Sstevel@tonic-gate 		if (devfsadm_noupdate() == DEVFSADM_FALSE) {
10530Sstevel@tonic-gate 			if (sac_exitval = execute(cmdline)) {
10540Sstevel@tonic-gate 				devfsadm_print(VERBOSE_MID,
10550Sstevel@tonic-gate 				    "failed to add port monitor ttymon%d\n",
10560Sstevel@tonic-gate 				    PM_NUM(port));
10570Sstevel@tonic-gate 				devfsadm_print(VERBOSE_MID, "sacadm: (%s) %s\n",
10580Sstevel@tonic-gate 				    SAC_EID(sac_exitval),
10590Sstevel@tonic-gate 				    SAC_EMSG(sac_exitval));
10600Sstevel@tonic-gate 			}
10610Sstevel@tonic-gate 		}
10620Sstevel@tonic-gate 		devfsadm_print(VERBOSE_MID, "%s: port monitor ttymon%d added\n",
10630Sstevel@tonic-gate 		    modname, PM_NUM(port));
10640Sstevel@tonic-gate 	}
10650Sstevel@tonic-gate 	pma[PM_SLOT(port)].flags |= HAS_PORT_MON;
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate  * parse port number from string
10700Sstevel@tonic-gate  * returns port number if in range [0..maxports]
10710Sstevel@tonic-gate  */
10720Sstevel@tonic-gate static int
parse_portno(char * dname)10730Sstevel@tonic-gate parse_portno(char *dname)
10740Sstevel@tonic-gate {
10750Sstevel@tonic-gate 	int pn;
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	if (sscanf(dname, "%d", &pn) != 1)
10780Sstevel@tonic-gate 		return (-1);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	if ((pn < 0) || (pn > maxports)) {
10810Sstevel@tonic-gate 		devfsadm_print(VERBOSE_MID,
10820Sstevel@tonic-gate 		    "%s:parse_portno: %d not in range (0..%d)\n",
10830Sstevel@tonic-gate 		    modname, pn, maxports);
10840Sstevel@tonic-gate 		return (-1);
10850Sstevel@tonic-gate 	}
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	return (pn);
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate /*
10920Sstevel@tonic-gate  * fork and exec a command, waiting for the command to
10930Sstevel@tonic-gate  * complete and return it's status
10940Sstevel@tonic-gate  */
10950Sstevel@tonic-gate static int
execute(const char * s)10960Sstevel@tonic-gate execute(const char *s)
10970Sstevel@tonic-gate {
10980Sstevel@tonic-gate 	int	status;
10990Sstevel@tonic-gate 	int	fd;
11000Sstevel@tonic-gate 	pid_t	pid;
11010Sstevel@tonic-gate 	pid_t	w;
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	/*
11040Sstevel@tonic-gate 	 * fork a single threaded child proc to execute the
11050Sstevel@tonic-gate 	 * sacadm command string
11060Sstevel@tonic-gate 	 */
11070Sstevel@tonic-gate 	devfsadm_print(PORT_MID, "%s: execute:\n\t%s\n", modname, s);
11080Sstevel@tonic-gate 	if ((pid = fork1()) == 0) {
11090Sstevel@tonic-gate 		(void) close(0);
11100Sstevel@tonic-gate 		(void) close(1);
11110Sstevel@tonic-gate 		(void) close(2);
11120Sstevel@tonic-gate 		fd = open("/dev/null", O_RDWR);
11130Sstevel@tonic-gate 		(void) dup(fd);
11140Sstevel@tonic-gate 		(void) dup(fd);
11150Sstevel@tonic-gate 		(void) execl("/sbin/sh", "sh", "-c", s, 0);
11160Sstevel@tonic-gate 		/*
11170Sstevel@tonic-gate 		 * return the sacadm exit status (see _exit(2))
11180Sstevel@tonic-gate 		 */
11190Sstevel@tonic-gate 		_exit(127);
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	/*
11230Sstevel@tonic-gate 	 * wait for child process to terminate
11240Sstevel@tonic-gate 	 */
11250Sstevel@tonic-gate 	for (;;) {
11260Sstevel@tonic-gate 		w = wait(&status);
11270Sstevel@tonic-gate 		if (w == pid) {
11280Sstevel@tonic-gate 			devfsadm_print(PORT_MID, "%s:exit status (%d)\n",
11290Sstevel@tonic-gate 			    modname, SAC_EXITVAL(status));
11300Sstevel@tonic-gate 			return (SAC_EXITVAL(status));
11310Sstevel@tonic-gate 		}
11320Sstevel@tonic-gate 		if (w == (pid_t)-1) {
11330Sstevel@tonic-gate 			devfsadm_print(VERBOSE_MID, "%s: exec failed\n",
11349241SVikram.Hegde@Sun.COM 			    modname);
11350Sstevel@tonic-gate 			return (-1);
11360Sstevel@tonic-gate 		}
11370Sstevel@tonic-gate 	}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	/* NOTREACHED */
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate /*
11440Sstevel@tonic-gate  * check if the minor name is suffixed with ",cu"
11450Sstevel@tonic-gate  */
11460Sstevel@tonic-gate static int
is_dialout(char * name)11470Sstevel@tonic-gate is_dialout(char *name)
11480Sstevel@tonic-gate {
11490Sstevel@tonic-gate 	char *s_chr;
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	if ((name == NULL) || (s_chr = strrchr(name, MN_SEPR)) == NULL)
11520Sstevel@tonic-gate 		return (0);
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	if (strcmp(s_chr, DIALOUT_SUFFIX) == 0) {
11550Sstevel@tonic-gate 		return (1);
11560Sstevel@tonic-gate 	} else {
11570Sstevel@tonic-gate 		return (0);
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate /*
11630Sstevel@tonic-gate  * Get the name of the port device from a pmtab entry.
11640Sstevel@tonic-gate  * Note the /dev/term/ part is taken off.
11650Sstevel@tonic-gate  */
11660Sstevel@tonic-gate static char *
pmtab_parse_portname(char * buffer)11670Sstevel@tonic-gate pmtab_parse_portname(char *buffer)
11680Sstevel@tonic-gate {
11690Sstevel@tonic-gate 	int i;
11700Sstevel@tonic-gate 	char *bufp, *devnamep, *portnamep;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	/*
11730Sstevel@tonic-gate 	 * position to the device name (field 8)
11740Sstevel@tonic-gate 	 */
11750Sstevel@tonic-gate 	bufp = strchr(buffer, PMTAB_SEPR);
11760Sstevel@tonic-gate 	for (i = 0; i < PMTAB_DEVNAME_FIELD; i++) {
11770Sstevel@tonic-gate 		if (bufp == NULL)
11780Sstevel@tonic-gate 			return (NULL);
11790Sstevel@tonic-gate 		bufp = strchr(++bufp, PMTAB_SEPR);
11800Sstevel@tonic-gate 	}
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	/* move past the ':' and locate the end of the devname */
11830Sstevel@tonic-gate 	devnamep = bufp++;
11840Sstevel@tonic-gate 	if ((bufp = strchr(bufp, PMTAB_SEPR)) == NULL)
11850Sstevel@tonic-gate 		return (NULL);
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	*bufp = MN_NULLCHAR;
11880Sstevel@tonic-gate 	if ((portnamep = strrchr(devnamep, DEVNAME_SEPR)) == NULL) {
11890Sstevel@tonic-gate 		*bufp = PMTAB_SEPR;
11900Sstevel@tonic-gate 		return (NULL);
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/* return with "buffer" chopped after the /dev/term entry */
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	return (++portnamep);
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate  * port monitor array mgmt
12000Sstevel@tonic-gate  */
12010Sstevel@tonic-gate static void *
pma_alloc(void)12020Sstevel@tonic-gate pma_alloc(void)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	if (pma != NULL) {
12060Sstevel@tonic-gate 		devfsadm_errprint("%s:pma_alloc:pma != NULL\n", modname);
12070Sstevel@tonic-gate 		return (NULL);
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	if ((pma = calloc(maxports + 1, sizeof (*pma))) == NULL) {
12110Sstevel@tonic-gate 		devfsadm_errprint("%s:pma_alloc:pma alloc failure\n", modname);
12120Sstevel@tonic-gate 		return (NULL);
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	return ((void *)pma);
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate static void
pma_free(void)12190Sstevel@tonic-gate pma_free(void)
12200Sstevel@tonic-gate {
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	int i;
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	if (pma == NULL)
12250Sstevel@tonic-gate 		return;
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	/*
12280Sstevel@tonic-gate 	 * free any strings we had allocated
12290Sstevel@tonic-gate 	 */
12300Sstevel@tonic-gate 	for (i = 0; i <= maxports; i++) {
12310Sstevel@tonic-gate 		if (pma[i].pm_tag != NULL)
12320Sstevel@tonic-gate 			free(pma[i].pm_tag);
12330Sstevel@tonic-gate 	}
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	free(pma);
12360Sstevel@tonic-gate 	pma = NULL;
12370Sstevel@tonic-gate }
1238