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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Implements the "putdev" command. 32 */ 33 #include <sys/types.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <errno.h> 38 #include <unistd.h> 39 #include <fmtmsg.h> 40 #include <devmgmt.h> 41 #include <devtab.h> 42 43 44 /* 45 * General Purpose Constants 46 * TRUE Boolean TRUE (if not already defined) 47 * FALSE Boolean FALSE (if not already defined) 48 * NULL Null address (if not already defined) 49 */ 50 51 #ifndef TRUE 52 #define TRUE (1) 53 #endif 54 55 #ifndef FALSE 56 #define FALSE (0) 57 #endif 58 59 /* 60 * Exit codes 61 * EX_OK All went well 62 * EX_ERROR Usage or internal error 63 * EX_DEVTAB Had trouble accessing/reading/writing the device table 64 * EX_EXISTS The specified alias already exists 65 * EX_ATTRIB One or more attributes requested for removal was not 66 * defined for the device 67 * EX_RELPATH Pathname supplied for cdevice, bdevice or pathname 68 * attributes was not a full pathname 69 */ 70 71 #define EX_OK 0 72 #define EX_ERROR 1 73 #define EX_DEVTAB 2 74 #define EX_EXISTS 3 75 #define EX_ATTRIB 4 76 #define EX_RELPATH 4 77 78 79 /* 80 * Error messages 81 */ 82 83 #define E_USAGE "usage: putdev -a alias [attribute=value [...]]\n putdev -m device attribute=value [attribute=value [...]]\n putdev -d device [attribute [...]]" 84 #define E_ALIASIS "Alias already exists in table: %s" 85 #define E_NODEV "Device does not exist in table: %s" 86 #define E_NOALIAS "Cannot use \"alias\" as an attribute" 87 #define E_NOATTR "Attribute not found: %s" 88 #define E_NODEVTAB "Cannot open the device table: %s" 89 #define E_NOMKDTAB "Cannot create a new device table: %s" 90 #define E_INVALIAS "Not a valid device alias: %s" 91 #define E_MULTIPLE "Multiple definitions of an attribute are not allowed." 92 #define E_INTERNAL "Internal error, errno=%d" 93 #define E_RELPATH "Full pathname required for cdevice,bdevice and pathname attributes." 94 95 96 /* 97 * Macros 98 * stdmsg(r,l,s,t) Using fmtmsg(), write a standard message to the 99 * standard error stream. 100 * Where: 101 * r The recoverability of the error 102 * l The label-component 103 * s The severity-component 104 * t The text-component 105 */ 106 107 #define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG) 108 109 110 /* 111 * Static data 112 * msg Space for message's text-component 113 */ 114 115 static char msg[256]; /* Space for text of message */ 116 117 /* 118 * char *mklbl(cmd) 119 * char *cmd 120 * 121 * This function builds a standard label from the command used to invoke 122 * this process and the standard label prefix ("UX:") 123 * 124 * Arguments: 125 * char *cmd The command used to invoke this process. 126 * 127 * Returns: char * 128 * Pointer to malloc()ed space containing the standard label, 129 * or (char *) NULL if an error occurred. 130 */ 131 132 static char * 133 mklbl(cmd) 134 char *cmd; 135 { 136 /* Automatic data */ 137 char *rtn; /* Value to return */ 138 char *p; /* Temporary */ 139 140 /* Find the 1st char of the basename of the command */ 141 if (p = strrchr(cmd, '/')) p++; 142 else p = cmd; 143 144 /* Allocate and build the string value to return */ 145 if (rtn = (char *) malloc(strlen("UX:")+strlen(p)+1)) { 146 (void) strcpy(rtn, "UX:"); 147 (void) strcat(rtn, p); 148 } 149 150 151 /* Now that we've done all of that work, change the environment 152 * so that only the text-component is written by fmtmsg(). 153 * (This should go away in SVR4.1) 154 */ 155 156 (void) putenv("MSGVERB=text"); 157 158 159 /* Done */ 160 return(rtn); 161 } 162 163 /* 164 * putdev -a alias [attribute=value [...]] 165 * putdev -m alias attribute=value [attribute=value [...]] 166 * putdev -d alias [attribute [...]] 167 * 168 * Modify the device-table. If -a specified, add a record for <alias> 169 * to the table. If -m specified, modify the attributes specified for 170 * the <device> specified. If -d specified, remove the specified 171 * attributes from the specified device or remove the specified device. 172 * 173 * Options: 174 * -a Add an alias description to the device table 175 * -m Modify an existing device description 176 * -d (if no attributes specified) remove the specified 177 * device from the device table, or (if attributes 178 * specified) remove the specified attributes from 179 * the specified device. 180 * 181 * Exit values: 182 * 0 All went well 183 * 1 Usage error (includes specifying "alias" as an 184 * <attribute>) 185 * 2 The device table file could not be opened, read 186 * or modified 187 * 3 If -a, the alias already exists. Otherwise, the 188 * specified device does not exist in the table 189 * 4 One of the specified attributes did not exist 190 * for the device and therefore wasn't removed 191 */ 192 193 int 194 main(int argc, char *argv[]) 195 { 196 /* Automatic data */ 197 char **plist; /* Ptr to list of undef'nd attrs */ 198 char *lbl; /* Ptr to label for messages */ 199 char *alias; /* Ptr to <alias> on command-line */ 200 char *device; /* Ptr to <device> on command-line */ 201 char *p; /* Temp ptr to char */ 202 int noerr; /* FLAG, TRUE if all's well */ 203 int a_seen; /* TRUE if -a seen on command-line */ 204 int m_seen; /* TRUE if -m seen on command-line */ 205 int d_seen; /* TRUE if -a seen on command-line */ 206 int optchar; /* Option extracted */ 207 int exitcd; /* Value to return at exit */ 208 int nattrs; /* Number of attributes on command */ 209 210 211 /* Generate the label for messages */ 212 lbl = mklbl(argv[0]); 213 214 /* Extract arguments - validate usage */ 215 noerr = TRUE; 216 a_seen = FALSE; 217 m_seen = FALSE; 218 d_seen = FALSE; 219 opterr = FALSE; 220 while ((optchar = getopt(argc, argv, "a:d:m:")) != EOF) switch (optchar) { 221 222 case 'a': 223 if (!(a_seen || m_seen || d_seen)) { 224 a_seen = TRUE; 225 alias = optarg; 226 } 227 else noerr = FALSE; 228 break; 229 230 case 'd': 231 if (!(a_seen || m_seen || d_seen)) { 232 d_seen = TRUE; 233 device = optarg; 234 } 235 else noerr = FALSE; 236 break; 237 238 case 'm': 239 if (!(a_seen || m_seen || d_seen)) { 240 m_seen = TRUE; 241 device = optarg; 242 } 243 else noerr = FALSE; 244 break; 245 246 case '?': 247 default: 248 noerr = FALSE; 249 } 250 251 252 /* Write a usage message if we've seen a blatant error */ 253 if (!(a_seen || m_seen || d_seen) || !noerr) { 254 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE); 255 exit(EX_ERROR); 256 } 257 258 259 /* Set up */ 260 exitcd = EX_OK; 261 nattrs = argc - optind; 262 263 264 /* putdev -a alias [attr=value [...]] */ 265 266 if (a_seen) { 267 268 /* Syntax check */ 269 if (nattrs < 0) { 270 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE); 271 exitcd = EX_ERROR; 272 } else { 273 274 /* Attempt to add the new alias */ 275 if (!(_adddevtabrec(alias, &argv[optind]))) { 276 277 /* Attempt failed. Write appropriate error message. */ 278 279 switch(errno) { 280 281 /* 282 * EINVAL indicates that <alias> is not valid or "alias" 283 * was mentioned as <attr> in <attr>=<value> pair. If the 284 * alias is a valid alias, assume that's the problem. 285 */ 286 287 case EINVAL: 288 if (_validalias(alias)) 289 p = E_NOALIAS; 290 else (void) snprintf(p=msg, sizeof(msg), E_INVALIAS, alias); 291 stdmsg(MM_NRECOV, lbl, MM_ERROR, p); 292 exitcd = EX_ERROR; 293 break; 294 295 /* 296 * EEXIST indicates that the alias <alias> already exists 297 * in the device table. 298 */ 299 300 case EEXIST: 301 (void) snprintf(msg, sizeof(msg), E_ALIASIS, alias); 302 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 303 exitcd = EX_EXISTS; 304 break; 305 306 /* 307 * EACCES and ENOENT indicate problems reading or writing 308 * the device table. 309 */ 310 311 case EACCES: 312 case ENOENT: 313 p = _devtabpath(); 314 if (access(p, R_OK) == 0) 315 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p); 316 else 317 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p); 318 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 319 exitcd = EX_DEVTAB; 320 break; 321 322 /* 323 * EAGAIN indicates that an attribute was defined on the 324 * command line more than once. 325 */ 326 327 case EAGAIN: 328 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_MULTIPLE); 329 exitcd = EX_ERROR; 330 break; 331 332 /* 333 * ENXIO indicates that a relative pathname was supplied 334 * for the cdevice, bdevice or pathname attributes. Full 335 * pathnames are required for these attributes. 336 */ 337 case ENXIO: 338 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_RELPATH); 339 exitcd = EX_RELPATH; 340 break; 341 342 /* 343 * Some other problem (odd?) 344 */ 345 346 default: 347 (void) sprintf(msg, E_INTERNAL, errno); 348 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 349 exitcd = EX_ERROR; 350 } 351 } 352 } 353 } /* End -a case */ 354 355 356 /* putdev -m device attr=value [...] */ 357 358 else if (m_seen) { 359 360 /* Check usage */ 361 362 if (nattrs <= 0) { 363 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE); 364 exitcd = EX_ERROR; 365 } else { 366 367 /* Attempt to modify a device's record */ 368 if (!(_moddevtabrec(device, &argv[optind]))) { 369 370 /* Modification attempt failed */ 371 372 switch(errno) { 373 374 /* 375 * EINVAL indicates that "alias" was used as an attribute 376 * in an <attr>=<value> pair. 377 */ 378 379 case EINVAL: 380 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_NOALIAS); 381 exitcd = EX_ERROR; 382 break; 383 384 /* 385 * ENODEV indicates that the device that was to 386 * be modified doesn't exist. 387 */ 388 389 case ENODEV: 390 (void) snprintf(msg, sizeof(msg), E_NODEV, device); 391 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 392 exitcd = EX_EXISTS; 393 break; 394 395 /* 396 * ENOENT indicates that the device-table doesn't exist. 397 */ 398 399 case ENOENT: 400 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath()); 401 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 402 exitcd = EX_DEVTAB; 403 break; 404 405 /* 406 * EACCES indicates that there was a problem reading the 407 * old device table or creating the new table. If the 408 * old table is readable, assume that we can't create the 409 * new table. Otherwise, assume that the old table isn't 410 * accessible. 411 */ 412 413 case EACCES: 414 p = _devtabpath(); 415 if (access(p, R_OK) == 0) 416 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p); 417 else 418 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p); 419 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 420 exitcd = EX_DEVTAB; 421 break; 422 423 /* 424 * EAGAIN indicates that an attribute was specified more than 425 * once on the command line. 426 */ 427 428 case EAGAIN: 429 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_MULTIPLE); 430 exitcd = EX_ERROR; 431 break; 432 433 /* 434 * ENXIO indicates that a relative pathname was supplied 435 * for the cdevice, bdevice or pathname attributes. Full 436 * pathnames are required for these attributes. 437 */ 438 case ENXIO: 439 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_RELPATH); 440 exitcd = EX_RELPATH; 441 break; 442 443 /* 444 * Some strange problem... 445 */ 446 447 default: 448 (void) sprintf(msg, E_INTERNAL, errno); 449 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 450 exitcd = EX_ERROR; 451 } 452 } 453 } 454 } /* End -m case */ 455 456 else if (d_seen) { 457 458 /* putdev -d device [attr [...]] */ 459 460 /* Check usage */ 461 if (nattrs < 0) { 462 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE); 463 exitcd = EX_ERROR; 464 } else { 465 466 /* 467 * Determine case (removing a device or attributes 468 * to a device. 469 */ 470 471 if (nattrs == 0) { 472 473 /* putdev -d device */ 474 475 /* Attempt to remove the specified device */ 476 if (!(_rmdevtabrec(device))) switch(errno) { 477 478 /* 479 * ENODEV indicates that the named device is not 480 * defined in the device table. 481 */ 482 483 case ENODEV: 484 (void) snprintf(msg, sizeof(msg), E_NODEV, device); 485 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 486 exitcd = EX_EXISTS; 487 break; 488 489 /* 490 * ENOENT indicates that the device table can't 491 * be found. 492 */ 493 494 case ENOENT: 495 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath()); 496 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 497 exitcd = EX_DEVTAB; 498 break; 499 500 /* 501 * EACCES indicates that there was a problem reading the 502 * old device table or creating the new table. If the 503 * old table is readable, assume that we can't create the 504 * new table. Otherwise, assume that the old table isn't 505 * accessible. 506 */ 507 508 case EACCES: 509 p = _devtabpath(); 510 if (access(p, R_OK) == 0) 511 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p); 512 else 513 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p); 514 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 515 exitcd = EX_DEVTAB; 516 break; 517 518 /* 519 * Some strange problem... 520 */ 521 522 default: 523 (void) sprintf(msg, E_INTERNAL, errno); 524 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 525 exitcd = EX_ERROR; 526 527 } /* End switch */ 528 } 529 else { 530 531 /* putdev -d device attr [attr [...]] */ 532 533 /* 534 * Attempt to remove the specified attributes from the 535 * specified device. 536 */ 537 if (!(_rmdevtabattrs(device, &argv[optind], &plist))) switch(errno) { 538 539 /* 540 * EINVAL indicates that a named attribute was not 541 * defined for the specified device or "alias" was 542 * requested. If "plist" points to a list of attrs, 543 * the former is the problem. Otherwise, the latter 544 * is the problem. 545 */ 546 547 case EINVAL: 548 if (plist) { 549 exitcd = EX_ATTRIB; 550 for (; *plist; plist++) { 551 (void) snprintf(msg, sizeof(msg), E_NOATTR, *plist); 552 stdmsg(MM_RECOVER, lbl, MM_WARNING, msg); 553 } 554 } else { 555 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_NOALIAS); 556 exitcd = EX_ERROR; 557 } 558 break; 559 560 /* 561 * ENODEV indicates that the named device is not 562 * defined in the device table. 563 */ 564 565 case ENODEV: 566 (void) snprintf(msg, sizeof(msg), E_NODEV, device); 567 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 568 exitcd = EX_EXISTS; 569 break; 570 571 /* 572 * ENOENT indicates that the device table can't 573 * be found. 574 */ 575 576 case ENOENT: 577 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath()); 578 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 579 exitcd = EX_DEVTAB; 580 break; 581 582 /* 583 * EACCES indicates that there was a problem reading the 584 * old device table or creating the new table. If the 585 * old table is readable, assume that we can't create the 586 * new table. Otherwise, assume that the old table isn't 587 * accessible. 588 */ 589 590 case EACCES: 591 p = _devtabpath(); 592 if (access(p, R_OK) == 0) 593 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p); 594 else 595 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p); 596 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 597 exitcd = EX_DEVTAB; 598 break; 599 600 /* 601 * Some strange problem... 602 */ 603 604 default: 605 (void) sprintf(msg, E_INTERNAL, errno); 606 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg); 607 exitcd = EX_ERROR; 608 609 } /* End switch */ 610 611 } /* End "putdev -d device attr [...]" case */ 612 613 } /* End passes usage-check case */ 614 615 } /* End -d case */ 616 617 618 /* Done. Return exit code (determined above) */ 619 return(exitcd); 620 } /* main() */ 621