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 /* 22d62bc4baSyz * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <unistd.h> 277c478bd9Sstevel@tonic-gate #include <errno.h> 28d62bc4baSyz #include <ctype.h> 290ba2cbe9Sxc #include <fcntl.h> 300ba2cbe9Sxc #include <strings.h> 310ba2cbe9Sxc #include <dirent.h> 32*da14cebeSEric Cheng #include <stdlib.h> 33b9e076dcSyz #include <sys/param.h> 340ba2cbe9Sxc #include <sys/stat.h> 350ba2cbe9Sxc #include <libdladm_impl.h> 3633343a97Smeem #include <libintl.h> 37d62bc4baSyz #include <libdlpi.h> 38aae21359Skrgopi 390ba2cbe9Sxc static char dladm_rootdir[MAXPATHLEN] = "/"; 400ba2cbe9Sxc 410ba2cbe9Sxc const char * 420ba2cbe9Sxc dladm_status2str(dladm_status_t status, char *buf) 430ba2cbe9Sxc { 440ba2cbe9Sxc const char *s; 450ba2cbe9Sxc 460ba2cbe9Sxc switch (status) { 470ba2cbe9Sxc case DLADM_STATUS_OK: 480ba2cbe9Sxc s = "ok"; 490ba2cbe9Sxc break; 500ba2cbe9Sxc case DLADM_STATUS_BADARG: 510ba2cbe9Sxc s = "invalid argument"; 520ba2cbe9Sxc break; 530ba2cbe9Sxc case DLADM_STATUS_FAILED: 540ba2cbe9Sxc s = "operation failed"; 550ba2cbe9Sxc break; 560ba2cbe9Sxc case DLADM_STATUS_TOOSMALL: 570ba2cbe9Sxc s = "buffer size too small"; 580ba2cbe9Sxc break; 590ba2cbe9Sxc case DLADM_STATUS_NOTSUP: 600ba2cbe9Sxc s = "operation not supported"; 610ba2cbe9Sxc break; 620ba2cbe9Sxc case DLADM_STATUS_NOTFOUND: 630ba2cbe9Sxc s = "object not found"; 640ba2cbe9Sxc break; 650ba2cbe9Sxc case DLADM_STATUS_BADVAL: 660ba2cbe9Sxc s = "invalid value"; 670ba2cbe9Sxc break; 680ba2cbe9Sxc case DLADM_STATUS_NOMEM: 690ba2cbe9Sxc s = "insufficient memory"; 700ba2cbe9Sxc break; 710ba2cbe9Sxc case DLADM_STATUS_EXIST: 720ba2cbe9Sxc s = "object already exists"; 730ba2cbe9Sxc break; 740ba2cbe9Sxc case DLADM_STATUS_LINKINVAL: 750ba2cbe9Sxc s = "invalid link"; 760ba2cbe9Sxc break; 770ba2cbe9Sxc case DLADM_STATUS_PROPRDONLY: 780ba2cbe9Sxc s = "read-only property"; 790ba2cbe9Sxc break; 800ba2cbe9Sxc case DLADM_STATUS_BADVALCNT: 810ba2cbe9Sxc s = "invalid number of values"; 820ba2cbe9Sxc break; 830ba2cbe9Sxc case DLADM_STATUS_DBNOTFOUND: 840ba2cbe9Sxc s = "database not found"; 850ba2cbe9Sxc break; 860ba2cbe9Sxc case DLADM_STATUS_DENIED: 870ba2cbe9Sxc s = "permission denied"; 880ba2cbe9Sxc break; 890ba2cbe9Sxc case DLADM_STATUS_IOERR: 900ba2cbe9Sxc s = "I/O error"; 910ba2cbe9Sxc break; 92f4b3ec61Sdh case DLADM_STATUS_TEMPONLY: 93*da14cebeSEric Cheng s = "change cannot be persistent"; 94f4b3ec61Sdh break; 95f595a68aSyz case DLADM_STATUS_TIMEDOUT: 96f595a68aSyz s = "operation timed out"; 97f595a68aSyz break; 98f595a68aSyz case DLADM_STATUS_ISCONN: 99f595a68aSyz s = "already connected"; 100f595a68aSyz break; 101f595a68aSyz case DLADM_STATUS_NOTCONN: 102f595a68aSyz s = "not connected"; 103f595a68aSyz break; 104f595a68aSyz case DLADM_STATUS_REPOSITORYINVAL: 105f595a68aSyz s = "invalid configuration repository"; 106f595a68aSyz break; 107f595a68aSyz case DLADM_STATUS_MACADDRINVAL: 108f595a68aSyz s = "invalid MAC address"; 109f595a68aSyz break; 110f595a68aSyz case DLADM_STATUS_KEYINVAL: 111f595a68aSyz s = "invalid key"; 112f595a68aSyz break; 113843e1988Sjohnlev case DLADM_STATUS_INVALIDMACADDRLEN: 114843e1988Sjohnlev s = "invalid MAC address length"; 115843e1988Sjohnlev break; 116843e1988Sjohnlev case DLADM_STATUS_INVALIDMACADDRTYPE: 117843e1988Sjohnlev s = "invalid MAC address type"; 118843e1988Sjohnlev break; 119d62bc4baSyz case DLADM_STATUS_LINKBUSY: 120d62bc4baSyz s = "link busy"; 121d62bc4baSyz break; 122d62bc4baSyz case DLADM_STATUS_VIDINVAL: 123d62bc4baSyz s = "invalid VLAN identifier"; 124843e1988Sjohnlev break; 125d62bc4baSyz case DLADM_STATUS_TRYAGAIN: 126d62bc4baSyz s = "try again later"; 127843e1988Sjohnlev break; 128d62bc4baSyz case DLADM_STATUS_NONOTIF: 129d62bc4baSyz s = "link notification is not supported"; 130843e1988Sjohnlev break; 131*da14cebeSEric Cheng case DLADM_STATUS_BADTIMEVAL: 132*da14cebeSEric Cheng s = "invalid time range"; 133*da14cebeSEric Cheng break; 134*da14cebeSEric Cheng case DLADM_STATUS_INVALIDMACADDR: 135*da14cebeSEric Cheng s = "invalid MAC address value"; 136*da14cebeSEric Cheng break; 137*da14cebeSEric Cheng case DLADM_STATUS_INVALIDMACADDRNIC: 138*da14cebeSEric Cheng s = "MAC address reserved for use by underlying data-link"; 139*da14cebeSEric Cheng break; 140*da14cebeSEric Cheng case DLADM_STATUS_INVALIDMACADDRINUSE: 141*da14cebeSEric Cheng s = "MAC address is already in use"; 142*da14cebeSEric Cheng break; 143*da14cebeSEric Cheng case DLADM_STATUS_MACFACTORYSLOTINVALID: 144*da14cebeSEric Cheng s = "invalid factory MAC address slot"; 145*da14cebeSEric Cheng break; 146*da14cebeSEric Cheng case DLADM_STATUS_MACFACTORYSLOTUSED: 147*da14cebeSEric Cheng s = "factory MAC address slot already used"; 148*da14cebeSEric Cheng break; 149*da14cebeSEric Cheng case DLADM_STATUS_MACFACTORYSLOTALLUSED: 150*da14cebeSEric Cheng s = "all factory MAC address slots are in use"; 151*da14cebeSEric Cheng break; 152*da14cebeSEric Cheng case DLADM_STATUS_MACFACTORYNOTSUP: 153*da14cebeSEric Cheng s = "factory MAC address slots not supported"; 154*da14cebeSEric Cheng break; 155*da14cebeSEric Cheng case DLADM_STATUS_INVALIDMACPREFIX: 156*da14cebeSEric Cheng s = "Invalid MAC address prefix value"; 157*da14cebeSEric Cheng break; 158*da14cebeSEric Cheng case DLADM_STATUS_INVALIDMACPREFIXLEN: 159*da14cebeSEric Cheng s = "Invalid MAC address prefix length"; 160*da14cebeSEric Cheng break; 161*da14cebeSEric Cheng case DLADM_STATUS_CPUMAX: 162*da14cebeSEric Cheng s = "non-existent processor ID"; 163*da14cebeSEric Cheng break; 164*da14cebeSEric Cheng case DLADM_STATUS_CPUERR: 165*da14cebeSEric Cheng s = "could not determine processor status"; 166*da14cebeSEric Cheng break; 167*da14cebeSEric Cheng case DLADM_STATUS_CPUNOTONLINE: 168*da14cebeSEric Cheng s = "processor not online"; 169*da14cebeSEric Cheng break; 170*da14cebeSEric Cheng case DLADM_STATUS_DB_NOTFOUND: 171*da14cebeSEric Cheng s = "database not found"; 172*da14cebeSEric Cheng break; 173*da14cebeSEric Cheng case DLADM_STATUS_DB_PARSE_ERR: 174*da14cebeSEric Cheng s = "database parse error"; 175*da14cebeSEric Cheng break; 176*da14cebeSEric Cheng case DLADM_STATUS_PROP_PARSE_ERR: 177*da14cebeSEric Cheng s = "property parse error"; 178*da14cebeSEric Cheng break; 179*da14cebeSEric Cheng case DLADM_STATUS_ATTR_PARSE_ERR: 180*da14cebeSEric Cheng s = "attribute parse error"; 181*da14cebeSEric Cheng break; 182*da14cebeSEric Cheng case DLADM_STATUS_FLOW_DB_ERR: 183*da14cebeSEric Cheng s = "flow database error"; 184*da14cebeSEric Cheng break; 185*da14cebeSEric Cheng case DLADM_STATUS_FLOW_DB_OPEN_ERR: 186*da14cebeSEric Cheng s = "flow database open error"; 187*da14cebeSEric Cheng break; 188*da14cebeSEric Cheng case DLADM_STATUS_FLOW_DB_PARSE_ERR: 189*da14cebeSEric Cheng s = "flow database parse error"; 190*da14cebeSEric Cheng break; 191*da14cebeSEric Cheng case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR: 192*da14cebeSEric Cheng s = "flow property database parse error"; 193*da14cebeSEric Cheng break; 194*da14cebeSEric Cheng case DLADM_STATUS_FLOW_ADD_ERR: 195*da14cebeSEric Cheng s = "flow add error"; 196*da14cebeSEric Cheng break; 197*da14cebeSEric Cheng case DLADM_STATUS_FLOW_WALK_ERR: 198*da14cebeSEric Cheng s = "flow walk error"; 199*da14cebeSEric Cheng break; 200*da14cebeSEric Cheng case DLADM_STATUS_FLOW_IDENTICAL: 201*da14cebeSEric Cheng s = "a flow with identical attributes exists"; 202*da14cebeSEric Cheng break; 203*da14cebeSEric Cheng case DLADM_STATUS_FLOW_INCOMPATIBLE: 204*da14cebeSEric Cheng s = "flow(s) with incompatible attributes exists"; 205*da14cebeSEric Cheng break; 206*da14cebeSEric Cheng case DLADM_STATUS_FLOW_EXISTS: 207*da14cebeSEric Cheng s = "link still has flows"; 208*da14cebeSEric Cheng break; 209*da14cebeSEric Cheng case DLADM_STATUS_PERSIST_FLOW_EXISTS: 210*da14cebeSEric Cheng s = "persistent flow with the same name exists"; 211*da14cebeSEric Cheng break; 212*da14cebeSEric Cheng case DLADM_STATUS_INVALID_IP: 213*da14cebeSEric Cheng s = "invalid IP address"; 214*da14cebeSEric Cheng break; 215*da14cebeSEric Cheng case DLADM_STATUS_INVALID_PREFIXLEN: 216*da14cebeSEric Cheng s = "invalid IP prefix length"; 217*da14cebeSEric Cheng break; 218*da14cebeSEric Cheng case DLADM_STATUS_INVALID_PROTOCOL: 219*da14cebeSEric Cheng s = "invalid IP protocol"; 220*da14cebeSEric Cheng break; 221*da14cebeSEric Cheng case DLADM_STATUS_INVALID_PORT: 222*da14cebeSEric Cheng s = "invalid port number"; 223*da14cebeSEric Cheng break; 224*da14cebeSEric Cheng case DLADM_STATUS_INVALID_DSF: 225*da14cebeSEric Cheng s = "invalid dsfield"; 226*da14cebeSEric Cheng break; 227*da14cebeSEric Cheng case DLADM_STATUS_INVALID_DSFMASK: 228*da14cebeSEric Cheng s = "invalid dsfield mask"; 229*da14cebeSEric Cheng break; 230*da14cebeSEric Cheng case DLADM_STATUS_INVALID_MACMARGIN: 231*da14cebeSEric Cheng s = "MTU check failed, use lower MTU or -f option"; 232*da14cebeSEric Cheng break; 233*da14cebeSEric Cheng case DLADM_STATUS_BADPROP: 234*da14cebeSEric Cheng s = "invalid property"; 235*da14cebeSEric Cheng break; 236*da14cebeSEric Cheng case DLADM_STATUS_MINMAXBW: 237*da14cebeSEric Cheng s = "minimum value for maxbw is 1.2M"; 238*da14cebeSEric Cheng break; 239*da14cebeSEric Cheng case DLADM_STATUS_NO_HWRINGS: 240*da14cebeSEric Cheng s = "request hw rings failed"; 241*da14cebeSEric Cheng break; 2420ba2cbe9Sxc default: 24333343a97Smeem s = "<unknown error>"; 24433343a97Smeem break; 2450ba2cbe9Sxc } 24633343a97Smeem (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 2470ba2cbe9Sxc return (buf); 2480ba2cbe9Sxc } 2490ba2cbe9Sxc 2500ba2cbe9Sxc /* 2510ba2cbe9Sxc * Convert a unix errno to a dladm_status_t. 2520ba2cbe9Sxc * We only convert errnos that are likely to be encountered. All others 2530ba2cbe9Sxc * are mapped to DLADM_STATUS_FAILED. 2540ba2cbe9Sxc */ 2550ba2cbe9Sxc dladm_status_t 2560ba2cbe9Sxc dladm_errno2status(int err) 2570ba2cbe9Sxc { 2580ba2cbe9Sxc switch (err) { 259e7801d59Ssowmini case 0: 260e7801d59Ssowmini return (DLADM_STATUS_OK); 2610ba2cbe9Sxc case EINVAL: 2620ba2cbe9Sxc return (DLADM_STATUS_BADARG); 2630ba2cbe9Sxc case EEXIST: 2640ba2cbe9Sxc return (DLADM_STATUS_EXIST); 2650ba2cbe9Sxc case ENOENT: 2660ba2cbe9Sxc return (DLADM_STATUS_NOTFOUND); 2670ba2cbe9Sxc case ENOSPC: 2680ba2cbe9Sxc return (DLADM_STATUS_TOOSMALL); 2690ba2cbe9Sxc case ENOMEM: 2700ba2cbe9Sxc return (DLADM_STATUS_NOMEM); 2710ba2cbe9Sxc case ENOTSUP: 2720ba2cbe9Sxc return (DLADM_STATUS_NOTSUP); 273d62bc4baSyz case ENETDOWN: 274d62bc4baSyz return (DLADM_STATUS_NONOTIF); 2750ba2cbe9Sxc case EACCES: 276eae72b5bSSebastien Roy case EPERM: 2770ba2cbe9Sxc return (DLADM_STATUS_DENIED); 2780ba2cbe9Sxc case EIO: 2790ba2cbe9Sxc return (DLADM_STATUS_IOERR); 280843e1988Sjohnlev case EBUSY: 281d62bc4baSyz return (DLADM_STATUS_LINKBUSY); 282d62bc4baSyz case EAGAIN: 283d62bc4baSyz return (DLADM_STATUS_TRYAGAIN); 284*da14cebeSEric Cheng case ENOTEMPTY: 285*da14cebeSEric Cheng return (DLADM_STATUS_FLOW_EXISTS); 286*da14cebeSEric Cheng case EOPNOTSUPP: 287*da14cebeSEric Cheng return (DLADM_STATUS_FLOW_INCOMPATIBLE); 288*da14cebeSEric Cheng case EALREADY: 289*da14cebeSEric Cheng return (DLADM_STATUS_FLOW_IDENTICAL); 2900ba2cbe9Sxc default: 2910ba2cbe9Sxc return (DLADM_STATUS_FAILED); 2920ba2cbe9Sxc } 2930ba2cbe9Sxc } 2940ba2cbe9Sxc 295*da14cebeSEric Cheng dladm_status_t 296*da14cebeSEric Cheng dladm_str2bw(char *oarg, uint64_t *bw) 297*da14cebeSEric Cheng { 298*da14cebeSEric Cheng char *endp = NULL; 299*da14cebeSEric Cheng int64_t n; 300*da14cebeSEric Cheng int mult = 1; 301*da14cebeSEric Cheng 302*da14cebeSEric Cheng n = strtoull(oarg, &endp, 10); 303*da14cebeSEric Cheng 304*da14cebeSEric Cheng if ((errno != 0) || (strlen(endp) > 1)) 305*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 306*da14cebeSEric Cheng 307*da14cebeSEric Cheng if (n < 0) 308*da14cebeSEric Cheng return (DLADM_STATUS_BADVAL); 309*da14cebeSEric Cheng 310*da14cebeSEric Cheng switch (*endp) { 311*da14cebeSEric Cheng case 'k': 312*da14cebeSEric Cheng case 'K': 313*da14cebeSEric Cheng mult = 1000; 314*da14cebeSEric Cheng break; 315*da14cebeSEric Cheng case 'm': 316*da14cebeSEric Cheng case 'M': 317*da14cebeSEric Cheng case '\0': 318*da14cebeSEric Cheng mult = 1000000; 319*da14cebeSEric Cheng break; 320*da14cebeSEric Cheng case 'g': 321*da14cebeSEric Cheng case 'G': 322*da14cebeSEric Cheng mult = 1000000000; 323*da14cebeSEric Cheng break; 324*da14cebeSEric Cheng case '%': 325*da14cebeSEric Cheng /* 326*da14cebeSEric Cheng * percentages not supported for now, 327*da14cebeSEric Cheng * see RFE 6540675 328*da14cebeSEric Cheng */ 329*da14cebeSEric Cheng return (DLADM_STATUS_NOTSUP); 330*da14cebeSEric Cheng default: 331*da14cebeSEric Cheng return (DLADM_STATUS_BADVAL); 332*da14cebeSEric Cheng } 333*da14cebeSEric Cheng 334*da14cebeSEric Cheng *bw = n * mult; 335*da14cebeSEric Cheng 336*da14cebeSEric Cheng /* check for overflow */ 337*da14cebeSEric Cheng if (*bw / mult != n) 338*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 339*da14cebeSEric Cheng 340*da14cebeSEric Cheng return (DLADM_STATUS_OK); 341*da14cebeSEric Cheng } 342*da14cebeSEric Cheng 343*da14cebeSEric Cheng /* 344*da14cebeSEric Cheng * Convert bandwidth in bps to a string in mpbs. For values greater 345*da14cebeSEric Cheng * than 1mbps or 1000000, print a whole mbps value. For values that 346*da14cebeSEric Cheng * have fractional Mbps in whole Kbps , print the bandwidth in a manner 347*da14cebeSEric Cheng * simlilar to a floating point format. 348*da14cebeSEric Cheng * 349*da14cebeSEric Cheng * bps string 350*da14cebeSEric Cheng * 0 0 351*da14cebeSEric Cheng * 100 0 352*da14cebeSEric Cheng * 2000 0.002 353*da14cebeSEric Cheng * 431000 0.431 354*da14cebeSEric Cheng * 1000000 1 355*da14cebeSEric Cheng * 1030000 1.030 356*da14cebeSEric Cheng * 100000000 100 357*da14cebeSEric Cheng */ 358*da14cebeSEric Cheng const char * 359*da14cebeSEric Cheng dladm_bw2str(int64_t bw, char *buf) 360*da14cebeSEric Cheng { 361*da14cebeSEric Cheng int kbps, mbps; 362*da14cebeSEric Cheng 363*da14cebeSEric Cheng kbps = (bw%1000000)/1000; 364*da14cebeSEric Cheng mbps = bw/1000000; 365*da14cebeSEric Cheng if (kbps != 0) { 366*da14cebeSEric Cheng if (mbps == 0) 367*da14cebeSEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps); 368*da14cebeSEric Cheng else 369*da14cebeSEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps, 370*da14cebeSEric Cheng kbps); 371*da14cebeSEric Cheng } else { 372*da14cebeSEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps); 373*da14cebeSEric Cheng } 374*da14cebeSEric Cheng 375*da14cebeSEric Cheng return (buf); 376*da14cebeSEric Cheng } 377*da14cebeSEric Cheng 378d62bc4baSyz #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 3790ba2cbe9Sxc 3800ba2cbe9Sxc static int 3810ba2cbe9Sxc i_dladm_lock_db(const char *lock_file, short type) 3820ba2cbe9Sxc { 3830ba2cbe9Sxc int lock_fd; 384d62bc4baSyz struct flock lock; 3850ba2cbe9Sxc 3860ba2cbe9Sxc if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 3870ba2cbe9Sxc LOCK_DB_PERMS)) < 0) 3880ba2cbe9Sxc return (-1); 3890ba2cbe9Sxc 3900ba2cbe9Sxc lock.l_type = type; 3910ba2cbe9Sxc lock.l_whence = SEEK_SET; 3920ba2cbe9Sxc lock.l_start = 0; 3930ba2cbe9Sxc lock.l_len = 0; 3940ba2cbe9Sxc 3950ba2cbe9Sxc if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 3960ba2cbe9Sxc int err = errno; 3970ba2cbe9Sxc 3980ba2cbe9Sxc (void) close(lock_fd); 3990ba2cbe9Sxc (void) unlink(lock_file); 4000ba2cbe9Sxc errno = err; 4010ba2cbe9Sxc return (-1); 4020ba2cbe9Sxc } 4030ba2cbe9Sxc return (lock_fd); 4040ba2cbe9Sxc } 4050ba2cbe9Sxc 4060ba2cbe9Sxc static void 4070ba2cbe9Sxc i_dladm_unlock_db(const char *lock_file, int fd) 4080ba2cbe9Sxc { 4090ba2cbe9Sxc struct flock lock; 4100ba2cbe9Sxc 4110ba2cbe9Sxc if (fd < 0) 4120ba2cbe9Sxc return; 4130ba2cbe9Sxc 4140ba2cbe9Sxc lock.l_type = F_UNLCK; 4150ba2cbe9Sxc lock.l_whence = SEEK_SET; 4160ba2cbe9Sxc lock.l_start = 0; 4170ba2cbe9Sxc lock.l_len = 0; 4180ba2cbe9Sxc 4190ba2cbe9Sxc (void) fcntl(fd, F_SETLKW, &lock); 4200ba2cbe9Sxc (void) close(fd); 4210ba2cbe9Sxc (void) unlink(lock_file); 4220ba2cbe9Sxc } 4230ba2cbe9Sxc 424d62bc4baSyz /* 425d62bc4baSyz * Given a link class, returns its class string. 426d62bc4baSyz */ 427d62bc4baSyz const char * 428d62bc4baSyz dladm_class2str(datalink_class_t class, char *buf) 429d62bc4baSyz { 430d62bc4baSyz const char *s; 431d62bc4baSyz 432d62bc4baSyz switch (class) { 433d62bc4baSyz case DATALINK_CLASS_PHYS: 434d62bc4baSyz s = "phys"; 435d62bc4baSyz break; 436d62bc4baSyz case DATALINK_CLASS_VLAN: 437d62bc4baSyz s = "vlan"; 438d62bc4baSyz break; 439d62bc4baSyz case DATALINK_CLASS_AGGR: 440d62bc4baSyz s = "aggr"; 441d62bc4baSyz break; 442d62bc4baSyz case DATALINK_CLASS_VNIC: 443d62bc4baSyz s = "vnic"; 444d62bc4baSyz break; 445*da14cebeSEric Cheng case DATALINK_CLASS_ETHERSTUB: 446*da14cebeSEric Cheng s = "etherstub"; 447*da14cebeSEric Cheng break; 448d62bc4baSyz default: 449d62bc4baSyz s = "unknown"; 450d62bc4baSyz break; 451d62bc4baSyz } 452d62bc4baSyz 453d62bc4baSyz (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 454d62bc4baSyz return (buf); 455d62bc4baSyz } 456d62bc4baSyz 457d62bc4baSyz /* 458d62bc4baSyz * Given a physical link media type, returns its media type string. 459d62bc4baSyz */ 460d62bc4baSyz const char * 461d62bc4baSyz dladm_media2str(uint32_t media, char *buf) 462d62bc4baSyz { 463d62bc4baSyz const char *s; 464d62bc4baSyz 465d62bc4baSyz switch (media) { 466d62bc4baSyz case DL_ETHER: 467d62bc4baSyz s = "Ethernet"; 468d62bc4baSyz break; 469d62bc4baSyz case DL_WIFI: 470d62bc4baSyz s = "WiFi"; 471d62bc4baSyz break; 472d62bc4baSyz case DL_IB: 473d62bc4baSyz s = "Infiniband"; 474d62bc4baSyz break; 475d62bc4baSyz case DL_IPV4: 476d62bc4baSyz s = "IPv4Tunnel"; 477d62bc4baSyz break; 478d62bc4baSyz case DL_IPV6: 479d62bc4baSyz s = "IPv6Tunnel"; 480d62bc4baSyz break; 481d62bc4baSyz case DL_CSMACD: 482d62bc4baSyz s = "CSMA/CD"; 483d62bc4baSyz break; 484d62bc4baSyz case DL_TPB: 485d62bc4baSyz s = "TokenBus"; 486d62bc4baSyz break; 487d62bc4baSyz case DL_TPR: 488d62bc4baSyz s = "TokenRing"; 489d62bc4baSyz break; 490d62bc4baSyz case DL_METRO: 491d62bc4baSyz s = "MetroNet"; 492d62bc4baSyz break; 493d62bc4baSyz case DL_HDLC: 494d62bc4baSyz s = "HDLC"; 495d62bc4baSyz break; 496d62bc4baSyz case DL_CHAR: 497d62bc4baSyz s = "SyncCharacter"; 498d62bc4baSyz break; 499d62bc4baSyz case DL_CTCA: 500d62bc4baSyz s = "CTCA"; 501d62bc4baSyz break; 502d62bc4baSyz case DL_FDDI: 503d62bc4baSyz s = "FDDI"; 504d62bc4baSyz break; 505d62bc4baSyz case DL_FC: 506d62bc4baSyz s = "FiberChannel"; 507d62bc4baSyz break; 508d62bc4baSyz case DL_ATM: 509d62bc4baSyz s = "ATM"; 510d62bc4baSyz break; 511d62bc4baSyz case DL_IPATM: 512d62bc4baSyz s = "ATM(ClassicIP)"; 513d62bc4baSyz break; 514d62bc4baSyz case DL_X25: 515d62bc4baSyz s = "X.25"; 516d62bc4baSyz break; 517d62bc4baSyz case DL_IPX25: 518d62bc4baSyz s = "X.25(ClassicIP)"; 519d62bc4baSyz break; 520d62bc4baSyz case DL_ISDN: 521d62bc4baSyz s = "ISDN"; 522d62bc4baSyz break; 523d62bc4baSyz case DL_HIPPI: 524d62bc4baSyz s = "HIPPI"; 525d62bc4baSyz break; 526d62bc4baSyz case DL_100VG: 527d62bc4baSyz s = "100BaseVGEthernet"; 528d62bc4baSyz break; 529d62bc4baSyz case DL_100VGTPR: 530d62bc4baSyz s = "100BaseVGTokenRing"; 531d62bc4baSyz break; 532d62bc4baSyz case DL_ETH_CSMA: 533d62bc4baSyz s = "IEEE802.3"; 534d62bc4baSyz break; 535d62bc4baSyz case DL_100BT: 536d62bc4baSyz s = "100BaseT"; 537d62bc4baSyz break; 538d62bc4baSyz case DL_FRAME: 539d62bc4baSyz s = "FrameRelay"; 540d62bc4baSyz break; 541d62bc4baSyz case DL_MPFRAME: 542d62bc4baSyz s = "MPFrameRelay"; 543d62bc4baSyz break; 544d62bc4baSyz case DL_ASYNC: 545d62bc4baSyz s = "AsyncCharacter"; 546d62bc4baSyz break; 547b127ac41SPhilip Kirk case DL_IPNET: 548b127ac41SPhilip Kirk s = "IPNET"; 549b127ac41SPhilip Kirk break; 550d62bc4baSyz default: 551d62bc4baSyz s = "--"; 552d62bc4baSyz break; 553d62bc4baSyz } 554d62bc4baSyz 555d62bc4baSyz (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 556d62bc4baSyz return (buf); 557d62bc4baSyz } 558d62bc4baSyz 5590ba2cbe9Sxc dladm_status_t 5600ba2cbe9Sxc i_dladm_rw_db(const char *db_file, mode_t db_perms, 5610ba2cbe9Sxc dladm_status_t (*process_db)(void *, FILE *, FILE *), 5620ba2cbe9Sxc void *arg, boolean_t writeop) 5630ba2cbe9Sxc { 5640ba2cbe9Sxc dladm_status_t status = DLADM_STATUS_OK; 5650ba2cbe9Sxc FILE *fp, *nfp = NULL; 5660ba2cbe9Sxc char lock[MAXPATHLEN]; 5670ba2cbe9Sxc char file[MAXPATHLEN]; 5680ba2cbe9Sxc char newfile[MAXPATHLEN]; 5690ba2cbe9Sxc char *db_basename; 5700ba2cbe9Sxc int nfd, lock_fd; 5710ba2cbe9Sxc 5720ba2cbe9Sxc /* 5730ba2cbe9Sxc * If we are called from a boot script such as net-physical, 5740ba2cbe9Sxc * it's quite likely that the root fs is still not writable. 5750ba2cbe9Sxc * For this case, it's ok for the lock creation to fail since 5760ba2cbe9Sxc * no one else could be accessing our configuration file. 5770ba2cbe9Sxc */ 5780ba2cbe9Sxc db_basename = strrchr(db_file, '/'); 5790ba2cbe9Sxc if (db_basename == NULL || db_basename[1] == '\0') 5800ba2cbe9Sxc return (dladm_errno2status(EINVAL)); 5810ba2cbe9Sxc db_basename++; 5820ba2cbe9Sxc (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 5830ba2cbe9Sxc if ((lock_fd = i_dladm_lock_db 5840ba2cbe9Sxc (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 5850ba2cbe9Sxc return (dladm_errno2status(errno)); 5860ba2cbe9Sxc 5870ba2cbe9Sxc (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 5880ba2cbe9Sxc if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 5890ba2cbe9Sxc int err = errno; 5900ba2cbe9Sxc 5910ba2cbe9Sxc i_dladm_unlock_db(lock, lock_fd); 5920ba2cbe9Sxc if (err == ENOENT) 5930ba2cbe9Sxc return (DLADM_STATUS_DBNOTFOUND); 5940ba2cbe9Sxc 5950ba2cbe9Sxc return (dladm_errno2status(err)); 5960ba2cbe9Sxc } 5970ba2cbe9Sxc 5980ba2cbe9Sxc if (writeop) { 5990ba2cbe9Sxc (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 6000ba2cbe9Sxc dladm_rootdir, db_file); 6010ba2cbe9Sxc if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 6020ba2cbe9Sxc db_perms)) < 0) { 6030ba2cbe9Sxc (void) fclose(fp); 6040ba2cbe9Sxc i_dladm_unlock_db(lock, lock_fd); 6050ba2cbe9Sxc return (dladm_errno2status(errno)); 6060ba2cbe9Sxc } 6070ba2cbe9Sxc 6080ba2cbe9Sxc if ((nfp = fdopen(nfd, "w")) == NULL) { 6090ba2cbe9Sxc (void) close(nfd); 6100ba2cbe9Sxc (void) fclose(fp); 6110ba2cbe9Sxc (void) unlink(newfile); 6120ba2cbe9Sxc i_dladm_unlock_db(lock, lock_fd); 6130ba2cbe9Sxc return (dladm_errno2status(errno)); 6140ba2cbe9Sxc } 6150ba2cbe9Sxc } 6160ba2cbe9Sxc status = (*process_db)(arg, fp, nfp); 6170ba2cbe9Sxc if (!writeop || status != DLADM_STATUS_OK) 6180ba2cbe9Sxc goto done; 6190ba2cbe9Sxc 6200ba2cbe9Sxc /* 6210ba2cbe9Sxc * Configuration files need to be owned by the 'dladm' user. 6220ba2cbe9Sxc * If we are invoked by root, the file ownership needs to be fixed. 6230ba2cbe9Sxc */ 6240ba2cbe9Sxc if (getuid() == 0 || geteuid() == 0) { 625b9e076dcSyz if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 6260ba2cbe9Sxc status = dladm_errno2status(errno); 6270ba2cbe9Sxc goto done; 6280ba2cbe9Sxc } 6290ba2cbe9Sxc } 6300ba2cbe9Sxc 6310ba2cbe9Sxc if (fflush(nfp) == EOF) { 6320ba2cbe9Sxc status = dladm_errno2status(errno); 6330ba2cbe9Sxc goto done; 6340ba2cbe9Sxc } 6350ba2cbe9Sxc (void) fclose(fp); 6360ba2cbe9Sxc (void) fclose(nfp); 6370ba2cbe9Sxc 6380ba2cbe9Sxc if (rename(newfile, file) < 0) { 6390ba2cbe9Sxc (void) unlink(newfile); 6400ba2cbe9Sxc i_dladm_unlock_db(lock, lock_fd); 6410ba2cbe9Sxc return (dladm_errno2status(errno)); 6420ba2cbe9Sxc } 6430ba2cbe9Sxc 6440ba2cbe9Sxc i_dladm_unlock_db(lock, lock_fd); 6450ba2cbe9Sxc return (DLADM_STATUS_OK); 6460ba2cbe9Sxc 6470ba2cbe9Sxc done: 6480ba2cbe9Sxc if (nfp != NULL) { 6490ba2cbe9Sxc (void) fclose(nfp); 6500ba2cbe9Sxc if (status != DLADM_STATUS_OK) 6510ba2cbe9Sxc (void) unlink(newfile); 6520ba2cbe9Sxc } 6530ba2cbe9Sxc (void) fclose(fp); 6540ba2cbe9Sxc i_dladm_unlock_db(lock, lock_fd); 6550ba2cbe9Sxc return (status); 6560ba2cbe9Sxc } 6570ba2cbe9Sxc 6580ba2cbe9Sxc dladm_status_t 6590ba2cbe9Sxc dladm_set_rootdir(const char *rootdir) 6600ba2cbe9Sxc { 6610ba2cbe9Sxc DIR *dp; 6620ba2cbe9Sxc 6630ba2cbe9Sxc if (rootdir == NULL || *rootdir != '/' || 6640ba2cbe9Sxc (dp = opendir(rootdir)) == NULL) 6650ba2cbe9Sxc return (DLADM_STATUS_BADARG); 6660ba2cbe9Sxc 6670ba2cbe9Sxc (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 6680ba2cbe9Sxc (void) closedir(dp); 6690ba2cbe9Sxc return (DLADM_STATUS_OK); 6700ba2cbe9Sxc } 671d62bc4baSyz 672d62bc4baSyz boolean_t 673d62bc4baSyz dladm_valid_linkname(const char *link) 674d62bc4baSyz { 675d62bc4baSyz size_t len = strlen(link); 676d62bc4baSyz const char *cp; 677d62bc4baSyz 678d62bc4baSyz if (len + 1 >= MAXLINKNAMELEN) 679d62bc4baSyz return (B_FALSE); 680d62bc4baSyz 681d62bc4baSyz /* 682d62bc4baSyz * The link name cannot start with a digit and must end with a digit. 683d62bc4baSyz */ 684d62bc4baSyz if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 685d62bc4baSyz return (B_FALSE); 686d62bc4baSyz 687d62bc4baSyz /* 688d62bc4baSyz * The legal characters in a link name are: 689d62bc4baSyz * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 690d62bc4baSyz */ 691d62bc4baSyz for (cp = link; *cp != '\0'; cp++) { 692d62bc4baSyz if ((isalnum(*cp) == 0) && (*cp != '_')) 693d62bc4baSyz return (B_FALSE); 694d62bc4baSyz } 695d62bc4baSyz 696d62bc4baSyz return (B_TRUE); 697d62bc4baSyz } 698*da14cebeSEric Cheng 699*da14cebeSEric Cheng /* 700*da14cebeSEric Cheng * Convert priority string to a value. 701*da14cebeSEric Cheng */ 702*da14cebeSEric Cheng dladm_status_t 703*da14cebeSEric Cheng dladm_str2pri(char *token, mac_priority_level_t *pri) 704*da14cebeSEric Cheng { 705*da14cebeSEric Cheng if (strlen(token) == strlen("low") && 706*da14cebeSEric Cheng strncasecmp(token, "low", strlen("low")) == 0) { 707*da14cebeSEric Cheng *pri = MPL_LOW; 708*da14cebeSEric Cheng } else if (strlen(token) == strlen("medium") && 709*da14cebeSEric Cheng strncasecmp(token, "medium", strlen("medium")) == 0) { 710*da14cebeSEric Cheng *pri = MPL_MEDIUM; 711*da14cebeSEric Cheng } else if (strlen(token) == strlen("high") && 712*da14cebeSEric Cheng strncasecmp(token, "high", strlen("high")) == 0) { 713*da14cebeSEric Cheng *pri = MPL_HIGH; 714*da14cebeSEric Cheng } else { 715*da14cebeSEric Cheng return (DLADM_STATUS_BADVAL); 716*da14cebeSEric Cheng } 717*da14cebeSEric Cheng return (DLADM_STATUS_OK); 718*da14cebeSEric Cheng } 719*da14cebeSEric Cheng 720*da14cebeSEric Cheng /* 721*da14cebeSEric Cheng * Convert priority value to a string. 722*da14cebeSEric Cheng */ 723*da14cebeSEric Cheng const char * 724*da14cebeSEric Cheng dladm_pri2str(mac_priority_level_t pri, char *buf) 725*da14cebeSEric Cheng { 726*da14cebeSEric Cheng const char *s; 727*da14cebeSEric Cheng 728*da14cebeSEric Cheng switch (pri) { 729*da14cebeSEric Cheng case MPL_LOW: 730*da14cebeSEric Cheng s = "low"; 731*da14cebeSEric Cheng break; 732*da14cebeSEric Cheng case MPL_MEDIUM: 733*da14cebeSEric Cheng s = "medium"; 734*da14cebeSEric Cheng break; 735*da14cebeSEric Cheng case MPL_HIGH: 736*da14cebeSEric Cheng s = "high"; 737*da14cebeSEric Cheng break; 738*da14cebeSEric Cheng default: 739*da14cebeSEric Cheng s = "--"; 740*da14cebeSEric Cheng break; 741*da14cebeSEric Cheng } 742*da14cebeSEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 743*da14cebeSEric Cheng return (buf); 744*da14cebeSEric Cheng } 745*da14cebeSEric Cheng 746*da14cebeSEric Cheng void 747*da14cebeSEric Cheng dladm_free_args(dladm_arg_list_t *list) 748*da14cebeSEric Cheng { 749*da14cebeSEric Cheng if (list != NULL) { 750*da14cebeSEric Cheng free(list->al_buf); 751*da14cebeSEric Cheng free(list); 752*da14cebeSEric Cheng } 753*da14cebeSEric Cheng } 754*da14cebeSEric Cheng 755*da14cebeSEric Cheng dladm_status_t 756*da14cebeSEric Cheng dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues) 757*da14cebeSEric Cheng { 758*da14cebeSEric Cheng dladm_arg_list_t *list; 759*da14cebeSEric Cheng dladm_arg_info_t *aip; 760*da14cebeSEric Cheng char *buf, *curr; 761*da14cebeSEric Cheng int len, i; 762*da14cebeSEric Cheng 763*da14cebeSEric Cheng list = malloc(sizeof (dladm_arg_list_t)); 764*da14cebeSEric Cheng if (list == NULL) 765*da14cebeSEric Cheng return (dladm_errno2status(errno)); 766*da14cebeSEric Cheng 767*da14cebeSEric Cheng list->al_count = 0; 768*da14cebeSEric Cheng list->al_buf = buf = strdup(str); 769*da14cebeSEric Cheng if (buf == NULL) 770*da14cebeSEric Cheng return (dladm_errno2status(errno)); 771*da14cebeSEric Cheng 772*da14cebeSEric Cheng curr = buf; 773*da14cebeSEric Cheng len = strlen(buf); 774*da14cebeSEric Cheng aip = NULL; 775*da14cebeSEric Cheng for (i = 0; i < len; i++) { 776*da14cebeSEric Cheng char c = buf[i]; 777*da14cebeSEric Cheng boolean_t match = (c == '=' || c == ','); 778*da14cebeSEric Cheng 779*da14cebeSEric Cheng if (!match && i != len - 1) 780*da14cebeSEric Cheng continue; 781*da14cebeSEric Cheng 782*da14cebeSEric Cheng if (match) { 783*da14cebeSEric Cheng buf[i] = '\0'; 784*da14cebeSEric Cheng if (*curr == '\0') 785*da14cebeSEric Cheng goto fail; 786*da14cebeSEric Cheng } 787*da14cebeSEric Cheng 788*da14cebeSEric Cheng if (aip != NULL && c != '=') { 789*da14cebeSEric Cheng if (aip->ai_count > DLADM_MAX_ARG_VALS) 790*da14cebeSEric Cheng goto fail; 791*da14cebeSEric Cheng 792*da14cebeSEric Cheng if (novalues) 793*da14cebeSEric Cheng goto fail; 794*da14cebeSEric Cheng 795*da14cebeSEric Cheng aip->ai_val[aip->ai_count] = curr; 796*da14cebeSEric Cheng aip->ai_count++; 797*da14cebeSEric Cheng } else { 798*da14cebeSEric Cheng if (list->al_count > DLADM_MAX_ARG_VALS) 799*da14cebeSEric Cheng goto fail; 800*da14cebeSEric Cheng 801*da14cebeSEric Cheng aip = &list->al_info[list->al_count]; 802*da14cebeSEric Cheng aip->ai_name = curr; 803*da14cebeSEric Cheng aip->ai_count = 0; 804*da14cebeSEric Cheng list->al_count++; 805*da14cebeSEric Cheng if (c == ',') 806*da14cebeSEric Cheng aip = NULL; 807*da14cebeSEric Cheng } 808*da14cebeSEric Cheng curr = buf + i + 1; 809*da14cebeSEric Cheng } 810*da14cebeSEric Cheng 811*da14cebeSEric Cheng *listp = list; 812*da14cebeSEric Cheng return (DLADM_STATUS_OK); 813*da14cebeSEric Cheng 814*da14cebeSEric Cheng fail: 815*da14cebeSEric Cheng dladm_free_args(list); 816*da14cebeSEric Cheng return (DLADM_STATUS_FAILED); 817*da14cebeSEric Cheng } 818