dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / devmgmt / cmds / putdev.c
blob6df19b82fbb11560fa123776383f514e3729adc8
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
34 * Implements the "putdev" command.
36 #include <sys/types.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <fmtmsg.h>
43 #include <devmgmt.h>
44 #include <devtab.h>
48 * General Purpose Constants
49 * TRUE Boolean TRUE (if not already defined)
50 * FALSE Boolean FALSE (if not already defined)
51 * NULL Null address (if not already defined)
54 #ifndef TRUE
55 #define TRUE (1)
56 #endif
58 #ifndef FALSE
59 #define FALSE (0)
60 #endif
63 * Exit codes
64 * EX_OK All went well
65 * EX_ERROR Usage or internal error
66 * EX_DEVTAB Had trouble accessing/reading/writing the device table
67 * EX_EXISTS The specified alias already exists
68 * EX_ATTRIB One or more attributes requested for removal was not
69 * defined for the device
70 * EX_RELPATH Pathname supplied for cdevice, bdevice or pathname
71 * attributes was not a full pathname
74 #define EX_OK 0
75 #define EX_ERROR 1
76 #define EX_DEVTAB 2
77 #define EX_EXISTS 3
78 #define EX_ATTRIB 4
79 #define EX_RELPATH 4
83 * Error messages
86 #define E_USAGE "usage: putdev -a alias [attribute=value [...]]\n putdev -m device attribute=value [attribute=value [...]]\n putdev -d device [attribute [...]]"
87 #define E_ALIASIS "Alias already exists in table: %s"
88 #define E_NODEV "Device does not exist in table: %s"
89 #define E_NOALIAS "Cannot use \"alias\" as an attribute"
90 #define E_NOATTR "Attribute not found: %s"
91 #define E_NODEVTAB "Cannot open the device table: %s"
92 #define E_NOMKDTAB "Cannot create a new device table: %s"
93 #define E_INVALIAS "Not a valid device alias: %s"
94 #define E_MULTIPLE "Multiple definitions of an attribute are not allowed."
95 #define E_INTERNAL "Internal error, errno=%d"
96 #define E_RELPATH "Full pathname required for cdevice,bdevice and pathname attributes."
100 * Macros
101 * stdmsg(r,l,s,t) Using fmtmsg(), write a standard message to the
102 * standard error stream.
103 * Where:
104 * r The recoverability of the error
105 * l The label-component
106 * s The severity-component
107 * t The text-component
110 #define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)
114 * Static data
115 * msg Space for message's text-component
118 static char msg[256]; /* Space for text of message */
121 * char *mklbl(cmd)
122 * char *cmd
124 * This function builds a standard label from the command used to invoke
125 * this process and the standard label prefix ("UX:")
127 * Arguments:
128 * char *cmd The command used to invoke this process.
130 * Returns: char *
131 * Pointer to malloc()ed space containing the standard label,
132 * or (char *) NULL if an error occurred.
135 static char *
136 mklbl(cmd)
137 char *cmd;
139 /* Automatic data */
140 char *rtn; /* Value to return */
141 char *p; /* Temporary */
143 /* Find the 1st char of the basename of the command */
144 if (p = strrchr(cmd, '/')) p++;
145 else p = cmd;
147 /* Allocate and build the string value to return */
148 if (rtn = (char *) malloc(strlen("UX:")+strlen(p)+1)) {
149 (void) strcpy(rtn, "UX:");
150 (void) strcat(rtn, p);
154 /* Now that we've done all of that work, change the environment
155 * so that only the text-component is written by fmtmsg().
156 * (This should go away in SVR4.1)
159 (void) putenv("MSGVERB=text");
162 /* Done */
163 return(rtn);
167 * putdev -a alias [attribute=value [...]]
168 * putdev -m alias attribute=value [attribute=value [...]]
169 * putdev -d alias [attribute [...]]
171 * Modify the device-table. If -a specified, add a record for <alias>
172 * to the table. If -m specified, modify the attributes specified for
173 * the <device> specified. If -d specified, remove the specified
174 * attributes from the specified device or remove the specified device.
176 * Options:
177 * -a Add an alias description to the device table
178 * -m Modify an existing device description
179 * -d (if no attributes specified) remove the specified
180 * device from the device table, or (if attributes
181 * specified) remove the specified attributes from
182 * the specified device.
184 * Exit values:
185 * 0 All went well
186 * 1 Usage error (includes specifying "alias" as an
187 * <attribute>)
188 * 2 The device table file could not be opened, read
189 * or modified
190 * 3 If -a, the alias already exists. Otherwise, the
191 * specified device does not exist in the table
192 * 4 One of the specified attributes did not exist
193 * for the device and therefore wasn't removed
197 main(int argc, char *argv[])
199 /* Automatic data */
200 char **plist; /* Ptr to list of undef'nd attrs */
201 char *lbl; /* Ptr to label for messages */
202 char *alias; /* Ptr to <alias> on command-line */
203 char *device; /* Ptr to <device> on command-line */
204 char *p; /* Temp ptr to char */
205 int noerr; /* FLAG, TRUE if all's well */
206 int a_seen; /* TRUE if -a seen on command-line */
207 int m_seen; /* TRUE if -m seen on command-line */
208 int d_seen; /* TRUE if -a seen on command-line */
209 int optchar; /* Option extracted */
210 int exitcd; /* Value to return at exit */
211 int nattrs; /* Number of attributes on command */
214 /* Generate the label for messages */
215 lbl = mklbl(argv[0]);
217 /* Extract arguments - validate usage */
218 noerr = TRUE;
219 a_seen = FALSE;
220 m_seen = FALSE;
221 d_seen = FALSE;
222 opterr = FALSE;
223 while ((optchar = getopt(argc, argv, "a:d:m:")) != EOF) switch (optchar) {
225 case 'a':
226 if (!(a_seen || m_seen || d_seen)) {
227 a_seen = TRUE;
228 alias = optarg;
230 else noerr = FALSE;
231 break;
233 case 'd':
234 if (!(a_seen || m_seen || d_seen)) {
235 d_seen = TRUE;
236 device = optarg;
238 else noerr = FALSE;
239 break;
241 case 'm':
242 if (!(a_seen || m_seen || d_seen)) {
243 m_seen = TRUE;
244 device = optarg;
246 else noerr = FALSE;
247 break;
249 case '?':
250 default:
251 noerr = FALSE;
255 /* Write a usage message if we've seen a blatant error */
256 if (!(a_seen || m_seen || d_seen) || !noerr) {
257 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
258 exit(EX_ERROR);
262 /* Set up */
263 exitcd = EX_OK;
264 nattrs = argc - optind;
267 /* putdev -a alias [attr=value [...]] */
269 if (a_seen) {
271 /* Syntax check */
272 if (nattrs < 0) {
273 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
274 exitcd = EX_ERROR;
275 } else {
277 /* Attempt to add the new alias */
278 if (!(_adddevtabrec(alias, &argv[optind]))) {
280 /* Attempt failed. Write appropriate error message. */
282 switch(errno) {
285 * EINVAL indicates that <alias> is not valid or "alias"
286 * was mentioned as <attr> in <attr>=<value> pair. If the
287 * alias is a valid alias, assume that's the problem.
290 case EINVAL:
291 if (_validalias(alias))
292 p = E_NOALIAS;
293 else (void) snprintf(p=msg, sizeof(msg), E_INVALIAS, alias);
294 stdmsg(MM_NRECOV, lbl, MM_ERROR, p);
295 exitcd = EX_ERROR;
296 break;
299 * EEXIST indicates that the alias <alias> already exists
300 * in the device table.
303 case EEXIST:
304 (void) snprintf(msg, sizeof(msg), E_ALIASIS, alias);
305 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
306 exitcd = EX_EXISTS;
307 break;
310 * EACCES and ENOENT indicate problems reading or writing
311 * the device table.
314 case EACCES:
315 case ENOENT:
316 p = _devtabpath();
317 if (access(p, R_OK) == 0)
318 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
319 else
320 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
321 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
322 exitcd = EX_DEVTAB;
323 break;
326 * EAGAIN indicates that an attribute was defined on the
327 * command line more than once.
330 case EAGAIN:
331 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_MULTIPLE);
332 exitcd = EX_ERROR;
333 break;
336 * ENXIO indicates that a relative pathname was supplied
337 * for the cdevice, bdevice or pathname attributes. Full
338 * pathnames are required for these attributes.
340 case ENXIO:
341 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_RELPATH);
342 exitcd = EX_RELPATH;
343 break;
346 * Some other problem (odd?)
349 default:
350 (void) sprintf(msg, E_INTERNAL, errno);
351 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
352 exitcd = EX_ERROR;
356 } /* End -a case */
359 /* putdev -m device attr=value [...] */
361 else if (m_seen) {
363 /* Check usage */
365 if (nattrs <= 0) {
366 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
367 exitcd = EX_ERROR;
368 } else {
370 /* Attempt to modify a device's record */
371 if (!(_moddevtabrec(device, &argv[optind]))) {
373 /* Modification attempt failed */
375 switch(errno) {
378 * EINVAL indicates that "alias" was used as an attribute
379 * in an <attr>=<value> pair.
382 case EINVAL:
383 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_NOALIAS);
384 exitcd = EX_ERROR;
385 break;
388 * ENODEV indicates that the device that was to
389 * be modified doesn't exist.
392 case ENODEV:
393 (void) snprintf(msg, sizeof(msg), E_NODEV, device);
394 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
395 exitcd = EX_EXISTS;
396 break;
399 * ENOENT indicates that the device-table doesn't exist.
402 case ENOENT:
403 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath());
404 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
405 exitcd = EX_DEVTAB;
406 break;
409 * EACCES indicates that there was a problem reading the
410 * old device table or creating the new table. If the
411 * old table is readable, assume that we can't create the
412 * new table. Otherwise, assume that the old table isn't
413 * accessible.
416 case EACCES:
417 p = _devtabpath();
418 if (access(p, R_OK) == 0)
419 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
420 else
421 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
422 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
423 exitcd = EX_DEVTAB;
424 break;
427 * EAGAIN indicates that an attribute was specified more than
428 * once on the command line.
431 case EAGAIN:
432 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_MULTIPLE);
433 exitcd = EX_ERROR;
434 break;
437 * ENXIO indicates that a relative pathname was supplied
438 * for the cdevice, bdevice or pathname attributes. Full
439 * pathnames are required for these attributes.
441 case ENXIO:
442 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_RELPATH);
443 exitcd = EX_RELPATH;
444 break;
447 * Some strange problem...
450 default:
451 (void) sprintf(msg, E_INTERNAL, errno);
452 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
453 exitcd = EX_ERROR;
457 } /* End -m case */
459 else if (d_seen) {
461 /* putdev -d device [attr [...]] */
463 /* Check usage */
464 if (nattrs < 0) {
465 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
466 exitcd = EX_ERROR;
467 } else {
470 * Determine case (removing a device or attributes
471 * to a device.
474 if (nattrs == 0) {
476 /* putdev -d device */
478 /* Attempt to remove the specified device */
479 if (!(_rmdevtabrec(device))) switch(errno) {
482 * ENODEV indicates that the named device is not
483 * defined in the device table.
486 case ENODEV:
487 (void) snprintf(msg, sizeof(msg), E_NODEV, device);
488 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
489 exitcd = EX_EXISTS;
490 break;
493 * ENOENT indicates that the device table can't
494 * be found.
497 case ENOENT:
498 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath());
499 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
500 exitcd = EX_DEVTAB;
501 break;
504 * EACCES indicates that there was a problem reading the
505 * old device table or creating the new table. If the
506 * old table is readable, assume that we can't create the
507 * new table. Otherwise, assume that the old table isn't
508 * accessible.
511 case EACCES:
512 p = _devtabpath();
513 if (access(p, R_OK) == 0)
514 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
515 else
516 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
517 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
518 exitcd = EX_DEVTAB;
519 break;
522 * Some strange problem...
525 default:
526 (void) sprintf(msg, E_INTERNAL, errno);
527 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
528 exitcd = EX_ERROR;
530 } /* End switch */
532 else {
534 /* putdev -d device attr [attr [...]] */
537 * Attempt to remove the specified attributes from the
538 * specified device.
540 if (!(_rmdevtabattrs(device, &argv[optind], &plist))) switch(errno) {
543 * EINVAL indicates that a named attribute was not
544 * defined for the specified device or "alias" was
545 * requested. If "plist" points to a list of attrs,
546 * the former is the problem. Otherwise, the latter
547 * is the problem.
550 case EINVAL:
551 if (plist) {
552 exitcd = EX_ATTRIB;
553 for (; *plist; plist++) {
554 (void) snprintf(msg, sizeof(msg), E_NOATTR, *plist);
555 stdmsg(MM_RECOVER, lbl, MM_WARNING, msg);
557 } else {
558 stdmsg(MM_NRECOV, lbl, MM_ERROR, E_NOALIAS);
559 exitcd = EX_ERROR;
561 break;
564 * ENODEV indicates that the named device is not
565 * defined in the device table.
568 case ENODEV:
569 (void) snprintf(msg, sizeof(msg), E_NODEV, device);
570 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
571 exitcd = EX_EXISTS;
572 break;
575 * ENOENT indicates that the device table can't
576 * be found.
579 case ENOENT:
580 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath());
581 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
582 exitcd = EX_DEVTAB;
583 break;
586 * EACCES indicates that there was a problem reading the
587 * old device table or creating the new table. If the
588 * old table is readable, assume that we can't create the
589 * new table. Otherwise, assume that the old table isn't
590 * accessible.
593 case EACCES:
594 p = _devtabpath();
595 if (access(p, R_OK) == 0)
596 (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
597 else
598 (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
599 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
600 exitcd = EX_DEVTAB;
601 break;
604 * Some strange problem...
607 default:
608 (void) sprintf(msg, E_INTERNAL, errno);
609 stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
610 exitcd = EX_ERROR;
612 } /* End switch */
614 } /* End "putdev -d device attr [...]" case */
616 } /* End passes usage-check case */
618 } /* End -d case */
621 /* Done. Return exit code (determined above) */
622 return(exitcd);
623 } /* main() */