xref: /titanic_51/usr/src/lib/libdladm/common/libdladm.c (revision d62bc4badc1c1f1549c961cfb8b420e650e1272b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <unistd.h>
297c478bd9Sstevel@tonic-gate #include <stropts.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
31*d62bc4baSyz147064 #include <ctype.h>
320ba2cbe9Sxc151355 #include <fcntl.h>
330ba2cbe9Sxc151355 #include <strings.h>
340ba2cbe9Sxc151355 #include <dirent.h>
350ba2cbe9Sxc151355 #include <sys/stat.h>
360ba2cbe9Sxc151355 #include <libdladm_impl.h>
3733343a97Smeem #include <libintl.h>
38*d62bc4baSyz147064 #include <libdlpi.h>
39aae21359Skrgopi 
400ba2cbe9Sxc151355 static char		dladm_rootdir[MAXPATHLEN] = "/";
410ba2cbe9Sxc151355 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
447c478bd9Sstevel@tonic-gate  * DLD control driver interface.
457c478bd9Sstevel@tonic-gate  */
460ba2cbe9Sxc151355 int
47210db224Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
487c478bd9Sstevel@tonic-gate {
497c478bd9Sstevel@tonic-gate 	struct strioctl	iocb;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
527c478bd9Sstevel@tonic-gate 	iocb.ic_timout = 0;
537c478bd9Sstevel@tonic-gate 	iocb.ic_len = ic_len;
54210db224Sericheng 	iocb.ic_dp = (char *)ic_dp;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate 
590ba2cbe9Sxc151355 const char *
600ba2cbe9Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
610ba2cbe9Sxc151355 {
620ba2cbe9Sxc151355 	const char	*s;
630ba2cbe9Sxc151355 
640ba2cbe9Sxc151355 	switch (status) {
650ba2cbe9Sxc151355 	case DLADM_STATUS_OK:
660ba2cbe9Sxc151355 		s = "ok";
670ba2cbe9Sxc151355 		break;
680ba2cbe9Sxc151355 	case DLADM_STATUS_BADARG:
690ba2cbe9Sxc151355 		s = "invalid argument";
700ba2cbe9Sxc151355 		break;
710ba2cbe9Sxc151355 	case DLADM_STATUS_FAILED:
720ba2cbe9Sxc151355 		s = "operation failed";
730ba2cbe9Sxc151355 		break;
740ba2cbe9Sxc151355 	case DLADM_STATUS_TOOSMALL:
750ba2cbe9Sxc151355 		s = "buffer size too small";
760ba2cbe9Sxc151355 		break;
770ba2cbe9Sxc151355 	case DLADM_STATUS_NOTSUP:
780ba2cbe9Sxc151355 		s = "operation not supported";
790ba2cbe9Sxc151355 		break;
800ba2cbe9Sxc151355 	case DLADM_STATUS_NOTFOUND:
810ba2cbe9Sxc151355 		s = "object not found";
820ba2cbe9Sxc151355 		break;
830ba2cbe9Sxc151355 	case DLADM_STATUS_BADVAL:
840ba2cbe9Sxc151355 		s = "invalid value";
850ba2cbe9Sxc151355 		break;
860ba2cbe9Sxc151355 	case DLADM_STATUS_NOMEM:
870ba2cbe9Sxc151355 		s = "insufficient memory";
880ba2cbe9Sxc151355 		break;
890ba2cbe9Sxc151355 	case DLADM_STATUS_EXIST:
900ba2cbe9Sxc151355 		s = "object already exists";
910ba2cbe9Sxc151355 		break;
920ba2cbe9Sxc151355 	case DLADM_STATUS_LINKINVAL:
930ba2cbe9Sxc151355 		s = "invalid link";
940ba2cbe9Sxc151355 		break;
950ba2cbe9Sxc151355 	case DLADM_STATUS_PROPRDONLY:
960ba2cbe9Sxc151355 		s = "read-only property";
970ba2cbe9Sxc151355 		break;
980ba2cbe9Sxc151355 	case DLADM_STATUS_BADVALCNT:
990ba2cbe9Sxc151355 		s = "invalid number of values";
1000ba2cbe9Sxc151355 		break;
1010ba2cbe9Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
1020ba2cbe9Sxc151355 		s = "database not found";
1030ba2cbe9Sxc151355 		break;
1040ba2cbe9Sxc151355 	case DLADM_STATUS_DENIED:
1050ba2cbe9Sxc151355 		s = "permission denied";
1060ba2cbe9Sxc151355 		break;
1070ba2cbe9Sxc151355 	case DLADM_STATUS_IOERR:
1080ba2cbe9Sxc151355 		s = "I/O error";
1090ba2cbe9Sxc151355 		break;
110f4b3ec61Sdh155122 	case DLADM_STATUS_TEMPONLY:
111f4b3ec61Sdh155122 		s = "change cannot be persistent, specify -t please";
112f4b3ec61Sdh155122 		break;
113f595a68aSyz147064 	case DLADM_STATUS_TIMEDOUT:
114f595a68aSyz147064 		s = "operation timed out";
115f595a68aSyz147064 		break;
116f595a68aSyz147064 	case DLADM_STATUS_ISCONN:
117f595a68aSyz147064 		s = "already connected";
118f595a68aSyz147064 		break;
119f595a68aSyz147064 	case DLADM_STATUS_NOTCONN:
120f595a68aSyz147064 		s = "not connected";
121f595a68aSyz147064 		break;
122f595a68aSyz147064 	case DLADM_STATUS_REPOSITORYINVAL:
123f595a68aSyz147064 		s = "invalid configuration repository";
124f595a68aSyz147064 		break;
125f595a68aSyz147064 	case DLADM_STATUS_MACADDRINVAL:
126f595a68aSyz147064 		s = "invalid MAC address";
127f595a68aSyz147064 		break;
128f595a68aSyz147064 	case DLADM_STATUS_KEYINVAL:
129f595a68aSyz147064 		s = "invalid key";
130f595a68aSyz147064 		break;
131843e1988Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRLEN:
132843e1988Sjohnlev 		s = "invalid MAC address length";
133843e1988Sjohnlev 		break;
134843e1988Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRTYPE:
135843e1988Sjohnlev 		s = "invalid MAC address type";
136843e1988Sjohnlev 		break;
137*d62bc4baSyz147064 	case DLADM_STATUS_LINKBUSY:
138*d62bc4baSyz147064 		s = "link busy";
139843e1988Sjohnlev 		break;
140*d62bc4baSyz147064 	case DLADM_STATUS_VIDINVAL:
141*d62bc4baSyz147064 		s = "invalid VLAN identifier";
142843e1988Sjohnlev 		break;
143*d62bc4baSyz147064 	case DLADM_STATUS_TRYAGAIN:
144*d62bc4baSyz147064 		s = "try again later";
145*d62bc4baSyz147064 		break;
146*d62bc4baSyz147064 	case DLADM_STATUS_NONOTIF:
147*d62bc4baSyz147064 		s = "link notification is not supported";
148843e1988Sjohnlev 		break;
1490ba2cbe9Sxc151355 	default:
15033343a97Smeem 		s = "<unknown error>";
15133343a97Smeem 		break;
1520ba2cbe9Sxc151355 	}
15333343a97Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
1540ba2cbe9Sxc151355 	return (buf);
1550ba2cbe9Sxc151355 }
1560ba2cbe9Sxc151355 
1570ba2cbe9Sxc151355 /*
1580ba2cbe9Sxc151355  * Convert a unix errno to a dladm_status_t.
1590ba2cbe9Sxc151355  * We only convert errnos that are likely to be encountered. All others
1600ba2cbe9Sxc151355  * are mapped to DLADM_STATUS_FAILED.
1610ba2cbe9Sxc151355  */
1620ba2cbe9Sxc151355 dladm_status_t
1630ba2cbe9Sxc151355 dladm_errno2status(int err)
1640ba2cbe9Sxc151355 {
1650ba2cbe9Sxc151355 	switch (err) {
1660ba2cbe9Sxc151355 	case EINVAL:
1670ba2cbe9Sxc151355 		return (DLADM_STATUS_BADARG);
1680ba2cbe9Sxc151355 	case EEXIST:
1690ba2cbe9Sxc151355 		return (DLADM_STATUS_EXIST);
1700ba2cbe9Sxc151355 	case ENOENT:
1710ba2cbe9Sxc151355 		return (DLADM_STATUS_NOTFOUND);
1720ba2cbe9Sxc151355 	case ENOSPC:
1730ba2cbe9Sxc151355 		return (DLADM_STATUS_TOOSMALL);
1740ba2cbe9Sxc151355 	case ENOMEM:
1750ba2cbe9Sxc151355 		return (DLADM_STATUS_NOMEM);
1760ba2cbe9Sxc151355 	case ENOTSUP:
1770ba2cbe9Sxc151355 		return (DLADM_STATUS_NOTSUP);
178*d62bc4baSyz147064 	case ENETDOWN:
179*d62bc4baSyz147064 		return (DLADM_STATUS_NONOTIF);
1800ba2cbe9Sxc151355 	case EACCES:
1810ba2cbe9Sxc151355 		return (DLADM_STATUS_DENIED);
1820ba2cbe9Sxc151355 	case EIO:
1830ba2cbe9Sxc151355 		return (DLADM_STATUS_IOERR);
184843e1988Sjohnlev 	case EBUSY:
185*d62bc4baSyz147064 		return (DLADM_STATUS_LINKBUSY);
186*d62bc4baSyz147064 	case EAGAIN:
187*d62bc4baSyz147064 		return (DLADM_STATUS_TRYAGAIN);
1880ba2cbe9Sxc151355 	default:
1890ba2cbe9Sxc151355 		return (DLADM_STATUS_FAILED);
1900ba2cbe9Sxc151355 	}
1910ba2cbe9Sxc151355 }
1920ba2cbe9Sxc151355 
1930ba2cbe9Sxc151355 /*
1940ba2cbe9Sxc151355  * These are the uid and gid of the user 'dladm'.
1950ba2cbe9Sxc151355  * The directory /etc/dladm and all files under it are owned by this user.
1960ba2cbe9Sxc151355  */
1970ba2cbe9Sxc151355 #define	DLADM_DB_OWNER	15
1980ba2cbe9Sxc151355 #define	DLADM_DB_GROUP	3
1990ba2cbe9Sxc151355 #define	LOCK_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
2000ba2cbe9Sxc151355 
2010ba2cbe9Sxc151355 static int
2020ba2cbe9Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
2030ba2cbe9Sxc151355 {
2040ba2cbe9Sxc151355 	int	lock_fd;
2050ba2cbe9Sxc151355 	struct	flock lock;
2060ba2cbe9Sxc151355 
2070ba2cbe9Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
2080ba2cbe9Sxc151355 	    LOCK_DB_PERMS)) < 0)
2090ba2cbe9Sxc151355 		return (-1);
2100ba2cbe9Sxc151355 
2110ba2cbe9Sxc151355 	lock.l_type = type;
2120ba2cbe9Sxc151355 	lock.l_whence = SEEK_SET;
2130ba2cbe9Sxc151355 	lock.l_start = 0;
2140ba2cbe9Sxc151355 	lock.l_len = 0;
2150ba2cbe9Sxc151355 
2160ba2cbe9Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
2170ba2cbe9Sxc151355 		int err = errno;
2180ba2cbe9Sxc151355 
2190ba2cbe9Sxc151355 		(void) close(lock_fd);
2200ba2cbe9Sxc151355 		(void) unlink(lock_file);
2210ba2cbe9Sxc151355 		errno = err;
2220ba2cbe9Sxc151355 		return (-1);
2230ba2cbe9Sxc151355 	}
2240ba2cbe9Sxc151355 	return (lock_fd);
2250ba2cbe9Sxc151355 }
2260ba2cbe9Sxc151355 
2270ba2cbe9Sxc151355 static void
2280ba2cbe9Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
2290ba2cbe9Sxc151355 {
2300ba2cbe9Sxc151355 	struct flock lock;
2310ba2cbe9Sxc151355 
2320ba2cbe9Sxc151355 	if (fd < 0)
2330ba2cbe9Sxc151355 		return;
2340ba2cbe9Sxc151355 
2350ba2cbe9Sxc151355 	lock.l_type = F_UNLCK;
2360ba2cbe9Sxc151355 	lock.l_whence = SEEK_SET;
2370ba2cbe9Sxc151355 	lock.l_start = 0;
2380ba2cbe9Sxc151355 	lock.l_len = 0;
2390ba2cbe9Sxc151355 
2400ba2cbe9Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
2410ba2cbe9Sxc151355 	(void) close(fd);
2420ba2cbe9Sxc151355 	(void) unlink(lock_file);
2430ba2cbe9Sxc151355 }
2440ba2cbe9Sxc151355 
245*d62bc4baSyz147064 /*
246*d62bc4baSyz147064  * Given a link class, returns its class string.
247*d62bc4baSyz147064  */
248*d62bc4baSyz147064 const char *
249*d62bc4baSyz147064 dladm_class2str(datalink_class_t class, char *buf)
250*d62bc4baSyz147064 {
251*d62bc4baSyz147064 	const char *s;
252*d62bc4baSyz147064 
253*d62bc4baSyz147064 	switch (class) {
254*d62bc4baSyz147064 	case DATALINK_CLASS_PHYS:
255*d62bc4baSyz147064 		s = "phys";
256*d62bc4baSyz147064 		break;
257*d62bc4baSyz147064 	case DATALINK_CLASS_VLAN:
258*d62bc4baSyz147064 		s = "vlan";
259*d62bc4baSyz147064 		break;
260*d62bc4baSyz147064 	case DATALINK_CLASS_AGGR:
261*d62bc4baSyz147064 		s = "aggr";
262*d62bc4baSyz147064 		break;
263*d62bc4baSyz147064 	case DATALINK_CLASS_VNIC:
264*d62bc4baSyz147064 		s = "vnic";
265*d62bc4baSyz147064 		break;
266*d62bc4baSyz147064 	default:
267*d62bc4baSyz147064 		s = "unknown";
268*d62bc4baSyz147064 		break;
269*d62bc4baSyz147064 	}
270*d62bc4baSyz147064 
271*d62bc4baSyz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
272*d62bc4baSyz147064 	return (buf);
273*d62bc4baSyz147064 }
274*d62bc4baSyz147064 
275*d62bc4baSyz147064 /*
276*d62bc4baSyz147064  * Given a physical link media type, returns its media type string.
277*d62bc4baSyz147064  */
278*d62bc4baSyz147064 const char *
279*d62bc4baSyz147064 dladm_media2str(uint32_t media, char *buf)
280*d62bc4baSyz147064 {
281*d62bc4baSyz147064 	const char *s;
282*d62bc4baSyz147064 
283*d62bc4baSyz147064 	switch (media) {
284*d62bc4baSyz147064 	case DL_ETHER:
285*d62bc4baSyz147064 		s = "Ethernet";
286*d62bc4baSyz147064 		break;
287*d62bc4baSyz147064 	case DL_WIFI:
288*d62bc4baSyz147064 		s = "WiFi";
289*d62bc4baSyz147064 		break;
290*d62bc4baSyz147064 	case DL_IB:
291*d62bc4baSyz147064 		s = "Infiniband";
292*d62bc4baSyz147064 		break;
293*d62bc4baSyz147064 	case DL_IPV4:
294*d62bc4baSyz147064 		s = "IPv4Tunnel";
295*d62bc4baSyz147064 		break;
296*d62bc4baSyz147064 	case DL_IPV6:
297*d62bc4baSyz147064 		s = "IPv6Tunnel";
298*d62bc4baSyz147064 		break;
299*d62bc4baSyz147064 	case DL_CSMACD:
300*d62bc4baSyz147064 		s = "CSMA/CD";
301*d62bc4baSyz147064 		break;
302*d62bc4baSyz147064 	case DL_TPB:
303*d62bc4baSyz147064 		s = "TokenBus";
304*d62bc4baSyz147064 		break;
305*d62bc4baSyz147064 	case DL_TPR:
306*d62bc4baSyz147064 		s = "TokenRing";
307*d62bc4baSyz147064 		break;
308*d62bc4baSyz147064 	case DL_METRO:
309*d62bc4baSyz147064 		s = "MetroNet";
310*d62bc4baSyz147064 		break;
311*d62bc4baSyz147064 	case DL_HDLC:
312*d62bc4baSyz147064 		s = "HDLC";
313*d62bc4baSyz147064 		break;
314*d62bc4baSyz147064 	case DL_CHAR:
315*d62bc4baSyz147064 		s = "SyncCharacter";
316*d62bc4baSyz147064 		break;
317*d62bc4baSyz147064 	case DL_CTCA:
318*d62bc4baSyz147064 		s = "CTCA";
319*d62bc4baSyz147064 		break;
320*d62bc4baSyz147064 	case DL_FDDI:
321*d62bc4baSyz147064 		s = "FDDI";
322*d62bc4baSyz147064 		break;
323*d62bc4baSyz147064 	case DL_FC:
324*d62bc4baSyz147064 		s = "FiberChannel";
325*d62bc4baSyz147064 		break;
326*d62bc4baSyz147064 	case DL_ATM:
327*d62bc4baSyz147064 		s = "ATM";
328*d62bc4baSyz147064 		break;
329*d62bc4baSyz147064 	case DL_IPATM:
330*d62bc4baSyz147064 		s = "ATM(ClassicIP)";
331*d62bc4baSyz147064 		break;
332*d62bc4baSyz147064 	case DL_X25:
333*d62bc4baSyz147064 		s = "X.25";
334*d62bc4baSyz147064 		break;
335*d62bc4baSyz147064 	case DL_IPX25:
336*d62bc4baSyz147064 		s = "X.25(ClassicIP)";
337*d62bc4baSyz147064 		break;
338*d62bc4baSyz147064 	case DL_ISDN:
339*d62bc4baSyz147064 		s = "ISDN";
340*d62bc4baSyz147064 		break;
341*d62bc4baSyz147064 	case DL_HIPPI:
342*d62bc4baSyz147064 		s = "HIPPI";
343*d62bc4baSyz147064 		break;
344*d62bc4baSyz147064 	case DL_100VG:
345*d62bc4baSyz147064 		s = "100BaseVGEthernet";
346*d62bc4baSyz147064 		break;
347*d62bc4baSyz147064 	case DL_100VGTPR:
348*d62bc4baSyz147064 		s = "100BaseVGTokenRing";
349*d62bc4baSyz147064 		break;
350*d62bc4baSyz147064 	case DL_ETH_CSMA:
351*d62bc4baSyz147064 		s = "IEEE802.3";
352*d62bc4baSyz147064 		break;
353*d62bc4baSyz147064 	case DL_100BT:
354*d62bc4baSyz147064 		s = "100BaseT";
355*d62bc4baSyz147064 		break;
356*d62bc4baSyz147064 	case DL_FRAME:
357*d62bc4baSyz147064 		s = "FrameRelay";
358*d62bc4baSyz147064 		break;
359*d62bc4baSyz147064 	case DL_MPFRAME:
360*d62bc4baSyz147064 		s = "MPFrameRelay";
361*d62bc4baSyz147064 		break;
362*d62bc4baSyz147064 	case DL_ASYNC:
363*d62bc4baSyz147064 		s = "AsyncCharacter";
364*d62bc4baSyz147064 		break;
365*d62bc4baSyz147064 	default:
366*d62bc4baSyz147064 		s = "--";
367*d62bc4baSyz147064 		break;
368*d62bc4baSyz147064 	}
369*d62bc4baSyz147064 
370*d62bc4baSyz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
371*d62bc4baSyz147064 	return (buf);
372*d62bc4baSyz147064 }
373*d62bc4baSyz147064 
3740ba2cbe9Sxc151355 dladm_status_t
3750ba2cbe9Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms,
3760ba2cbe9Sxc151355     dladm_status_t (*process_db)(void *, FILE *, FILE *),
3770ba2cbe9Sxc151355     void *arg, boolean_t writeop)
3780ba2cbe9Sxc151355 {
3790ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
3800ba2cbe9Sxc151355 	FILE		*fp, *nfp = NULL;
3810ba2cbe9Sxc151355 	char		lock[MAXPATHLEN];
3820ba2cbe9Sxc151355 	char		file[MAXPATHLEN];
3830ba2cbe9Sxc151355 	char		newfile[MAXPATHLEN];
3840ba2cbe9Sxc151355 	char		*db_basename;
3850ba2cbe9Sxc151355 	int		nfd, lock_fd;
3860ba2cbe9Sxc151355 
3870ba2cbe9Sxc151355 	/*
3880ba2cbe9Sxc151355 	 * If we are called from a boot script such as net-physical,
3890ba2cbe9Sxc151355 	 * it's quite likely that the root fs is still not writable.
3900ba2cbe9Sxc151355 	 * For this case, it's ok for the lock creation to fail since
3910ba2cbe9Sxc151355 	 * no one else could be accessing our configuration file.
3920ba2cbe9Sxc151355 	 */
3930ba2cbe9Sxc151355 	db_basename = strrchr(db_file, '/');
3940ba2cbe9Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
3950ba2cbe9Sxc151355 		return (dladm_errno2status(EINVAL));
3960ba2cbe9Sxc151355 	db_basename++;
3970ba2cbe9Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
3980ba2cbe9Sxc151355 	if ((lock_fd = i_dladm_lock_db
3990ba2cbe9Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
4000ba2cbe9Sxc151355 		return (dladm_errno2status(errno));
4010ba2cbe9Sxc151355 
4020ba2cbe9Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
4030ba2cbe9Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
4040ba2cbe9Sxc151355 		int	err = errno;
4050ba2cbe9Sxc151355 
4060ba2cbe9Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
4070ba2cbe9Sxc151355 		if (err == ENOENT)
4080ba2cbe9Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
4090ba2cbe9Sxc151355 
4100ba2cbe9Sxc151355 		return (dladm_errno2status(err));
4110ba2cbe9Sxc151355 	}
4120ba2cbe9Sxc151355 
4130ba2cbe9Sxc151355 	if (writeop) {
4140ba2cbe9Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
4150ba2cbe9Sxc151355 		    dladm_rootdir, db_file);
4160ba2cbe9Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
4170ba2cbe9Sxc151355 		    db_perms)) < 0) {
4180ba2cbe9Sxc151355 			(void) fclose(fp);
4190ba2cbe9Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
4200ba2cbe9Sxc151355 			return (dladm_errno2status(errno));
4210ba2cbe9Sxc151355 		}
4220ba2cbe9Sxc151355 
4230ba2cbe9Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
4240ba2cbe9Sxc151355 			(void) close(nfd);
4250ba2cbe9Sxc151355 			(void) fclose(fp);
4260ba2cbe9Sxc151355 			(void) unlink(newfile);
4270ba2cbe9Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
4280ba2cbe9Sxc151355 			return (dladm_errno2status(errno));
4290ba2cbe9Sxc151355 		}
4300ba2cbe9Sxc151355 	}
4310ba2cbe9Sxc151355 	status = (*process_db)(arg, fp, nfp);
4320ba2cbe9Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
4330ba2cbe9Sxc151355 		goto done;
4340ba2cbe9Sxc151355 
4350ba2cbe9Sxc151355 	/*
4360ba2cbe9Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
4370ba2cbe9Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
4380ba2cbe9Sxc151355 	 */
4390ba2cbe9Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
4400ba2cbe9Sxc151355 		if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) {
4410ba2cbe9Sxc151355 			status = dladm_errno2status(errno);
4420ba2cbe9Sxc151355 			goto done;
4430ba2cbe9Sxc151355 		}
4440ba2cbe9Sxc151355 	}
4450ba2cbe9Sxc151355 
4460ba2cbe9Sxc151355 	if (fflush(nfp) == EOF) {
4470ba2cbe9Sxc151355 		status = dladm_errno2status(errno);
4480ba2cbe9Sxc151355 		goto done;
4490ba2cbe9Sxc151355 	}
4500ba2cbe9Sxc151355 	(void) fclose(fp);
4510ba2cbe9Sxc151355 	(void) fclose(nfp);
4520ba2cbe9Sxc151355 
4530ba2cbe9Sxc151355 	if (rename(newfile, file) < 0) {
4540ba2cbe9Sxc151355 		(void) unlink(newfile);
4550ba2cbe9Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
4560ba2cbe9Sxc151355 		return (dladm_errno2status(errno));
4570ba2cbe9Sxc151355 	}
4580ba2cbe9Sxc151355 
4590ba2cbe9Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
4600ba2cbe9Sxc151355 	return (DLADM_STATUS_OK);
4610ba2cbe9Sxc151355 
4620ba2cbe9Sxc151355 done:
4630ba2cbe9Sxc151355 	if (nfp != NULL) {
4640ba2cbe9Sxc151355 		(void) fclose(nfp);
4650ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK)
4660ba2cbe9Sxc151355 			(void) unlink(newfile);
4670ba2cbe9Sxc151355 	}
4680ba2cbe9Sxc151355 	(void) fclose(fp);
4690ba2cbe9Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
4700ba2cbe9Sxc151355 	return (status);
4710ba2cbe9Sxc151355 }
4720ba2cbe9Sxc151355 
4730ba2cbe9Sxc151355 dladm_status_t
4740ba2cbe9Sxc151355 dladm_set_rootdir(const char *rootdir)
4750ba2cbe9Sxc151355 {
4760ba2cbe9Sxc151355 	DIR	*dp;
4770ba2cbe9Sxc151355 
4780ba2cbe9Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
4790ba2cbe9Sxc151355 	    (dp = opendir(rootdir)) == NULL)
4800ba2cbe9Sxc151355 		return (DLADM_STATUS_BADARG);
4810ba2cbe9Sxc151355 
4820ba2cbe9Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
4830ba2cbe9Sxc151355 	(void) closedir(dp);
4840ba2cbe9Sxc151355 	return (DLADM_STATUS_OK);
4850ba2cbe9Sxc151355 }
486*d62bc4baSyz147064 
487*d62bc4baSyz147064 boolean_t
488*d62bc4baSyz147064 dladm_valid_linkname(const char *link)
489*d62bc4baSyz147064 {
490*d62bc4baSyz147064 	size_t		len = strlen(link);
491*d62bc4baSyz147064 	const char	*cp;
492*d62bc4baSyz147064 
493*d62bc4baSyz147064 	if (len + 1 >= MAXLINKNAMELEN)
494*d62bc4baSyz147064 		return (B_FALSE);
495*d62bc4baSyz147064 
496*d62bc4baSyz147064 	/*
497*d62bc4baSyz147064 	 * The link name cannot start with a digit and must end with a digit.
498*d62bc4baSyz147064 	 */
499*d62bc4baSyz147064 	if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0))
500*d62bc4baSyz147064 		return (B_FALSE);
501*d62bc4baSyz147064 
502*d62bc4baSyz147064 	/*
503*d62bc4baSyz147064 	 * The legal characters in a link name are:
504*d62bc4baSyz147064 	 * alphanumeric (a-z,  A-Z,  0-9), and the underscore ('_').
505*d62bc4baSyz147064 	 */
506*d62bc4baSyz147064 	for (cp = link; *cp != '\0'; cp++) {
507*d62bc4baSyz147064 		if ((isalnum(*cp) == 0) && (*cp != '_'))
508*d62bc4baSyz147064 			return (B_FALSE);
509*d62bc4baSyz147064 	}
510*d62bc4baSyz147064 
511*d62bc4baSyz147064 	return (B_TRUE);
512*d62bc4baSyz147064 }
513