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 /* 22f4b3ec61Sdh155122 * Copyright 2007 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> 310ba2cbe9Sxc151355 #include <fcntl.h> 320ba2cbe9Sxc151355 #include <strings.h> 330ba2cbe9Sxc151355 #include <dirent.h> 340ba2cbe9Sxc151355 #include <sys/stat.h> 35f595a68aSyz147064 #include <libdladm.h> 360ba2cbe9Sxc151355 #include <libdladm_impl.h> 3733343a97Smeem #include <libintl.h> 38aae21359Skrgopi 390ba2cbe9Sxc151355 static char dladm_rootdir[MAXPATHLEN] = "/"; 400ba2cbe9Sxc151355 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * Issue an ioctl to the specified file descriptor attached to the 437c478bd9Sstevel@tonic-gate * DLD control driver interface. 447c478bd9Sstevel@tonic-gate */ 450ba2cbe9Sxc151355 int 46210db224Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate struct strioctl iocb; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate iocb.ic_cmd = ic_cmd; 517c478bd9Sstevel@tonic-gate iocb.ic_timout = 0; 527c478bd9Sstevel@tonic-gate iocb.ic_len = ic_len; 53210db224Sericheng iocb.ic_dp = (char *)ic_dp; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate return (ioctl(fd, I_STR, &iocb)); 567c478bd9Sstevel@tonic-gate } 577c478bd9Sstevel@tonic-gate 580ba2cbe9Sxc151355 const char * 590ba2cbe9Sxc151355 dladm_status2str(dladm_status_t status, char *buf) 600ba2cbe9Sxc151355 { 610ba2cbe9Sxc151355 const char *s; 620ba2cbe9Sxc151355 630ba2cbe9Sxc151355 switch (status) { 640ba2cbe9Sxc151355 case DLADM_STATUS_OK: 650ba2cbe9Sxc151355 s = "ok"; 660ba2cbe9Sxc151355 break; 670ba2cbe9Sxc151355 case DLADM_STATUS_BADARG: 680ba2cbe9Sxc151355 s = "invalid argument"; 690ba2cbe9Sxc151355 break; 700ba2cbe9Sxc151355 case DLADM_STATUS_FAILED: 710ba2cbe9Sxc151355 s = "operation failed"; 720ba2cbe9Sxc151355 break; 730ba2cbe9Sxc151355 case DLADM_STATUS_TOOSMALL: 740ba2cbe9Sxc151355 s = "buffer size too small"; 750ba2cbe9Sxc151355 break; 760ba2cbe9Sxc151355 case DLADM_STATUS_NOTSUP: 770ba2cbe9Sxc151355 s = "operation not supported"; 780ba2cbe9Sxc151355 break; 790ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 800ba2cbe9Sxc151355 s = "object not found"; 810ba2cbe9Sxc151355 break; 820ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: 830ba2cbe9Sxc151355 s = "invalid value"; 840ba2cbe9Sxc151355 break; 850ba2cbe9Sxc151355 case DLADM_STATUS_NOMEM: 860ba2cbe9Sxc151355 s = "insufficient memory"; 870ba2cbe9Sxc151355 break; 880ba2cbe9Sxc151355 case DLADM_STATUS_EXIST: 890ba2cbe9Sxc151355 s = "object already exists"; 900ba2cbe9Sxc151355 break; 910ba2cbe9Sxc151355 case DLADM_STATUS_LINKINVAL: 920ba2cbe9Sxc151355 s = "invalid link"; 930ba2cbe9Sxc151355 break; 940ba2cbe9Sxc151355 case DLADM_STATUS_PROPRDONLY: 950ba2cbe9Sxc151355 s = "read-only property"; 960ba2cbe9Sxc151355 break; 970ba2cbe9Sxc151355 case DLADM_STATUS_BADVALCNT: 980ba2cbe9Sxc151355 s = "invalid number of values"; 990ba2cbe9Sxc151355 break; 1000ba2cbe9Sxc151355 case DLADM_STATUS_DBNOTFOUND: 1010ba2cbe9Sxc151355 s = "database not found"; 1020ba2cbe9Sxc151355 break; 1030ba2cbe9Sxc151355 case DLADM_STATUS_DENIED: 1040ba2cbe9Sxc151355 s = "permission denied"; 1050ba2cbe9Sxc151355 break; 1060ba2cbe9Sxc151355 case DLADM_STATUS_IOERR: 1070ba2cbe9Sxc151355 s = "I/O error"; 1080ba2cbe9Sxc151355 break; 109f4b3ec61Sdh155122 case DLADM_STATUS_TEMPONLY: 110f4b3ec61Sdh155122 s = "change cannot be persistent, specify -t please"; 111f4b3ec61Sdh155122 break; 112f595a68aSyz147064 case DLADM_STATUS_TIMEDOUT: 113f595a68aSyz147064 s = "operation timed out"; 114f595a68aSyz147064 break; 115f595a68aSyz147064 case DLADM_STATUS_ISCONN: 116f595a68aSyz147064 s = "already connected"; 117f595a68aSyz147064 break; 118f595a68aSyz147064 case DLADM_STATUS_NOTCONN: 119f595a68aSyz147064 s = "not connected"; 120f595a68aSyz147064 break; 121f595a68aSyz147064 case DLADM_STATUS_REPOSITORYINVAL: 122f595a68aSyz147064 s = "invalid configuration repository"; 123f595a68aSyz147064 break; 124f595a68aSyz147064 case DLADM_STATUS_MACADDRINVAL: 125f595a68aSyz147064 s = "invalid MAC address"; 126f595a68aSyz147064 break; 127f595a68aSyz147064 case DLADM_STATUS_KEYINVAL: 128f595a68aSyz147064 s = "invalid key"; 129f595a68aSyz147064 break; 130*843e1988Sjohnlev case DLADM_STATUS_INVALIDID: 131*843e1988Sjohnlev s = "invalid VNIC id"; 132*843e1988Sjohnlev break; 133*843e1988Sjohnlev case DLADM_STATUS_INVALIDMACADDRLEN: 134*843e1988Sjohnlev s = "invalid MAC address length"; 135*843e1988Sjohnlev break; 136*843e1988Sjohnlev case DLADM_STATUS_INVALIDMACADDRTYPE: 137*843e1988Sjohnlev s = "invalid MAC address type"; 138*843e1988Sjohnlev break; 139*843e1988Sjohnlev case DLADM_STATUS_AUTOIDNOTEMP: 140*843e1988Sjohnlev s = "automatic VNIC ID assigment not supported with" 141*843e1988Sjohnlev "persistant operations"; 142*843e1988Sjohnlev break; 143*843e1988Sjohnlev case DLADM_STATUS_AUTOIDNOAVAILABLEID: 144*843e1988Sjohnlev s = "no available VNIC ID for automatic assignment"; 145*843e1988Sjohnlev break; 146*843e1988Sjohnlev case DLADM_STATUS_BUSY: 147*843e1988Sjohnlev s = "device busy"; 148*843e1988Sjohnlev 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); 1780ba2cbe9Sxc151355 case EACCES: 1790ba2cbe9Sxc151355 return (DLADM_STATUS_DENIED); 1800ba2cbe9Sxc151355 case EIO: 1810ba2cbe9Sxc151355 return (DLADM_STATUS_IOERR); 182*843e1988Sjohnlev case EBUSY: 183*843e1988Sjohnlev return (DLADM_STATUS_BUSY); 1840ba2cbe9Sxc151355 default: 1850ba2cbe9Sxc151355 return (DLADM_STATUS_FAILED); 1860ba2cbe9Sxc151355 } 1870ba2cbe9Sxc151355 } 1880ba2cbe9Sxc151355 1890ba2cbe9Sxc151355 /* 1900ba2cbe9Sxc151355 * These are the uid and gid of the user 'dladm'. 1910ba2cbe9Sxc151355 * The directory /etc/dladm and all files under it are owned by this user. 1920ba2cbe9Sxc151355 */ 1930ba2cbe9Sxc151355 #define DLADM_DB_OWNER 15 1940ba2cbe9Sxc151355 #define DLADM_DB_GROUP 3 1950ba2cbe9Sxc151355 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 1960ba2cbe9Sxc151355 1970ba2cbe9Sxc151355 static int 1980ba2cbe9Sxc151355 i_dladm_lock_db(const char *lock_file, short type) 1990ba2cbe9Sxc151355 { 2000ba2cbe9Sxc151355 int lock_fd; 2010ba2cbe9Sxc151355 struct flock lock; 2020ba2cbe9Sxc151355 2030ba2cbe9Sxc151355 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 2040ba2cbe9Sxc151355 LOCK_DB_PERMS)) < 0) 2050ba2cbe9Sxc151355 return (-1); 2060ba2cbe9Sxc151355 2070ba2cbe9Sxc151355 lock.l_type = type; 2080ba2cbe9Sxc151355 lock.l_whence = SEEK_SET; 2090ba2cbe9Sxc151355 lock.l_start = 0; 2100ba2cbe9Sxc151355 lock.l_len = 0; 2110ba2cbe9Sxc151355 2120ba2cbe9Sxc151355 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 2130ba2cbe9Sxc151355 int err = errno; 2140ba2cbe9Sxc151355 2150ba2cbe9Sxc151355 (void) close(lock_fd); 2160ba2cbe9Sxc151355 (void) unlink(lock_file); 2170ba2cbe9Sxc151355 errno = err; 2180ba2cbe9Sxc151355 return (-1); 2190ba2cbe9Sxc151355 } 2200ba2cbe9Sxc151355 return (lock_fd); 2210ba2cbe9Sxc151355 } 2220ba2cbe9Sxc151355 2230ba2cbe9Sxc151355 static void 2240ba2cbe9Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd) 2250ba2cbe9Sxc151355 { 2260ba2cbe9Sxc151355 struct flock lock; 2270ba2cbe9Sxc151355 2280ba2cbe9Sxc151355 if (fd < 0) 2290ba2cbe9Sxc151355 return; 2300ba2cbe9Sxc151355 2310ba2cbe9Sxc151355 lock.l_type = F_UNLCK; 2320ba2cbe9Sxc151355 lock.l_whence = SEEK_SET; 2330ba2cbe9Sxc151355 lock.l_start = 0; 2340ba2cbe9Sxc151355 lock.l_len = 0; 2350ba2cbe9Sxc151355 2360ba2cbe9Sxc151355 (void) fcntl(fd, F_SETLKW, &lock); 2370ba2cbe9Sxc151355 (void) close(fd); 2380ba2cbe9Sxc151355 (void) unlink(lock_file); 2390ba2cbe9Sxc151355 } 2400ba2cbe9Sxc151355 2410ba2cbe9Sxc151355 dladm_status_t 2420ba2cbe9Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms, 2430ba2cbe9Sxc151355 dladm_status_t (*process_db)(void *, FILE *, FILE *), 2440ba2cbe9Sxc151355 void *arg, boolean_t writeop) 2450ba2cbe9Sxc151355 { 2460ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 2470ba2cbe9Sxc151355 FILE *fp, *nfp = NULL; 2480ba2cbe9Sxc151355 char lock[MAXPATHLEN]; 2490ba2cbe9Sxc151355 char file[MAXPATHLEN]; 2500ba2cbe9Sxc151355 char newfile[MAXPATHLEN]; 2510ba2cbe9Sxc151355 char *db_basename; 2520ba2cbe9Sxc151355 int nfd, lock_fd; 2530ba2cbe9Sxc151355 2540ba2cbe9Sxc151355 /* 2550ba2cbe9Sxc151355 * If we are called from a boot script such as net-physical, 2560ba2cbe9Sxc151355 * it's quite likely that the root fs is still not writable. 2570ba2cbe9Sxc151355 * For this case, it's ok for the lock creation to fail since 2580ba2cbe9Sxc151355 * no one else could be accessing our configuration file. 2590ba2cbe9Sxc151355 */ 2600ba2cbe9Sxc151355 db_basename = strrchr(db_file, '/'); 2610ba2cbe9Sxc151355 if (db_basename == NULL || db_basename[1] == '\0') 2620ba2cbe9Sxc151355 return (dladm_errno2status(EINVAL)); 2630ba2cbe9Sxc151355 db_basename++; 2640ba2cbe9Sxc151355 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 2650ba2cbe9Sxc151355 if ((lock_fd = i_dladm_lock_db 2660ba2cbe9Sxc151355 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 2670ba2cbe9Sxc151355 return (dladm_errno2status(errno)); 2680ba2cbe9Sxc151355 2690ba2cbe9Sxc151355 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 2700ba2cbe9Sxc151355 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 2710ba2cbe9Sxc151355 int err = errno; 2720ba2cbe9Sxc151355 2730ba2cbe9Sxc151355 i_dladm_unlock_db(lock, lock_fd); 2740ba2cbe9Sxc151355 if (err == ENOENT) 2750ba2cbe9Sxc151355 return (DLADM_STATUS_DBNOTFOUND); 2760ba2cbe9Sxc151355 2770ba2cbe9Sxc151355 return (dladm_errno2status(err)); 2780ba2cbe9Sxc151355 } 2790ba2cbe9Sxc151355 2800ba2cbe9Sxc151355 if (writeop) { 2810ba2cbe9Sxc151355 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 2820ba2cbe9Sxc151355 dladm_rootdir, db_file); 2830ba2cbe9Sxc151355 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 2840ba2cbe9Sxc151355 db_perms)) < 0) { 2850ba2cbe9Sxc151355 (void) fclose(fp); 2860ba2cbe9Sxc151355 i_dladm_unlock_db(lock, lock_fd); 2870ba2cbe9Sxc151355 return (dladm_errno2status(errno)); 2880ba2cbe9Sxc151355 } 2890ba2cbe9Sxc151355 2900ba2cbe9Sxc151355 if ((nfp = fdopen(nfd, "w")) == NULL) { 2910ba2cbe9Sxc151355 (void) close(nfd); 2920ba2cbe9Sxc151355 (void) fclose(fp); 2930ba2cbe9Sxc151355 (void) unlink(newfile); 2940ba2cbe9Sxc151355 i_dladm_unlock_db(lock, lock_fd); 2950ba2cbe9Sxc151355 return (dladm_errno2status(errno)); 2960ba2cbe9Sxc151355 } 2970ba2cbe9Sxc151355 } 2980ba2cbe9Sxc151355 status = (*process_db)(arg, fp, nfp); 2990ba2cbe9Sxc151355 if (!writeop || status != DLADM_STATUS_OK) 3000ba2cbe9Sxc151355 goto done; 3010ba2cbe9Sxc151355 3020ba2cbe9Sxc151355 /* 3030ba2cbe9Sxc151355 * Configuration files need to be owned by the 'dladm' user. 3040ba2cbe9Sxc151355 * If we are invoked by root, the file ownership needs to be fixed. 3050ba2cbe9Sxc151355 */ 3060ba2cbe9Sxc151355 if (getuid() == 0 || geteuid() == 0) { 3070ba2cbe9Sxc151355 if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) { 3080ba2cbe9Sxc151355 status = dladm_errno2status(errno); 3090ba2cbe9Sxc151355 goto done; 3100ba2cbe9Sxc151355 } 3110ba2cbe9Sxc151355 } 3120ba2cbe9Sxc151355 3130ba2cbe9Sxc151355 if (fflush(nfp) == EOF) { 3140ba2cbe9Sxc151355 status = dladm_errno2status(errno); 3150ba2cbe9Sxc151355 goto done; 3160ba2cbe9Sxc151355 } 3170ba2cbe9Sxc151355 (void) fclose(fp); 3180ba2cbe9Sxc151355 (void) fclose(nfp); 3190ba2cbe9Sxc151355 3200ba2cbe9Sxc151355 if (rename(newfile, file) < 0) { 3210ba2cbe9Sxc151355 (void) unlink(newfile); 3220ba2cbe9Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3230ba2cbe9Sxc151355 return (dladm_errno2status(errno)); 3240ba2cbe9Sxc151355 } 3250ba2cbe9Sxc151355 3260ba2cbe9Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3270ba2cbe9Sxc151355 return (DLADM_STATUS_OK); 3280ba2cbe9Sxc151355 3290ba2cbe9Sxc151355 done: 3300ba2cbe9Sxc151355 if (nfp != NULL) { 3310ba2cbe9Sxc151355 (void) fclose(nfp); 3320ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 3330ba2cbe9Sxc151355 (void) unlink(newfile); 3340ba2cbe9Sxc151355 } 3350ba2cbe9Sxc151355 (void) fclose(fp); 3360ba2cbe9Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3370ba2cbe9Sxc151355 return (status); 3380ba2cbe9Sxc151355 } 3390ba2cbe9Sxc151355 3400ba2cbe9Sxc151355 dladm_status_t 3410ba2cbe9Sxc151355 dladm_set_rootdir(const char *rootdir) 3420ba2cbe9Sxc151355 { 3430ba2cbe9Sxc151355 DIR *dp; 3440ba2cbe9Sxc151355 3450ba2cbe9Sxc151355 if (rootdir == NULL || *rootdir != '/' || 3460ba2cbe9Sxc151355 (dp = opendir(rootdir)) == NULL) 3470ba2cbe9Sxc151355 return (DLADM_STATUS_BADARG); 3480ba2cbe9Sxc151355 3490ba2cbe9Sxc151355 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 3500ba2cbe9Sxc151355 (void) closedir(dp); 3510ba2cbe9Sxc151355 return (DLADM_STATUS_OK); 3520ba2cbe9Sxc151355 } 353