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