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