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
52311Sseb  * Common Development and Distribution License (the "License").
62311Sseb  * 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  */
210Sstevel@tonic-gate /*
225895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <unistd.h>
270Sstevel@tonic-gate #include <errno.h>
285895Syz147064 #include <ctype.h>
293147Sxc151355 #include <fcntl.h>
303147Sxc151355 #include <strings.h>
313147Sxc151355 #include <dirent.h>
326173Syz147064 #include <sys/param.h>
333147Sxc151355 #include <sys/stat.h>
343147Sxc151355 #include <libdladm_impl.h>
353184Smeem #include <libintl.h>
365895Syz147064 #include <libdlpi.h>
37733Skrgopi 
383147Sxc151355 static char		dladm_rootdir[MAXPATHLEN] = "/";
393147Sxc151355 
403147Sxc151355 const char *
413147Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
423147Sxc151355 {
433147Sxc151355 	const char	*s;
443147Sxc151355 
453147Sxc151355 	switch (status) {
463147Sxc151355 	case DLADM_STATUS_OK:
473147Sxc151355 		s = "ok";
483147Sxc151355 		break;
493147Sxc151355 	case DLADM_STATUS_BADARG:
503147Sxc151355 		s = "invalid argument";
513147Sxc151355 		break;
523147Sxc151355 	case DLADM_STATUS_FAILED:
533147Sxc151355 		s = "operation failed";
543147Sxc151355 		break;
553147Sxc151355 	case DLADM_STATUS_TOOSMALL:
563147Sxc151355 		s = "buffer size too small";
573147Sxc151355 		break;
583147Sxc151355 	case DLADM_STATUS_NOTSUP:
593147Sxc151355 		s = "operation not supported";
603147Sxc151355 		break;
613147Sxc151355 	case DLADM_STATUS_NOTFOUND:
623147Sxc151355 		s = "object not found";
633147Sxc151355 		break;
643147Sxc151355 	case DLADM_STATUS_BADVAL:
653147Sxc151355 		s = "invalid value";
663147Sxc151355 		break;
673147Sxc151355 	case DLADM_STATUS_NOMEM:
683147Sxc151355 		s = "insufficient memory";
693147Sxc151355 		break;
703147Sxc151355 	case DLADM_STATUS_EXIST:
713147Sxc151355 		s = "object already exists";
723147Sxc151355 		break;
733147Sxc151355 	case DLADM_STATUS_LINKINVAL:
743147Sxc151355 		s = "invalid link";
753147Sxc151355 		break;
763147Sxc151355 	case DLADM_STATUS_PROPRDONLY:
773147Sxc151355 		s = "read-only property";
783147Sxc151355 		break;
793147Sxc151355 	case DLADM_STATUS_BADVALCNT:
803147Sxc151355 		s = "invalid number of values";
813147Sxc151355 		break;
823147Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
833147Sxc151355 		s = "database not found";
843147Sxc151355 		break;
853147Sxc151355 	case DLADM_STATUS_DENIED:
863147Sxc151355 		s = "permission denied";
873147Sxc151355 		break;
883147Sxc151355 	case DLADM_STATUS_IOERR:
893147Sxc151355 		s = "I/O error";
903147Sxc151355 		break;
913448Sdh155122 	case DLADM_STATUS_TEMPONLY:
923448Sdh155122 		s = "change cannot be persistent, specify -t please";
933448Sdh155122 		break;
943871Syz147064 	case DLADM_STATUS_TIMEDOUT:
953871Syz147064 		s = "operation timed out";
963871Syz147064 		break;
973871Syz147064 	case DLADM_STATUS_ISCONN:
983871Syz147064 		s = "already connected";
993871Syz147064 		break;
1003871Syz147064 	case DLADM_STATUS_NOTCONN:
1013871Syz147064 		s = "not connected";
1023871Syz147064 		break;
1033871Syz147064 	case DLADM_STATUS_REPOSITORYINVAL:
1043871Syz147064 		s = "invalid configuration repository";
1053871Syz147064 		break;
1063871Syz147064 	case DLADM_STATUS_MACADDRINVAL:
1073871Syz147064 		s = "invalid MAC address";
1083871Syz147064 		break;
1093871Syz147064 	case DLADM_STATUS_KEYINVAL:
1103871Syz147064 		s = "invalid key";
1113871Syz147064 		break;
1125084Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRLEN:
1135084Sjohnlev 		s = "invalid MAC address length";
1145084Sjohnlev 		break;
1155084Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRTYPE:
1165084Sjohnlev 		s = "invalid MAC address type";
1175084Sjohnlev 		break;
1185895Syz147064 	case DLADM_STATUS_LINKBUSY:
1195895Syz147064 		s = "link busy";
1205895Syz147064 		break;
1215895Syz147064 	case DLADM_STATUS_VIDINVAL:
1225895Syz147064 		s = "invalid VLAN identifier";
1235084Sjohnlev 		break;
1245895Syz147064 	case DLADM_STATUS_TRYAGAIN:
1255895Syz147064 		s = "try again later";
1265084Sjohnlev 		break;
1275895Syz147064 	case DLADM_STATUS_NONOTIF:
1285895Syz147064 		s = "link notification is not supported";
1295084Sjohnlev 		break;
1303147Sxc151355 	default:
1313184Smeem 		s = "<unknown error>";
1323184Smeem 		break;
1333147Sxc151355 	}
1343184Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
1353147Sxc151355 	return (buf);
1363147Sxc151355 }
1373147Sxc151355 
1383147Sxc151355 /*
1393147Sxc151355  * Convert a unix errno to a dladm_status_t.
1403147Sxc151355  * We only convert errnos that are likely to be encountered. All others
1413147Sxc151355  * are mapped to DLADM_STATUS_FAILED.
1423147Sxc151355  */
1433147Sxc151355 dladm_status_t
1443147Sxc151355 dladm_errno2status(int err)
1453147Sxc151355 {
1463147Sxc151355 	switch (err) {
1475903Ssowmini 	case 0:
1485903Ssowmini 		return (DLADM_STATUS_OK);
1493147Sxc151355 	case EINVAL:
1503147Sxc151355 		return (DLADM_STATUS_BADARG);
1513147Sxc151355 	case EEXIST:
1523147Sxc151355 		return (DLADM_STATUS_EXIST);
1533147Sxc151355 	case ENOENT:
1543147Sxc151355 		return (DLADM_STATUS_NOTFOUND);
1553147Sxc151355 	case ENOSPC:
1563147Sxc151355 		return (DLADM_STATUS_TOOSMALL);
1573147Sxc151355 	case ENOMEM:
1583147Sxc151355 		return (DLADM_STATUS_NOMEM);
1593147Sxc151355 	case ENOTSUP:
1603147Sxc151355 		return (DLADM_STATUS_NOTSUP);
1615895Syz147064 	case ENETDOWN:
1625895Syz147064 		return (DLADM_STATUS_NONOTIF);
1633147Sxc151355 	case EACCES:
164*7408SSebastien.Roy@Sun.COM 	case EPERM:
1653147Sxc151355 		return (DLADM_STATUS_DENIED);
1663147Sxc151355 	case EIO:
1673147Sxc151355 		return (DLADM_STATUS_IOERR);
1685084Sjohnlev 	case EBUSY:
1695895Syz147064 		return (DLADM_STATUS_LINKBUSY);
1705895Syz147064 	case EAGAIN:
1715895Syz147064 		return (DLADM_STATUS_TRYAGAIN);
1723147Sxc151355 	default:
1733147Sxc151355 		return (DLADM_STATUS_FAILED);
1743147Sxc151355 	}
1753147Sxc151355 }
1763147Sxc151355 
1775895Syz147064 #define	LOCK_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
1783147Sxc151355 
1793147Sxc151355 static int
1803147Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
1813147Sxc151355 {
1823147Sxc151355 	int	lock_fd;
1835895Syz147064 	struct	flock lock;
1843147Sxc151355 
1853147Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
1863147Sxc151355 	    LOCK_DB_PERMS)) < 0)
1873147Sxc151355 		return (-1);
1883147Sxc151355 
1893147Sxc151355 	lock.l_type = type;
1903147Sxc151355 	lock.l_whence = SEEK_SET;
1913147Sxc151355 	lock.l_start = 0;
1923147Sxc151355 	lock.l_len = 0;
1933147Sxc151355 
1943147Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
1953147Sxc151355 		int err = errno;
1963147Sxc151355 
1973147Sxc151355 		(void) close(lock_fd);
1983147Sxc151355 		(void) unlink(lock_file);
1993147Sxc151355 		errno = err;
2003147Sxc151355 		return (-1);
2013147Sxc151355 	}
2023147Sxc151355 	return (lock_fd);
2033147Sxc151355 }
2043147Sxc151355 
2053147Sxc151355 static void
2063147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
2073147Sxc151355 {
2083147Sxc151355 	struct flock lock;
2093147Sxc151355 
2103147Sxc151355 	if (fd < 0)
2113147Sxc151355 		return;
2123147Sxc151355 
2133147Sxc151355 	lock.l_type = F_UNLCK;
2143147Sxc151355 	lock.l_whence = SEEK_SET;
2153147Sxc151355 	lock.l_start = 0;
2163147Sxc151355 	lock.l_len = 0;
2173147Sxc151355 
2183147Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
2193147Sxc151355 	(void) close(fd);
2203147Sxc151355 	(void) unlink(lock_file);
2213147Sxc151355 }
2223147Sxc151355 
2235895Syz147064 /*
2245895Syz147064  * Given a link class, returns its class string.
2255895Syz147064  */
2265895Syz147064 const char *
2275895Syz147064 dladm_class2str(datalink_class_t class, char *buf)
2285895Syz147064 {
2295895Syz147064 	const char *s;
2305895Syz147064 
2315895Syz147064 	switch (class) {
2325895Syz147064 	case DATALINK_CLASS_PHYS:
2335895Syz147064 		s = "phys";
2345895Syz147064 		break;
2355895Syz147064 	case DATALINK_CLASS_VLAN:
2365895Syz147064 		s = "vlan";
2375895Syz147064 		break;
2385895Syz147064 	case DATALINK_CLASS_AGGR:
2395895Syz147064 		s = "aggr";
2405895Syz147064 		break;
2415895Syz147064 	case DATALINK_CLASS_VNIC:
2425895Syz147064 		s = "vnic";
2435895Syz147064 		break;
2445895Syz147064 	default:
2455895Syz147064 		s = "unknown";
2465895Syz147064 		break;
2475895Syz147064 	}
2485895Syz147064 
2495895Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
2505895Syz147064 	return (buf);
2515895Syz147064 }
2525895Syz147064 
2535895Syz147064 /*
2545895Syz147064  * Given a physical link media type, returns its media type string.
2555895Syz147064  */
2565895Syz147064 const char *
2575895Syz147064 dladm_media2str(uint32_t media, char *buf)
2585895Syz147064 {
2595895Syz147064 	const char *s;
2605895Syz147064 
2615895Syz147064 	switch (media) {
2625895Syz147064 	case DL_ETHER:
2635895Syz147064 		s = "Ethernet";
2645895Syz147064 		break;
2655895Syz147064 	case DL_WIFI:
2665895Syz147064 		s = "WiFi";
2675895Syz147064 		break;
2685895Syz147064 	case DL_IB:
2695895Syz147064 		s = "Infiniband";
2705895Syz147064 		break;
2715895Syz147064 	case DL_IPV4:
2725895Syz147064 		s = "IPv4Tunnel";
2735895Syz147064 		break;
2745895Syz147064 	case DL_IPV6:
2755895Syz147064 		s = "IPv6Tunnel";
2765895Syz147064 		break;
2775895Syz147064 	case DL_CSMACD:
2785895Syz147064 		s = "CSMA/CD";
2795895Syz147064 		break;
2805895Syz147064 	case DL_TPB:
2815895Syz147064 		s = "TokenBus";
2825895Syz147064 		break;
2835895Syz147064 	case DL_TPR:
2845895Syz147064 		s = "TokenRing";
2855895Syz147064 		break;
2865895Syz147064 	case DL_METRO:
2875895Syz147064 		s = "MetroNet";
2885895Syz147064 		break;
2895895Syz147064 	case DL_HDLC:
2905895Syz147064 		s = "HDLC";
2915895Syz147064 		break;
2925895Syz147064 	case DL_CHAR:
2935895Syz147064 		s = "SyncCharacter";
2945895Syz147064 		break;
2955895Syz147064 	case DL_CTCA:
2965895Syz147064 		s = "CTCA";
2975895Syz147064 		break;
2985895Syz147064 	case DL_FDDI:
2995895Syz147064 		s = "FDDI";
3005895Syz147064 		break;
3015895Syz147064 	case DL_FC:
3025895Syz147064 		s = "FiberChannel";
3035895Syz147064 		break;
3045895Syz147064 	case DL_ATM:
3055895Syz147064 		s = "ATM";
3065895Syz147064 		break;
3075895Syz147064 	case DL_IPATM:
3085895Syz147064 		s = "ATM(ClassicIP)";
3095895Syz147064 		break;
3105895Syz147064 	case DL_X25:
3115895Syz147064 		s = "X.25";
3125895Syz147064 		break;
3135895Syz147064 	case DL_IPX25:
3145895Syz147064 		s = "X.25(ClassicIP)";
3155895Syz147064 		break;
3165895Syz147064 	case DL_ISDN:
3175895Syz147064 		s = "ISDN";
3185895Syz147064 		break;
3195895Syz147064 	case DL_HIPPI:
3205895Syz147064 		s = "HIPPI";
3215895Syz147064 		break;
3225895Syz147064 	case DL_100VG:
3235895Syz147064 		s = "100BaseVGEthernet";
3245895Syz147064 		break;
3255895Syz147064 	case DL_100VGTPR:
3265895Syz147064 		s = "100BaseVGTokenRing";
3275895Syz147064 		break;
3285895Syz147064 	case DL_ETH_CSMA:
3295895Syz147064 		s = "IEEE802.3";
3305895Syz147064 		break;
3315895Syz147064 	case DL_100BT:
3325895Syz147064 		s = "100BaseT";
3335895Syz147064 		break;
3345895Syz147064 	case DL_FRAME:
3355895Syz147064 		s = "FrameRelay";
3365895Syz147064 		break;
3375895Syz147064 	case DL_MPFRAME:
3385895Syz147064 		s = "MPFrameRelay";
3395895Syz147064 		break;
3405895Syz147064 	case DL_ASYNC:
3415895Syz147064 		s = "AsyncCharacter";
3425895Syz147064 		break;
3435895Syz147064 	default:
3445895Syz147064 		s = "--";
3455895Syz147064 		break;
3465895Syz147064 	}
3475895Syz147064 
3485895Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
3495895Syz147064 	return (buf);
3505895Syz147064 }
3515895Syz147064 
3523147Sxc151355 dladm_status_t
3533147Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms,
3543147Sxc151355     dladm_status_t (*process_db)(void *, FILE *, FILE *),
3553147Sxc151355     void *arg, boolean_t writeop)
3563147Sxc151355 {
3573147Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
3583147Sxc151355 	FILE		*fp, *nfp = NULL;
3593147Sxc151355 	char		lock[MAXPATHLEN];
3603147Sxc151355 	char		file[MAXPATHLEN];
3613147Sxc151355 	char		newfile[MAXPATHLEN];
3623147Sxc151355 	char		*db_basename;
3633147Sxc151355 	int		nfd, lock_fd;
3643147Sxc151355 
3653147Sxc151355 	/*
3663147Sxc151355 	 * If we are called from a boot script such as net-physical,
3673147Sxc151355 	 * it's quite likely that the root fs is still not writable.
3683147Sxc151355 	 * For this case, it's ok for the lock creation to fail since
3693147Sxc151355 	 * no one else could be accessing our configuration file.
3703147Sxc151355 	 */
3713147Sxc151355 	db_basename = strrchr(db_file, '/');
3723147Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
3733147Sxc151355 		return (dladm_errno2status(EINVAL));
3743147Sxc151355 	db_basename++;
3753147Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
3763147Sxc151355 	if ((lock_fd = i_dladm_lock_db
3773147Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
3783147Sxc151355 		return (dladm_errno2status(errno));
3793147Sxc151355 
3803147Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
3813147Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
3823147Sxc151355 		int	err = errno;
3833147Sxc151355 
3843147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
3853147Sxc151355 		if (err == ENOENT)
3863147Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
3873147Sxc151355 
3883147Sxc151355 		return (dladm_errno2status(err));
3893147Sxc151355 	}
3903147Sxc151355 
3913147Sxc151355 	if (writeop) {
3923147Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
3933147Sxc151355 		    dladm_rootdir, db_file);
3943147Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
3953147Sxc151355 		    db_perms)) < 0) {
3963147Sxc151355 			(void) fclose(fp);
3973147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
3983147Sxc151355 			return (dladm_errno2status(errno));
3993147Sxc151355 		}
4003147Sxc151355 
4013147Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
4023147Sxc151355 			(void) close(nfd);
4033147Sxc151355 			(void) fclose(fp);
4043147Sxc151355 			(void) unlink(newfile);
4053147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
4063147Sxc151355 			return (dladm_errno2status(errno));
4073147Sxc151355 		}
4083147Sxc151355 	}
4093147Sxc151355 	status = (*process_db)(arg, fp, nfp);
4103147Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
4113147Sxc151355 		goto done;
4123147Sxc151355 
4133147Sxc151355 	/*
4143147Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
4153147Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
4163147Sxc151355 	 */
4173147Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
4186173Syz147064 		if (fchown(nfd, UID_DLADM, GID_SYS) < 0) {
4193147Sxc151355 			status = dladm_errno2status(errno);
4203147Sxc151355 			goto done;
4213147Sxc151355 		}
4223147Sxc151355 	}
4233147Sxc151355 
4243147Sxc151355 	if (fflush(nfp) == EOF) {
4253147Sxc151355 		status = dladm_errno2status(errno);
4263147Sxc151355 		goto done;
4273147Sxc151355 	}
4283147Sxc151355 	(void) fclose(fp);
4293147Sxc151355 	(void) fclose(nfp);
4303147Sxc151355 
4313147Sxc151355 	if (rename(newfile, file) < 0) {
4323147Sxc151355 		(void) unlink(newfile);
4333147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
4343147Sxc151355 		return (dladm_errno2status(errno));
4353147Sxc151355 	}
4363147Sxc151355 
4373147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
4383147Sxc151355 	return (DLADM_STATUS_OK);
4393147Sxc151355 
4403147Sxc151355 done:
4413147Sxc151355 	if (nfp != NULL) {
4423147Sxc151355 		(void) fclose(nfp);
4433147Sxc151355 		if (status != DLADM_STATUS_OK)
4443147Sxc151355 			(void) unlink(newfile);
4453147Sxc151355 	}
4463147Sxc151355 	(void) fclose(fp);
4473147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
4483147Sxc151355 	return (status);
4493147Sxc151355 }
4503147Sxc151355 
4513147Sxc151355 dladm_status_t
4523147Sxc151355 dladm_set_rootdir(const char *rootdir)
4533147Sxc151355 {
4543147Sxc151355 	DIR	*dp;
4553147Sxc151355 
4563147Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
4573147Sxc151355 	    (dp = opendir(rootdir)) == NULL)
4583147Sxc151355 		return (DLADM_STATUS_BADARG);
4593147Sxc151355 
4603147Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
4613147Sxc151355 	(void) closedir(dp);
4623147Sxc151355 	return (DLADM_STATUS_OK);
4633147Sxc151355 }
4645895Syz147064 
4655895Syz147064 boolean_t
4665895Syz147064 dladm_valid_linkname(const char *link)
4675895Syz147064 {
4685895Syz147064 	size_t		len = strlen(link);
4695895Syz147064 	const char	*cp;
4705895Syz147064 
4715895Syz147064 	if (len + 1 >= MAXLINKNAMELEN)
4725895Syz147064 		return (B_FALSE);
4735895Syz147064 
4745895Syz147064 	/*
4755895Syz147064 	 * The link name cannot start with a digit and must end with a digit.
4765895Syz147064 	 */
4775895Syz147064 	if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0))
4785895Syz147064 		return (B_FALSE);
4795895Syz147064 
4805895Syz147064 	/*
4815895Syz147064 	 * The legal characters in a link name are:
4825895Syz147064 	 * alphanumeric (a-z,  A-Z,  0-9), and the underscore ('_').
4835895Syz147064 	 */
4845895Syz147064 	for (cp = link; *cp != '\0'; cp++) {
4855895Syz147064 		if ((isalnum(*cp) == 0) && (*cp != '_'))
4865895Syz147064 			return (B_FALSE);
4875895Syz147064 	}
4885895Syz147064 
4895895Syz147064 	return (B_TRUE);
4905895Syz147064 }
491