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 /* 223448Sdh155122 * Copyright 2007 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 <sys/stat.h> 35*3871Syz147064 #include <libdladm.h> 363147Sxc151355 #include <libdladm_impl.h> 373184Smeem #include <libintl.h> 38733Skrgopi 393147Sxc151355 static char dladm_rootdir[MAXPATHLEN] = "/"; 403147Sxc151355 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * Issue an ioctl to the specified file descriptor attached to the 430Sstevel@tonic-gate * DLD control driver interface. 440Sstevel@tonic-gate */ 453147Sxc151355 int 46269Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) 470Sstevel@tonic-gate { 480Sstevel@tonic-gate struct strioctl iocb; 490Sstevel@tonic-gate 500Sstevel@tonic-gate iocb.ic_cmd = ic_cmd; 510Sstevel@tonic-gate iocb.ic_timout = 0; 520Sstevel@tonic-gate iocb.ic_len = ic_len; 53269Sericheng iocb.ic_dp = (char *)ic_dp; 540Sstevel@tonic-gate 550Sstevel@tonic-gate return (ioctl(fd, I_STR, &iocb)); 560Sstevel@tonic-gate } 570Sstevel@tonic-gate 583147Sxc151355 const char * 593147Sxc151355 dladm_status2str(dladm_status_t status, char *buf) 603147Sxc151355 { 613147Sxc151355 const char *s; 623147Sxc151355 633147Sxc151355 switch (status) { 643147Sxc151355 case DLADM_STATUS_OK: 653147Sxc151355 s = "ok"; 663147Sxc151355 break; 673147Sxc151355 case DLADM_STATUS_BADARG: 683147Sxc151355 s = "invalid argument"; 693147Sxc151355 break; 703147Sxc151355 case DLADM_STATUS_FAILED: 713147Sxc151355 s = "operation failed"; 723147Sxc151355 break; 733147Sxc151355 case DLADM_STATUS_TOOSMALL: 743147Sxc151355 s = "buffer size too small"; 753147Sxc151355 break; 763147Sxc151355 case DLADM_STATUS_NOTSUP: 773147Sxc151355 s = "operation not supported"; 783147Sxc151355 break; 793147Sxc151355 case DLADM_STATUS_NOTFOUND: 803147Sxc151355 s = "object not found"; 813147Sxc151355 break; 823147Sxc151355 case DLADM_STATUS_BADVAL: 833147Sxc151355 s = "invalid value"; 843147Sxc151355 break; 853147Sxc151355 case DLADM_STATUS_NOMEM: 863147Sxc151355 s = "insufficient memory"; 873147Sxc151355 break; 883147Sxc151355 case DLADM_STATUS_EXIST: 893147Sxc151355 s = "object already exists"; 903147Sxc151355 break; 913147Sxc151355 case DLADM_STATUS_LINKINVAL: 923147Sxc151355 s = "invalid link"; 933147Sxc151355 break; 943147Sxc151355 case DLADM_STATUS_PROPRDONLY: 953147Sxc151355 s = "read-only property"; 963147Sxc151355 break; 973147Sxc151355 case DLADM_STATUS_BADVALCNT: 983147Sxc151355 s = "invalid number of values"; 993147Sxc151355 break; 1003147Sxc151355 case DLADM_STATUS_DBNOTFOUND: 1013147Sxc151355 s = "database not found"; 1023147Sxc151355 break; 1033147Sxc151355 case DLADM_STATUS_DENIED: 1043147Sxc151355 s = "permission denied"; 1053147Sxc151355 break; 1063147Sxc151355 case DLADM_STATUS_IOERR: 1073147Sxc151355 s = "I/O error"; 1083147Sxc151355 break; 1093448Sdh155122 case DLADM_STATUS_TEMPONLY: 1103448Sdh155122 s = "change cannot be persistent, specify -t please"; 1113448Sdh155122 break; 112*3871Syz147064 case DLADM_STATUS_TIMEDOUT: 113*3871Syz147064 s = "operation timed out"; 114*3871Syz147064 break; 115*3871Syz147064 case DLADM_STATUS_ISCONN: 116*3871Syz147064 s = "already connected"; 117*3871Syz147064 break; 118*3871Syz147064 case DLADM_STATUS_NOTCONN: 119*3871Syz147064 s = "not connected"; 120*3871Syz147064 break; 121*3871Syz147064 case DLADM_STATUS_REPOSITORYINVAL: 122*3871Syz147064 s = "invalid configuration repository"; 123*3871Syz147064 break; 124*3871Syz147064 case DLADM_STATUS_MACADDRINVAL: 125*3871Syz147064 s = "invalid MAC address"; 126*3871Syz147064 break; 127*3871Syz147064 case DLADM_STATUS_KEYINVAL: 128*3871Syz147064 s = "invalid key"; 129*3871Syz147064 break; 1303147Sxc151355 default: 1313184Smeem s = "<unknown error>"; 1323184Smeem break; 1333147Sxc151355 } 1343184Smeem (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 1353147Sxc151355 return (buf); 1363147Sxc151355 } 1373147Sxc151355 1383147Sxc151355 /* 1393147Sxc151355 * Convert a unix errno to a dladm_status_t. 1403147Sxc151355 * We only convert errnos that are likely to be encountered. All others 1413147Sxc151355 * are mapped to DLADM_STATUS_FAILED. 1423147Sxc151355 */ 1433147Sxc151355 dladm_status_t 1443147Sxc151355 dladm_errno2status(int err) 1453147Sxc151355 { 1463147Sxc151355 switch (err) { 1473147Sxc151355 case EINVAL: 1483147Sxc151355 return (DLADM_STATUS_BADARG); 1493147Sxc151355 case EEXIST: 1503147Sxc151355 return (DLADM_STATUS_EXIST); 1513147Sxc151355 case ENOENT: 1523147Sxc151355 return (DLADM_STATUS_NOTFOUND); 1533147Sxc151355 case ENOSPC: 1543147Sxc151355 return (DLADM_STATUS_TOOSMALL); 1553147Sxc151355 case ENOMEM: 1563147Sxc151355 return (DLADM_STATUS_NOMEM); 1573147Sxc151355 case ENOTSUP: 1583147Sxc151355 return (DLADM_STATUS_NOTSUP); 1593147Sxc151355 case EACCES: 1603147Sxc151355 return (DLADM_STATUS_DENIED); 1613147Sxc151355 case EIO: 1623147Sxc151355 return (DLADM_STATUS_IOERR); 1633147Sxc151355 default: 1643147Sxc151355 return (DLADM_STATUS_FAILED); 1653147Sxc151355 } 1663147Sxc151355 } 1673147Sxc151355 1683147Sxc151355 /* 1693147Sxc151355 * These are the uid and gid of the user 'dladm'. 1703147Sxc151355 * The directory /etc/dladm and all files under it are owned by this user. 1713147Sxc151355 */ 1723147Sxc151355 #define DLADM_DB_OWNER 15 1733147Sxc151355 #define DLADM_DB_GROUP 3 1743147Sxc151355 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 1753147Sxc151355 1763147Sxc151355 static int 1773147Sxc151355 i_dladm_lock_db(const char *lock_file, short type) 1783147Sxc151355 { 1793147Sxc151355 int lock_fd; 1803147Sxc151355 struct flock lock; 1813147Sxc151355 1823147Sxc151355 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 1833147Sxc151355 LOCK_DB_PERMS)) < 0) 1843147Sxc151355 return (-1); 1853147Sxc151355 1863147Sxc151355 lock.l_type = type; 1873147Sxc151355 lock.l_whence = SEEK_SET; 1883147Sxc151355 lock.l_start = 0; 1893147Sxc151355 lock.l_len = 0; 1903147Sxc151355 1913147Sxc151355 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 1923147Sxc151355 int err = errno; 1933147Sxc151355 1943147Sxc151355 (void) close(lock_fd); 1953147Sxc151355 (void) unlink(lock_file); 1963147Sxc151355 errno = err; 1973147Sxc151355 return (-1); 1983147Sxc151355 } 1993147Sxc151355 return (lock_fd); 2003147Sxc151355 } 2013147Sxc151355 2023147Sxc151355 static void 2033147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd) 2043147Sxc151355 { 2053147Sxc151355 struct flock lock; 2063147Sxc151355 2073147Sxc151355 if (fd < 0) 2083147Sxc151355 return; 2093147Sxc151355 2103147Sxc151355 lock.l_type = F_UNLCK; 2113147Sxc151355 lock.l_whence = SEEK_SET; 2123147Sxc151355 lock.l_start = 0; 2133147Sxc151355 lock.l_len = 0; 2143147Sxc151355 2153147Sxc151355 (void) fcntl(fd, F_SETLKW, &lock); 2163147Sxc151355 (void) close(fd); 2173147Sxc151355 (void) unlink(lock_file); 2183147Sxc151355 } 2193147Sxc151355 2203147Sxc151355 dladm_status_t 2213147Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms, 2223147Sxc151355 dladm_status_t (*process_db)(void *, FILE *, FILE *), 2233147Sxc151355 void *arg, boolean_t writeop) 2243147Sxc151355 { 2253147Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 2263147Sxc151355 FILE *fp, *nfp = NULL; 2273147Sxc151355 char lock[MAXPATHLEN]; 2283147Sxc151355 char file[MAXPATHLEN]; 2293147Sxc151355 char newfile[MAXPATHLEN]; 2303147Sxc151355 char *db_basename; 2313147Sxc151355 int nfd, lock_fd; 2323147Sxc151355 2333147Sxc151355 /* 2343147Sxc151355 * If we are called from a boot script such as net-physical, 2353147Sxc151355 * it's quite likely that the root fs is still not writable. 2363147Sxc151355 * For this case, it's ok for the lock creation to fail since 2373147Sxc151355 * no one else could be accessing our configuration file. 2383147Sxc151355 */ 2393147Sxc151355 db_basename = strrchr(db_file, '/'); 2403147Sxc151355 if (db_basename == NULL || db_basename[1] == '\0') 2413147Sxc151355 return (dladm_errno2status(EINVAL)); 2423147Sxc151355 db_basename++; 2433147Sxc151355 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 2443147Sxc151355 if ((lock_fd = i_dladm_lock_db 2453147Sxc151355 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 2463147Sxc151355 return (dladm_errno2status(errno)); 2473147Sxc151355 2483147Sxc151355 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 2493147Sxc151355 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 2503147Sxc151355 int err = errno; 2513147Sxc151355 2523147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 2533147Sxc151355 if (err == ENOENT) 2543147Sxc151355 return (DLADM_STATUS_DBNOTFOUND); 2553147Sxc151355 2563147Sxc151355 return (dladm_errno2status(err)); 2573147Sxc151355 } 2583147Sxc151355 2593147Sxc151355 if (writeop) { 2603147Sxc151355 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 2613147Sxc151355 dladm_rootdir, db_file); 2623147Sxc151355 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 2633147Sxc151355 db_perms)) < 0) { 2643147Sxc151355 (void) fclose(fp); 2653147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 2663147Sxc151355 return (dladm_errno2status(errno)); 2673147Sxc151355 } 2683147Sxc151355 2693147Sxc151355 if ((nfp = fdopen(nfd, "w")) == NULL) { 2703147Sxc151355 (void) close(nfd); 2713147Sxc151355 (void) fclose(fp); 2723147Sxc151355 (void) unlink(newfile); 2733147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 2743147Sxc151355 return (dladm_errno2status(errno)); 2753147Sxc151355 } 2763147Sxc151355 } 2773147Sxc151355 status = (*process_db)(arg, fp, nfp); 2783147Sxc151355 if (!writeop || status != DLADM_STATUS_OK) 2793147Sxc151355 goto done; 2803147Sxc151355 2813147Sxc151355 /* 2823147Sxc151355 * Configuration files need to be owned by the 'dladm' user. 2833147Sxc151355 * If we are invoked by root, the file ownership needs to be fixed. 2843147Sxc151355 */ 2853147Sxc151355 if (getuid() == 0 || geteuid() == 0) { 2863147Sxc151355 if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) { 2873147Sxc151355 status = dladm_errno2status(errno); 2883147Sxc151355 goto done; 2893147Sxc151355 } 2903147Sxc151355 } 2913147Sxc151355 2923147Sxc151355 if (fflush(nfp) == EOF) { 2933147Sxc151355 status = dladm_errno2status(errno); 2943147Sxc151355 goto done; 2953147Sxc151355 } 2963147Sxc151355 (void) fclose(fp); 2973147Sxc151355 (void) fclose(nfp); 2983147Sxc151355 2993147Sxc151355 if (rename(newfile, file) < 0) { 3003147Sxc151355 (void) unlink(newfile); 3013147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3023147Sxc151355 return (dladm_errno2status(errno)); 3033147Sxc151355 } 3043147Sxc151355 3053147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3063147Sxc151355 return (DLADM_STATUS_OK); 3073147Sxc151355 3083147Sxc151355 done: 3093147Sxc151355 if (nfp != NULL) { 3103147Sxc151355 (void) fclose(nfp); 3113147Sxc151355 if (status != DLADM_STATUS_OK) 3123147Sxc151355 (void) unlink(newfile); 3133147Sxc151355 } 3143147Sxc151355 (void) fclose(fp); 3153147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 3163147Sxc151355 return (status); 3173147Sxc151355 } 3183147Sxc151355 3193147Sxc151355 dladm_status_t 3203147Sxc151355 dladm_set_rootdir(const char *rootdir) 3213147Sxc151355 { 3223147Sxc151355 DIR *dp; 3233147Sxc151355 3243147Sxc151355 if (rootdir == NULL || *rootdir != '/' || 3253147Sxc151355 (dp = opendir(rootdir)) == NULL) 3263147Sxc151355 return (DLADM_STATUS_BADARG); 3273147Sxc151355 3283147Sxc151355 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 3293147Sxc151355 (void) closedir(dp); 3303147Sxc151355 return (DLADM_STATUS_OK); 3313147Sxc151355 } 332