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
139static char	lbl[MM_MXLABELLN+1];
140static 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
160int
161main(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