xref: /titanic_51/usr/src/lib/libdladm/common/libdladm.c (revision 0ba2cbe97e0678a691742f98d2532caed0a2c4aa)
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 /*
22ba2e4443Sseb  * Copyright 2006 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*0ba2cbe9Sxc151355 #include <fcntl.h>
32*0ba2cbe9Sxc151355 #include <strings.h>
33*0ba2cbe9Sxc151355 #include <dirent.h>
347c478bd9Sstevel@tonic-gate #include <net/if.h>
35*0ba2cbe9Sxc151355 #include <sys/stat.h>
36*0ba2cbe9Sxc151355 #include <sys/dld.h>
37*0ba2cbe9Sxc151355 #include <libdlpi.h>
38*0ba2cbe9Sxc151355 #include <libdevinfo.h>
39*0ba2cbe9Sxc151355 #include <libdladm_impl.h>
407c478bd9Sstevel@tonic-gate 
41aae21359Skrgopi typedef struct dladm_dev {
42aae21359Skrgopi 	char			dd_name[IFNAMSIZ];
43aae21359Skrgopi 	struct dladm_dev	*dd_next;
44aae21359Skrgopi } dladm_dev_t;
45aae21359Skrgopi 
46aae21359Skrgopi typedef struct dladm_walk {
47aae21359Skrgopi 	dladm_dev_t		*dw_dev_list;
48aae21359Skrgopi } dladm_walk_t;
49aae21359Skrgopi 
50*0ba2cbe9Sxc151355 static char		dladm_rootdir[MAXPATHLEN] = "/";
51*0ba2cbe9Sxc151355 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
547c478bd9Sstevel@tonic-gate  * DLD control driver interface.
557c478bd9Sstevel@tonic-gate  */
56*0ba2cbe9Sxc151355 int
57210db224Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	struct strioctl	iocb;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
627c478bd9Sstevel@tonic-gate 	iocb.ic_timout = 0;
637c478bd9Sstevel@tonic-gate 	iocb.ic_len = ic_len;
64210db224Sericheng 	iocb.ic_dp = (char *)ic_dp;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Return the attributes of the specified datalink from the DLD driver.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate static int
737c478bd9Sstevel@tonic-gate i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	dld_ioc_attr_t	dia;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	if (strlen(name) >= IFNAMSIZ) {
787c478bd9Sstevel@tonic-gate 		errno = EINVAL;
797c478bd9Sstevel@tonic-gate 		return (-1);
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
837c478bd9Sstevel@tonic-gate 
84210db224Sericheng 	if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0)
857c478bd9Sstevel@tonic-gate 		return (-1);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
88210db224Sericheng 	dap->da_max_sdu = dia.dia_max_sdu;
897c478bd9Sstevel@tonic-gate 	dap->da_vid = dia.dia_vid;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	return (0);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Adds a datalink to the array corresponding to arg.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate static void
987c478bd9Sstevel@tonic-gate i_dladm_nt_net_add(void *arg, char *name)
997c478bd9Sstevel@tonic-gate {
100aae21359Skrgopi 	dladm_walk_t	*dwp = arg;
101aae21359Skrgopi 	dladm_dev_t	*ddp = dwp->dw_dev_list;
102aae21359Skrgopi 	dladm_dev_t	**lastp = &dwp->dw_dev_list;
1037c478bd9Sstevel@tonic-gate 
104aae21359Skrgopi 	while (ddp) {
105aae21359Skrgopi 		/*
106aae21359Skrgopi 		 * Skip duplicates.
107aae21359Skrgopi 		 */
108aae21359Skrgopi 		if (strcmp(ddp->dd_name, name) == 0)
1097c478bd9Sstevel@tonic-gate 			return;
110aae21359Skrgopi 
111aae21359Skrgopi 		lastp = &ddp->dd_next;
112aae21359Skrgopi 		ddp = ddp->dd_next;
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 
115aae21359Skrgopi 	if ((ddp = malloc(sizeof (*ddp))) == NULL)
116aae21359Skrgopi 		return;
117aae21359Skrgopi 
118aae21359Skrgopi 	(void) strlcpy(ddp->dd_name, name, IFNAMSIZ);
119aae21359Skrgopi 	ddp->dd_next = NULL;
120aae21359Skrgopi 	*lastp = ddp;
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * Walker callback invoked for each DDI_NT_NET node.
1257c478bd9Sstevel@tonic-gate  */
1267c478bd9Sstevel@tonic-gate static int
1277c478bd9Sstevel@tonic-gate i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	dl_info_ack_t	dlia;
1307c478bd9Sstevel@tonic-gate 	char		name[IFNAMSIZ];
1317c478bd9Sstevel@tonic-gate 	int		fd;
1327c478bd9Sstevel@tonic-gate 	char		*provider;
1337c478bd9Sstevel@tonic-gate 	uint_t		ppa;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	provider = di_minor_name(minor);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	if ((fd = dlpi_open(provider)) < 0)
1387c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
1417c478bd9Sstevel@tonic-gate 		(void) dlpi_close(fd);
1427c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (dlia.dl_provider_style == DL_STYLE1) {
1467c478bd9Sstevel@tonic-gate 		i_dladm_nt_net_add(arg, provider);
1477c478bd9Sstevel@tonic-gate 		(void) dlpi_close(fd);
1487c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	ppa = di_instance(node);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if (dlpi_attach(fd, -1, ppa) < 0) {
1547c478bd9Sstevel@tonic-gate 		(void) dlpi_close(fd);
1557c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
1587c478bd9Sstevel@tonic-gate 	i_dladm_nt_net_add(arg, name);
1597c478bd9Sstevel@tonic-gate 	(void) dlpi_close(fd);
1607c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * Invoke the specified callback function for each active DDI_NT_NET
1657c478bd9Sstevel@tonic-gate  * node.
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate int
1687c478bd9Sstevel@tonic-gate dladm_walk(void (*fn)(void *, const char *), void *arg)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	di_node_t	root;
171aae21359Skrgopi 	dladm_walk_t	dw;
172aae21359Skrgopi 	dladm_dev_t	*ddp, *last_ddp;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
1757c478bd9Sstevel@tonic-gate 		errno = EFAULT;
1767c478bd9Sstevel@tonic-gate 		return (-1);
1777c478bd9Sstevel@tonic-gate 	}
178aae21359Skrgopi 	dw.dw_dev_list = NULL;
1797c478bd9Sstevel@tonic-gate 
180aae21359Skrgopi 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw,
1817c478bd9Sstevel@tonic-gate 	    i_dladm_nt_net_walk);
182aae21359Skrgopi 
1837c478bd9Sstevel@tonic-gate 	di_fini(root);
1847c478bd9Sstevel@tonic-gate 
185aae21359Skrgopi 	ddp = dw.dw_dev_list;
186aae21359Skrgopi 	while (ddp) {
187aae21359Skrgopi 		fn(arg, ddp->dd_name);
1886e61f8d9Skrgopi 		(void) dladm_walk_vlan(fn, arg, ddp->dd_name);
189aae21359Skrgopi 		last_ddp = ddp;
190aae21359Skrgopi 		ddp = ddp->dd_next;
191aae21359Skrgopi 		free(last_ddp);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
194aae21359Skrgopi 	return (0);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
198210db224Sericheng  * Invoke the specified callback function for each vlan managed by dld
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate int
201aae21359Skrgopi dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name)
2027c478bd9Sstevel@tonic-gate {
203aae21359Skrgopi 	int		fd, bufsize, i;
204aae21359Skrgopi 	int		nvlan = 4094;
205210db224Sericheng 	dld_ioc_vlan_t	*iocp = NULL;
206210db224Sericheng 	dld_vlan_info_t	*dvip;
2077c478bd9Sstevel@tonic-gate 
208210db224Sericheng 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
2097c478bd9Sstevel@tonic-gate 		return (-1);
210210db224Sericheng 
211aae21359Skrgopi 	bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t);
212210db224Sericheng 
213aae21359Skrgopi 	if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL)
214aae21359Skrgopi 		return (-1);
215210db224Sericheng 
216aae21359Skrgopi 	(void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ);
217aae21359Skrgopi 	if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) {
218210db224Sericheng 		dvip = (dld_vlan_info_t *)(iocp + 1);
219aae21359Skrgopi 		for (i = 0; i < iocp->div_count; i++)
220210db224Sericheng 			(*fn)(arg, dvip[i].dvi_name);
2217c478bd9Sstevel@tonic-gate 	}
222aae21359Skrgopi 	/*
223aae21359Skrgopi 	 * Note: Callers of dladm_walk_vlan() ignore the return
224aae21359Skrgopi 	 * value of this routine. So ignoring ioctl failure case
225aae21359Skrgopi 	 * and just returning 0.
226aae21359Skrgopi 	 */
227210db224Sericheng 	free(iocp);
2287c478bd9Sstevel@tonic-gate 	(void) close(fd);
2297c478bd9Sstevel@tonic-gate 	return (0);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /*
2347c478bd9Sstevel@tonic-gate  * Returns the current attributes of the specified datalink.
2357c478bd9Sstevel@tonic-gate  */
2367c478bd9Sstevel@tonic-gate int
2377c478bd9Sstevel@tonic-gate dladm_info(const char *name, dladm_attr_t *dap)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	int		fd;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
2427c478bd9Sstevel@tonic-gate 		return (-1);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (i_dladm_info(fd, name, dap) < 0)
2457c478bd9Sstevel@tonic-gate 		goto failed;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	(void) close(fd);
2487c478bd9Sstevel@tonic-gate 	return (0);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate failed:
2517c478bd9Sstevel@tonic-gate 	(void) close(fd);
2527c478bd9Sstevel@tonic-gate 	return (-1);
2537c478bd9Sstevel@tonic-gate }
254*0ba2cbe9Sxc151355 
255*0ba2cbe9Sxc151355 const char *
256*0ba2cbe9Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
257*0ba2cbe9Sxc151355 {
258*0ba2cbe9Sxc151355 	const char	*s;
259*0ba2cbe9Sxc151355 
260*0ba2cbe9Sxc151355 	switch (status) {
261*0ba2cbe9Sxc151355 	case DLADM_STATUS_OK:
262*0ba2cbe9Sxc151355 		s = "ok";
263*0ba2cbe9Sxc151355 		break;
264*0ba2cbe9Sxc151355 	case DLADM_STATUS_BADARG:
265*0ba2cbe9Sxc151355 		s = "invalid argument";
266*0ba2cbe9Sxc151355 		break;
267*0ba2cbe9Sxc151355 	case DLADM_STATUS_FAILED:
268*0ba2cbe9Sxc151355 		s = "operation failed";
269*0ba2cbe9Sxc151355 		break;
270*0ba2cbe9Sxc151355 	case DLADM_STATUS_TOOSMALL:
271*0ba2cbe9Sxc151355 		s = "buffer size too small";
272*0ba2cbe9Sxc151355 		break;
273*0ba2cbe9Sxc151355 	case DLADM_STATUS_NOTSUP:
274*0ba2cbe9Sxc151355 		s = "operation not supported";
275*0ba2cbe9Sxc151355 		break;
276*0ba2cbe9Sxc151355 	case DLADM_STATUS_NOTFOUND:
277*0ba2cbe9Sxc151355 		s = "object not found";
278*0ba2cbe9Sxc151355 		break;
279*0ba2cbe9Sxc151355 	case DLADM_STATUS_BADVAL:
280*0ba2cbe9Sxc151355 		s = "invalid value";
281*0ba2cbe9Sxc151355 		break;
282*0ba2cbe9Sxc151355 	case DLADM_STATUS_NOMEM:
283*0ba2cbe9Sxc151355 		s = "insufficient memory";
284*0ba2cbe9Sxc151355 		break;
285*0ba2cbe9Sxc151355 	case DLADM_STATUS_EXIST:
286*0ba2cbe9Sxc151355 		s = "object already exists";
287*0ba2cbe9Sxc151355 		break;
288*0ba2cbe9Sxc151355 	case DLADM_STATUS_LINKINVAL:
289*0ba2cbe9Sxc151355 		s = "invalid link";
290*0ba2cbe9Sxc151355 		break;
291*0ba2cbe9Sxc151355 	case DLADM_STATUS_PROPRDONLY:
292*0ba2cbe9Sxc151355 		s = "read-only property";
293*0ba2cbe9Sxc151355 		break;
294*0ba2cbe9Sxc151355 	case DLADM_STATUS_BADVALCNT:
295*0ba2cbe9Sxc151355 		s = "invalid number of values";
296*0ba2cbe9Sxc151355 		break;
297*0ba2cbe9Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
298*0ba2cbe9Sxc151355 		s = "database not found";
299*0ba2cbe9Sxc151355 		break;
300*0ba2cbe9Sxc151355 	case DLADM_STATUS_DENIED:
301*0ba2cbe9Sxc151355 		s = "permission denied";
302*0ba2cbe9Sxc151355 		break;
303*0ba2cbe9Sxc151355 	case DLADM_STATUS_IOERR:
304*0ba2cbe9Sxc151355 		s = "I/O error";
305*0ba2cbe9Sxc151355 		break;
306*0ba2cbe9Sxc151355 	default:
307*0ba2cbe9Sxc151355 		s = "";
308*0ba2cbe9Sxc151355 	}
309*0ba2cbe9Sxc151355 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
310*0ba2cbe9Sxc151355 	return (buf);
311*0ba2cbe9Sxc151355 }
312*0ba2cbe9Sxc151355 
313*0ba2cbe9Sxc151355 /*
314*0ba2cbe9Sxc151355  * Convert a unix errno to a dladm_status_t.
315*0ba2cbe9Sxc151355  * We only convert errnos that are likely to be encountered. All others
316*0ba2cbe9Sxc151355  * are mapped to DLADM_STATUS_FAILED.
317*0ba2cbe9Sxc151355  */
318*0ba2cbe9Sxc151355 dladm_status_t
319*0ba2cbe9Sxc151355 dladm_errno2status(int err)
320*0ba2cbe9Sxc151355 {
321*0ba2cbe9Sxc151355 	switch (err) {
322*0ba2cbe9Sxc151355 	case EINVAL:
323*0ba2cbe9Sxc151355 		return (DLADM_STATUS_BADARG);
324*0ba2cbe9Sxc151355 	case EEXIST:
325*0ba2cbe9Sxc151355 		return (DLADM_STATUS_EXIST);
326*0ba2cbe9Sxc151355 	case ENOENT:
327*0ba2cbe9Sxc151355 		return (DLADM_STATUS_NOTFOUND);
328*0ba2cbe9Sxc151355 	case ENOSPC:
329*0ba2cbe9Sxc151355 		return (DLADM_STATUS_TOOSMALL);
330*0ba2cbe9Sxc151355 	case ENOMEM:
331*0ba2cbe9Sxc151355 		return (DLADM_STATUS_NOMEM);
332*0ba2cbe9Sxc151355 	case ENOTSUP:
333*0ba2cbe9Sxc151355 		return (DLADM_STATUS_NOTSUP);
334*0ba2cbe9Sxc151355 	case EACCES:
335*0ba2cbe9Sxc151355 		return (DLADM_STATUS_DENIED);
336*0ba2cbe9Sxc151355 	case EIO:
337*0ba2cbe9Sxc151355 		return (DLADM_STATUS_IOERR);
338*0ba2cbe9Sxc151355 	default:
339*0ba2cbe9Sxc151355 		return (DLADM_STATUS_FAILED);
340*0ba2cbe9Sxc151355 	}
341*0ba2cbe9Sxc151355 }
342*0ba2cbe9Sxc151355 
343*0ba2cbe9Sxc151355 /*
344*0ba2cbe9Sxc151355  * These are the uid and gid of the user 'dladm'.
345*0ba2cbe9Sxc151355  * The directory /etc/dladm and all files under it are owned by this user.
346*0ba2cbe9Sxc151355  */
347*0ba2cbe9Sxc151355 #define	DLADM_DB_OWNER		15
348*0ba2cbe9Sxc151355 #define	DLADM_DB_GROUP		3
349*0ba2cbe9Sxc151355 #define	LOCK_DB_PERMS		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
350*0ba2cbe9Sxc151355 
351*0ba2cbe9Sxc151355 static int
352*0ba2cbe9Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
353*0ba2cbe9Sxc151355 {
354*0ba2cbe9Sxc151355 	int	lock_fd;
355*0ba2cbe9Sxc151355 	struct  flock lock;
356*0ba2cbe9Sxc151355 
357*0ba2cbe9Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
358*0ba2cbe9Sxc151355 	    LOCK_DB_PERMS)) < 0)
359*0ba2cbe9Sxc151355 		return (-1);
360*0ba2cbe9Sxc151355 
361*0ba2cbe9Sxc151355 	lock.l_type = type;
362*0ba2cbe9Sxc151355 	lock.l_whence = SEEK_SET;
363*0ba2cbe9Sxc151355 	lock.l_start = 0;
364*0ba2cbe9Sxc151355 	lock.l_len = 0;
365*0ba2cbe9Sxc151355 
366*0ba2cbe9Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
367*0ba2cbe9Sxc151355 		int err = errno;
368*0ba2cbe9Sxc151355 
369*0ba2cbe9Sxc151355 		(void) close(lock_fd);
370*0ba2cbe9Sxc151355 		(void) unlink(lock_file);
371*0ba2cbe9Sxc151355 		errno = err;
372*0ba2cbe9Sxc151355 		return (-1);
373*0ba2cbe9Sxc151355 	}
374*0ba2cbe9Sxc151355 	return (lock_fd);
375*0ba2cbe9Sxc151355 }
376*0ba2cbe9Sxc151355 
377*0ba2cbe9Sxc151355 static void
378*0ba2cbe9Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
379*0ba2cbe9Sxc151355 {
380*0ba2cbe9Sxc151355 	struct flock lock;
381*0ba2cbe9Sxc151355 
382*0ba2cbe9Sxc151355 	if (fd < 0)
383*0ba2cbe9Sxc151355 		return;
384*0ba2cbe9Sxc151355 
385*0ba2cbe9Sxc151355 	lock.l_type = F_UNLCK;
386*0ba2cbe9Sxc151355 	lock.l_whence = SEEK_SET;
387*0ba2cbe9Sxc151355 	lock.l_start = 0;
388*0ba2cbe9Sxc151355 	lock.l_len = 0;
389*0ba2cbe9Sxc151355 
390*0ba2cbe9Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
391*0ba2cbe9Sxc151355 	(void) close(fd);
392*0ba2cbe9Sxc151355 	(void) unlink(lock_file);
393*0ba2cbe9Sxc151355 }
394*0ba2cbe9Sxc151355 
395*0ba2cbe9Sxc151355 dladm_status_t
396*0ba2cbe9Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms,
397*0ba2cbe9Sxc151355     dladm_status_t (*process_db)(void *, FILE *, FILE *),
398*0ba2cbe9Sxc151355     void *arg, boolean_t writeop)
399*0ba2cbe9Sxc151355 {
400*0ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
401*0ba2cbe9Sxc151355 	FILE		*fp, *nfp = NULL;
402*0ba2cbe9Sxc151355 	char		lock[MAXPATHLEN];
403*0ba2cbe9Sxc151355 	char		file[MAXPATHLEN];
404*0ba2cbe9Sxc151355 	char		newfile[MAXPATHLEN];
405*0ba2cbe9Sxc151355 	char		*db_basename;
406*0ba2cbe9Sxc151355 	int		nfd, lock_fd;
407*0ba2cbe9Sxc151355 
408*0ba2cbe9Sxc151355 	/*
409*0ba2cbe9Sxc151355 	 * If we are called from a boot script such as net-physical,
410*0ba2cbe9Sxc151355 	 * it's quite likely that the root fs is still not writable.
411*0ba2cbe9Sxc151355 	 * For this case, it's ok for the lock creation to fail since
412*0ba2cbe9Sxc151355 	 * no one else could be accessing our configuration file.
413*0ba2cbe9Sxc151355 	 */
414*0ba2cbe9Sxc151355 	db_basename = strrchr(db_file, '/');
415*0ba2cbe9Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
416*0ba2cbe9Sxc151355 		return (dladm_errno2status(EINVAL));
417*0ba2cbe9Sxc151355 	db_basename++;
418*0ba2cbe9Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
419*0ba2cbe9Sxc151355 	if ((lock_fd = i_dladm_lock_db
420*0ba2cbe9Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
421*0ba2cbe9Sxc151355 		return (dladm_errno2status(errno));
422*0ba2cbe9Sxc151355 
423*0ba2cbe9Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
424*0ba2cbe9Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
425*0ba2cbe9Sxc151355 		int	err = errno;
426*0ba2cbe9Sxc151355 
427*0ba2cbe9Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
428*0ba2cbe9Sxc151355 		if (err == ENOENT)
429*0ba2cbe9Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
430*0ba2cbe9Sxc151355 
431*0ba2cbe9Sxc151355 		return (dladm_errno2status(err));
432*0ba2cbe9Sxc151355 	}
433*0ba2cbe9Sxc151355 
434*0ba2cbe9Sxc151355 	if (writeop) {
435*0ba2cbe9Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
436*0ba2cbe9Sxc151355 		    dladm_rootdir, db_file);
437*0ba2cbe9Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
438*0ba2cbe9Sxc151355 		    db_perms)) < 0) {
439*0ba2cbe9Sxc151355 			(void) fclose(fp);
440*0ba2cbe9Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
441*0ba2cbe9Sxc151355 			return (dladm_errno2status(errno));
442*0ba2cbe9Sxc151355 		}
443*0ba2cbe9Sxc151355 
444*0ba2cbe9Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
445*0ba2cbe9Sxc151355 			(void) close(nfd);
446*0ba2cbe9Sxc151355 			(void) fclose(fp);
447*0ba2cbe9Sxc151355 			(void) unlink(newfile);
448*0ba2cbe9Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
449*0ba2cbe9Sxc151355 			return (dladm_errno2status(errno));
450*0ba2cbe9Sxc151355 		}
451*0ba2cbe9Sxc151355 	}
452*0ba2cbe9Sxc151355 	status = (*process_db)(arg, fp, nfp);
453*0ba2cbe9Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
454*0ba2cbe9Sxc151355 		goto done;
455*0ba2cbe9Sxc151355 
456*0ba2cbe9Sxc151355 	/*
457*0ba2cbe9Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
458*0ba2cbe9Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
459*0ba2cbe9Sxc151355 	 */
460*0ba2cbe9Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
461*0ba2cbe9Sxc151355 		if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) {
462*0ba2cbe9Sxc151355 			status = dladm_errno2status(errno);
463*0ba2cbe9Sxc151355 			goto done;
464*0ba2cbe9Sxc151355 		}
465*0ba2cbe9Sxc151355 	}
466*0ba2cbe9Sxc151355 
467*0ba2cbe9Sxc151355 	if (fflush(nfp) == EOF) {
468*0ba2cbe9Sxc151355 		status = dladm_errno2status(errno);
469*0ba2cbe9Sxc151355 		goto done;
470*0ba2cbe9Sxc151355 	}
471*0ba2cbe9Sxc151355 	(void) fclose(fp);
472*0ba2cbe9Sxc151355 	(void) fclose(nfp);
473*0ba2cbe9Sxc151355 
474*0ba2cbe9Sxc151355 	if (rename(newfile, file) < 0) {
475*0ba2cbe9Sxc151355 		(void) unlink(newfile);
476*0ba2cbe9Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
477*0ba2cbe9Sxc151355 		return (dladm_errno2status(errno));
478*0ba2cbe9Sxc151355 	}
479*0ba2cbe9Sxc151355 
480*0ba2cbe9Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
481*0ba2cbe9Sxc151355 	return (DLADM_STATUS_OK);
482*0ba2cbe9Sxc151355 
483*0ba2cbe9Sxc151355 done:
484*0ba2cbe9Sxc151355 	if (nfp != NULL) {
485*0ba2cbe9Sxc151355 		(void) fclose(nfp);
486*0ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK)
487*0ba2cbe9Sxc151355 			(void) unlink(newfile);
488*0ba2cbe9Sxc151355 	}
489*0ba2cbe9Sxc151355 	(void) fclose(fp);
490*0ba2cbe9Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
491*0ba2cbe9Sxc151355 	return (status);
492*0ba2cbe9Sxc151355 }
493*0ba2cbe9Sxc151355 
494*0ba2cbe9Sxc151355 dladm_status_t
495*0ba2cbe9Sxc151355 dladm_set_rootdir(const char *rootdir)
496*0ba2cbe9Sxc151355 {
497*0ba2cbe9Sxc151355 	DIR	*dp;
498*0ba2cbe9Sxc151355 
499*0ba2cbe9Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
500*0ba2cbe9Sxc151355 	    (dp = opendir(rootdir)) == NULL)
501*0ba2cbe9Sxc151355 		return (DLADM_STATUS_BADARG);
502*0ba2cbe9Sxc151355 
503*0ba2cbe9Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
504*0ba2cbe9Sxc151355 	(void) closedir(dp);
505*0ba2cbe9Sxc151355 	return (DLADM_STATUS_OK);
506*0ba2cbe9Sxc151355 }
507