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 #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 int 164 main(int argc, char **argv) 165 { 166 167 /* 168 * Automatic data 169 */ 170 171 char **arglist; /* List of arguments (subset of argv) */ 172 char **criterialist; /* List of criteria */ 173 char **dgrouplist; /* List of device groups to search or ignore */ 174 char **fitgrouplist; /* List of device groups that fit criteria */ 175 char *cmdname; /* Simple command name */ 176 char *dgroup; /* Pointer to device group name in list */ 177 char *filename; /* Pointer to filename in "error" */ 178 int exitcode; /* Value to return to the caller */ 179 int sev; /* Message severity */ 180 int optchar; /* Option character (returned by getopt()) */ 181 int andflag; /* TRUE if anding criteria, FALSE if or'ed */ 182 int excludeflag; /* TRUE if the dgroups list those to exclude */ 183 int allflag; /* TRUE if all device grps are to be displayed */ 184 int options; /* Options to pass to getdgrp() */ 185 int usageerr; /* TRUE if syntax error */ 186 187 188 /* Build the message label from the (simple) command name */ 189 if (cmdname = strrchr(argv[0], '/')) cmdname++; 190 else cmdname = argv[0]; 191 (void) strlcat(strcpy(lbl, "UX:"), cmdname, sizeof(lbl)); 192 193 /* Only write the text-component of messages (this goes away in SVR4.1) */ 194 (void) putenv("MSGVERB=text"); 195 196 /* 197 * Parse the command line: 198 * - Options 199 * - Selection criteria 200 * - Device groups to include or exclude 201 */ 202 203 /* 204 * Extract options from the command line 205 */ 206 207 /* Initializations */ 208 andflag = FALSE; /* No -a */ 209 excludeflag = FALSE; /* No -e */ 210 allflag = FALSE; /* No -l */ 211 usageerr = FALSE; /* No errors yet */ 212 213 /* 214 * Loop until all of the command line options have been parced 215 */ 216 opterr = FALSE; /* Don't let getopt() write messages */ 217 while ((optchar = getopt(argc, argv, "ael")) != EOF) switch (optchar) { 218 219 /* -a List device groups that fit all of the criteria listed */ 220 case 'a': 221 if (andflag) usageerr = TRUE; 222 else andflag = TRUE; 223 break; 224 225 /* -e Exclude those device groups mentioned on the command line */ 226 case 'e': 227 if (excludeflag) usageerr = TRUE; 228 else excludeflag = TRUE; 229 break; 230 231 /* -l List all device groups (if no criteria is specified) */ 232 case 'l': 233 if (allflag) usageerr = TRUE; 234 else allflag = TRUE; 235 break; 236 237 /* Default case -- command usage error */ 238 case '?': 239 default: 240 usageerr = TRUE; 241 break; 242 } 243 244 /* If there is a usage error, write an appropriate message and exit */ 245 if (usageerr) { 246 stdmsg(MM_NRECOV, lbl, MM_ERROR, M_USAGE); 247 exit(EX_ERROR); 248 } 249 250 /* Open the device file (if there's one to be opened) */ 251 if (!_opendevtab("r")) { 252 if (filename = _devtabpath()) { 253 (void) snprintf(txt, sizeof(txt), M_DEVTAB, filename); 254 exitcode = EX_DTAB; 255 sev = MM_ERROR; 256 } else { 257 (void) sprintf(txt, M_ERROR, errno); 258 exitcode = EX_ERROR; 259 sev = MM_HALT; 260 } 261 stdmsg(MM_NRECOV, lbl, sev, txt); 262 exit(exitcode); 263 } 264 265 /* Open the device file (if there's one to be opened) */ 266 if (!_opendgrptab("r")) { 267 if (filename = _dgrptabpath()) { 268 (void) snprintf(txt, sizeof(txt), M_DGROUP, filename); 269 exitcode = EX_DGRP; 270 sev = MM_ERROR; 271 } else { 272 (void) sprintf(txt, M_ERROR, errno); 273 exitcode = EX_ERROR; 274 sev = MM_HALT; 275 } 276 stdmsg(MM_NRECOV, lbl, sev, txt); 277 exit(exitcode); 278 } 279 280 /* Build the list of criteria and device groups */ 281 arglist = argv + optind; 282 criterialist = buildcriterialist(arglist); 283 dgrouplist = builddgrouplist(arglist); 284 options = (excludeflag ? DTAB_EXCLUDEFLAG : 0) | 285 (andflag ? DTAB_ANDCRITERIA : 0) | 286 (allflag ? DTAB_LISTALL : 0) ; 287 288 /* 289 * Get the list of device groups that meets the criteria requested. 290 * If we got a list (that might be empty), write that list to the 291 * standard output file (stdout). 292 */ 293 294 exitcode = EX_OK; 295 if (!(fitgrouplist = getdgrp(dgrouplist, criterialist, options))) { 296 exitcode = EX_ERROR; 297 } 298 else for (dgroup = *fitgrouplist++ ; dgroup ; dgroup = *fitgrouplist++) 299 (void) puts(dgroup); 300 301 /* Finished */ 302 return(exitcode); 303 } 304 305 /* 306 * char **buildcriterialist(arglist) 307 * char **arglist 308 * 309 * This function builds a list of criteria descriptions from the 310 * list of arguments given. The list returned is in malloc()ed 311 * space. 312 * 313 * Arguments: 314 * arglist The address of the first element in the list 315 * of arguments (possibly) containing criterion 316 * 317 * Returns: char ** 318 * A pointer to the first element in the list of criterion. 319 * If there was a problem, the function returns (char **) NULL. 320 * If there are no criteria in the list, the function returns 321 * an empty list. 322 */ 323 324 static char ** 325 buildcriterialist(arglist) 326 char **arglist; /* Pointer to the list of argument pointers */ 327 { 328 /* 329 * Automatic data 330 */ 331 332 char **pp; /* Pointer to a criteria */ 333 void *allocbuf; /* Pointer to the allocated data */ 334 int ncriteria; /* Number of criteria found */ 335 336 337 /* 338 * Search the argument list, looking for the end of the list or 339 * the first thing that's not a criteria. (A criteria is a 340 * character-string that contains a colon (':') or an equal-sign ('=') 341 */ 342 343 pp = arglist; 344 ncriteria = 1; 345 while (*pp && (strchr(*pp, '=') || strchr(*pp, ':'))) { 346 ncriteria++; 347 pp++; 348 } 349 350 /* Allocate space for the list of criteria pointers */ 351 if (allocbuf = malloc(ncriteria*sizeof(char **))) { 352 353 /* Build the list of criteria arguments */ 354 pp = (char **) allocbuf; 355 while ((*arglist != (char *) NULL) && isacriterion(*arglist)) *pp++ = *arglist++; 356 *pp = (char *) NULL; 357 } 358 359 return ((char **) allocbuf); 360 } 361 362 /* 363 * char **builddgrouplist(arglist) 364 * char **arglist 365 * 366 * This function returns a pointer to the first element in a list of 367 * device-groups (i.e. not criteria) specified in the list of arguments 368 * whose first element is pointed to by <arglist>. 369 * 370 * Arguments: 371 * arglist The address of the first element in the list of 372 * arguments to be searched for non-criteria 373 * 374 * Returns: char ** 375 * The address of the first item in the list of arguments that are 376 * not criteria. If none, the function returns a pointer to a 377 * null list. 378 * 379 * Note: 380 * - The current implementation returns a pointer to an element in 381 * <arglist>. 382 */ 383 384 static char ** 385 builddgrouplist(arglist) 386 char **arglist; /* First item in the list of arguments */ 387 { 388 /* 389 * Automatic data 390 */ 391 392 /* 393 * Search the argument list, looking for the end of the list or 394 * the first thing that's not a criteria. It is the first device 395 * group in the list of device groups (if any). 396 */ 397 398 while (*arglist && isacriterion(*arglist)) arglist++; 399 400 /* Return a pointer to the argument list. */ 401 return(arglist); 402 } 403