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