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 /*
222311Sseb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate #include <stropts.h>
300Sstevel@tonic-gate #include <errno.h>
313147Sxc151355 #include <fcntl.h>
323147Sxc151355 #include <strings.h>
333147Sxc151355 #include <dirent.h>
343147Sxc151355 #include <net/if.h>
353147Sxc151355 #include <sys/stat.h>
363147Sxc151355 #include <sys/dld.h>
370Sstevel@tonic-gate #include <libdlpi.h>
383147Sxc151355 #include <libdevinfo.h>
393147Sxc151355 #include <libdladm_impl.h>
40*3184Smeem #include <libintl.h>
410Sstevel@tonic-gate 
42733Skrgopi typedef struct dladm_dev {
43733Skrgopi 	char			dd_name[IFNAMSIZ];
44733Skrgopi 	struct dladm_dev	*dd_next;
45733Skrgopi } dladm_dev_t;
46733Skrgopi 
47733Skrgopi typedef struct dladm_walk {
48733Skrgopi 	dladm_dev_t		*dw_dev_list;
49733Skrgopi } dladm_walk_t;
50733Skrgopi 
513147Sxc151355 static char		dladm_rootdir[MAXPATHLEN] = "/";
523147Sxc151355 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
550Sstevel@tonic-gate  * DLD control driver interface.
560Sstevel@tonic-gate  */
573147Sxc151355 int
58269Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	struct strioctl	iocb;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
630Sstevel@tonic-gate 	iocb.ic_timout = 0;
640Sstevel@tonic-gate 	iocb.ic_len = ic_len;
65269Sericheng 	iocb.ic_dp = (char *)ic_dp;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
680Sstevel@tonic-gate }
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * Return the attributes of the specified datalink from the DLD driver.
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate static int
740Sstevel@tonic-gate i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	dld_ioc_attr_t	dia;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	if (strlen(name) >= IFNAMSIZ) {
790Sstevel@tonic-gate 		errno = EINVAL;
800Sstevel@tonic-gate 		return (-1);
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
840Sstevel@tonic-gate 
85269Sericheng 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
860Sstevel@tonic-gate 		return (-1);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
89269Sericheng 	dap->da_max_sdu = dia.dia_max_sdu;
900Sstevel@tonic-gate 	dap->da_vid = dia.dia_vid;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	return (0);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * Adds a datalink to the array corresponding to arg.
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate static void
990Sstevel@tonic-gate i_dladm_nt_net_add(void *arg, char *name)
1000Sstevel@tonic-gate {
101733Skrgopi 	dladm_walk_t	*dwp = arg;
102733Skrgopi 	dladm_dev_t	*ddp = dwp->dw_dev_list;
103733Skrgopi 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
1040Sstevel@tonic-gate 
105733Skrgopi 	while (ddp) {
106733Skrgopi 		/*
107733Skrgopi 		 * Skip duplicates.
108733Skrgopi 		 */
109733Skrgopi 		if (strcmp(ddp->dd_name, name) == 0)
1100Sstevel@tonic-gate 			return;
111733Skrgopi 
112733Skrgopi 		lastp = &ddp->dd_next;
113733Skrgopi 		ddp = ddp->dd_next;
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
116733Skrgopi 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
117733Skrgopi 		return;
118733Skrgopi 
119733Skrgopi 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
120733Skrgopi 	ddp->dd_next = NULL;
121733Skrgopi 	*lastp = ddp;
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * Walker callback invoked for each DDI_NT_NET node.
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate static int
1280Sstevel@tonic-gate i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	dl_info_ack_t	dlia;
1310Sstevel@tonic-gate 	char		name[IFNAMSIZ];
1320Sstevel@tonic-gate 	int		fd;
1330Sstevel@tonic-gate 	char		*provider;
1340Sstevel@tonic-gate 	uint_t		ppa;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	provider = di_minor_name(minor);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if ((fd = dlpi_open(provider)) < 0)
1390Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
1420Sstevel@tonic-gate 		(void) dlpi_close(fd);
1430Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	if (dlia.dl_provider_style == DL_STYLE1) {
1470Sstevel@tonic-gate 		i_dladm_nt_net_add(arg, provider);
1480Sstevel@tonic-gate 		(void) dlpi_close(fd);
1490Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	ppa = di_instance(node);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	if (dlpi_attach(fd, -1, ppa) < 0) {
1550Sstevel@tonic-gate 		(void) dlpi_close(fd);
1560Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
1590Sstevel@tonic-gate 	i_dladm_nt_net_add(arg, name);
1600Sstevel@tonic-gate 	(void) dlpi_close(fd);
1610Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate  * Invoke the specified callback function for each active DDI_NT_NET
1660Sstevel@tonic-gate  * node.
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate int
1690Sstevel@tonic-gate dladm_walk(void (*fn)(void *, const char *), void *arg)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	di_node_t	root;
172733Skrgopi 	dladm_walk_t	dw;
173733Skrgopi 	dladm_dev_t	*ddp, *last_ddp;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
1760Sstevel@tonic-gate 		errno = EFAULT;
1770Sstevel@tonic-gate 		return (-1);
1780Sstevel@tonic-gate 	}
179733Skrgopi 	dw.dw_dev_list = NULL;
1800Sstevel@tonic-gate 
181733Skrgopi 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
182733Skrgopi 	    i_dladm_nt_net_walk);
1830Sstevel@tonic-gate 
184733Skrgopi 	di_fini(root);
1850Sstevel@tonic-gate 
186733Skrgopi 	ddp = dw.dw_dev_list;
187733Skrgopi 	while (ddp) {
188733Skrgopi 		fn(arg, ddp->dd_name);
189737Skrgopi 		(void) dladm_walk_vlan(fn, arg, ddp->dd_name);
190733Skrgopi 		last_ddp = ddp;
191733Skrgopi 		ddp = ddp->dd_next;
192733Skrgopi 		free(last_ddp);
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
195733Skrgopi 	return (0);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
199269Sericheng  * Invoke the specified callback function for each vlan managed by dld
2000Sstevel@tonic-gate  */
2010Sstevel@tonic-gate int
202733Skrgopi dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name)
2030Sstevel@tonic-gate {
204733Skrgopi 	int		fd, bufsize, i;
205733Skrgopi 	int		nvlan = 4094;
206269Sericheng 	dld_ioc_vlan_t	*iocp = NULL;
207269Sericheng 	dld_vlan_info_t	*dvip;
208269Sericheng 
209269Sericheng 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
210269Sericheng 		return (-1);
211269Sericheng 
212733Skrgopi 	bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t);
2130Sstevel@tonic-gate 
214733Skrgopi 	if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL)
215733Skrgopi 		return (-1);
216269Sericheng 
2172311Sseb 	(void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ);
218733Skrgopi 	if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) {
219733Skrgopi 		dvip = (dld_vlan_info_t *)(iocp + 1);
220733Skrgopi 		for (i = 0; i < iocp->div_count; i++)
221269Sericheng 			(*fn)(arg, dvip[i].dvi_name);
2220Sstevel@tonic-gate 	}
223733Skrgopi 	/*
224733Skrgopi 	 * Note: Callers of dladm_walk_vlan() ignore the return
225733Skrgopi 	 * value of this routine. So ignoring ioctl failure case
226733Skrgopi 	 * and just returning 0.
227733Skrgopi 	 */
228269Sericheng 	free(iocp);
229269Sericheng 	(void) close(fd);
2300Sstevel@tonic-gate 	return (0);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * Returns the current attributes of the specified datalink.
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate int
2380Sstevel@tonic-gate dladm_info(const char *name, dladm_attr_t *dap)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	int		fd;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
2430Sstevel@tonic-gate 		return (-1);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (i_dladm_info(fd, name, dap) < 0)
2460Sstevel@tonic-gate 		goto failed;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	(void) close(fd);
2490Sstevel@tonic-gate 	return (0);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate failed:
2520Sstevel@tonic-gate 	(void) close(fd);
2530Sstevel@tonic-gate 	return (-1);
2540Sstevel@tonic-gate }
2553147Sxc151355 
2563147Sxc151355 const char *
2573147Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
2583147Sxc151355 {
2593147Sxc151355 	const char	*s;
2603147Sxc151355 
2613147Sxc151355 	switch (status) {
2623147Sxc151355 	case DLADM_STATUS_OK:
2633147Sxc151355 		s = "ok";
2643147Sxc151355 		break;
2653147Sxc151355 	case DLADM_STATUS_BADARG:
2663147Sxc151355 		s = "invalid argument";
2673147Sxc151355 		break;
2683147Sxc151355 	case DLADM_STATUS_FAILED:
2693147Sxc151355 		s = "operation failed";
2703147Sxc151355 		break;
2713147Sxc151355 	case DLADM_STATUS_TOOSMALL:
2723147Sxc151355 		s = "buffer size too small";
2733147Sxc151355 		break;
2743147Sxc151355 	case DLADM_STATUS_NOTSUP:
2753147Sxc151355 		s = "operation not supported";
2763147Sxc151355 		break;
2773147Sxc151355 	case DLADM_STATUS_NOTFOUND:
2783147Sxc151355 		s = "object not found";
2793147Sxc151355 		break;
2803147Sxc151355 	case DLADM_STATUS_BADVAL:
2813147Sxc151355 		s = "invalid value";
2823147Sxc151355 		break;
2833147Sxc151355 	case DLADM_STATUS_NOMEM:
2843147Sxc151355 		s = "insufficient memory";
2853147Sxc151355 		break;
2863147Sxc151355 	case DLADM_STATUS_EXIST:
2873147Sxc151355 		s = "object already exists";
2883147Sxc151355 		break;
2893147Sxc151355 	case DLADM_STATUS_LINKINVAL:
2903147Sxc151355 		s = "invalid link";
2913147Sxc151355 		break;
2923147Sxc151355 	case DLADM_STATUS_PROPRDONLY:
2933147Sxc151355 		s = "read-only property";
2943147Sxc151355 		break;
2953147Sxc151355 	case DLADM_STATUS_BADVALCNT:
2963147Sxc151355 		s = "invalid number of values";
2973147Sxc151355 		break;
2983147Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
2993147Sxc151355 		s = "database not found";
3003147Sxc151355 		break;
3013147Sxc151355 	case DLADM_STATUS_DENIED:
3023147Sxc151355 		s = "permission denied";
3033147Sxc151355 		break;
3043147Sxc151355 	case DLADM_STATUS_IOERR:
3053147Sxc151355 		s = "I/O error";
3063147Sxc151355 		break;
3073147Sxc151355 	default:
308*3184Smeem 		s = "<unknown error>";
309*3184Smeem 		break;
3103147Sxc151355 	}
311*3184Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
3123147Sxc151355 	return (buf);
3133147Sxc151355 }
3143147Sxc151355 
3153147Sxc151355 /*
3163147Sxc151355  * Convert a unix errno to a dladm_status_t.
3173147Sxc151355  * We only convert errnos that are likely to be encountered. All others
3183147Sxc151355  * are mapped to DLADM_STATUS_FAILED.
3193147Sxc151355  */
3203147Sxc151355 dladm_status_t
3213147Sxc151355 dladm_errno2status(int err)
3223147Sxc151355 {
3233147Sxc151355 	switch (err) {
3243147Sxc151355 	case EINVAL:
3253147Sxc151355 		return (DLADM_STATUS_BADARG);
3263147Sxc151355 	case EEXIST:
3273147Sxc151355 		return (DLADM_STATUS_EXIST);
3283147Sxc151355 	case ENOENT:
3293147Sxc151355 		return (DLADM_STATUS_NOTFOUND);
3303147Sxc151355 	case ENOSPC:
3313147Sxc151355 		return (DLADM_STATUS_TOOSMALL);
3323147Sxc151355 	case ENOMEM:
3333147Sxc151355 		return (DLADM_STATUS_NOMEM);
3343147Sxc151355 	case ENOTSUP:
3353147Sxc151355 		return (DLADM_STATUS_NOTSUP);
3363147Sxc151355 	case EACCES:
3373147Sxc151355 		return (DLADM_STATUS_DENIED);
3383147Sxc151355 	case EIO:
3393147Sxc151355 		return (DLADM_STATUS_IOERR);
3403147Sxc151355 	default:
3413147Sxc151355 		return (DLADM_STATUS_FAILED);
3423147Sxc151355 	}
3433147Sxc151355 }
3443147Sxc151355 
3453147Sxc151355 /*
3463147Sxc151355  * These are the uid and gid of the user 'dladm'.
3473147Sxc151355  * The directory /etc/dladm and all files under it are owned by this user.
3483147Sxc151355  */
3493147Sxc151355 #define	DLADM_DB_OWNER		15
3503147Sxc151355 #define	DLADM_DB_GROUP		3
3513147Sxc151355 #define	LOCK_DB_PERMS		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
3523147Sxc151355 
3533147Sxc151355 static int
3543147Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
3553147Sxc151355 {
3563147Sxc151355 	int	lock_fd;
3573147Sxc151355 	struct  flock lock;
3583147Sxc151355 
3593147Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
3603147Sxc151355 	    LOCK_DB_PERMS)) < 0)
3613147Sxc151355 		return (-1);
3623147Sxc151355 
3633147Sxc151355 	lock.l_type = type;
3643147Sxc151355 	lock.l_whence = SEEK_SET;
3653147Sxc151355 	lock.l_start = 0;
3663147Sxc151355 	lock.l_len = 0;
3673147Sxc151355 
3683147Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
3693147Sxc151355 		int err = errno;
3703147Sxc151355 
3713147Sxc151355 		(void) close(lock_fd);
3723147Sxc151355 		(void) unlink(lock_file);
3733147Sxc151355 		errno = err;
3743147Sxc151355 		return (-1);
3753147Sxc151355 	}
3763147Sxc151355 	return (lock_fd);
3773147Sxc151355 }
3783147Sxc151355 
3793147Sxc151355 static void
3803147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
3813147Sxc151355 {
3823147Sxc151355 	struct flock lock;
3833147Sxc151355 
3843147Sxc151355 	if (fd < 0)
3853147Sxc151355 		return;
3863147Sxc151355 
3873147Sxc151355 	lock.l_type = F_UNLCK;
3883147Sxc151355 	lock.l_whence = SEEK_SET;
3893147Sxc151355 	lock.l_start = 0;
3903147Sxc151355 	lock.l_len = 0;
3913147Sxc151355 
3923147Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
3933147Sxc151355 	(void) close(fd);
3943147Sxc151355 	(void) unlink(lock_file);
3953147Sxc151355 }
3963147Sxc151355 
3973147Sxc151355 dladm_status_t
3983147Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms,
3993147Sxc151355     dladm_status_t (*process_db)(void *, FILE *, FILE *),
4003147Sxc151355     void *arg, boolean_t writeop)
4013147Sxc151355 {
4023147Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
4033147Sxc151355 	FILE		*fp, *nfp = NULL;
4043147Sxc151355 	char		lock[MAXPATHLEN];
4053147Sxc151355 	char		file[MAXPATHLEN];
4063147Sxc151355 	char		newfile[MAXPATHLEN];
4073147Sxc151355 	char		*db_basename;
4083147Sxc151355 	int		nfd, lock_fd;
4093147Sxc151355 
4103147Sxc151355 	/*
4113147Sxc151355 	 * If we are called from a boot script such as net-physical,
4123147Sxc151355 	 * it's quite likely that the root fs is still not writable.
4133147Sxc151355 	 * For this case, it's ok for the lock creation to fail since
4143147Sxc151355 	 * no one else could be accessing our configuration file.
4153147Sxc151355 	 */
4163147Sxc151355 	db_basename = strrchr(db_file, '/');
4173147Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
4183147Sxc151355 		return (dladm_errno2status(EINVAL));
4193147Sxc151355 	db_basename++;
4203147Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
4213147Sxc151355 	if ((lock_fd = i_dladm_lock_db
4223147Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
4233147Sxc151355 		return (dladm_errno2status(errno));
4243147Sxc151355 
4253147Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
4263147Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
4273147Sxc151355 		int	err = errno;
4283147Sxc151355 
4293147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
4303147Sxc151355 		if (err == ENOENT)
4313147Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
4323147Sxc151355 
4333147Sxc151355 		return (dladm_errno2status(err));
4343147Sxc151355 	}
4353147Sxc151355 
4363147Sxc151355 	if (writeop) {
4373147Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
4383147Sxc151355 		    dladm_rootdir, db_file);
4393147Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
4403147Sxc151355 		    db_perms)) < 0) {
4413147Sxc151355 			(void) fclose(fp);
4423147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
4433147Sxc151355 			return (dladm_errno2status(errno));
4443147Sxc151355 		}
4453147Sxc151355 
4463147Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
4473147Sxc151355 			(void) close(nfd);
4483147Sxc151355 			(void) fclose(fp);
4493147Sxc151355 			(void) unlink(newfile);
4503147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
4513147Sxc151355 			return (dladm_errno2status(errno));
4523147Sxc151355 		}
4533147Sxc151355 	}
4543147Sxc151355 	status = (*process_db)(arg, fp, nfp);
4553147Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
4563147Sxc151355 		goto done;
4573147Sxc151355 
4583147Sxc151355 	/*
4593147Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
4603147Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
4613147Sxc151355 	 */
4623147Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
4633147Sxc151355 		if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) {
4643147Sxc151355 			status = dladm_errno2status(errno);
4653147Sxc151355 			goto done;
4663147Sxc151355 		}
4673147Sxc151355 	}
4683147Sxc151355 
4693147Sxc151355 	if (fflush(nfp) == EOF) {
4703147Sxc151355 		status = dladm_errno2status(errno);
4713147Sxc151355 		goto done;
4723147Sxc151355 	}
4733147Sxc151355 	(void) fclose(fp);
4743147Sxc151355 	(void) fclose(nfp);
4753147Sxc151355 
4763147Sxc151355 	if (rename(newfile, file) < 0) {
4773147Sxc151355 		(void) unlink(newfile);
4783147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
4793147Sxc151355 		return (dladm_errno2status(errno));
4803147Sxc151355 	}
4813147Sxc151355 
4823147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
4833147Sxc151355 	return (DLADM_STATUS_OK);
4843147Sxc151355 
4853147Sxc151355 done:
4863147Sxc151355 	if (nfp != NULL) {
4873147Sxc151355 		(void) fclose(nfp);
4883147Sxc151355 		if (status != DLADM_STATUS_OK)
4893147Sxc151355 			(void) unlink(newfile);
4903147Sxc151355 	}
4913147Sxc151355 	(void) fclose(fp);
4923147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
4933147Sxc151355 	return (status);
4943147Sxc151355 }
4953147Sxc151355 
4963147Sxc151355 dladm_status_t
4973147Sxc151355 dladm_set_rootdir(const char *rootdir)
4983147Sxc151355 {
4993147Sxc151355 	DIR	*dp;
5003147Sxc151355 
5013147Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
5023147Sxc151355 	    (dp = opendir(rootdir)) == NULL)
5033147Sxc151355 		return (DLADM_STATUS_BADARG);
5043147Sxc151355 
5053147Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
5063147Sxc151355 	(void) closedir(dp);
5073147Sxc151355 	return (DLADM_STATUS_OK);
5083147Sxc151355 }
509