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 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 ** 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 ** 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