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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <unistd.h> 27 #include <errno.h> 28 #include <ctype.h> 29 #include <fcntl.h> 30 #include <strings.h> 31 #include <dirent.h> 32 #include <stdlib.h> 33 #include <sys/param.h> 34 #include <sys/stat.h> 35 #include <sys/dld.h> 36 #include <sys/dld_ioc.h> 37 #include <libdladm_impl.h> 38 #include <libintl.h> 39 #include <libdlpi.h> 40 41 static char dladm_rootdir[MAXPATHLEN] = "/"; 42 43 typedef struct media_type_desc { 44 uint32_t media_type; 45 #define MAX_MEDIA_TYPE_STRING 32 46 const char media_type_str[MAX_MEDIA_TYPE_STRING]; 47 } media_type_t; 48 49 static media_type_t media_type_table[] = { 50 { DL_ETHER, "Ethernet" }, 51 { DL_WIFI, "WiFi" }, 52 { DL_IB, "Infiniband" }, 53 { DL_IPV4, "IPv4Tunnel" }, 54 { DL_IPV6, "IPv6Tunnel" }, 55 { DL_6TO4, "6to4Tunnel" }, 56 { DL_CSMACD, "CSMA/CD" }, 57 { DL_TPB, "TokenBus" }, 58 { DL_TPR, "TokenRing" }, 59 { DL_METRO, "MetroNet" }, 60 { DL_HDLC, "HDLC" }, 61 { DL_CHAR, "SyncCharacter" }, 62 { DL_CTCA, "CTCA" }, 63 { DL_FDDI, "FDDI" }, 64 { DL_FC, "FiberChannel" }, 65 { DL_ATM, "ATM" }, 66 { DL_IPATM, "ATM(ClassicIP)" }, 67 { DL_X25, "X.25" }, 68 { DL_IPX25, "X.25(ClassicIP)" }, 69 { DL_ISDN, "ISDN" }, 70 { DL_HIPPI, "HIPPI" }, 71 { DL_100VG, "100BaseVGEthernet" }, 72 { DL_100VGTPR, "100BaseVGTokenRing" }, 73 { DL_ETH_CSMA, "IEEE802.3" }, 74 { DL_100BT, "100BaseT" }, 75 { DL_FRAME, "FrameRelay" }, 76 { DL_MPFRAME, "MPFrameRelay" }, 77 { DL_ASYNC, "AsyncCharacter" }, 78 { DL_IPNET, "IPNET" }, 79 { DL_OTHER, "Other" } 80 }; 81 #define MEDIATYPECOUNT (sizeof (media_type_table) / sizeof (media_type_t)) 82 83 dladm_status_t 84 dladm_open(dladm_handle_t *handle) 85 { 86 int dld_fd; 87 88 if (handle == NULL) 89 return (DLADM_STATUS_BADARG); 90 91 if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 92 return (dladm_errno2status(errno)); 93 94 /* 95 * Don't open DLMGMT_DOOR now. dlmgmtd(1M) is not able to 96 * open the door when the dladm handle is opened because the 97 * door hasn't been created yet at that time. Thus, we must 98 * open it on-demand in dladm_door_fd(). Move the open() 99 * to dladm_door_fd() for all cases. 100 */ 101 102 if ((*handle = malloc(sizeof (struct dladm_handle))) == NULL) { 103 (void) close(dld_fd); 104 return (DLADM_STATUS_NOMEM); 105 } 106 107 (*handle)->dld_fd = dld_fd; 108 (*handle)->door_fd = -1; 109 110 return (DLADM_STATUS_OK); 111 } 112 113 void 114 dladm_close(dladm_handle_t handle) 115 { 116 if (handle != NULL) { 117 (void) close(handle->dld_fd); 118 if (handle->door_fd != -1) 119 (void) close(handle->door_fd); 120 free(handle); 121 } 122 } 123 124 int 125 dladm_dld_fd(dladm_handle_t handle) 126 { 127 return (handle->dld_fd); 128 } 129 130 /* 131 * If DLMGMT_DOOR hasn't been opened in the handle yet, open it. 132 */ 133 dladm_status_t 134 dladm_door_fd(dladm_handle_t handle, int *door_fd) 135 { 136 int fd; 137 138 if (handle->door_fd == -1) { 139 if ((fd = open(DLMGMT_DOOR, O_RDONLY)) < 0) 140 return (dladm_errno2status(errno)); 141 handle->door_fd = fd; 142 } 143 *door_fd = handle->door_fd; 144 145 return (DLADM_STATUS_OK); 146 } 147 148 const char * 149 dladm_status2str(dladm_status_t status, char *buf) 150 { 151 const char *s; 152 153 switch (status) { 154 case DLADM_STATUS_OK: 155 s = "ok"; 156 break; 157 case DLADM_STATUS_BADARG: 158 s = "invalid argument"; 159 break; 160 case DLADM_STATUS_FAILED: 161 s = "operation failed"; 162 break; 163 case DLADM_STATUS_TOOSMALL: 164 s = "buffer size too small"; 165 break; 166 case DLADM_STATUS_NOTSUP: 167 s = "operation not supported"; 168 break; 169 case DLADM_STATUS_NOTFOUND: 170 s = "object not found"; 171 break; 172 case DLADM_STATUS_BADVAL: 173 s = "invalid value"; 174 break; 175 case DLADM_STATUS_NOMEM: 176 s = "insufficient memory"; 177 break; 178 case DLADM_STATUS_EXIST: 179 s = "object already exists"; 180 break; 181 case DLADM_STATUS_LINKINVAL: 182 s = "invalid link"; 183 break; 184 case DLADM_STATUS_PROPRDONLY: 185 s = "read-only property"; 186 break; 187 case DLADM_STATUS_BADVALCNT: 188 s = "invalid number of values"; 189 break; 190 case DLADM_STATUS_DBNOTFOUND: 191 s = "database not found"; 192 break; 193 case DLADM_STATUS_DENIED: 194 s = "permission denied"; 195 break; 196 case DLADM_STATUS_IOERR: 197 s = "I/O error"; 198 break; 199 case DLADM_STATUS_TEMPONLY: 200 s = "change cannot be persistent"; 201 break; 202 case DLADM_STATUS_TIMEDOUT: 203 s = "operation timed out"; 204 break; 205 case DLADM_STATUS_ISCONN: 206 s = "already connected"; 207 break; 208 case DLADM_STATUS_NOTCONN: 209 s = "not connected"; 210 break; 211 case DLADM_STATUS_REPOSITORYINVAL: 212 s = "invalid configuration repository"; 213 break; 214 case DLADM_STATUS_MACADDRINVAL: 215 s = "invalid MAC address"; 216 break; 217 case DLADM_STATUS_KEYINVAL: 218 s = "invalid key"; 219 break; 220 case DLADM_STATUS_INVALIDMACADDRLEN: 221 s = "invalid MAC address length"; 222 break; 223 case DLADM_STATUS_INVALIDMACADDRTYPE: 224 s = "invalid MAC address type"; 225 break; 226 case DLADM_STATUS_LINKBUSY: 227 s = "link busy"; 228 break; 229 case DLADM_STATUS_VIDINVAL: 230 s = "invalid VLAN identifier"; 231 break; 232 case DLADM_STATUS_TRYAGAIN: 233 s = "try again later"; 234 break; 235 case DLADM_STATUS_NONOTIF: 236 s = "link notification is not supported"; 237 break; 238 case DLADM_STATUS_BADTIMEVAL: 239 s = "invalid time range"; 240 break; 241 case DLADM_STATUS_INVALIDMACADDR: 242 s = "invalid MAC address value"; 243 break; 244 case DLADM_STATUS_INVALIDMACADDRNIC: 245 s = "MAC address reserved for use by underlying data-link"; 246 break; 247 case DLADM_STATUS_INVALIDMACADDRINUSE: 248 s = "MAC address is already in use"; 249 break; 250 case DLADM_STATUS_MACFACTORYSLOTINVALID: 251 s = "invalid factory MAC address slot"; 252 break; 253 case DLADM_STATUS_MACFACTORYSLOTUSED: 254 s = "factory MAC address slot already used"; 255 break; 256 case DLADM_STATUS_MACFACTORYSLOTALLUSED: 257 s = "all factory MAC address slots are in use"; 258 break; 259 case DLADM_STATUS_MACFACTORYNOTSUP: 260 s = "factory MAC address slots not supported"; 261 break; 262 case DLADM_STATUS_INVALIDMACPREFIX: 263 s = "Invalid MAC address prefix value"; 264 break; 265 case DLADM_STATUS_INVALIDMACPREFIXLEN: 266 s = "Invalid MAC address prefix length"; 267 break; 268 case DLADM_STATUS_CPUMAX: 269 s = "non-existent processor ID"; 270 break; 271 case DLADM_STATUS_CPUERR: 272 s = "could not determine processor status"; 273 break; 274 case DLADM_STATUS_CPUNOTONLINE: 275 s = "processor not online"; 276 break; 277 case DLADM_STATUS_DB_NOTFOUND: 278 s = "database not found"; 279 break; 280 case DLADM_STATUS_DB_PARSE_ERR: 281 s = "database parse error"; 282 break; 283 case DLADM_STATUS_PROP_PARSE_ERR: 284 s = "property parse error"; 285 break; 286 case DLADM_STATUS_ATTR_PARSE_ERR: 287 s = "attribute parse error"; 288 break; 289 case DLADM_STATUS_FLOW_DB_ERR: 290 s = "flow database error"; 291 break; 292 case DLADM_STATUS_FLOW_DB_OPEN_ERR: 293 s = "flow database open error"; 294 break; 295 case DLADM_STATUS_FLOW_DB_PARSE_ERR: 296 s = "flow database parse error"; 297 break; 298 case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR: 299 s = "flow property database parse error"; 300 break; 301 case DLADM_STATUS_FLOW_ADD_ERR: 302 s = "flow add error"; 303 break; 304 case DLADM_STATUS_FLOW_WALK_ERR: 305 s = "flow walk error"; 306 break; 307 case DLADM_STATUS_FLOW_IDENTICAL: 308 s = "a flow with identical attributes exists"; 309 break; 310 case DLADM_STATUS_FLOW_INCOMPATIBLE: 311 s = "flow(s) with incompatible attributes exists"; 312 break; 313 case DLADM_STATUS_FLOW_EXISTS: 314 s = "link still has flows"; 315 break; 316 case DLADM_STATUS_PERSIST_FLOW_EXISTS: 317 s = "persistent flow with the same name exists"; 318 break; 319 case DLADM_STATUS_INVALID_IP: 320 s = "invalid IP address"; 321 break; 322 case DLADM_STATUS_INVALID_PREFIXLEN: 323 s = "invalid IP prefix length"; 324 break; 325 case DLADM_STATUS_INVALID_PROTOCOL: 326 s = "invalid IP protocol"; 327 break; 328 case DLADM_STATUS_INVALID_PORT: 329 s = "invalid port number"; 330 break; 331 case DLADM_STATUS_INVALID_DSF: 332 s = "invalid dsfield"; 333 break; 334 case DLADM_STATUS_INVALID_DSFMASK: 335 s = "invalid dsfield mask"; 336 break; 337 case DLADM_STATUS_INVALID_MACMARGIN: 338 s = "MTU check failed, use lower MTU or -f option"; 339 break; 340 case DLADM_STATUS_BADPROP: 341 s = "invalid property"; 342 break; 343 case DLADM_STATUS_MINMAXBW: 344 s = "minimum value for maxbw is 1.2M"; 345 break; 346 case DLADM_STATUS_NO_HWRINGS: 347 s = "request hw rings failed"; 348 break; 349 case DLADM_STATUS_PERMONLY: 350 s = "change must be persistent"; 351 break; 352 case DLADM_STATUS_OPTMISSING: 353 s = "optional software not installed"; 354 break; 355 case DLADM_STATUS_IPTUNTYPE: 356 s = "invalid IP tunnel type"; 357 break; 358 case DLADM_STATUS_IPTUNTYPEREQD: 359 s = "IP tunnel type required"; 360 break; 361 case DLADM_STATUS_BADIPTUNLADDR: 362 s = "invalid local IP tunnel address"; 363 break; 364 case DLADM_STATUS_BADIPTUNRADDR: 365 s = "invalid remote IP tunnel address"; 366 break; 367 case DLADM_STATUS_ADDRINUSE: 368 s = "address already in use"; 369 break; 370 default: 371 s = "<unknown error>"; 372 break; 373 } 374 (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 375 return (buf); 376 } 377 378 /* 379 * Convert a unix errno to a dladm_status_t. 380 * We only convert errnos that are likely to be encountered. All others 381 * are mapped to DLADM_STATUS_FAILED. 382 */ 383 dladm_status_t 384 dladm_errno2status(int err) 385 { 386 switch (err) { 387 case 0: 388 return (DLADM_STATUS_OK); 389 case EINVAL: 390 return (DLADM_STATUS_BADARG); 391 case EEXIST: 392 return (DLADM_STATUS_EXIST); 393 case ENOENT: 394 return (DLADM_STATUS_NOTFOUND); 395 case ENOSPC: 396 return (DLADM_STATUS_TOOSMALL); 397 case ENOMEM: 398 return (DLADM_STATUS_NOMEM); 399 case ENOTSUP: 400 return (DLADM_STATUS_NOTSUP); 401 case ENETDOWN: 402 return (DLADM_STATUS_NONOTIF); 403 case EACCES: 404 case EPERM: 405 return (DLADM_STATUS_DENIED); 406 case EIO: 407 return (DLADM_STATUS_IOERR); 408 case EBUSY: 409 return (DLADM_STATUS_LINKBUSY); 410 case EAGAIN: 411 return (DLADM_STATUS_TRYAGAIN); 412 case ENOTEMPTY: 413 return (DLADM_STATUS_FLOW_EXISTS); 414 case EOPNOTSUPP: 415 return (DLADM_STATUS_FLOW_INCOMPATIBLE); 416 case EALREADY: 417 return (DLADM_STATUS_FLOW_IDENTICAL); 418 case EADDRINUSE: 419 return (DLADM_STATUS_ADDRINUSE); 420 default: 421 return (DLADM_STATUS_FAILED); 422 } 423 } 424 425 boolean_t 426 dladm_str2interval(char *oarg, uint32_t *interval) 427 { 428 int val; 429 char *endp = NULL; 430 431 errno = 0; 432 val = strtol(oarg, &endp, 10); 433 if (errno != 0 || val <= 0 || *endp != '\0') 434 return (B_FALSE); 435 436 *interval = val; 437 438 return (B_TRUE); 439 } 440 441 dladm_status_t 442 dladm_str2bw(char *oarg, uint64_t *bw) 443 { 444 char *endp = NULL; 445 int64_t n; 446 int mult = 1; 447 448 n = strtoull(oarg, &endp, 10); 449 450 if ((errno != 0) || (strlen(endp) > 1)) 451 return (DLADM_STATUS_BADARG); 452 453 if (n < 0) 454 return (DLADM_STATUS_BADVAL); 455 456 switch (*endp) { 457 case 'k': 458 case 'K': 459 mult = 1000; 460 break; 461 case 'm': 462 case 'M': 463 case '\0': 464 mult = 1000000; 465 break; 466 case 'g': 467 case 'G': 468 mult = 1000000000; 469 break; 470 case '%': 471 /* 472 * percentages not supported for now, 473 * see RFE 6540675 474 */ 475 return (DLADM_STATUS_NOTSUP); 476 default: 477 return (DLADM_STATUS_BADVAL); 478 } 479 480 *bw = n * mult; 481 482 /* check for overflow */ 483 if (*bw / mult != n) 484 return (DLADM_STATUS_BADARG); 485 486 return (DLADM_STATUS_OK); 487 } 488 489 /* 490 * Convert bandwidth in bps to a string in mpbs. For values greater 491 * than 1mbps or 1000000, print a whole mbps value. For values that 492 * have fractional Mbps in whole Kbps , print the bandwidth in a manner 493 * simlilar to a floating point format. 494 * 495 * bps string 496 * 0 0 497 * 100 0 498 * 2000 0.002 499 * 431000 0.431 500 * 1000000 1 501 * 1030000 1.030 502 * 100000000 100 503 */ 504 const char * 505 dladm_bw2str(int64_t bw, char *buf) 506 { 507 int kbps, mbps; 508 509 kbps = (bw%1000000)/1000; 510 mbps = bw/1000000; 511 if (kbps != 0) { 512 if (mbps == 0) 513 (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps); 514 else 515 (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps, 516 kbps); 517 } else { 518 (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps); 519 } 520 521 return (buf); 522 } 523 524 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 525 526 static int 527 i_dladm_lock_db(const char *lock_file, short type) 528 { 529 int lock_fd; 530 struct flock lock; 531 532 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 533 LOCK_DB_PERMS)) < 0) 534 return (-1); 535 536 lock.l_type = type; 537 lock.l_whence = SEEK_SET; 538 lock.l_start = 0; 539 lock.l_len = 0; 540 541 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 542 int err = errno; 543 544 (void) close(lock_fd); 545 (void) unlink(lock_file); 546 errno = err; 547 return (-1); 548 } 549 return (lock_fd); 550 } 551 552 static void 553 i_dladm_unlock_db(const char *lock_file, int fd) 554 { 555 struct flock lock; 556 557 if (fd < 0) 558 return; 559 560 lock.l_type = F_UNLCK; 561 lock.l_whence = SEEK_SET; 562 lock.l_start = 0; 563 lock.l_len = 0; 564 565 (void) fcntl(fd, F_SETLKW, &lock); 566 (void) close(fd); 567 (void) unlink(lock_file); 568 } 569 570 /* 571 * Given a link class, returns its class string. 572 */ 573 const char * 574 dladm_class2str(datalink_class_t class, char *buf) 575 { 576 const char *s; 577 578 switch (class) { 579 case DATALINK_CLASS_PHYS: 580 s = "phys"; 581 break; 582 case DATALINK_CLASS_VLAN: 583 s = "vlan"; 584 break; 585 case DATALINK_CLASS_AGGR: 586 s = "aggr"; 587 break; 588 case DATALINK_CLASS_VNIC: 589 s = "vnic"; 590 break; 591 case DATALINK_CLASS_ETHERSTUB: 592 s = "etherstub"; 593 break; 594 case DATALINK_CLASS_IPTUN: 595 s = "iptun"; 596 break; 597 case DATALINK_CLASS_SIMNET: 598 s = "simnet"; 599 break; 600 case DATALINK_CLASS_BRIDGE: 601 s = "bridge"; 602 break; 603 default: 604 s = "unknown"; 605 break; 606 } 607 608 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 609 return (buf); 610 } 611 612 /* 613 * Given a physical link media type, returns its media type string. 614 */ 615 const char * 616 dladm_media2str(uint32_t media, char *buf) 617 { 618 const char *s = "--"; 619 media_type_t *mt; 620 int idx; 621 622 for (idx = 0; idx < MEDIATYPECOUNT; idx++) { 623 mt = media_type_table + idx; 624 if (mt->media_type == media) { 625 s = mt->media_type_str; 626 break; 627 } 628 } 629 630 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 631 return (buf); 632 } 633 634 /* 635 * Given a physical link media type string, returns its media type constant. 636 */ 637 uint32_t 638 dladm_str2media(const char *buf) 639 { 640 media_type_t *mt; 641 int idx; 642 643 for (idx = 0; idx < MEDIATYPECOUNT; idx++) { 644 mt = media_type_table + idx; 645 if (strcasecmp(buf, mt->media_type_str) == 0) 646 return (mt->media_type); 647 } 648 649 return (DL_OTHER); 650 } 651 652 dladm_status_t 653 i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms, 654 dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *), 655 void *arg, boolean_t writeop) 656 { 657 dladm_status_t status = DLADM_STATUS_OK; 658 FILE *fp, *nfp = NULL; 659 char lock[MAXPATHLEN]; 660 char file[MAXPATHLEN]; 661 char newfile[MAXPATHLEN]; 662 char *db_basename; 663 int nfd, lock_fd; 664 665 /* 666 * If we are called from a boot script such as net-physical, 667 * it's quite likely that the root fs is still not writable. 668 * For this case, it's ok for the lock creation to fail since 669 * no one else could be accessing our configuration file. 670 */ 671 db_basename = strrchr(db_file, '/'); 672 if (db_basename == NULL || db_basename[1] == '\0') 673 return (dladm_errno2status(EINVAL)); 674 db_basename++; 675 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 676 if ((lock_fd = i_dladm_lock_db 677 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 678 return (dladm_errno2status(errno)); 679 680 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 681 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 682 int err = errno; 683 684 i_dladm_unlock_db(lock, lock_fd); 685 if (err == ENOENT) 686 return (DLADM_STATUS_DBNOTFOUND); 687 688 return (dladm_errno2status(err)); 689 } 690 691 if (writeop) { 692 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 693 dladm_rootdir, db_file); 694 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 695 db_perms)) < 0) { 696 (void) fclose(fp); 697 i_dladm_unlock_db(lock, lock_fd); 698 return (dladm_errno2status(errno)); 699 } 700 701 if ((nfp = fdopen(nfd, "w")) == NULL) { 702 (void) close(nfd); 703 (void) fclose(fp); 704 (void) unlink(newfile); 705 i_dladm_unlock_db(lock, lock_fd); 706 return (dladm_errno2status(errno)); 707 } 708 } 709 status = (*process_db)(handle, arg, fp, nfp); 710 if (!writeop || status != DLADM_STATUS_OK) 711 goto done; 712 713 /* 714 * Configuration files need to be owned by the 'dladm' user. 715 * If we are invoked by root, the file ownership needs to be fixed. 716 */ 717 if (getuid() == 0 || geteuid() == 0) { 718 if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 719 status = dladm_errno2status(errno); 720 goto done; 721 } 722 } 723 724 if (fflush(nfp) == EOF) { 725 status = dladm_errno2status(errno); 726 goto done; 727 } 728 (void) fclose(fp); 729 (void) fclose(nfp); 730 731 if (rename(newfile, file) < 0) { 732 (void) unlink(newfile); 733 i_dladm_unlock_db(lock, lock_fd); 734 return (dladm_errno2status(errno)); 735 } 736 737 i_dladm_unlock_db(lock, lock_fd); 738 return (DLADM_STATUS_OK); 739 740 done: 741 if (nfp != NULL) { 742 (void) fclose(nfp); 743 if (status != DLADM_STATUS_OK) 744 (void) unlink(newfile); 745 } 746 (void) fclose(fp); 747 i_dladm_unlock_db(lock, lock_fd); 748 return (status); 749 } 750 751 dladm_status_t 752 dladm_set_rootdir(const char *rootdir) 753 { 754 DIR *dp; 755 756 if (rootdir == NULL || *rootdir != '/' || 757 (dp = opendir(rootdir)) == NULL) 758 return (DLADM_STATUS_BADARG); 759 760 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 761 (void) closedir(dp); 762 return (DLADM_STATUS_OK); 763 } 764 765 boolean_t 766 dladm_valid_linkname(const char *link) 767 { 768 size_t len = strlen(link); 769 const char *cp; 770 771 if (len >= MAXLINKNAMELEN) 772 return (B_FALSE); 773 774 /* 775 * The link name cannot start with a digit and must end with a digit. 776 */ 777 if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 778 return (B_FALSE); 779 780 /* 781 * The legal characters in a link name are: 782 * alphanumeric (a-z, A-Z, 0-9), underscore ('_'), and '.'. 783 */ 784 for (cp = link; *cp != '\0'; cp++) { 785 if ((isalnum(*cp) == 0) && (*cp != '_') && (*cp != '.')) 786 return (B_FALSE); 787 } 788 789 return (B_TRUE); 790 } 791 792 /* 793 * Convert priority string to a value. 794 */ 795 dladm_status_t 796 dladm_str2pri(char *token, mac_priority_level_t *pri) 797 { 798 if (strlen(token) == strlen("low") && 799 strncasecmp(token, "low", strlen("low")) == 0) { 800 *pri = MPL_LOW; 801 } else if (strlen(token) == strlen("medium") && 802 strncasecmp(token, "medium", strlen("medium")) == 0) { 803 *pri = MPL_MEDIUM; 804 } else if (strlen(token) == strlen("high") && 805 strncasecmp(token, "high", strlen("high")) == 0) { 806 *pri = MPL_HIGH; 807 } else { 808 return (DLADM_STATUS_BADVAL); 809 } 810 return (DLADM_STATUS_OK); 811 } 812 813 /* 814 * Convert priority value to a string. 815 */ 816 const char * 817 dladm_pri2str(mac_priority_level_t pri, char *buf) 818 { 819 const char *s; 820 821 switch (pri) { 822 case MPL_LOW: 823 s = "low"; 824 break; 825 case MPL_MEDIUM: 826 s = "medium"; 827 break; 828 case MPL_HIGH: 829 s = "high"; 830 break; 831 default: 832 s = "--"; 833 break; 834 } 835 (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 836 return (buf); 837 } 838 839 void 840 dladm_free_args(dladm_arg_list_t *list) 841 { 842 if (list != NULL) { 843 free(list->al_buf); 844 free(list); 845 } 846 } 847 848 dladm_status_t 849 dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues) 850 { 851 dladm_arg_list_t *list; 852 dladm_arg_info_t *aip; 853 char *buf, *curr; 854 int len, i; 855 856 if (str == NULL) 857 return (DLADM_STATUS_BADVAL); 858 859 if (str[0] == '\0') 860 return (DLADM_STATUS_OK); 861 862 list = malloc(sizeof (dladm_arg_list_t)); 863 if (list == NULL) 864 return (dladm_errno2status(errno)); 865 866 list->al_count = 0; 867 list->al_buf = buf = strdup(str); 868 if (buf == NULL) 869 return (dladm_errno2status(errno)); 870 871 curr = buf; 872 len = strlen(buf); 873 aip = NULL; 874 for (i = 0; i < len; i++) { 875 char c = buf[i]; 876 boolean_t match = (c == '=' || c == ','); 877 878 if (!match && i != len - 1) 879 continue; 880 881 if (match) { 882 buf[i] = '\0'; 883 if (*curr == '\0') 884 goto fail; 885 } 886 887 if (aip != NULL && c != '=') { 888 if (aip->ai_count > DLADM_MAX_ARG_VALS) 889 goto fail; 890 891 if (novalues) 892 goto fail; 893 894 aip->ai_val[aip->ai_count] = curr; 895 aip->ai_count++; 896 } else { 897 if (list->al_count > DLADM_MAX_ARG_VALS) 898 goto fail; 899 900 aip = &list->al_info[list->al_count]; 901 aip->ai_name = curr; 902 aip->ai_count = 0; 903 list->al_count++; 904 if (c == ',') 905 aip = NULL; 906 } 907 curr = buf + i + 1; 908 } 909 910 *listp = list; 911 return (DLADM_STATUS_OK); 912 913 fail: 914 dladm_free_args(list); 915 return (DLADM_STATUS_FAILED); 916 } 917