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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Implements the main body of the "getdgrp" command.
31 */
32 #include <sys/types.h>
33 #include <stdio.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <devmgmt.h>
38 #include <devtab.h>
39 #include <fmtmsg.h>
40
41
42 /*
43 * Local Definitions
44 * TRUE Boolean TRUE value
45 * FALSE Boolean FALSE value
46 * NULL Null address
47 */
48
49 #ifndef TRUE
50 #define TRUE 1
51 #endif
52
53 #ifndef FALSE
54 #define FALSE 0
55 #endif
56
57
58 /*
59 * Exit codes:
60 * EX_OK All's well that ends well
61 * EX_ERROR Some other error occurred
62 * EX_DTAB Device table couldn't be opened
63 * EX_DGRP Device-group table couldn't be open.
64 */
65
66 #define EX_OK 0
67 #define EX_ERROR 1
68 #define EX_DTAB 2
69 #define EX_DGRP 2
70
71
72 /*
73 * Messages:
74 * M_USAGE Command usage error
75 * M_ERROR Some unexpected error
76 * M_DEVTAB Device table couldn't be opened
77 * M_DGROUP Device-group table couldn't be opened
78 */
79
80 #define M_USAGE "usage: getdgrp [-ael] [criterion [...]] [dgroup [...]]"
81 #define M_ERROR "Internal error, errno=%d"
82 #define M_DEVTAB "Cannot open the device table: %s"
83 #define M_DGROUP "Cannot open the device-group table: %s"
84
85
86 /*
87 * Internal References
88 * buildcriterialist() Builds a list of the criteria on the
89 * command line
90 * buildgrouplist() Builds a list of the device-groups mentioned
91 * on the command line
92 */
93
94 static char **buildcriterialist(); /* Builds criteria list from command line */
95 static char **builddgrouplist(); /* Builds dgroup list from command line */
96
97
98 /*
99 * Macros
100 * stdmsg(r,l,s,t) Generate a standard message
101 * r Recoverability flag
102 * l Standard label
103 * s Severity
104 * t Text
105 * isacriterion(p) Returns TRUE if *p is a criterion, FALSE otherwise
106 */
107
108 #define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)
109 #define isacriterion(p) (strchr(*arglist,'=')||strchr(*arglist,':'))
110
111
112 /*
113 * Static Variables
114 * lbl Buffer for standard message label
115 * txt Buffer for standard message text
116 */
117
118 static char lbl[MM_MXLABELLN+1];
119 static char txt[MM_MXTXTLN+1];
120
121 /*
122 * getdgrp [-ael] [criterion [...]] [dgroup [...]]
123 *
124 * This function gets the device groups that contain as members devices
125 * that match the given criteria.
126 *
127 * Options:
128 * -a A device must meet all criteria before the device-group in
129 * which it is a member can be selected for inclusion in the
130 * generated list. If this option is missing, a device must
131 * meet at least one criterion before it's group can be
132 * selected. This option has no affect if there are no criterion
133 * on the command-line.
134 * -e The list of device groups specifies groups to exclude from
135 * the generated list. If this option is omitted, the list
136 * of groups is the set of groups that can be selected. This
137 * option has no effect if there are no device-groups on the
138 * command-line.
139 * -l List all device groups, even those that have no valid
140 * members (this option has no effect if criterion are specified
141 *
142 * Arguments:
143 * criterion A device criterion of the form <attr><op><val> where
144 * <attr> is the name of an attribute, <op> is "=", "!=",
145 * ":", or "!:" for "is equal to", "is not equal to",
146 * "is defined," or "is not defined." <val> is the value
147 * that the attribute must be equal to or not equal to.
148 * (<val> must be "*" if <op> is ":" or "!:").
149 * dgroup A device group that is to be exclude selected for the
150 * generated list or excluded from the the generated
151 * list.
152 *
153 * Exit values:
154 * 0 Success
155 * 1 Usage or an internal error
156 * 2 The device table or the device-group table could not be
157 * opened for reading
158 */
159
160 int
main(int argc,char ** argv)161 main(int argc, char **argv)
162 {
163
164 /*
165 * Automatic data
166 */
167
168 char **arglist; /* List of arguments (subset of argv) */
169 char **criterialist; /* List of criteria */
170 char **dgrouplist; /* List of device groups to search or ignore */
171 char **fitgrouplist; /* List of device groups that fit criteria */
172 char *cmdname; /* Simple command name */
173 char *dgroup; /* Pointer to device group name in list */
174 char *filename; /* Pointer to filename in "error" */
175 int exitcode; /* Value to return to the caller */
176 int sev; /* Message severity */
177 int optchar; /* Option character (returned by getopt()) */
178 int andflag; /* TRUE if anding criteria, FALSE if or'ed */
179 int excludeflag; /* TRUE if the dgroups list those to exclude */
180 int allflag; /* TRUE if all device grps are to be displayed */
181 int options; /* Options to pass to getdgrp() */
182 int usageerr; /* TRUE if syntax error */
183
184
185 /* Build the message label from the (simple) command name */
186 if (cmdname = strrchr(argv[0], '/')) cmdname++;
187 else cmdname = argv[0];
188 (void) strlcat(strcpy(lbl, "UX:"), cmdname, sizeof(lbl));
189
190 /* Only write the text-component of messages (this goes away in SVR4.1) */
191 (void) putenv("MSGVERB=text");
192
193 /*
194 * Parse the command line:
195 * - Options
196 * - Selection criteria
197 * - Device groups to include or exclude
198 */
199
200 /*
201 * Extract options from the command line
202 */
203
204 /* Initializations */
205 andflag = FALSE; /* No -a */
206 excludeflag = FALSE; /* No -e */
207 allflag = FALSE; /* No -l */
208 usageerr = FALSE; /* No errors yet */
209
210 /*
211 * Loop until all of the command line options have been parced
212 */
213 opterr = FALSE; /* Don't let getopt() write messages */
214 while ((optchar = getopt(argc, argv, "ael")) != EOF) switch (optchar) {
215
216 /* -a List device groups that fit all of the criteria listed */
217 case 'a':
218 if (andflag) usageerr = TRUE;
219 else andflag = TRUE;
220 break;
221
222 /* -e Exclude those device groups mentioned on the command line */
223 case 'e':
224 if (excludeflag) usageerr = TRUE;
225 else excludeflag = TRUE;
226 break;
227
228 /* -l List all device groups (if no criteria is specified) */
229 case 'l':
230 if (allflag) usageerr = TRUE;
231 else allflag = TRUE;
232 break;
233
234 /* Default case -- command usage error */
235 case '?':
236 default:
237 usageerr = TRUE;
238 break;
239 }
240
241 /* If there is a usage error, write an appropriate message and exit */
242 if (usageerr) {
243 stdmsg(MM_NRECOV, lbl, MM_ERROR, M_USAGE);
244 exit(EX_ERROR);
245 }
246
247 /* Open the device file (if there's one to be opened) */
248 if (!_opendevtab("r")) {
249 if (filename = _devtabpath()) {
250 (void) snprintf(txt, sizeof(txt), M_DEVTAB, filename);
251 exitcode = EX_DTAB;
252 sev = MM_ERROR;
253 } else {
254 (void) sprintf(txt, M_ERROR, errno);
255 exitcode = EX_ERROR;
256 sev = MM_HALT;
257 }
258 stdmsg(MM_NRECOV, lbl, sev, txt);
259 exit(exitcode);
260 }
261
262 /* Open the device file (if there's one to be opened) */
263 if (!_opendgrptab("r")) {
264 if (filename = _dgrptabpath()) {
265 (void) snprintf(txt, sizeof(txt), M_DGROUP, filename);
266 exitcode = EX_DGRP;
267 sev = MM_ERROR;
268 } else {
269 (void) sprintf(txt, M_ERROR, errno);
270 exitcode = EX_ERROR;
271 sev = MM_HALT;
272 }
273 stdmsg(MM_NRECOV, lbl, sev, txt);
274 exit(exitcode);
275 }
276
277 /* Build the list of criteria and device groups */
278 arglist = argv + optind;
279 criterialist = buildcriterialist(arglist);
280 dgrouplist = builddgrouplist(arglist);
281 options = (excludeflag ? DTAB_EXCLUDEFLAG : 0) |
282 (andflag ? DTAB_ANDCRITERIA : 0) |
283 (allflag ? DTAB_LISTALL : 0) ;
284
285 /*
286 * Get the list of device groups that meets the criteria requested.
287 * If we got a list (that might be empty), write that list to the
288 * standard output file (stdout).
289 */
290
291 exitcode = EX_OK;
292 if (!(fitgrouplist = getdgrp(dgrouplist, criterialist, options))) {
293 exitcode = EX_ERROR;
294 }
295 else for (dgroup = *fitgrouplist++ ; dgroup ; dgroup = *fitgrouplist++)
296 (void) puts(dgroup);
297
298 /* Finished */
299 return(exitcode);
300 }
301
302 /*
303 * char **buildcriterialist(arglist)
304 * char **arglist
305 *
306 * This function builds a list of criteria descriptions from the
307 * list of arguments given. The list returned is in malloc()ed
308 * space.
309 *
310 * Arguments:
311 * arglist The address of the first element in the list
312 * of arguments (possibly) containing criterion
313 *
314 * Returns: char **
315 * A pointer to the first element in the list of criterion.
316 * If there was a problem, the function returns (char **) NULL.
317 * If there are no criteria in the list, the function returns
318 * an empty list.
319 */
320
321 static char **
buildcriterialist(arglist)322 buildcriterialist(arglist)
323 char **arglist; /* Pointer to the list of argument pointers */
324 {
325 /*
326 * Automatic data
327 */
328
329 char **pp; /* Pointer to a criteria */
330 void *allocbuf; /* Pointer to the allocated data */
331 int ncriteria; /* Number of criteria found */
332
333
334 /*
335 * Search the argument list, looking for the end of the list or
336 * the first thing that's not a criteria. (A criteria is a
337 * character-string that contains a colon (':') or an equal-sign ('=')
338 */
339
340 pp = arglist;
341 ncriteria = 1;
342 while (*pp && (strchr(*pp, '=') || strchr(*pp, ':'))) {
343 ncriteria++;
344 pp++;
345 }
346
347 /* Allocate space for the list of criteria pointers */
348 if (allocbuf = malloc(ncriteria*sizeof(char **))) {
349
350 /* Build the list of criteria arguments */
351 pp = (char **) allocbuf;
352 while ((*arglist != (char *) NULL) && isacriterion(*arglist)) *pp++ = *arglist++;
353 *pp = (char *) NULL;
354 }
355
356 return ((char **) allocbuf);
357 }
358
359 /*
360 * char **builddgrouplist(arglist)
361 * char **arglist
362 *
363 * This function returns a pointer to the first element in a list of
364 * device-groups (i.e. not criteria) specified in the list of arguments
365 * whose first element is pointed to by <arglist>.
366 *
367 * Arguments:
368 * arglist The address of the first element in the list of
369 * arguments to be searched for non-criteria
370 *
371 * Returns: char **
372 * The address of the first item in the list of arguments that are
373 * not criteria. If none, the function returns a pointer to a
374 * null list.
375 *
376 * Note:
377 * - The current implementation returns a pointer to an element in
378 * <arglist>.
379 */
380
381 static char **
builddgrouplist(arglist)382 builddgrouplist(arglist)
383 char **arglist; /* First item in the list of arguments */
384 {
385 /*
386 * Automatic data
387 */
388
389 /*
390 * Search the argument list, looking for the end of the list or
391 * the first thing that's not a criteria. It is the first device
392 * group in the list of device groups (if any).
393 */
394
395 while (*arglist && isacriterion(*arglist)) arglist++;
396
397 /* Return a pointer to the argument list. */
398 return(arglist);
399 }
400