xref: /illumos-gate/usr/src/cmd/devmgmt/cmds/devattr.c (revision bd97c7ce2344fa3252d8785c35895490916bc79b)
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  *  devattr.c
32  *
33  *  Contains the following:
34  *	devattr		Command that returns [specific] attributes for
35  *			a device.
36  */
37 
38 /*
39  *  devattr [-v] device [attr [...]]
40  *
41  *	This command searches the device table file for the device specified.
42  *	If it finds the device (matched either by alias or major and minor
43  *	device number), it extracts the attribute(s) specified and writes
44  *	that value to the standard output stream (stdout).
45  *
46  *	The command writes the values of the attributes to stdout one per
47  *	line, in the order that they were requested.  If the -v option is
48  *	requested, it writes the attributes in the form <attr>='<value>' where
49  *	<attr> is the name of the attribute and <value> is the value of that
50  *	attribute.
51  *
52  *  Returns:
53  *	0	The command succeeded
54  *	1	The command syntax is incorrect,
55  *		An invalid option was used,
56  *		An internal error occurred that prevented completion
57  *	2	The device table could not be opened for reading.
58  *	3	The requested device was not found in the device table
59  *	4	A requested attribute was not defined for the device
60  */
61 
62 #include	<sys/types.h>
63 #include	<stdio.h>
64 #include	<string.h>
65 #include	<errno.h>
66 #include	<fmtmsg.h>
67 #include	<devmgmt.h>
68 #include	<devtab.h>
69 #include	<stdlib.h>
70 
71 
72 /*
73  *  Local constant definitions
74  *	TRUE		Boolean TRUE
75  *	FALSE		Boolean FALSE
76  */
77 
78 #ifndef	TRUE
79 #define	TRUE	1
80 #endif
81 
82 #ifndef	FALSE
83 #define	FALSE	0
84 #endif
85 
86 /*
87  *  Messages
88  *	M_USAGE		Usage error
89  *	M_ERROR		Unexpected internal error
90  *	M_NODEV		Device not found in the device table
91  *	M_NOATTR	Attribute not found
92  *	M_DEVTAB	Can't open the device table
93  */
94 
95 #define	M_USAGE		"usage: devattr [-v] device [attribute [...]]"
96 #define	M_ERROR		"Internal error, errno=%d"
97 #define	M_NODEV		"Device not found in the device table: %s"
98 #define	M_NOATTR	"Attrubute not found: %s"
99 #define	M_DEVTAB	"Cannot open the device table: %s"
100 
101 
102 /*
103  * Exit codes:
104  *	EX_OK		All's well that ends well
105  *	EX_ERROR	Some problem caused termination
106  *	EX_DEVTAB	Device table could not be opened
107  *	EX_NODEV	The device wasn't found in the device table
108  *	EX_NOATTR	A requested attribute wasn't defined for the device
109  */
110 
111 #define	EX_OK 		0
112 #define	EX_ERROR	1
113 #define	EX_DEVTAB	2
114 #define	EX_NODEV	3
115 #define	EX_NOATTR	4
116 
117 
118 /*
119  *  Macros
120  *	stdmsg(r,l,s,t)	    Standard Message Generator
121  *				r	Recoverability flag
122  *				l	Standard Label
123  *				s	Severity
124  *				t	Text
125  */
126 
127 #define	stdmsg(r,l,s,t)	(void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)
128 
129 
130 /*
131  *  Local static data
132  *	lbl	Buffer for the command label (for messages)
133  *	txt		Buffer for the text of messages
134  */
135 
136 static char	lbl[MM_MXLABELLN+1];
137 static char	txt[MM_MXTXTLN+1];
138 
139 /*
140  *  main()
141  *
142  *	Implements the command "devattr".   This function parses the command
143  *	line, then calls the devattr() function looking for the specified
144  *	device and the requested attribute.  It writes the information to
145  *	the standard output file in the requested format.
146  *
147  * Exits:
148  *	0	The command succeeded
149  *	1	The command syntax is incorrect,
150  *		An invalid option was used,
151  *		An internal error occurred that prevented completion
152  *	2	The device table could not be opened for reading.
153  *	3	The requested device was not found in the device table
154  *	4	A requested attribute was not defined for the device
155  */
156 
157 int
158 main(int argc, char *argv[])
159 {
160 
161 	/* Automatic data */
162 	char   *cmdname;		/* Pointer to command name */
163 	char   *device;			/* Pointer to device name */
164 	char   *attr;			/* Pointer to current attribute */
165 	char   *value;			/* Pointer to current attr value */
166 	char   *p;			/* Temporary character pointer */
167 	char  **argptr;			/* Pointer into argv[] list */
168 	int	syntaxerr;		/* TRUE if invalid option seen */
169 	int	noerr;			/* TRUE if all's well in processing */
170 	int	v_seen;			/* TRUE if -v is on the command-line */
171 	int	exitcode;		/* Value to return */
172 	int	severity;		/* Message severity */
173 	int	c;			/* Temp char value */
174 
175 
176 	/*
177 	 *  Parse the command-line.
178 	 */
179 
180 	syntaxerr = FALSE;
181 	v_seen = FALSE;
182 
183 	/* Extract options */
184 	opterr = FALSE;
185 	while ((c = getopt(argc, argv, "v")) != EOF) switch(c) {
186 
187 	    /* -v option:  No argument, may be seen only once */
188 	    case 'v':
189 		if (!v_seen) v_seen = TRUE;
190 		else syntaxerr = TRUE;
191 		break;
192 
193 	    /* Unknown option */
194 	    default:
195 		syntaxerr = TRUE;
196 	    break;
197 	}
198 
199 	/* Build the command name */
200 	cmdname = argv[0];
201 	if ((p = strrchr(cmdname, '/')) != (char *) NULL) cmdname = p+1;
202 	(void) strlcat(strcpy(lbl, "UX:"), cmdname, sizeof(lbl));
203 
204 	/* Make only the text-component of messages appear (remove this in SVR4.1) */
205 	(void) putenv("MSGVERB=text");
206 
207 	/*
208 	 * Check for a usage error
209 	 *  - invalid option
210 	 *  - arg count < 2
211 	 *  - arg count < 3 && -v used
212 	 */
213 
214 	if (syntaxerr || (argc < (optind+1))) {
215 	    stdmsg(MM_NRECOV, lbl, MM_ERROR, M_USAGE);
216 	    exit(EX_ERROR);
217 	}
218 
219 	/* Open the device file (if there's one to be opened) */
220 	if (!_opendevtab("r")) {
221 	    if (p = _devtabpath()) {
222 		(void) snprintf(txt, sizeof(txt), M_DEVTAB, p);
223 		exitcode = EX_DEVTAB;
224 		severity = MM_ERROR;
225 	    } else {
226 		(void) sprintf(txt, M_ERROR, errno);
227 		exitcode = EX_ERROR;
228 		severity = MM_HALT;
229 	    }
230 	    stdmsg(MM_NRECOV, lbl, severity, txt);
231 	    exit(exitcode);
232 	}
233 
234 
235 	/*
236 	 *  Get the list of known attributes for the device.  This does
237 	 *  two things.  First, it verifies that the device is known in the
238 	 *  device table.  Second, it gets the attributes to list just in
239 	 *  case no attributes were specified.  Then, set a pointer to the
240 	 *  list of attributes to be extracted and listed...
241 	 */
242 
243 	device = argv[optind];
244 	if ((argptr = listdev(device)) == (char **) NULL) {
245 	    if (errno == ENODEV) {
246 		(void) snprintf(txt, sizeof(txt), M_NODEV, device);
247 		exitcode = EX_NODEV;
248 		severity = MM_ERROR;
249 	    } else {
250 		(void) sprintf(txt, M_ERROR, errno);
251 		exitcode = EX_ERROR;
252 		severity = MM_HALT;
253 	    }
254 	    stdmsg(MM_NRECOV, lbl, severity, txt);
255 	    exit(exitcode);
256 	}
257 	if (argc > (optind+1)) argptr = &argv[optind+1];
258 
259 
260 	/*
261 	 *  List attributes.  If a requested attribute is not defined,
262 	 *  list the value of that attribute as null.  (Using shell
263 	 *  variables as the model for this.)
264 	 */
265 
266 	exitcode = EX_OK;
267 	noerr = TRUE;
268 	while (noerr && ((attr = *argptr++) != (char *) NULL)) {
269 	    if (!(value = devattr(device, attr))) {
270 		if (errno == EINVAL) {
271 		    value = "";
272 		    (void) snprintf(txt, sizeof(txt), M_NOATTR, attr);
273 		    /* stdmsg(MM_RECOVER, lbl, MM_WARNING, txt); */
274 		    exitcode = EX_NOATTR;
275 		} else {
276 		    noerr = FALSE;
277 		    (void) sprintf(txt, M_ERROR, errno);
278 		    stdmsg(MM_NRECOV, lbl, MM_ERROR, txt);
279 		    exitcode = EX_ERROR;
280 		}
281 	    }
282 	    if (noerr && v_seen) {
283 		(void) fputs(attr, stdout);
284 		(void) fputs("='", stdout);
285 		for (p = value ; *p ; p++) {
286 		    (void) putc(*p, stdout);
287 		    if (*p == '\'') (void) fputs("\"'\"'", stdout);
288 		}
289 		(void) fputs("'\n", stdout);
290 	    } else if (noerr) {
291 		(void) fputs(value, stdout);
292 		(void) putc('\n', stdout);
293 	    }
294 	}
295 
296 	return (exitcode);
297 }
298