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