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 case DLADM_STATUS_INVALIDID: 131 s = "invalid VNIC id"; 132 break; 133 case DLADM_STATUS_INVALIDMACADDRLEN: 134 s = "invalid MAC address length"; 135 break; 136 case DLADM_STATUS_INVALIDMACADDRTYPE: 137 s = "invalid MAC address type"; 138 break; 139 case DLADM_STATUS_AUTOIDNOTEMP: 140 s = "automatic VNIC ID assigment not supported with" 141 "persistant operations"; 142 break; 143 case DLADM_STATUS_AUTOIDNOAVAILABLEID: 144 s = "no available VNIC ID for automatic assignment"; 145 break; 146 case DLADM_STATUS_BUSY: 147 s = "device busy"; 148 break; 149 default: 150 s = "<unknown error>"; 151 break; 152 } 153 (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 154 return (buf); 155 } 156 157 /* 158 * Convert a unix errno to a dladm_status_t. 159 * We only convert errnos that are likely to be encountered. All others 160 * are mapped to DLADM_STATUS_FAILED. 161 */ 162 dladm_status_t 163 dladm_errno2status(int err) 164 { 165 switch (err) { 166 case EINVAL: 167 return (DLADM_STATUS_BADARG); 168 case EEXIST: 169 return (DLADM_STATUS_EXIST); 170 case ENOENT: 171 return (DLADM_STATUS_NOTFOUND); 172 case ENOSPC: 173 return (DLADM_STATUS_TOOSMALL); 174 case ENOMEM: 175 return (DLADM_STATUS_NOMEM); 176 case ENOTSUP: 177 return (DLADM_STATUS_NOTSUP); 178 case EACCES: 179 return (DLADM_STATUS_DENIED); 180 case EIO: 181 return (DLADM_STATUS_IOERR); 182 case EBUSY: 183 return (DLADM_STATUS_BUSY); 184 default: 185 return (DLADM_STATUS_FAILED); 186 } 187 } 188 189 /* 190 * These are the uid and gid of the user 'dladm'. 191 * The directory /etc/dladm and all files under it are owned by this user. 192 */ 193 #define DLADM_DB_OWNER 15 194 #define DLADM_DB_GROUP 3 195 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 196 197 static int 198 i_dladm_lock_db(const char *lock_file, short type) 199 { 200 int lock_fd; 201 struct flock lock; 202 203 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 204 LOCK_DB_PERMS)) < 0) 205 return (-1); 206 207 lock.l_type = type; 208 lock.l_whence = SEEK_SET; 209 lock.l_start = 0; 210 lock.l_len = 0; 211 212 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 213 int err = errno; 214 215 (void) close(lock_fd); 216 (void) unlink(lock_file); 217 errno = err; 218 return (-1); 219 } 220 return (lock_fd); 221 } 222 223 static void 224 i_dladm_unlock_db(const char *lock_file, int fd) 225 { 226 struct flock lock; 227 228 if (fd < 0) 229 return; 230 231 lock.l_type = F_UNLCK; 232 lock.l_whence = SEEK_SET; 233 lock.l_start = 0; 234 lock.l_len = 0; 235 236 (void) fcntl(fd, F_SETLKW, &lock); 237 (void) close(fd); 238 (void) unlink(lock_file); 239 } 240 241 dladm_status_t 242 i_dladm_rw_db(const char *db_file, mode_t db_perms, 243 dladm_status_t (*process_db)(void *, FILE *, FILE *), 244 void *arg, boolean_t writeop) 245 { 246 dladm_status_t status = DLADM_STATUS_OK; 247 FILE *fp, *nfp = NULL; 248 char lock[MAXPATHLEN]; 249 char file[MAXPATHLEN]; 250 char newfile[MAXPATHLEN]; 251 char *db_basename; 252 int nfd, lock_fd; 253 254 /* 255 * If we are called from a boot script such as net-physical, 256 * it's quite likely that the root fs is still not writable. 257 * For this case, it's ok for the lock creation to fail since 258 * no one else could be accessing our configuration file. 259 */ 260 db_basename = strrchr(db_file, '/'); 261 if (db_basename == NULL || db_basename[1] == '\0') 262 return (dladm_errno2status(EINVAL)); 263 db_basename++; 264 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 265 if ((lock_fd = i_dladm_lock_db 266 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 267 return (dladm_errno2status(errno)); 268 269 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 270 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 271 int err = errno; 272 273 i_dladm_unlock_db(lock, lock_fd); 274 if (err == ENOENT) 275 return (DLADM_STATUS_DBNOTFOUND); 276 277 return (dladm_errno2status(err)); 278 } 279 280 if (writeop) { 281 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 282 dladm_rootdir, db_file); 283 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 284 db_perms)) < 0) { 285 (void) fclose(fp); 286 i_dladm_unlock_db(lock, lock_fd); 287 return (dladm_errno2status(errno)); 288 } 289 290 if ((nfp = fdopen(nfd, "w")) == NULL) { 291 (void) close(nfd); 292 (void) fclose(fp); 293 (void) unlink(newfile); 294 i_dladm_unlock_db(lock, lock_fd); 295 return (dladm_errno2status(errno)); 296 } 297 } 298 status = (*process_db)(arg, fp, nfp); 299 if (!writeop || status != DLADM_STATUS_OK) 300 goto done; 301 302 /* 303 * Configuration files need to be owned by the 'dladm' user. 304 * If we are invoked by root, the file ownership needs to be fixed. 305 */ 306 if (getuid() == 0 || geteuid() == 0) { 307 if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) { 308 status = dladm_errno2status(errno); 309 goto done; 310 } 311 } 312 313 if (fflush(nfp) == EOF) { 314 status = dladm_errno2status(errno); 315 goto done; 316 } 317 (void) fclose(fp); 318 (void) fclose(nfp); 319 320 if (rename(newfile, file) < 0) { 321 (void) unlink(newfile); 322 i_dladm_unlock_db(lock, lock_fd); 323 return (dladm_errno2status(errno)); 324 } 325 326 i_dladm_unlock_db(lock, lock_fd); 327 return (DLADM_STATUS_OK); 328 329 done: 330 if (nfp != NULL) { 331 (void) fclose(nfp); 332 if (status != DLADM_STATUS_OK) 333 (void) unlink(newfile); 334 } 335 (void) fclose(fp); 336 i_dladm_unlock_db(lock, lock_fd); 337 return (status); 338 } 339 340 dladm_status_t 341 dladm_set_rootdir(const char *rootdir) 342 { 343 DIR *dp; 344 345 if (rootdir == NULL || *rootdir != '/' || 346 (dp = opendir(rootdir)) == NULL) 347 return (DLADM_STATUS_BADARG); 348 349 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 350 (void) closedir(dp); 351 return (DLADM_STATUS_OK); 352 } 353