1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <unistd.h> 29 #include <stropts.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <strings.h> 33 #include <dirent.h> 34 #include <sys/stat.h> 35 #include <libdladm.h> 36 #include <libdladm_impl.h> 37 #include <libintl.h> 38 39 static char dladm_rootdir[MAXPATHLEN] = "/"; 40 41 /* 42 * Issue an ioctl to the specified file descriptor attached to the 43 * DLD control driver interface. 44 */ 45 int 46 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) 47 { 48 struct strioctl iocb; 49 50 iocb.ic_cmd = ic_cmd; 51 iocb.ic_timout = 0; 52 iocb.ic_len = ic_len; 53 iocb.ic_dp = (char *)ic_dp; 54 55 return (ioctl(fd, I_STR, &iocb)); 56 } 57 58 const char * 59 dladm_status2str(dladm_status_t status, char *buf) 60 { 61 const char *s; 62 63 switch (status) { 64 case DLADM_STATUS_OK: 65 s = "ok"; 66 break; 67 case DLADM_STATUS_BADARG: 68 s = "invalid argument"; 69 break; 70 case DLADM_STATUS_FAILED: 71 s = "operation failed"; 72 break; 73 case DLADM_STATUS_TOOSMALL: 74 s = "buffer size too small"; 75 break; 76 case DLADM_STATUS_NOTSUP: 77 s = "operation not supported"; 78 break; 79 case DLADM_STATUS_NOTFOUND: 80 s = "object not found"; 81 break; 82 case DLADM_STATUS_BADVAL: 83 s = "invalid value"; 84 break; 85 case DLADM_STATUS_NOMEM: 86 s = "insufficient memory"; 87 break; 88 case DLADM_STATUS_EXIST: 89 s = "object already exists"; 90 break; 91 case DLADM_STATUS_LINKINVAL: 92 s = "invalid link"; 93 break; 94 case DLADM_STATUS_PROPRDONLY: 95 s = "read-only property"; 96 break; 97 case DLADM_STATUS_BADVALCNT: 98 s = "invalid number of values"; 99 break; 100 case DLADM_STATUS_DBNOTFOUND: 101 s = "database not found"; 102 break; 103 case DLADM_STATUS_DENIED: 104 s = "permission denied"; 105 break; 106 case DLADM_STATUS_IOERR: 107 s = "I/O error"; 108 break; 109 case DLADM_STATUS_TEMPONLY: 110 s = "change cannot be persistent, specify -t please"; 111 break; 112 case DLADM_STATUS_TIMEDOUT: 113 s = "operation timed out"; 114 break; 115 case DLADM_STATUS_ISCONN: 116 s = "already connected"; 117 break; 118 case DLADM_STATUS_NOTCONN: 119 s = "not connected"; 120 break; 121 case DLADM_STATUS_REPOSITORYINVAL: 122 s = "invalid configuration repository"; 123 break; 124 case DLADM_STATUS_MACADDRINVAL: 125 s = "invalid MAC address"; 126 break; 127 case DLADM_STATUS_KEYINVAL: 128 s = "invalid key"; 129 break; 130 default: 131 s = "<unknown error>"; 132 break; 133 } 134 (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 135 return (buf); 136 } 137 138 /* 139 * Convert a unix errno to a dladm_status_t. 140 * We only convert errnos that are likely to be encountered. All others 141 * are mapped to DLADM_STATUS_FAILED. 142 */ 143 dladm_status_t 144 dladm_errno2status(int err) 145 { 146 switch (err) { 147 case EINVAL: 148 return (DLADM_STATUS_BADARG); 149 case EEXIST: 150 return (DLADM_STATUS_EXIST); 151 case ENOENT: 152 return (DLADM_STATUS_NOTFOUND); 153 case ENOSPC: 154 return (DLADM_STATUS_TOOSMALL); 155 case ENOMEM: 156 return (DLADM_STATUS_NOMEM); 157 case ENOTSUP: 158 return (DLADM_STATUS_NOTSUP); 159 case EACCES: 160 return (DLADM_STATUS_DENIED); 161 case EIO: 162 return (DLADM_STATUS_IOERR); 163 default: 164 return (DLADM_STATUS_FAILED); 165 } 166 } 167 168 /* 169 * These are the uid and gid of the user 'dladm'. 170 * The directory /etc/dladm and all files under it are owned by this user. 171 */ 172 #define DLADM_DB_OWNER 15 173 #define DLADM_DB_GROUP 3 174 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 175 176 static int 177 i_dladm_lock_db(const char *lock_file, short type) 178 { 179 int lock_fd; 180 struct flock lock; 181 182 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 183 LOCK_DB_PERMS)) < 0) 184 return (-1); 185 186 lock.l_type = type; 187 lock.l_whence = SEEK_SET; 188 lock.l_start = 0; 189 lock.l_len = 0; 190 191 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 192 int err = errno; 193 194 (void) close(lock_fd); 195 (void) unlink(lock_file); 196 errno = err; 197 return (-1); 198 } 199 return (lock_fd); 200 } 201 202 static void 203 i_dladm_unlock_db(const char *lock_file, int fd) 204 { 205 struct flock lock; 206 207 if (fd < 0) 208 return; 209 210 lock.l_type = F_UNLCK; 211 lock.l_whence = SEEK_SET; 212 lock.l_start = 0; 213 lock.l_len = 0; 214 215 (void) fcntl(fd, F_SETLKW, &lock); 216 (void) close(fd); 217 (void) unlink(lock_file); 218 } 219 220 dladm_status_t 221 i_dladm_rw_db(const char *db_file, mode_t db_perms, 222 dladm_status_t (*process_db)(void *, FILE *, FILE *), 223 void *arg, boolean_t writeop) 224 { 225 dladm_status_t status = DLADM_STATUS_OK; 226 FILE *fp, *nfp = NULL; 227 char lock[MAXPATHLEN]; 228 char file[MAXPATHLEN]; 229 char newfile[MAXPATHLEN]; 230 char *db_basename; 231 int nfd, lock_fd; 232 233 /* 234 * If we are called from a boot script such as net-physical, 235 * it's quite likely that the root fs is still not writable. 236 * For this case, it's ok for the lock creation to fail since 237 * no one else could be accessing our configuration file. 238 */ 239 db_basename = strrchr(db_file, '/'); 240 if (db_basename == NULL || db_basename[1] == '\0') 241 return (dladm_errno2status(EINVAL)); 242 db_basename++; 243 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 244 if ((lock_fd = i_dladm_lock_db 245 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 246 return (dladm_errno2status(errno)); 247 248 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 249 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 250 int err = errno; 251 252 i_dladm_unlock_db(lock, lock_fd); 253 if (err == ENOENT) 254 return (DLADM_STATUS_DBNOTFOUND); 255 256 return (dladm_errno2status(err)); 257 } 258 259 if (writeop) { 260 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 261 dladm_rootdir, db_file); 262 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 263 db_perms)) < 0) { 264 (void) fclose(fp); 265 i_dladm_unlock_db(lock, lock_fd); 266 return (dladm_errno2status(errno)); 267 } 268 269 if ((nfp = fdopen(nfd, "w")) == NULL) { 270 (void) close(nfd); 271 (void) fclose(fp); 272 (void) unlink(newfile); 273 i_dladm_unlock_db(lock, lock_fd); 274 return (dladm_errno2status(errno)); 275 } 276 } 277 status = (*process_db)(arg, fp, nfp); 278 if (!writeop || status != DLADM_STATUS_OK) 279 goto done; 280 281 /* 282 * Configuration files need to be owned by the 'dladm' user. 283 * If we are invoked by root, the file ownership needs to be fixed. 284 */ 285 if (getuid() == 0 || geteuid() == 0) { 286 if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) { 287 status = dladm_errno2status(errno); 288 goto done; 289 } 290 } 291 292 if (fflush(nfp) == EOF) { 293 status = dladm_errno2status(errno); 294 goto done; 295 } 296 (void) fclose(fp); 297 (void) fclose(nfp); 298 299 if (rename(newfile, file) < 0) { 300 (void) unlink(newfile); 301 i_dladm_unlock_db(lock, lock_fd); 302 return (dladm_errno2status(errno)); 303 } 304 305 i_dladm_unlock_db(lock, lock_fd); 306 return (DLADM_STATUS_OK); 307 308 done: 309 if (nfp != NULL) { 310 (void) fclose(nfp); 311 if (status != DLADM_STATUS_OK) 312 (void) unlink(newfile); 313 } 314 (void) fclose(fp); 315 i_dladm_unlock_db(lock, lock_fd); 316 return (status); 317 } 318 319 dladm_status_t 320 dladm_set_rootdir(const char *rootdir) 321 { 322 DIR *dp; 323 324 if (rootdir == NULL || *rootdir != '/' || 325 (dp = opendir(rootdir)) == NULL) 326 return (DLADM_STATUS_BADARG); 327 328 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 329 (void) closedir(dp); 330 return (DLADM_STATUS_OK); 331 } 332