xref: /illumos-gate/usr/src/cmd/sgs/elfedit/modules/common/cap.c (revision 77c0a660417a046bfab6c8ef58d00c181c0264b3)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2022 Oxide Computer Company
27  */
28 
29 #include	<ctype.h>
30 #include	<elfedit.h>
31 #include	<sys/elf_SPARC.h>
32 #include	<strings.h>
33 #include	<debug.h>
34 #include	<conv.h>
35 #include	<cap_msg.h>
36 
37 
38 /*
39  * Capabilities section
40  */
41 
42 
43 
44 
45 /*
46  * This module uses shared code for several of the commands.
47  * It is sometimes necessary to know which specific command
48  * is active.
49  */
50 typedef enum {
51 	/* Dump command, used as module default to display dynamic section */
52 	CAP_CMD_T_DUMP =	0,	/* cap:dump */
53 
54 	/* Commands that do not correspond directly to a specific DT tag */
55 	CAP_CMD_T_TAG =		1,	/* cap:tag */
56 	CAP_CMD_T_VALUE =	2,	/* cap:value */
57 	CAP_CMD_T_DELETE =	3,	/* cap:delete */
58 	CAP_CMD_T_MOVE =	4,	/* cap:shift */
59 
60 	/* Commands that embody tag specific knowledge */
61 	CAP_CMD_T_HW1 =		5,	/* cap:hw1 */
62 	CAP_CMD_T_SF1 =		6,	/* cap:sf1 */
63 	CAP_CMD_T_HW2 =		7,	/* cap:hw2 */
64 	CAP_CMD_T_HW3 =		8,	/* cap:hw3 */
65 } CAP_CMD_T;
66 
67 
68 
69 #ifndef _ELF64
70 /*
71  * We supply this function for the msg module
72  */
73 const char *
74 _cap_msg(Msg mid)
75 {
76 	return (gettext(MSG_ORIG(mid)));
77 }
78 #endif
79 
80 
81 /*
82  * This function is supplied to elfedit through our elfedit_module_t
83  * definition. It translates the opaque elfedit_i18nhdl_t handles
84  * in our module interface into the actual strings for elfedit to
85  * use.
86  *
87  * note:
88  *	This module uses Msg codes for its i18n handle type.
89  *	So the translation is simply to use MSG_INTL() to turn
90  *	it into a string and return it.
91  */
92 static const char *
93 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
94 {
95 	Msg msg = (Msg)hdl;
96 
97 	return (MSG_INTL(msg));
98 }
99 
100 
101 
102 /*
103  * The cap_opt_t enum specifies a bit value for every optional
104  * argument allowed by a command in this module.
105  */
106 typedef enum {
107 	CAP_OPT_F_AND =		1,	/* -and: AND (&) values to dest */
108 	CAP_OPT_F_CMP =		2,	/* -cmp: Complement (~) values */
109 	CAP_OPT_F_CAPID =	4,	/* -capid id: elt limited to given */
110 					/*	capabilities group */
111 	CAP_OPT_F_CAPNDX =	8,	/* -capndx: elt is tag index, */
112 					/*	not name */
113 	CAP_OPT_F_OR =		16,	/* -or: OR (|) values to dest */
114 	CAP_OPT_F_STRVAL =	32	/* -s: value is string, not integer */
115 } cap_opt_t;
116 
117 
118 /*
119  * A variable of type ARGSTATE is used by each command to maintain
120  * information about the arguments and related things. It is
121  * initialized by process_args(), and used by the other routines.
122  */
123 typedef struct {
124 	elfedit_obj_state_t	*obj_state;
125 	struct {
126 		elfedit_section_t *sec;	/* Capabilities section reference */
127 		Cap	*data;		/* Start of capabilities section data */
128 		Word	num;		/* # Capabilities elts */
129 		Boolean	grp_set;	/* TRUE when cap group is set */
130 		Word	grp_start_ndx;	/* capabilities group starting index */
131 		Word	grp_end_ndx;	/* capabilities group ending index */
132 	} cap;
133 	struct {			/* String table */
134 		elfedit_section_t *sec;
135 	} str;
136 	cap_opt_t	optmask;	/* Mask of options used */
137 	int		argc;		/* # of plain arguments */
138 	const char	**argv;		/* Plain arguments */
139 } ARGSTATE;
140 
141 
142 
143 /*
144  * Lookup the string table associated with the capabilities
145  * section.
146  *
147  * entry:
148  *	argstate - Argument state block
149  *	required - If TRUE, failure to obtain a string table should be
150  *		considered to be an error.
151  *
152  * exit:
153  *	If a string table is found, argstate->str is updated to reference it.
154  *	If no string table is found, and required is TRUE, an error is issued
155  *	and this routine does not return to the caller. Otherwise, this
156  *	routine returns quietly without modifying argstate->str.
157  */
158 static void
159 argstate_add_str(ARGSTATE *argstate, Boolean required)
160 {
161 	/* String table already loaded? */
162 	if (argstate->str.sec != NULL)
163 		return;
164 
165 	/*
166 	 * We can't proceed if the capabilities section does not have
167 	 * an associated string table.
168 	 */
169 	if (argstate->cap.sec->sec_shdr->sh_info == 0) {
170 		/* Error if the operation requires a string table */
171 		if (required)
172 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRTAB),
173 			    EC_WORD(argstate->cap.sec->sec_shndx),
174 			    argstate->cap.sec->sec_name);
175 		return;
176 	}
177 
178 	argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
179 	    argstate->cap.sec->sec_shdr->sh_info, 0);
180 }
181 
182 /*
183  * Given an index into the capabilities array, locate the index of the
184  * initial element in its capabilities group, and the number of elements
185  * in the group.
186  */
187 static void
188 cap_group_extents(ARGSTATE *argstate, Word ndx, Word *ret_start_ndx,
189     Word *ret_end_ndx)
190 {
191 	*ret_end_ndx = ndx;
192 
193 	/*
194 	 * The group starts with a non-NULL tag that is either the
195 	 * first tag in the array, or is preceded by a NULL tag.
196 	 */
197 	while ((ndx > 0) && (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL))
198 		ndx--;
199 	while ((ndx > 0) && (argstate->cap.data[ndx - 1].c_tag != CA_SUNW_NULL))
200 		ndx--;
201 	*ret_start_ndx = ndx;
202 
203 
204 	/*
205 	 * The group is terminated by a series of 1 or more NULL tags.
206 	 */
207 	ndx = *ret_end_ndx;
208 	while (((ndx + 1) < argstate->cap.num) &&
209 	    (argstate->cap.data[ndx].c_tag != CA_SUNW_NULL))
210 		ndx++;
211 	while (((ndx + 1) < argstate->cap.num) &&
212 	    (argstate->cap.data[ndx + 1].c_tag == CA_SUNW_NULL))
213 		ndx++;
214 	*ret_end_ndx = ndx;
215 }
216 
217 /*
218  * If a CA_SUNW_ID element exists within the current capabilities group
219  * in the given argument state, return the string pointer to the name.
220  * Otherwise return a pointer to a descriptive "noname" string.
221  */
222 static const char *
223 cap_group_id(ARGSTATE *argstate)
224 {
225 	Word		ndx = argstate->cap.grp_start_ndx;
226 	Cap		*cap = argstate->cap.data + ndx;
227 
228 	for (; ndx <= argstate->cap.grp_end_ndx; ndx++, cap++) {
229 		if (cap->c_tag == CA_SUNW_ID) {
230 			argstate_add_str(argstate, TRUE);
231 			return (elfedit_offset_to_str(argstate->str.sec,
232 			    cap->c_un.c_val, ELFEDIT_MSG_ERR, 0));
233 		}
234 
235 		if (cap->c_tag == CA_SUNW_NULL)
236 			break;
237 	}
238 
239 	return ((argstate->cap.grp_start_ndx == 0) ?
240 	    MSG_INTL(MSG_STR_OBJECT) : MSG_INTL(MSG_STR_NONAME));
241 }
242 
243 
244 /*
245  * Given an index into the capabilities array, set the argstate cap.grp_*
246  * fields to reflect the capabilities group containing the index.
247  *
248  * The group concept is used to limit operations to a related group
249  * of capabilities, and prevent insert/delete/move operations from
250  * spilling across groups.
251  */
252 static void
253 argstate_cap_group(ARGSTATE *argstate, Word ndx)
254 {
255 	if (argstate->cap.grp_set == TRUE)
256 		return;
257 
258 	cap_group_extents(argstate, ndx, &argstate->cap.grp_start_ndx,
259 	    &argstate->cap.grp_end_ndx);
260 
261 	argstate->cap.grp_set = TRUE;
262 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CAPGRP),
263 	    EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name,
264 	    EC_WORD(argstate->cap.grp_start_ndx),
265 	    EC_WORD(argstate->cap.grp_end_ndx), cap_group_id(argstate));
266 }
267 
268 /*
269  * Given an index into the capabilities array, issue a group title for
270  * the capabilities group that contains it.
271  */
272 static void
273 group_title(ARGSTATE *argstate, Word ndx)
274 {
275 	ARGSTATE	loc_argstate;
276 
277 	loc_argstate = *argstate;
278 	cap_group_extents(argstate, ndx, &loc_argstate.cap.grp_start_ndx,
279 	    &loc_argstate.cap.grp_end_ndx);
280 	elfedit_printf(MSG_INTL(MSG_FMT_CAPGRP),
281 	    EC_WORD(loc_argstate.cap.grp_start_ndx),
282 	    EC_WORD(loc_argstate.cap.grp_end_ndx), cap_group_id(&loc_argstate));
283 }
284 
285 /*
286  * Standard argument processing for cap module
287  *
288  * entry
289  *	obj_state, argc, argv - Standard command arguments
290  *	argstate - Address of ARGSTATE block to be initialized
291  *
292  * exit:
293  *	On success, *argstate is initialized. On error,
294  *	an error is issued and this routine does not return.
295  */
296 static void
297 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
298     ARGSTATE *argstate)
299 {
300 	elfedit_getopt_state_t	getopt_state;
301 	elfedit_getopt_ret_t	*getopt_ret;
302 	const char		*capid = NULL;
303 
304 	bzero(argstate, sizeof (*argstate));
305 	argstate->obj_state = obj_state;
306 
307 	elfedit_getopt_init(&getopt_state, &argc, &argv);
308 
309 	/* Add each new option to the options mask */
310 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
311 		argstate->optmask |= getopt_ret->gor_idmask;
312 
313 		if (getopt_ret->gor_idmask == CAP_OPT_F_CAPID)
314 			capid = getopt_ret->gor_value;
315 	}
316 
317 	/* If there may be an arbitrary amount of output, use a pager */
318 	if (argc == 0)
319 		elfedit_pager_init();
320 
321 	/* Return the updated values of argc/argv */
322 	argstate->argc = argc;
323 	argstate->argv = argv;
324 
325 	/* Locate the capabilities section */
326 	argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data,
327 	    &argstate->cap.num);
328 
329 	/*
330 	 * If -capid was specified, locate the specified capabilities group,
331 	 * and narrow the section data to use only that group. Otherwise,
332 	 * use the whole array.
333 	 */
334 	if (capid != NULL) {
335 		Word	i;
336 		Cap	*cap = argstate->cap.data;
337 
338 		/*
339 		 * -capid requires the capability section to have an
340 		 * associated string table.
341 		 */
342 		argstate_add_str(argstate, TRUE);
343 
344 		for (i = 0; i < argstate->cap.num; i++, cap++)
345 			if ((cap->c_tag == CA_SUNW_ID) &&
346 			    (strcmp(capid, elfedit_offset_to_str(
347 			    argstate->str.sec, cap->c_un.c_val,
348 			    ELFEDIT_MSG_ERR, 0)) == 0))
349 				break;
350 
351 		if (i == argstate->cap.num)
352 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCAPID),
353 			    EC_WORD(argstate->cap.sec->sec_shndx),
354 			    argstate->cap.sec->sec_name, capid);
355 		argstate_cap_group(argstate, i);
356 	} else {
357 		argstate->cap.grp_start_ndx = 0;
358 		argstate->cap.grp_end_ndx = argstate->cap.num - 1;
359 	}
360 }
361 
362 
363 
364 /*
365  * Print ELF capabilities values, taking the calling command, and output style
366  * into account.
367  *
368  * entry:
369  *	cmd - CAP_CMD_T_* value giving identify of caller
370  *	autoprint - If True, output is only produced if the elfedit
371  *		autoprint flag is set. If False, output is always produced.
372  *	argstate - Argument state block
373  *	print_type - Specifies which capabilities elements to display.
374  *	ndx = If print_type is PRINT_CAP_T_NDX, displays the index specified.
375  *		Otherwise ignored.
376  */
377 typedef enum {
378 	PRINT_CAP_T_ALL =	0,	/* Show all indexes */
379 	PRINT_CAP_T_NDX =	1,	/* Show capabilities[arg] only */
380 	PRINT_CAP_T_TAG =	2	/* Show all elts with tag type */
381 					/*	given by arg */
382 } PRINT_CAP_T;
383 
384 static void
385 print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate,
386     PRINT_CAP_T print_type, Word arg)
387 {
388 	elfedit_outstyle_t	outstyle;
389 	Word		cnt, ndx, printed = 0;
390 	Cap		*cap;
391 	Boolean		header_done = FALSE, null_seen = FALSE;
392 	const char	*str;
393 	size_t		str_size;
394 
395 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
396 		return;
397 
398 	/*
399 	 * Pick an output style. cap:dump is required to use the default
400 	 * style. The other commands use the current output style.
401 	 */
402 	outstyle = (cmd == CAP_CMD_T_DUMP) ?
403 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
404 
405 	/* How many elements do we examine? */
406 	if (print_type == PRINT_CAP_T_NDX) {
407 		if (arg >= argstate->cap.num)
408 			return;		/* Out of range */
409 		ndx = arg;
410 		cnt = 1;
411 	} else {
412 		ndx = argstate->cap.grp_start_ndx;
413 		cnt = argstate->cap.grp_end_ndx - ndx + 1;
414 	}
415 
416 	/* Load string table if there is one */
417 	argstate_add_str(argstate, FALSE);
418 	if (argstate->str.sec == NULL) {
419 		str = NULL;
420 		str_size = 0;
421 	} else {
422 		str = (const char *)argstate->str.sec->sec_data->d_buf;
423 		str_size = argstate->str.sec->sec_data->d_size;
424 	}
425 
426 	cap = &argstate->cap.data[ndx];
427 	for (; cnt--; cap++, ndx++) {
428 		/*
429 		 * If we are only displaying certain tag types and
430 		 * this isn't one of those, move on to next element.
431 		 */
432 		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg)) {
433 			if (cap->c_tag == CA_SUNW_NULL)
434 				null_seen = TRUE;
435 			continue;
436 		}
437 
438 		/*
439 		 * If capability type requires a string table, and we don't
440 		 * have one, force an error.
441 		 */
442 		switch (cap->c_tag) {
443 		case CA_SUNW_PLAT:
444 		case CA_SUNW_MACH:
445 		case CA_SUNW_ID:
446 			if (argstate->str.sec == NULL)
447 				argstate_add_str(argstate, TRUE);
448 			break;
449 		}
450 
451 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
452 			if (null_seen && (cap->c_tag != CA_SUNW_NULL)) {
453 				null_seen = FALSE;
454 				if (header_done) {
455 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
456 					    MSG_ORIG(MSG_STR_EMPTY));
457 					header_done = FALSE;
458 				}
459 			}
460 
461 			if (header_done == FALSE) {
462 				header_done = TRUE;
463 				group_title(argstate, ndx);
464 				Elf_cap_title(0);
465 			}
466 			Elf_cap_entry(NULL, cap, ndx, str, str_size,
467 			    argstate->obj_state->os_ehdr->e_machine);
468 		} else {
469 			/*
470 			 * If CAP_CMD_T_TAG, and not in default output
471 			 * style, display the tag rather than the value.
472 			 */
473 			if (cmd == CAP_CMD_T_TAG) {
474 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
475 					Conv_inv_buf_t	inv_buf;
476 
477 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
478 					    conv_cap_tag(cap->c_tag, 0,
479 					    &inv_buf));
480 				} else {
481 					elfedit_printf(
482 					    MSG_ORIG(MSG_FMT_WORDVALNL),
483 					    EC_WORD(cap->c_tag));
484 				}
485 				printed = 1;
486 				continue;
487 			}
488 
489 			/* Displaying the value in simple or numeric mode */
490 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
491 				Conv_cap_val_buf_t	cap_val_buf;
492 
493 				if (print_type == PRINT_CAP_T_TAG) {
494 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
495 					    conv_cap_val_hw1(cap->c_un.c_val,
496 					    argstate->obj_state->os_ehdr->
497 					    e_machine, CONV_FMT_NOBKT,
498 					    &cap_val_buf.cap_val_hw1_buf));
499 					printed = 1;
500 					continue;
501 				}
502 
503 				switch (cap->c_tag) {
504 				case CA_SUNW_HW_1:
505 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
506 					    conv_cap_val_hw1(cap->c_un.c_val,
507 					    argstate->obj_state->os_ehdr->
508 					    e_machine, CONV_FMT_NOBKT,
509 					    &cap_val_buf.cap_val_hw1_buf));
510 					printed = 1;
511 					continue;
512 				case CA_SUNW_SF_1:
513 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
514 					    conv_cap_val_sf1(cap->c_un.c_val,
515 					    argstate->obj_state->os_ehdr->
516 					    e_machine, CONV_FMT_NOBKT,
517 					    &cap_val_buf.cap_val_sf1_buf));
518 					printed = 1;
519 					continue;
520 				case CA_SUNW_HW_2:
521 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
522 					    conv_cap_val_hw2(cap->c_un.c_val,
523 					    argstate->obj_state->os_ehdr->
524 					    e_machine, CONV_FMT_NOBKT,
525 					    &cap_val_buf.cap_val_hw2_buf));
526 					printed = 1;
527 					continue;
528 				case CA_SUNW_PLAT:
529 				case CA_SUNW_MACH:
530 				case CA_SUNW_ID:
531 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
532 					    elfedit_offset_to_str(
533 					    argstate->str.sec, cap->c_un.c_val,
534 					    ELFEDIT_MSG_ERR, 0));
535 					printed = 1;
536 					continue;
537 				case CA_SUNW_HW_3:
538 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
539 					    conv_cap_val_hw3(cap->c_un.c_val,
540 					    argstate->obj_state->os_ehdr->
541 					    e_machine, CONV_FMT_NOBKT,
542 					    &cap_val_buf.cap_val_hw3_buf));
543 					printed = 1;
544 					continue;
545 				}
546 			}
547 			elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
548 			    EC_XWORD(cap->c_un.c_val));
549 		}
550 		printed = 1;
551 		if (cap->c_tag == CA_SUNW_NULL)
552 			null_seen = TRUE;
553 	}
554 
555 	/*
556 	 * If nothing was output under the print types that are
557 	 * based on tag type, issue an error saying it doesn't exist.
558 	 */
559 	if (!printed && (print_type == PRINT_CAP_T_TAG)) {
560 		Conv_inv_buf_t	inv_buf;
561 
562 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
563 		    EC_WORD(argstate->cap.sec->sec_shndx),
564 		    argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx,
565 		    argstate->cap.grp_end_ndx, cap_group_id(argstate),
566 		    conv_cap_tag(arg, 0, &inv_buf));
567 	}
568 }
569 
570 
571 /*
572  * Process the elt argument: This will be a tag type if -capndx is
573  * not present and this is a print request. It will be an index otherwise.
574  *
575  * entry:
576  *	argstate - Argument state block
577  *	arg - Argument string to be converted into an index
578  *	argname - String giving the name by which the argument is
579  *		referred in the online help for the command.
580  *	print_request - True if the command is to print the current
581  *		value(s) and return without changing anything.
582  *	print_type - Address of variable containing PRINT_CAP_T_
583  *		code specifying how the elements will be displayed.
584  *
585  * exit:
586  *	If print_request is False: arg is converted into an integer value.
587  *	If -capndx was used, we convert it into an integer. If it was not
588  *	used, then arg is a tag name --- we find the first capabilities entry
589  *	that matches. If no entry matches, and there is an extra CA_NULL,
590  *	it is added. Otherwise an error is issued. *print_type is set
591  *	to PRINT_CAP_T_NDX.
592  *
593  *	If print_request is True: If -capndx was used, arg is converted into
594  *	an integer value, *print_type is set to PRINT_CAP_T_NDX, and
595  *	the value is returned. If -capndx was not used, *print_type is set to
596  *	PRINT_CAP_T_TAG, and the tag value is returned.
597  */
598 static Word
599 arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname,
600     int print_request, PRINT_CAP_T *print_type)
601 {
602 	Word		ndx, ca_value;
603 
604 
605 	/* Assume we are returning an index, alter as needed below */
606 	*print_type = PRINT_CAP_T_NDX;
607 
608 	/*
609 	 * If -capndx was used, this is a simple numeric index.
610 	 * Determine its capability group because some operations
611 	 * (move, delete) are limited to operate within it.
612 	 */
613 	if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0) {
614 		ndx = (Word) elfedit_atoui_range(arg, argname, 0,
615 		    argstate->cap.num - 1, NULL);
616 		argstate_cap_group(argstate, ndx);
617 		return (ndx);
618 	}
619 
620 	/* The argument is a CA_ tag type, not a numeric index */
621 	ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA);
622 
623 	/*
624 	 * If this is a printing request, then we let print_cap() show
625 	 * all the items with this tag type.
626 	 */
627 	if (print_request) {
628 		*print_type = PRINT_CAP_T_TAG;
629 		return (ca_value);
630 	}
631 
632 	/*
633 	 * If we haven't determined a capability group yet, either via
634 	 * -capid, or -capndx, then make it the initial group, which
635 	 * represent the object capabilities.
636 	 */
637 	if (!argstate->cap.grp_set)
638 		argstate_cap_group(argstate, 0);
639 
640 	/*
641 	 * Locate the first entry with the given tag type within the
642 	 * capabilities group.
643 	 */
644 	for (ndx = argstate->cap.grp_start_ndx;
645 	    ndx <= argstate->cap.grp_end_ndx; ndx++) {
646 		if (argstate->cap.data[ndx].c_tag == ca_value) {
647 			elfedit_msg(ELFEDIT_MSG_DEBUG,
648 			    MSG_INTL(MSG_DEBUG_CA2NDX),
649 			    EC_WORD(argstate->cap.sec->sec_shndx),
650 			    argstate->cap.sec->sec_name, EC_WORD(ndx), arg);
651 			return (ndx);
652 		}
653 
654 		/*
655 		 * If we hit a NULL, then only more NULLs can follow it and
656 		 * there's no need to look further. If there is more than
657 		 * one NULL, we can grab the first one and turn it into
658 		 * an element of the desired type.
659 		 */
660 		if (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL) {
661 			if (ndx < argstate->cap.grp_end_ndx) {
662 				Conv_inv_buf_t	inv_buf;
663 
664 				elfedit_msg(ELFEDIT_MSG_DEBUG,
665 				    MSG_INTL(MSG_DEBUG_CONVNULL),
666 				    EC_WORD(argstate->cap.sec->sec_shndx),
667 				    argstate->cap.sec->sec_name, EC_WORD(ndx),
668 				    conv_cap_tag(ca_value, 0, &inv_buf));
669 				argstate->cap.data[ndx].c_tag = ca_value;
670 				bzero(&argstate->cap.data[ndx].c_un,
671 				    sizeof (argstate->cap.data[ndx].c_un));
672 				return (ndx);
673 			}
674 			break;
675 		}
676 	}
677 
678 	/* No room to create one, so we're out of options and must fail */
679 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
680 	    EC_WORD(argstate->cap.sec->sec_shndx),
681 	    argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx,
682 	    argstate->cap.grp_end_ndx, cap_group_id(argstate), arg);
683 
684 	/*NOTREACHED*/
685 	return (0);		/* For lint */
686 }
687 
688 
689 /*
690  * Argument processing for the bitmask commands. Convert the arguments
691  * to integer form, apply -and/-cmp/-or, and return the resulting value.
692  *
693  * entry:
694  *	argstate - Argument state block
695  *	orig - Value of original bitmask
696  *	const_sym - NULL, or array of name->integer mappings for
697  *		applicable symbolic constant names.
698  */
699 static Word
700 flag_bitop(ARGSTATE *argstate, Word orig, const elfedit_atoui_sym_t *const_sym)
701 {
702 	Word flags = 0;
703 	int i;
704 
705 	/* Collect the arguments */
706 	for (i = 0; i < argstate->argc; i++)
707 		flags |= (Word) elfedit_atoui(argstate->argv[i], const_sym);
708 
709 	/* Complement the value? */
710 	if (argstate->optmask & CAP_OPT_F_CMP)
711 		flags = ~flags;
712 
713 	/* Perform any requested bit operations */
714 	if (argstate->optmask & CAP_OPT_F_AND)
715 		flags &= orig;
716 	else if (argstate->optmask & CAP_OPT_F_OR)
717 		flags |= orig;
718 
719 	return (flags);
720 }
721 
722 /*
723  * Common processing for capabilities value setting.
724  *
725  * entry:
726  *	argstate - Argument state block
727  *	cap - capabilities data pointer
728  *	ndx - capabilities data index
729  *	cap_ndx - capabilities section index
730  *	cap_name - capabilities section name
731  *	cap_tag - capabilities tag
732  *	const_type - data conversion type
733  */
734 static elfedit_cmdret_t
735 cap_set(ARGSTATE *argstate, Cap *cap, Word ndx, Word cap_ndx,
736     const char *cap_name, Xword cap_tag, elfedit_const_t const_type)
737 {
738 	Conv_cap_val_buf_t	buf1, buf2;
739 	Half			mach = argstate->obj_state->os_ehdr->e_machine;
740 	Xword			ncap, ocap;
741 
742 	ncap = flag_bitop(argstate, cap[ndx].c_un.c_val,
743 	    elfedit_const_to_atoui(const_type));
744 
745 	/* Set the value */
746 	if ((ocap = cap[ndx].c_un.c_val) == ncap) {
747 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_OK),
748 		    cap_ndx, cap_name, EC_WORD(ndx),
749 		    conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1));
750 
751 		return (ELFEDIT_CMDRET_NONE);
752 	} else {
753 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_CHG),
754 		    cap_ndx, cap_name, EC_WORD(ndx),
755 		    conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1),
756 		    conv_cap_val(cap_tag, ncap, mach, CONV_FMT_NOBKT, &buf2));
757 
758 		cap[ndx].c_un.c_val = ncap;
759 		return (ELFEDIT_CMDRET_MOD);
760 	}
761 }
762 
763 /*
764  * Common body for the cap: module commands. These commands
765  * share a large amount of common behavior, so it is convenient
766  * to centralize things and use the cmd argument to handle the
767  * small differences.
768  *
769  * entry:
770  *	cmd - One of the CAP_CMD_T_* constants listed above, specifying
771  *		which command to implement.
772  *	obj_state, argc, argv - Standard command arguments
773  */
774 static elfedit_cmdret_t
775 cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state,
776     int argc, const char *argv[])
777 {
778 	ARGSTATE		argstate;
779 	Cap			*cap;
780 	const char		*cap_name;
781 	Word			cap_ndx;
782 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
783 	PRINT_CAP_T		print_type = PRINT_CAP_T_ALL;
784 	Word			ndx;
785 	int			print_only = 0;
786 	int			do_autoprint = 1;
787 
788 	/* Process the optional arguments */
789 	process_args(obj_state, argc, argv, &argstate);
790 
791 	cap = argstate.cap.data;
792 	cap_name = argstate.cap.sec->sec_name;
793 	cap_ndx = argstate.cap.sec->sec_shndx;
794 
795 	/* Check number of arguments, gather information */
796 	switch (cmd) {
797 	case CAP_CMD_T_DUMP:
798 		/* cap:dump can accept an optional index argument */
799 		if (argstate.argc > 1)
800 			elfedit_command_usage();
801 		print_only = 1;
802 		if (argstate.argc == 1)
803 			ndx = arg_to_index(&argstate, argstate.argv[0],
804 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
805 		break;
806 
807 	case CAP_CMD_T_TAG:
808 	case CAP_CMD_T_VALUE:
809 		print_only = (argstate.argc != 2);
810 		if (argstate.argc > 0) {
811 			if (argstate.argc > 2)
812 				elfedit_command_usage();
813 			ndx = arg_to_index(&argstate, argstate.argv[0],
814 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
815 		}
816 		break;
817 
818 	case CAP_CMD_T_DELETE:
819 		if ((argstate.argc < 1) || (argstate.argc > 2))
820 			elfedit_command_usage();
821 		ndx = arg_to_index(&argstate, argstate.argv[0],
822 		    MSG_ORIG(MSG_STR_ELT),
823 		    0, &print_type);
824 		do_autoprint = 0;
825 		break;
826 
827 	case CAP_CMD_T_MOVE:
828 		if ((argstate.argc < 2) || (argstate.argc > 3))
829 			elfedit_command_usage();
830 		ndx = arg_to_index(&argstate, argstate.argv[0],
831 		    MSG_ORIG(MSG_STR_ELT), 0, &print_type);
832 		do_autoprint = 0;
833 		break;
834 
835 	case CAP_CMD_T_HW1:
836 		print_only = (argstate.argc == 0);
837 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
838 		    ELFEDIT_CONST_CA, CA_SUNW_HW_1, 1),
839 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
840 		break;
841 
842 	case CAP_CMD_T_SF1:
843 		print_only = (argstate.argc == 0);
844 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
845 		    ELFEDIT_CONST_CA, CA_SUNW_SF_1, 1),
846 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
847 		break;
848 
849 	case CAP_CMD_T_HW2:
850 		print_only = (argstate.argc == 0);
851 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
852 		    ELFEDIT_CONST_CA, CA_SUNW_HW_2, 1),
853 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
854 		break;
855 
856 	case CAP_CMD_T_HW3:
857 		print_only = (argstate.argc == 0);
858 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
859 		    ELFEDIT_CONST_CA, CA_SUNW_HW_3, 1),
860 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
861 		break;
862 
863 	default:
864 		/* Note expected: All commands should have been caught above */
865 		elfedit_command_usage();
866 		break;
867 	}
868 
869 
870 	/* If this is a request to print current values, do it and return */
871 	if (print_only) {
872 		print_cap(cmd, 0, &argstate, print_type, ndx);
873 		return (ELFEDIT_CMDRET_NONE);
874 	}
875 
876 
877 	switch (cmd) {
878 		/*
879 		 * CAP_CMD_T_DUMP can't get here: It is a print-only
880 		 * command.
881 		 */
882 
883 	case CAP_CMD_T_TAG:
884 		{
885 			Conv_inv_buf_t	inv_buf1, inv_buf2;
886 			Word c_tag = (Word) elfedit_atoconst(argstate.argv[1],
887 			    ELFEDIT_CONST_CA);
888 
889 			if (cap[ndx].c_tag == c_tag) {
890 				elfedit_msg(ELFEDIT_MSG_DEBUG,
891 				    MSG_INTL(MSG_DEBUG_S_OK),
892 				    cap_ndx, cap_name, EC_WORD(ndx),
893 				    conv_cap_tag(c_tag, 0, &inv_buf1));
894 			} else {
895 				elfedit_msg(ELFEDIT_MSG_DEBUG,
896 				    MSG_INTL(MSG_DEBUG_S_CHG),
897 				    cap_ndx, cap_name, EC_WORD(ndx),
898 				    conv_cap_tag(cap[ndx].c_tag, 0, &inv_buf1),
899 				    conv_cap_tag(c_tag, 0, &inv_buf2));
900 				cap[ndx].c_tag = c_tag;
901 				ret = ELFEDIT_CMDRET_MOD;
902 			}
903 		}
904 		break;
905 
906 	case CAP_CMD_T_VALUE:
907 		{
908 			Xword c_val;
909 
910 			if (argstate.optmask & CAP_OPT_F_STRVAL) {
911 				argstate_add_str(&argstate, TRUE);
912 				c_val = elfedit_strtab_insert(obj_state,
913 				    argstate.str.sec, NULL, argstate.argv[1]);
914 			} else {
915 				c_val = (Xword)
916 				    elfedit_atoui(argstate.argv[1], NULL);
917 			}
918 
919 			if (cap[ndx].c_un.c_val == c_val) {
920 				elfedit_msg(ELFEDIT_MSG_DEBUG,
921 				    MSG_INTL(MSG_DEBUG_X_OK),
922 				    argstate.cap.sec->sec_shndx,
923 				    argstate.cap.sec->sec_name,
924 				    EC_WORD(ndx), EC_XWORD(c_val));
925 			} else {
926 				elfedit_msg(ELFEDIT_MSG_DEBUG,
927 				    MSG_INTL(MSG_DEBUG_X_CHG),
928 				    argstate.cap.sec->sec_shndx,
929 				    argstate.cap.sec->sec_name,
930 				    EC_WORD(ndx), EC_XWORD(cap[ndx].c_un.c_val),
931 				    EC_XWORD(c_val));
932 				cap[ndx].c_un.c_val = c_val;
933 				ret = ELFEDIT_CMDRET_MOD;
934 			}
935 		}
936 		break;
937 
938 	case CAP_CMD_T_DELETE:
939 		{
940 			Word cnt = (argstate.argc == 1) ? 1 :
941 			    (Word) elfedit_atoui_range(argstate.argv[1],
942 			    MSG_ORIG(MSG_STR_COUNT), 1,
943 			    argstate.cap.grp_end_ndx - ndx + 1, NULL);
944 			const char *msg_prefix =
945 			    elfedit_sec_msgprefix(argstate.cap.sec);
946 
947 			/*
948 			 * We want to limit the deleted elements to be
949 			 * in the range of the current capabilities group,
950 			 * and for the resulting NULL elements to be inserted
951 			 * at the end of the group, rather than at the end
952 			 * of the section. To do this, we set the array length
953 			 * in the call to the delete function so that it thinks
954 			 * the array ends with the current group.
955 			 *
956 			 * The delete function will catch attempts to delete
957 			 * past this virtual end, but the error message will
958 			 * not make sense to the user. In order to prevent that,
959 			 * we check for the condition here and provide a more
960 			 * useful error.
961 			 */
962 			if ((ndx + cnt - 1) > argstate.cap.grp_end_ndx)
963 				elfedit_msg(ELFEDIT_MSG_ERR,
964 				    MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix,
965 				    argstate.cap.grp_start_ndx,
966 				    argstate.cap.grp_end_ndx,
967 				    cap_group_id(&argstate));
968 			elfedit_array_elts_delete(msg_prefix, cap, sizeof (Cap),
969 			    argstate.cap.grp_end_ndx + 1, ndx, cnt);
970 			ret = ELFEDIT_CMDRET_MOD;
971 		}
972 		break;
973 
974 	case CAP_CMD_T_MOVE:
975 		{
976 			Cap	save;
977 			Word	cnt;
978 			Word	dstndx;
979 			const char *msg_prefix =
980 			    elfedit_sec_msgprefix(argstate.cap.sec);
981 
982 			dstndx = (Word)
983 			    elfedit_atoui_range(argstate.argv[1],
984 			    MSG_ORIG(MSG_STR_DST_INDEX),
985 			    argstate.cap.grp_start_ndx,
986 			    argstate.cap.grp_end_ndx, NULL);
987 			if (argstate.argc == 2) {
988 				cnt = 1;
989 			} else {
990 				Word max;
991 
992 				max = argstate.cap.grp_end_ndx -
993 				    ((ndx > dstndx) ? ndx : dstndx) + 1;
994 				cnt = (Word) elfedit_atoui_range(
995 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
996 				    1, max, NULL);
997 			}
998 
999 			/*
1000 			 * Moves are required to be self contained within
1001 			 * the bounds of the selected capability group.
1002 			 * The move utility function contains bounds checking,
1003 			 * but is not sub-array aware. Hence, we bounds check
1004 			 * check it here, and then hand of the validated
1005 			 * operation to the move utility function to execute.
1006 			 */
1007 			if ((ndx < argstate.cap.grp_start_ndx) ||
1008 			    ((ndx + cnt) > argstate.cap.grp_end_ndx) ||
1009 			    (dstndx < argstate.cap.grp_start_ndx) ||
1010 			    ((dstndx + cnt) > argstate.cap.grp_end_ndx))
1011 				elfedit_msg(ELFEDIT_MSG_ERR,
1012 				    MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix,
1013 				    argstate.cap.grp_start_ndx,
1014 				    argstate.cap.grp_end_ndx,
1015 				    cap_group_id(&argstate));
1016 			elfedit_array_elts_move(msg_prefix, cap, sizeof (save),
1017 			    argstate.cap.grp_end_ndx + 1, ndx, dstndx,
1018 			    cnt, &save);
1019 			ret = ELFEDIT_CMDRET_MOD;
1020 		}
1021 		break;
1022 
1023 
1024 	case CAP_CMD_T_HW1:
1025 		{
1026 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1027 			    CA_SUNW_HW_1, ELFEDIT_CONST_HW1_SUNW);
1028 		}
1029 		break;
1030 
1031 	case CAP_CMD_T_SF1:
1032 		{
1033 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1034 			    CA_SUNW_SF_1, ELFEDIT_CONST_SF1_SUNW);
1035 		}
1036 		break;
1037 
1038 	case CAP_CMD_T_HW2:
1039 		{
1040 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1041 			    CA_SUNW_HW_2, ELFEDIT_CONST_HW2_SUNW);
1042 		}
1043 		break;
1044 
1045 	case CAP_CMD_T_HW3:
1046 		{
1047 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1048 			    CA_SUNW_HW_3, ELFEDIT_CONST_HW3_SUNW);
1049 		}
1050 		break;
1051 
1052 	}
1053 
1054 	/*
1055 	 * If we modified the capabilities section header, tell libelf.
1056 	 */
1057 	if (ret == ELFEDIT_CMDRET_MOD)
1058 		elfedit_modified_data(argstate.cap.sec);
1059 
1060 	/* Do autoprint */
1061 	if (do_autoprint)
1062 		print_cap(cmd, 1, &argstate, print_type, ndx);
1063 
1064 	return (ret);
1065 }
1066 
1067 
1068 
1069 /*
1070  * Command completion functions for the commands
1071  */
1072 
1073 /*
1074  * -capid command completion: Supply all CA_SUNW_ID names found in the object.
1075  */
1076 static void
1077 cpl_capid_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1078     const char *argv[], int num_opt)
1079 {
1080 	elfedit_section_t	*cap_sec, *str_sec;
1081 	Cap			*cap;
1082 	Word			num;
1083 
1084 	if (obj_state == NULL)	 /* No object available */
1085 		return;
1086 
1087 	if ((argc > num_opt) || (argc < 2) ||
1088 	    (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_CAPID)) != 0))
1089 		return;
1090 
1091 	cap_sec = elfedit_sec_getcap(obj_state, &cap, &num);
1092 
1093 	/* If no associated string table, we have no strings to complete */
1094 	if (cap_sec->sec_shdr->sh_info == 0)
1095 		return;
1096 
1097 	str_sec = elfedit_sec_getstr(obj_state, cap_sec->sec_shdr->sh_info, 0);
1098 
1099 	for (; num--; cap++)
1100 		if (cap->c_tag == CA_SUNW_ID)
1101 			elfedit_cpl_match(cpldata, elfedit_offset_to_str(
1102 			    str_sec, cap->c_un.c_val, ELFEDIT_MSG_ERR, 0), 0);
1103 }
1104 
1105 /*
1106  * Command completion for the first argument, which specifies
1107  * the capabilities element to use. Examines the options to see if
1108  * -capndx is present, and if not, supplies the completion
1109  * strings for argument 1.
1110  */
1111 /*ARGSUSED*/
1112 static void
1113 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1114     const char *argv[], int num_opt)
1115 {
1116 	Word	i;
1117 
1118 	/* -capid id_name */
1119 	if (argc <= num_opt) {
1120 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1121 		return;
1122 	}
1123 
1124 	/* Make sure it's the first argument */
1125 	if ((argc - num_opt) != 1)
1126 		return;
1127 
1128 	/* Is -capndx present? If so, we don't complete tag types */
1129 	for (i = 0; i < num_opt; i++)
1130 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_CAPNDX)) == 0)
1131 			return;
1132 
1133 	/*
1134 	 * Supply capability tag names. There are very few of these, so
1135 	 * rather than worry about whether a given tag exists in the
1136 	 * file or not, we simply serve up all the possibilities.
1137 	 */
1138 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
1139 }
1140 
1141 /*ARGSUSED*/
1142 static void
1143 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1144     const char *argv[], int num_opt)
1145 {
1146 	/* -capid id_name */
1147 	if (argc <= num_opt) {
1148 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1149 		return;
1150 	}
1151 
1152 	/* First plain argument */
1153 	if ((argc - num_opt) == 1) {
1154 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
1155 		return;
1156 	}
1157 
1158 	/* The second argument is always a tag value */
1159 	if ((argc - num_opt) == 2)
1160 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
1161 }
1162 
1163 /*ARGSUSED*/
1164 static void
1165 cpl_hw1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1166     const char *argv[], int num_opt)
1167 {
1168 	/* -capid id_name */
1169 	if (argc <= num_opt) {
1170 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1171 		return;
1172 	}
1173 
1174 	/* This routine allows multiple flags to be specified */
1175 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW1_SUNW);
1176 }
1177 
1178 /*ARGSUSED*/
1179 static void
1180 cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1181     const char *argv[], int num_opt)
1182 {
1183 	/* -capid id_name */
1184 	if (argc <= num_opt) {
1185 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1186 		return;
1187 	}
1188 
1189 	/* This routine allows multiple flags to be specified */
1190 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW);
1191 }
1192 
1193 /*ARGSUSED*/
1194 static void
1195 cpl_hw2(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1196     const char *argv[], int num_opt)
1197 {
1198 	/* -capid id_name */
1199 	if (argc <= num_opt) {
1200 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1201 		return;
1202 	}
1203 
1204 	/* This routine allows multiple flags to be specified */
1205 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW2_SUNW);
1206 }
1207 
1208 static void
1209 cpl_hw3(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1210     const char *argv[], int num_opt)
1211 {
1212 	/* -capid id_name */
1213 	if (argc <= num_opt) {
1214 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1215 		return;
1216 	}
1217 
1218 	/* This routine allows multiple flags to be specified */
1219 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW3_SUNW);
1220 }
1221 /*
1222  * Implementation functions for the commands
1223  */
1224 static elfedit_cmdret_t
1225 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1226 {
1227 	return (cmd_body(CAP_CMD_T_DUMP, obj_state, argc, argv));
1228 }
1229 
1230 static elfedit_cmdret_t
1231 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1232 {
1233 	return (cmd_body(CAP_CMD_T_TAG, obj_state, argc, argv));
1234 }
1235 
1236 static elfedit_cmdret_t
1237 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1238 {
1239 	return (cmd_body(CAP_CMD_T_VALUE, obj_state, argc, argv));
1240 }
1241 
1242 static elfedit_cmdret_t
1243 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1244 {
1245 	return (cmd_body(CAP_CMD_T_DELETE, obj_state, argc, argv));
1246 }
1247 
1248 static elfedit_cmdret_t
1249 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1250 {
1251 	return (cmd_body(CAP_CMD_T_MOVE, obj_state, argc, argv));
1252 }
1253 
1254 static elfedit_cmdret_t
1255 cmd_hw1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1256 {
1257 	return (cmd_body(CAP_CMD_T_HW1, obj_state, argc, argv));
1258 }
1259 
1260 static elfedit_cmdret_t
1261 cmd_sf1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1262 {
1263 	return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv));
1264 }
1265 
1266 static elfedit_cmdret_t
1267 cmd_hw2(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1268 {
1269 	return (cmd_body(CAP_CMD_T_HW2, obj_state, argc, argv));
1270 }
1271 
1272 static elfedit_cmdret_t
1273 cmd_hw3(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1274 {
1275 	return (cmd_body(CAP_CMD_T_HW3, obj_state, argc, argv));
1276 }
1277 
1278 /*ARGSUSED*/
1279 elfedit_module_t *
1280 elfedit_init(elfedit_module_version_t version)
1281 {
1282 	/* For commands that only accept -capid, -and, -cmp, -o, and -or */
1283 	static elfedit_cmd_optarg_t opt_ostyle_capid_bitop[] = {
1284 		{ ELFEDIT_STDOA_OPT_AND, 0,
1285 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR },
1286 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1287 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1288 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1289 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1290 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1291 		{ ELFEDIT_STDOA_OPT_CMP, 0,
1292 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
1293 		{ ELFEDIT_STDOA_OPT_O, 0,
1294 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1295 		{ ELFEDIT_STDOA_OPT_OR, 0,
1296 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_OR, CAP_OPT_F_AND },
1297 		{ NULL }
1298 	};
1299 
1300 	/* For commands that only accept -capid and -capndx */
1301 	static elfedit_cmd_optarg_t opt_capid_capndx[] = {
1302 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1303 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1304 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1305 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1306 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1307 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
1308 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
1309 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
1310 		    CAP_OPT_F_CAPNDX, CAP_OPT_F_CAPID },
1311 		{ NULL }
1312 	};
1313 
1314 
1315 	/* cap:dump */
1316 	static const char *name_dump[] = {
1317 	    MSG_ORIG(MSG_CMD_DUMP),
1318 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
1319 	    NULL
1320 	};
1321 	static elfedit_cmd_optarg_t arg_dump[] = {
1322 		{ MSG_ORIG(MSG_STR_ELT),
1323 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1324 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1325 		    ELFEDIT_CMDOA_F_OPT },
1326 		{ NULL }
1327 	};
1328 
1329 
1330 	/* cap:tag */
1331 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
1332 	static elfedit_cmd_optarg_t opt_tag[] = {
1333 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1334 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1335 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1336 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1337 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1338 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
1339 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
1340 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
1341 		    CAP_OPT_F_CAPNDX, 0 },
1342 		{ ELFEDIT_STDOA_OPT_O, 0,
1343 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1344 		{ NULL }
1345 	};
1346 	static elfedit_cmd_optarg_t arg_tag[] = {
1347 		{ MSG_ORIG(MSG_STR_ELT),
1348 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
1349 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
1350 		    ELFEDIT_CMDOA_F_OPT },
1351 		{ MSG_ORIG(MSG_STR_VALUE),
1352 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
1353 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
1354 		    ELFEDIT_CMDOA_F_OPT },
1355 		{ NULL }
1356 	};
1357 
1358 
1359 	/* cap:value */
1360 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
1361 	static elfedit_cmd_optarg_t opt_value[] = {
1362 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1363 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1364 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1365 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1366 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1367 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
1368 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
1369 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
1370 		    CAP_OPT_F_CAPNDX, 0 },
1371 		{ ELFEDIT_STDOA_OPT_O, 0,
1372 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1373 		{ MSG_ORIG(MSG_STR_MINUS_S),
1374 		    /* MSG_INTL(MSG_OPTDESC_S) */
1375 		    ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
1376 		    CAP_OPT_F_STRVAL, 0 },
1377 		{ NULL }
1378 	};
1379 	static elfedit_cmd_optarg_t arg_value[] = {
1380 		{ MSG_ORIG(MSG_STR_ELT),
1381 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1382 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1383 		    ELFEDIT_CMDOA_F_OPT },
1384 		{ MSG_ORIG(MSG_STR_VALUE),
1385 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
1386 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
1387 		    ELFEDIT_CMDOA_F_OPT },
1388 		{ NULL }
1389 	};
1390 
1391 	/* cap:delete */
1392 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
1393 	static elfedit_cmd_optarg_t arg_delete[] = {
1394 		{ MSG_ORIG(MSG_STR_ELT),
1395 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1396 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1397 		    0 },
1398 		{ MSG_ORIG(MSG_STR_COUNT),
1399 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
1400 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
1401 		    ELFEDIT_CMDOA_F_OPT },
1402 		{ NULL }
1403 	};
1404 
1405 	/* cap:move */
1406 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
1407 	static elfedit_cmd_optarg_t arg_move[] = {
1408 		{ MSG_ORIG(MSG_STR_ELT),
1409 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1410 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1411 		    0 },
1412 		{ MSG_ORIG(MSG_STR_DST_INDEX),
1413 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
1414 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
1415 		    0 },
1416 		{ MSG_ORIG(MSG_STR_COUNT),
1417 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
1418 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
1419 		    ELFEDIT_CMDOA_F_OPT },
1420 		{ NULL }
1421 	};
1422 
1423 	/* cap:hw1 */
1424 	static const char *name_hw1[] = { MSG_ORIG(MSG_CMD_HW1), NULL };
1425 	static elfedit_cmd_optarg_t arg_hw1[] = {
1426 		{ MSG_ORIG(MSG_STR_VALUE),
1427 		    /* MSG_INTL(MSG_A1_HW1_VALUE) */
1428 		    ELFEDIT_I18NHDL(MSG_A1_HW1_VALUE),
1429 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1430 		{ NULL }
1431 	};
1432 
1433 	/* cap:sf1 */
1434 	static const char *name_sf1[] = { MSG_ORIG(MSG_CMD_SF1), NULL };
1435 	static elfedit_cmd_optarg_t arg_sf1[] = {
1436 		{ MSG_ORIG(MSG_STR_VALUE),
1437 		    /* MSG_INTL(MSG_A1_SF1_VALUE) */
1438 		    ELFEDIT_I18NHDL(MSG_A1_SF1_VALUE),
1439 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1440 		{ NULL }
1441 	};
1442 
1443 	/* cap:hw2 */
1444 	static const char *name_hw2[] = { MSG_ORIG(MSG_CMD_HW2), NULL };
1445 	static elfedit_cmd_optarg_t arg_hw2[] = {
1446 		{ MSG_ORIG(MSG_STR_VALUE),
1447 		    /* MSG_INTL(MSG_A1_HW2_VALUE) */
1448 		    ELFEDIT_I18NHDL(MSG_A1_HW2_VALUE),
1449 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1450 		{ NULL }
1451 	};
1452 
1453 	/* cap:hw3 */
1454 	static const char *name_hw3[] = { MSG_ORIG(MSG_CMD_HW3), NULL };
1455 	static elfedit_cmd_optarg_t arg_hw3[] = {
1456 		{ MSG_ORIG(MSG_STR_VALUE),
1457 		    /* MSG_INTL(MSG_A1_HW3_VALUE) */
1458 		    ELFEDIT_I18NHDL(MSG_A1_HW3_VALUE),
1459 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1460 		{ NULL }
1461 	};
1462 
1463 	static elfedit_cmd_t cmds[] = {
1464 		/* cap:dump */
1465 		{ cmd_dump, cpl_eltarg, name_dump,
1466 		    /* MSG_INTL(MSG_DESC_DUMP) */
1467 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
1468 		    /* MSG_INTL(MSG_HELP_DUMP) */
1469 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
1470 		    opt_capid_capndx, arg_dump },
1471 
1472 		/* cap:tag */
1473 		{ cmd_tag, cpl_tag, name_tag,
1474 		    /* MSG_INTL(MSG_DESC_TAG) */
1475 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
1476 		    /* MSG_INTL(MSG_HELP_TAG) */
1477 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
1478 		    opt_tag, arg_tag },
1479 
1480 		/* cap:value */
1481 		{ cmd_value, cpl_eltarg, name_value,
1482 		    /* MSG_INTL(MSG_DESC_VALUE) */
1483 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
1484 		    /* MSG_INTL(MSG_HELP_VALUE) */
1485 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
1486 		    opt_value, arg_value },
1487 
1488 		/* cap:delete */
1489 		{ cmd_delete, cpl_eltarg, name_delete,
1490 		    /* MSG_INTL(MSG_DESC_DELETE) */
1491 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
1492 		    /* MSG_INTL(MSG_HELP_DELETE) */
1493 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
1494 		    opt_capid_capndx, arg_delete },
1495 
1496 		/* cap:move */
1497 		{ cmd_move, cpl_eltarg, name_move,
1498 		    /* MSG_INTL(MSG_DESC_MOVE) */
1499 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
1500 		    /* MSG_INTL(MSG_HELP_MOVE) */
1501 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
1502 		    opt_capid_capndx, arg_move },
1503 
1504 		/* cap:hw1 */
1505 		{ cmd_hw1, cpl_hw1, name_hw1,
1506 		    /* MSG_INTL(MSG_DESC_HW1) */
1507 		    ELFEDIT_I18NHDL(MSG_DESC_HW1),
1508 		    /* MSG_INTL(MSG_HELP_HW1) */
1509 		    ELFEDIT_I18NHDL(MSG_HELP_HW1),
1510 		    opt_ostyle_capid_bitop, arg_hw1 },
1511 
1512 		/* cap:sf1 */
1513 		{ cmd_sf1, cpl_sf1, name_sf1,
1514 		    /* MSG_INTL(MSG_DESC_SF1) */
1515 		    ELFEDIT_I18NHDL(MSG_DESC_SF1),
1516 		    /* MSG_INTL(MSG_HELP_SF1) */
1517 		    ELFEDIT_I18NHDL(MSG_HELP_SF1),
1518 		    opt_ostyle_capid_bitop, arg_sf1 },
1519 
1520 		/* cap:hw2 */
1521 		{ cmd_hw2, cpl_hw2, name_hw2,
1522 		    /* MSG_INTL(MSG_DESC_HW2) */
1523 		    ELFEDIT_I18NHDL(MSG_DESC_HW2),
1524 		    /* MSG_INTL(MSG_HELP_HW2) */
1525 		    ELFEDIT_I18NHDL(MSG_HELP_HW2),
1526 		    opt_ostyle_capid_bitop, arg_hw2 },
1527 
1528 		/* cap:hw3 */
1529 		{ cmd_hw3, cpl_hw3, name_hw3,
1530 		    /* MSG_INTL(MSG_DESC_HW3) */
1531 		    ELFEDIT_I18NHDL(MSG_DESC_HW3),
1532 		    /* MSG_INTL(MSG_HELP_HW3) */
1533 		    ELFEDIT_I18NHDL(MSG_HELP_HW3),
1534 		    opt_ostyle_capid_bitop, arg_hw3 },
1535 
1536 		{ NULL }
1537 	};
1538 
1539 	static elfedit_module_t module = {
1540 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
1541 	    /* MSG_INTL(MSG_MOD_DESC) */
1542 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
1543 	    cmds, mod_i18nhdl_to_str };
1544 
1545 	return (&module);
1546 }
1547