1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * memtoy:  commands.c - command line interface
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * A brute force/ad hoc command interpreter:
5f08c3bdfSopenharmony_ci * + parse commands [interactive or batch]
6f08c3bdfSopenharmony_ci * + convert/validate arguments
7f08c3bdfSopenharmony_ci * + some general/administrative commands herein
8f08c3bdfSopenharmony_ci * + actual segment management routines in segment.c
9f08c3bdfSopenharmony_ci */
10f08c3bdfSopenharmony_ci/*
11f08c3bdfSopenharmony_ci *  Copyright (c) 2005 Hewlett-Packard, Inc
12f08c3bdfSopenharmony_ci *  All rights reserved.
13f08c3bdfSopenharmony_ci */
14f08c3bdfSopenharmony_ci
15f08c3bdfSopenharmony_ci/*
16f08c3bdfSopenharmony_ci *  This program is free software; you can redistribute it and/or modify
17f08c3bdfSopenharmony_ci *  it under the terms of the GNU General Public License as published by
18f08c3bdfSopenharmony_ci *  the Free Software Foundation; either version 2 of the License, or
19f08c3bdfSopenharmony_ci *  (at your option) any later version.
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci *  This program is distributed in the hope that it will be useful,
22f08c3bdfSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23f08c3bdfSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24f08c3bdfSopenharmony_ci *  GNU General Public License for more details.
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci *  You should have received a copy of the GNU General Public License
27f08c3bdfSopenharmony_ci *  along with this program; if not, write to the Free Software
28f08c3bdfSopenharmony_ci *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
29f08c3bdfSopenharmony_ci */
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci#include "config.h"
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci#ifdef HAVE_NUMA_V2
34f08c3bdfSopenharmony_ci#include <sys/types.h>
35f08c3bdfSopenharmony_ci#include <sys/time.h>
36f08c3bdfSopenharmony_ci#include <sys/mman.h>
37f08c3bdfSopenharmony_ci#include <ctype.h>
38f08c3bdfSopenharmony_ci#include <errno.h>
39f08c3bdfSopenharmony_ci#include <fcntl.h>
40f08c3bdfSopenharmony_ci#include <numa.h>
41f08c3bdfSopenharmony_ci#include <numaif.h>
42f08c3bdfSopenharmony_ci#include <stdarg.h>
43f08c3bdfSopenharmony_ci#include <stdlib.h>
44f08c3bdfSopenharmony_ci#include <stdio.h>
45f08c3bdfSopenharmony_ci#include <string.h>
46f08c3bdfSopenharmony_ci#include <unistd.h>
47f08c3bdfSopenharmony_ci#include <sys/syscall.h>
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci#include "memtoy.h"
50f08c3bdfSopenharmony_ci#include "test.h"
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci#define CMD_SUCCESS 0
53f08c3bdfSopenharmony_ci#define CMD_ERROR   1
54f08c3bdfSopenharmony_ci#define CMDBUFSZ 256
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci#ifndef __NR_migrate_pages
57f08c3bdfSopenharmony_ci#define __NR_migrate_pages 0
58f08c3bdfSopenharmony_ci#endif
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci#ifndef MPOL_MF_WAIT
61f08c3bdfSopenharmony_ci#define MPOL_MF_WAIT    (1<<2)	/* Wait for existing pages to migrate */
62f08c3bdfSopenharmony_ci#endif
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_cistatic inline int nodemask_isset(nodemask_t * mask, int node)
65f08c3bdfSopenharmony_ci{
66f08c3bdfSopenharmony_ci	if ((unsigned)node >= NUMA_NUM_NODES)
67f08c3bdfSopenharmony_ci		return 0;
68f08c3bdfSopenharmony_ci	if (mask->n[node / (8 * sizeof(unsigned long))] &
69f08c3bdfSopenharmony_ci	    (1UL << (node % (8 * sizeof(unsigned long)))))
70f08c3bdfSopenharmony_ci		return 1;
71f08c3bdfSopenharmony_ci	return 0;
72f08c3bdfSopenharmony_ci}
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_cistatic inline void nodemask_set(nodemask_t * mask, int node)
75f08c3bdfSopenharmony_ci{
76f08c3bdfSopenharmony_ci	mask->n[node / (8 * sizeof(unsigned long))] |=
77f08c3bdfSopenharmony_ci	    (1UL << (node % (8 * sizeof(unsigned long))));
78f08c3bdfSopenharmony_ci}
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_cistatic char *whitespace = " \t";
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_ciinline char *get_next_arg(char *args, char *nextarg)
83f08c3bdfSopenharmony_ci{
84f08c3bdfSopenharmony_ci	return nextarg ? nextarg + strspn(nextarg, whitespace) : args + strnlen(args, CMDBUFSZ);
85f08c3bdfSopenharmony_ci}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci/*
88f08c3bdfSopenharmony_ci * =========================================================================
89f08c3bdfSopenharmony_ci */
90f08c3bdfSopenharmony_cistatic int help_me(char *);	/* forward reference */
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci/*
93f08c3bdfSopenharmony_ci * required_arg -- check for a required argument; issue message if not there
94f08c3bdfSopenharmony_ci *
95f08c3bdfSopenharmony_ci * return true if arg [something] exists; else return false
96f08c3bdfSopenharmony_ci */
97f08c3bdfSopenharmony_cistatic bool required_arg(char *arg, char *arg_name)
98f08c3bdfSopenharmony_ci{
99f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	if (*arg != '\0')
102f08c3bdfSopenharmony_ci		return true;
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	fprintf(stderr, "%s:  command '%s' missing required argument: %s\n\n",
105f08c3bdfSopenharmony_ci		gcp->program_name, gcp->cmd_name, arg_name);
106f08c3bdfSopenharmony_ci	help_me(gcp->cmd_name);
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_ci	return false;
109f08c3bdfSopenharmony_ci}
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci/*
112f08c3bdfSopenharmony_ci *  size_kmgp() -- convert ascii arg to numeric and scale as requested
113f08c3bdfSopenharmony_ci */
114f08c3bdfSopenharmony_ci#define KILO_SHIFT 10
115f08c3bdfSopenharmony_cistatic size_t size_kmgp(char *arg)
116f08c3bdfSopenharmony_ci{
117f08c3bdfSopenharmony_ci	size_t argval;
118f08c3bdfSopenharmony_ci	char *next;
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci	argval = strtoul(arg, &next, 0);
121f08c3bdfSopenharmony_ci	if (*next == '\0')
122f08c3bdfSopenharmony_ci		return argval;
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_ci	switch (tolower(*next)) {
125f08c3bdfSopenharmony_ci	case 'p':		/* pages */
126f08c3bdfSopenharmony_ci		argval *= glctx.pagesize;
127f08c3bdfSopenharmony_ci		break;
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_ci	case 'k':
130f08c3bdfSopenharmony_ci		argval <<= KILO_SHIFT;
131f08c3bdfSopenharmony_ci		break;
132f08c3bdfSopenharmony_ci
133f08c3bdfSopenharmony_ci	case 'm':
134f08c3bdfSopenharmony_ci		argval <<= KILO_SHIFT * 2;
135f08c3bdfSopenharmony_ci		break;
136f08c3bdfSopenharmony_ci
137f08c3bdfSopenharmony_ci	case 'g':
138f08c3bdfSopenharmony_ci		argval <<= KILO_SHIFT * 3;
139f08c3bdfSopenharmony_ci		break;
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	default:
142f08c3bdfSopenharmony_ci		return BOGUS_SIZE;	/* bogus chars after number */
143f08c3bdfSopenharmony_ci	}
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_ci	return argval;
146f08c3bdfSopenharmony_ci}
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_cistatic size_t get_scaled_value(char *args, char *what)
149f08c3bdfSopenharmony_ci{
150f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
151f08c3bdfSopenharmony_ci	size_t size = size_kmgp(args);
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci	if (size == BOGUS_SIZE) {
154f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  segment %s must be numeric value"
155f08c3bdfSopenharmony_ci			" followed by optional k, m, g or p [pages] scale factor.\n",
156f08c3bdfSopenharmony_ci			gcp->program_name, what);
157f08c3bdfSopenharmony_ci	}
158f08c3bdfSopenharmony_ci
159f08c3bdfSopenharmony_ci	return size;
160f08c3bdfSopenharmony_ci}
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_cistatic int get_range(char *args, range_t * range, char **nextarg)
163f08c3bdfSopenharmony_ci{
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci	if (isdigit(*args)) {
166f08c3bdfSopenharmony_ci		char *nextarg;
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_ci		args = strtok_r(args, whitespace, &nextarg);
169f08c3bdfSopenharmony_ci		range->offset = get_scaled_value(args, "offset");
170f08c3bdfSopenharmony_ci		if (range->offset == BOGUS_SIZE)
171f08c3bdfSopenharmony_ci			return CMD_ERROR;
172f08c3bdfSopenharmony_ci		args = get_next_arg(args, nextarg);
173f08c3bdfSopenharmony_ci
174f08c3bdfSopenharmony_ci		/*
175f08c3bdfSopenharmony_ci		 * <length> ... only if offset specified
176f08c3bdfSopenharmony_ci		 */
177f08c3bdfSopenharmony_ci		if (*args != '\0') {
178f08c3bdfSopenharmony_ci			args = strtok_r(args, whitespace, &nextarg);
179f08c3bdfSopenharmony_ci			if (*args != '*') {
180f08c3bdfSopenharmony_ci				range->length =
181f08c3bdfSopenharmony_ci				    get_scaled_value(args, "length");
182f08c3bdfSopenharmony_ci				if (range->length == BOGUS_SIZE)
183f08c3bdfSopenharmony_ci					return CMD_ERROR;
184f08c3bdfSopenharmony_ci			} else
185f08c3bdfSopenharmony_ci				range->length = 0;	/* map to end of file */
186f08c3bdfSopenharmony_ci			args = get_next_arg(args, nextarg);
187f08c3bdfSopenharmony_ci		}
188f08c3bdfSopenharmony_ci	}
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_ci	*nextarg = args;
191f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
192f08c3bdfSopenharmony_ci}
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_cistatic int get_shared(char *args)
195f08c3bdfSopenharmony_ci{
196f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
197f08c3bdfSopenharmony_ci	int segflag = MAP_PRIVATE;
198f08c3bdfSopenharmony_ci
199f08c3bdfSopenharmony_ci	if (!strcmp(args, "shared"))
200f08c3bdfSopenharmony_ci		segflag = MAP_SHARED;
201f08c3bdfSopenharmony_ci	else if (*args != '\0' && strcmp(args, "private")) {
202f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  anon seg access type must be one of:  "
203f08c3bdfSopenharmony_ci			"'private' or 'shared'\n", gcp->program_name);
204f08c3bdfSopenharmony_ci		return -1;
205f08c3bdfSopenharmony_ci	}
206f08c3bdfSopenharmony_ci	return segflag;
207f08c3bdfSopenharmony_ci}
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ci/*
210f08c3bdfSopenharmony_ci * get_access() - check args for 'read'\'write'
211f08c3bdfSopenharmony_ci * return:
212f08c3bdfSopenharmony_ci *	1 = read
213f08c3bdfSopenharmony_ci *	2 = write
214f08c3bdfSopenharmony_ci *	0 = neither [error]
215f08c3bdfSopenharmony_ci */
216f08c3bdfSopenharmony_cistatic int get_access(char *args)
217f08c3bdfSopenharmony_ci{
218f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
219f08c3bdfSopenharmony_ci	int axcs = 1;
220f08c3bdfSopenharmony_ci	int len = strlen(args);
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_ci	if (tolower(*args) == 'w')
223f08c3bdfSopenharmony_ci		axcs = 2;
224f08c3bdfSopenharmony_ci	else if (len != 0 && tolower(*args) != 'r') {
225f08c3bdfSopenharmony_ci		fprintf(stderr,
226f08c3bdfSopenharmony_ci			"%s:  segment access must be 'r[ead]' or 'w[rite]'\n",
227f08c3bdfSopenharmony_ci			gcp->program_name);
228f08c3bdfSopenharmony_ci		return 0;
229f08c3bdfSopenharmony_ci	}
230f08c3bdfSopenharmony_ci
231f08c3bdfSopenharmony_ci	return axcs;
232f08c3bdfSopenharmony_ci}
233f08c3bdfSopenharmony_ci
234f08c3bdfSopenharmony_cistatic bool numa_supported(void)
235f08c3bdfSopenharmony_ci{
236f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
237f08c3bdfSopenharmony_ci
238f08c3bdfSopenharmony_ci	if (gcp->numa_max_node <= 0) {
239f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no NUMA support on this platform\n",
240f08c3bdfSopenharmony_ci			gcp->program_name);
241f08c3bdfSopenharmony_ci		return false;
242f08c3bdfSopenharmony_ci	}
243f08c3bdfSopenharmony_ci	return true;
244f08c3bdfSopenharmony_ci}
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_cistatic struct policies {
247f08c3bdfSopenharmony_ci	char *pol_name;
248f08c3bdfSopenharmony_ci	int pol_flag;
249f08c3bdfSopenharmony_ci} policies[] = {
250f08c3bdfSopenharmony_ci	{
251f08c3bdfSopenharmony_ci	"default", MPOL_DEFAULT}, {
252f08c3bdfSopenharmony_ci	"preferred", MPOL_PREFERRED}, {
253f08c3bdfSopenharmony_ci	"bind", MPOL_BIND}, {
254f08c3bdfSopenharmony_ci	"interleaved", MPOL_INTERLEAVE}, {
255f08c3bdfSopenharmony_ci	NULL, -1}
256f08c3bdfSopenharmony_ci};
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci/*
259f08c3bdfSopenharmony_ci * get_mbind_policy() - parse <policy> argument to mbind command
260f08c3bdfSopenharmony_ci *
261f08c3bdfSopenharmony_ci * format:  <mpol>[+<flags>]
262f08c3bdfSopenharmony_ci * <mpol> is one of the policies[] above.
263f08c3bdfSopenharmony_ci * '+<flags>' = modifiers to mbind() call.  parsed by get_mbind_flags()
264f08c3bdfSopenharmony_ci */
265f08c3bdfSopenharmony_cistatic int get_mbind_policy(char *args, char **nextarg)
266f08c3bdfSopenharmony_ci{
267f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
268f08c3bdfSopenharmony_ci	struct policies *polp;
269f08c3bdfSopenharmony_ci	char *pol;
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_ci	pol = args;
272f08c3bdfSopenharmony_ci	args += strcspn(args, " 	+");
273f08c3bdfSopenharmony_ci
274f08c3bdfSopenharmony_ci	for (polp = policies; polp->pol_name != NULL; ++polp) {
275f08c3bdfSopenharmony_ci		size_t plen = args - pol;
276f08c3bdfSopenharmony_ci
277f08c3bdfSopenharmony_ci		if (strncmp(pol, polp->pol_name, plen))
278f08c3bdfSopenharmony_ci			continue;
279f08c3bdfSopenharmony_ci
280f08c3bdfSopenharmony_ci		*nextarg = args;
281f08c3bdfSopenharmony_ci		return polp->pol_flag;
282f08c3bdfSopenharmony_ci	}
283f08c3bdfSopenharmony_ci
284f08c3bdfSopenharmony_ci	fprintf(stderr, "%s:  unrecognized policy %s\n",
285f08c3bdfSopenharmony_ci		gcp->program_name, pol);
286f08c3bdfSopenharmony_ci	return CMD_ERROR;
287f08c3bdfSopenharmony_ci}
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_ci/*
290f08c3bdfSopenharmony_ci * get_mbind_flags() - parse mbind(2) modifier flags
291f08c3bdfSopenharmony_ci *
292f08c3bdfSopenharmony_ci * format: +move[+wait]
293f08c3bdfSopenharmony_ci * 'move' specifies that currently allocated pages should be migrated.
294f08c3bdfSopenharmony_ci *        => MPOL_MF_MOVE
295f08c3bdfSopenharmony_ci * 'wait' [only if 'move' specified] specifies that mbind(2) should not
296f08c3bdfSopenharmony_ci *        return until all pages that can be migrated have been.
297f08c3bdfSopenharmony_ci *        => MPOL_MF_WAIT
298f08c3bdfSopenharmony_ci *
299f08c3bdfSopenharmony_ci * returns flags on success; -1 on error
300f08c3bdfSopenharmony_ci */
301f08c3bdfSopenharmony_cistatic int get_mbind_flags(char *args, char **nextarg)
302f08c3bdfSopenharmony_ci{
303f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
304f08c3bdfSopenharmony_ci	char *arg;
305f08c3bdfSopenharmony_ci	int flags = 0;
306f08c3bdfSopenharmony_ci
307f08c3bdfSopenharmony_ci	arg = args;
308f08c3bdfSopenharmony_ci	args += strcspn(args, " 	+");
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_ci	if (strncmp(arg, "move", args - arg))
311f08c3bdfSopenharmony_ci		goto flags_err;
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_ci	flags = MPOL_MF_MOVE;
314f08c3bdfSopenharmony_ci
315f08c3bdfSopenharmony_ci	if (*args == '+') {
316f08c3bdfSopenharmony_ci		++args;
317f08c3bdfSopenharmony_ci		if (*args == '\0') {
318f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  expected 'wait' after '+'\n",
319f08c3bdfSopenharmony_ci				gcp->program_name);
320f08c3bdfSopenharmony_ci			return -1;
321f08c3bdfSopenharmony_ci		}
322f08c3bdfSopenharmony_ci		arg = strtok_r(args, "  ", &args);
323f08c3bdfSopenharmony_ci		if (strncmp(arg, "wait", strlen(arg)))
324f08c3bdfSopenharmony_ci			goto flags_err;
325f08c3bdfSopenharmony_ci
326f08c3bdfSopenharmony_ci		flags |= MPOL_MF_WAIT;
327f08c3bdfSopenharmony_ci	}
328f08c3bdfSopenharmony_ci
329f08c3bdfSopenharmony_ci	*nextarg = args;
330f08c3bdfSopenharmony_ci	return flags;
331f08c3bdfSopenharmony_ci
332f08c3bdfSopenharmony_ciflags_err:
333f08c3bdfSopenharmony_ci	fprintf(stderr, "%s: unrecognized mbind flag: %s\n",
334f08c3bdfSopenharmony_ci		gcp->program_name, arg);
335f08c3bdfSopenharmony_ci	return -1;
336f08c3bdfSopenharmony_ci
337f08c3bdfSopenharmony_ci}
338f08c3bdfSopenharmony_ci
339f08c3bdfSopenharmony_ci/*
340f08c3bdfSopenharmony_ci * get_nodemask() -- get nodemask from comma-separated list of node ids.
341f08c3bdfSopenharmony_ci *
342f08c3bdfSopenharmony_ci * N.B., caller must free returned nodemask
343f08c3bdfSopenharmony_ci */
344f08c3bdfSopenharmony_cistatic nodemask_t *get_nodemask(char *args)
345f08c3bdfSopenharmony_ci{
346f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
347f08c3bdfSopenharmony_ci	nodemask_t *nmp = (nodemask_t *) calloc(1, sizeof(nodemask_t));
348f08c3bdfSopenharmony_ci	char *next;
349f08c3bdfSopenharmony_ci	int node;
350f08c3bdfSopenharmony_ci	while (*args != '\0') {
351f08c3bdfSopenharmony_ci		if (!isdigit(*args)) {
352f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  expected digit for <node/list>\n",
353f08c3bdfSopenharmony_ci				gcp->program_name);
354f08c3bdfSopenharmony_ci			goto out_err;
355f08c3bdfSopenharmony_ci		}
356f08c3bdfSopenharmony_ci
357f08c3bdfSopenharmony_ci		node = strtoul(args, &next, 10);
358f08c3bdfSopenharmony_ci
359f08c3bdfSopenharmony_ci		if (node > gcp->numa_max_node) {
360f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  node ids must be <= %d\n",
361f08c3bdfSopenharmony_ci				gcp->program_name, gcp->numa_max_node);
362f08c3bdfSopenharmony_ci			goto out_err;
363f08c3bdfSopenharmony_ci		}
364f08c3bdfSopenharmony_ci
365f08c3bdfSopenharmony_ci		nodemask_set(nmp, node);
366f08c3bdfSopenharmony_ci
367f08c3bdfSopenharmony_ci		if (*next == '\0')
368f08c3bdfSopenharmony_ci			return nmp;
369f08c3bdfSopenharmony_ci		if (*next != ',') {
370f08c3bdfSopenharmony_ci			break;
371f08c3bdfSopenharmony_ci		}
372f08c3bdfSopenharmony_ci		args = next + 1;
373f08c3bdfSopenharmony_ci	}
374f08c3bdfSopenharmony_ci
375f08c3bdfSopenharmony_ciout_err:
376f08c3bdfSopenharmony_ci	free(nmp);
377f08c3bdfSopenharmony_ci	return NULL;
378f08c3bdfSopenharmony_ci}
379f08c3bdfSopenharmony_ci
380f08c3bdfSopenharmony_ci/*
381f08c3bdfSopenharmony_ci * get_arg_nodeid_list() -- get list [array] of node ids from comma-separated list.
382f08c3bdfSopenharmony_ci *
383f08c3bdfSopenharmony_ci * on success, returns count of id's in list; on error -1
384f08c3bdfSopenharmony_ci */
385f08c3bdfSopenharmony_cistatic int get_arg_nodeid_list(char *args, unsigned int *list)
386f08c3bdfSopenharmony_ci{
387f08c3bdfSopenharmony_ci	glctx_t *gcp;
388f08c3bdfSopenharmony_ci	char *next;
389f08c3bdfSopenharmony_ci	nodemask_t my_allowed_nodes;
390f08c3bdfSopenharmony_ci	int node, count = 0;
391f08c3bdfSopenharmony_ci
392f08c3bdfSopenharmony_ci	gcp = &glctx;
393f08c3bdfSopenharmony_ci	my_allowed_nodes = numa_get_membind_compat();
394f08c3bdfSopenharmony_ci	while (*args != '\0') {
395f08c3bdfSopenharmony_ci		if (!isdigit(*args)) {
396f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  expected digit for <node/list>\n",
397f08c3bdfSopenharmony_ci				gcp->program_name);
398f08c3bdfSopenharmony_ci			return -1;
399f08c3bdfSopenharmony_ci		}
400f08c3bdfSopenharmony_ci
401f08c3bdfSopenharmony_ci		node = strtoul(args, &next, 10);
402f08c3bdfSopenharmony_ci
403f08c3bdfSopenharmony_ci		if (node > gcp->numa_max_node) {
404f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  node ids must be <= %d\n",
405f08c3bdfSopenharmony_ci				gcp->program_name, gcp->numa_max_node);
406f08c3bdfSopenharmony_ci			return -1;
407f08c3bdfSopenharmony_ci		}
408f08c3bdfSopenharmony_ci
409f08c3bdfSopenharmony_ci		if (!nodemask_isset(&my_allowed_nodes, node)) {
410f08c3bdfSopenharmony_ci			fprintf(stderr,
411f08c3bdfSopenharmony_ci				"%s:  node %d is not in my allowed node mask\n",
412f08c3bdfSopenharmony_ci				gcp->program_name, node);
413f08c3bdfSopenharmony_ci			return -1;
414f08c3bdfSopenharmony_ci		}
415f08c3bdfSopenharmony_ci
416f08c3bdfSopenharmony_ci		*(list + count++) = node;
417f08c3bdfSopenharmony_ci
418f08c3bdfSopenharmony_ci		if (*next == '\0')
419f08c3bdfSopenharmony_ci			return count;
420f08c3bdfSopenharmony_ci		if (*next != ',') {
421f08c3bdfSopenharmony_ci			break;
422f08c3bdfSopenharmony_ci		}
423f08c3bdfSopenharmony_ci
424f08c3bdfSopenharmony_ci		if (count >= gcp->numa_max_node) {
425f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  too many node ids in list\n",
426f08c3bdfSopenharmony_ci				gcp->program_name);
427f08c3bdfSopenharmony_ci		}
428f08c3bdfSopenharmony_ci		args = next + 1;
429f08c3bdfSopenharmony_ci	}
430f08c3bdfSopenharmony_ci
431f08c3bdfSopenharmony_ci	return -1;
432f08c3bdfSopenharmony_ci}
433f08c3bdfSopenharmony_ci
434f08c3bdfSopenharmony_ci/*
435f08c3bdfSopenharmony_ci * get_current_nodeid_list() - fill arg array with nodes from
436f08c3bdfSopenharmony_ci * current thread's allowed node mask.  return # of nodes in
437f08c3bdfSopenharmony_ci * mask.
438f08c3bdfSopenharmony_ci */
439f08c3bdfSopenharmony_cistatic int get_current_nodeid_list(unsigned int *fromids)
440f08c3bdfSopenharmony_ci{
441f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
442f08c3bdfSopenharmony_ci	nodemask_t my_allowed_nodes;
443f08c3bdfSopenharmony_ci	int nr_nodes = 0, max_node = gcp->numa_max_node;
444f08c3bdfSopenharmony_ci	int node;
445f08c3bdfSopenharmony_ci
446f08c3bdfSopenharmony_ci	my_allowed_nodes = numa_get_membind_compat();
447f08c3bdfSopenharmony_ci	for (node = 0; node <= max_node; ++node) {
448f08c3bdfSopenharmony_ci		if (nodemask_isset(&my_allowed_nodes, node))
449f08c3bdfSopenharmony_ci			*(fromids + nr_nodes++) = node;
450f08c3bdfSopenharmony_ci	}
451f08c3bdfSopenharmony_ci
452f08c3bdfSopenharmony_ci	/*
453f08c3bdfSopenharmony_ci	 * shouldn't happen, but let 'em know if it does
454f08c3bdfSopenharmony_ci	 */
455f08c3bdfSopenharmony_ci	if (nr_nodes == 0)
456f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  my allowed node mask is empty !!???\n",
457f08c3bdfSopenharmony_ci			gcp->program_name);
458f08c3bdfSopenharmony_ci	return nr_nodes;
459f08c3bdfSopenharmony_ci}
460f08c3bdfSopenharmony_ci
461f08c3bdfSopenharmony_ci/*
462f08c3bdfSopenharmony_ci * NOTE (garrcoop): Get rid of an -Wunused warning. This wasn't deleted because
463f08c3bdfSopenharmony_ci * I don't know what the original intent was for this code.
464f08c3bdfSopenharmony_ci */
465f08c3bdfSopenharmony_ci#if 0
466f08c3bdfSopenharmony_cistatic void not_implemented()
467f08c3bdfSopenharmony_ci{
468f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
469f08c3bdfSopenharmony_ci
470f08c3bdfSopenharmony_ci	fprintf(stderr, "%s:  %s not implemented yet\n",
471f08c3bdfSopenharmony_ci		gcp->program_name, gcp->cmd_name);
472f08c3bdfSopenharmony_ci}
473f08c3bdfSopenharmony_ci#endif
474f08c3bdfSopenharmony_ci
475f08c3bdfSopenharmony_ci/*
476f08c3bdfSopenharmony_ci * =========================================================================
477f08c3bdfSopenharmony_ci */
478f08c3bdfSopenharmony_cistatic int quit(char *args)
479f08c3bdfSopenharmony_ci{
480f08c3bdfSopenharmony_ci	exit(0);		/* let cleanup() do its thing */
481f08c3bdfSopenharmony_ci}
482f08c3bdfSopenharmony_ci
483f08c3bdfSopenharmony_cistatic int show_pid(char *args)
484f08c3bdfSopenharmony_ci{
485f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
486f08c3bdfSopenharmony_ci
487f08c3bdfSopenharmony_ci	printf("%s:  pid = %d\n", gcp->program_name, getpid());
488f08c3bdfSopenharmony_ci
489f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
490f08c3bdfSopenharmony_ci}
491f08c3bdfSopenharmony_ci
492f08c3bdfSopenharmony_cistatic int pause_me(char *args)
493f08c3bdfSopenharmony_ci{
494f08c3bdfSopenharmony_ci	// glctx_t *gcp = &glctx;
495f08c3bdfSopenharmony_ci
496f08c3bdfSopenharmony_ci	pause();
497f08c3bdfSopenharmony_ci	reset_signal();
498f08c3bdfSopenharmony_ci
499f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
500f08c3bdfSopenharmony_ci}
501f08c3bdfSopenharmony_ci
502f08c3bdfSopenharmony_cistatic char *numa_header = "  Node  Total Mem[MB]  Free Mem[MB]\n";
503f08c3bdfSopenharmony_cistatic int numa_info(char *args)
504f08c3bdfSopenharmony_ci{
505f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
506f08c3bdfSopenharmony_ci	unsigned int *nodeids;
507f08c3bdfSopenharmony_ci	int nr_nodes, i;
508f08c3bdfSopenharmony_ci	bool do_header = true;
509f08c3bdfSopenharmony_ci
510f08c3bdfSopenharmony_ci	if (!numa_supported())
511f08c3bdfSopenharmony_ci		return CMD_ERROR;
512f08c3bdfSopenharmony_ci
513f08c3bdfSopenharmony_ci	nodeids = calloc(gcp->numa_max_node, sizeof(*nodeids));
514f08c3bdfSopenharmony_ci	nr_nodes = get_current_nodeid_list(nodeids);
515f08c3bdfSopenharmony_ci	if (nr_nodes < 0)
516f08c3bdfSopenharmony_ci		return CMD_ERROR;
517f08c3bdfSopenharmony_ci
518f08c3bdfSopenharmony_ci	for (i = 0; i < nr_nodes; ++i) {
519f08c3bdfSopenharmony_ci		int node = nodeids[i];
520f08c3bdfSopenharmony_ci		long node_size, node_free;
521f08c3bdfSopenharmony_ci
522f08c3bdfSopenharmony_ci		node_size = numa_node_size(node, &node_free);
523f08c3bdfSopenharmony_ci		if (node_size < 0) {
524f08c3bdfSopenharmony_ci			fprintf(stderr,
525f08c3bdfSopenharmony_ci				"%s:  numa_node_size() failed for node %d\n",
526f08c3bdfSopenharmony_ci				gcp->program_name, node);
527f08c3bdfSopenharmony_ci			return CMD_ERROR;
528f08c3bdfSopenharmony_ci		}
529f08c3bdfSopenharmony_ci
530f08c3bdfSopenharmony_ci		if (do_header) {
531f08c3bdfSopenharmony_ci			do_header = false;
532f08c3bdfSopenharmony_ci			puts(numa_header);
533f08c3bdfSopenharmony_ci		}
534f08c3bdfSopenharmony_ci		printf("  %3d  %9ld      %8ld\n", node,
535f08c3bdfSopenharmony_ci		       node_size / (1024 * 1024), node_free / (1024 * 1024));
536f08c3bdfSopenharmony_ci	}
537f08c3bdfSopenharmony_ci
538f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
539f08c3bdfSopenharmony_ci}
540f08c3bdfSopenharmony_ci
541f08c3bdfSopenharmony_ci/*
542f08c3bdfSopenharmony_ci * migrate <to-node-id[s]> [<from-node-id[s]>]
543f08c3bdfSopenharmony_ci *
544f08c3bdfSopenharmony_ci * Node id[s] - single node id or comma-separated list
545f08c3bdfSopenharmony_ci * <to-node-id[s]> - 1-for-1 with <from-node-id[s]>, OR
546f08c3bdfSopenharmony_ci * if <from-node-id[s]> omitted, <to-node-id[s]> must be
547f08c3bdfSopenharmony_ci * a single node id.
548f08c3bdfSopenharmony_ci */
549f08c3bdfSopenharmony_cistatic int migrate_process(char *args)
550f08c3bdfSopenharmony_ci{
551f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
552f08c3bdfSopenharmony_ci	unsigned int *fromids, *toids;
553f08c3bdfSopenharmony_ci	char *idlist, *nextarg;
554f08c3bdfSopenharmony_ci	struct timeval t_start, t_end;
555f08c3bdfSopenharmony_ci	int nr_to, nr_from;
556f08c3bdfSopenharmony_ci	int nr_migrated;
557f08c3bdfSopenharmony_ci	int ret = CMD_ERROR;
558f08c3bdfSopenharmony_ci
559f08c3bdfSopenharmony_ci	if (!numa_supported())
560f08c3bdfSopenharmony_ci		return CMD_ERROR;
561f08c3bdfSopenharmony_ci
562f08c3bdfSopenharmony_ci	toids = calloc(gcp->numa_max_node, sizeof(*toids));
563f08c3bdfSopenharmony_ci	fromids = calloc(gcp->numa_max_node, sizeof(*fromids));
564f08c3bdfSopenharmony_ci
565f08c3bdfSopenharmony_ci	/*
566f08c3bdfSopenharmony_ci	 * <to-node-id[s]>
567f08c3bdfSopenharmony_ci	 */
568f08c3bdfSopenharmony_ci	if (!required_arg(args, "<to-node-id[s]>"))
569f08c3bdfSopenharmony_ci		return CMD_ERROR;
570f08c3bdfSopenharmony_ci	idlist = strtok_r(args, whitespace, &nextarg);
571f08c3bdfSopenharmony_ci	nr_to = get_arg_nodeid_list(idlist, toids);
572f08c3bdfSopenharmony_ci	if (nr_to <= 0)
573f08c3bdfSopenharmony_ci		goto out_free;
574f08c3bdfSopenharmony_ci	args = nextarg + strspn(nextarg, whitespace);
575f08c3bdfSopenharmony_ci
576f08c3bdfSopenharmony_ci	if (*args != '\0') {
577f08c3bdfSopenharmony_ci		/*
578f08c3bdfSopenharmony_ci		 * apparently, <from-node-id[s]> present
579f08c3bdfSopenharmony_ci		 */
580f08c3bdfSopenharmony_ci		idlist = strtok_r(args, whitespace, &nextarg);
581f08c3bdfSopenharmony_ci		nr_from = get_arg_nodeid_list(idlist, fromids);
582f08c3bdfSopenharmony_ci		if (nr_from <= 0)
583f08c3bdfSopenharmony_ci			goto out_free;
584f08c3bdfSopenharmony_ci		if (nr_from != nr_to) {
585f08c3bdfSopenharmony_ci			fprintf(stderr,
586f08c3bdfSopenharmony_ci				"%s:  # of 'from' ids must = # of 'to' ids\n",
587f08c3bdfSopenharmony_ci				gcp->program_name);
588f08c3bdfSopenharmony_ci			goto out_free;
589f08c3bdfSopenharmony_ci		}
590f08c3bdfSopenharmony_ci	} else {
591f08c3bdfSopenharmony_ci		int i;
592f08c3bdfSopenharmony_ci
593f08c3bdfSopenharmony_ci		/*
594f08c3bdfSopenharmony_ci		 * no <from-node-id[s]>, nr_to must == 1,
595f08c3bdfSopenharmony_ci		 * get fromids from memory policy.
596f08c3bdfSopenharmony_ci		 */
597f08c3bdfSopenharmony_ci		if (nr_to > 1) {
598f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  # to ids must = 1"
599f08c3bdfSopenharmony_ci				" when no 'from' ids specified\n",
600f08c3bdfSopenharmony_ci				gcp->program_name);
601f08c3bdfSopenharmony_ci			goto out_free;
602f08c3bdfSopenharmony_ci		}
603f08c3bdfSopenharmony_ci		nr_from = get_current_nodeid_list(fromids);
604f08c3bdfSopenharmony_ci		if (nr_from <= 0)
605f08c3bdfSopenharmony_ci			goto out_free;
606f08c3bdfSopenharmony_ci
607f08c3bdfSopenharmony_ci		/*
608f08c3bdfSopenharmony_ci		 * remove 'to' node from 'from' list.  to and from
609f08c3bdfSopenharmony_ci		 * lists can't intersect.
610f08c3bdfSopenharmony_ci		 */
611f08c3bdfSopenharmony_ci		for (i = nr_from - 1; i >= 0; --i) {
612f08c3bdfSopenharmony_ci			if (*toids == *(fromids + i)) {
613f08c3bdfSopenharmony_ci				while (i <= nr_from) {
614f08c3bdfSopenharmony_ci					*(fromids + i) = *(fromids + i + 1);
615f08c3bdfSopenharmony_ci					++i;
616f08c3bdfSopenharmony_ci				}
617f08c3bdfSopenharmony_ci				--nr_from;
618f08c3bdfSopenharmony_ci				break;
619f08c3bdfSopenharmony_ci			}
620f08c3bdfSopenharmony_ci		}
621f08c3bdfSopenharmony_ci
622f08c3bdfSopenharmony_ci		/*
623f08c3bdfSopenharmony_ci		 * fill out nr_from toids with the single 'to' node
624f08c3bdfSopenharmony_ci		 */
625f08c3bdfSopenharmony_ci		for (; nr_to < nr_from; ++nr_to)
626f08c3bdfSopenharmony_ci			*(toids + nr_to) = *toids;	/* toids[0] */
627f08c3bdfSopenharmony_ci	}
628f08c3bdfSopenharmony_ci
629f08c3bdfSopenharmony_ci	gettimeofday(&t_start, NULL);
630f08c3bdfSopenharmony_ci	nr_migrated =
631f08c3bdfSopenharmony_ci	    syscall(__NR_migrate_pages, getpid(), nr_from, fromids, toids);
632f08c3bdfSopenharmony_ci	if (nr_migrated < 0) {
633f08c3bdfSopenharmony_ci		int err = errno;
634f08c3bdfSopenharmony_ci		fprintf(stderr, "%s: migrate_pages failed - %s\n",
635f08c3bdfSopenharmony_ci			gcp->program_name, strerror(err));
636f08c3bdfSopenharmony_ci		goto out_free;
637f08c3bdfSopenharmony_ci	}
638f08c3bdfSopenharmony_ci	gettimeofday(&t_end, NULL);
639f08c3bdfSopenharmony_ci	printf("%s:  migrated %d pages in %6.3fsecs\n",
640f08c3bdfSopenharmony_ci	       gcp->program_name, nr_migrated,
641f08c3bdfSopenharmony_ci	       (float)(tv_diff_usec(&t_start, &t_end)) / 1000000.0);
642f08c3bdfSopenharmony_ci	ret = CMD_SUCCESS;
643f08c3bdfSopenharmony_ci
644f08c3bdfSopenharmony_ciout_free:
645f08c3bdfSopenharmony_ci	free(toids);
646f08c3bdfSopenharmony_ci	free(fromids);
647f08c3bdfSopenharmony_ci	return ret;
648f08c3bdfSopenharmony_ci}
649f08c3bdfSopenharmony_ci
650f08c3bdfSopenharmony_cistatic int show_seg(char *args)
651f08c3bdfSopenharmony_ci{
652f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
653f08c3bdfSopenharmony_ci
654f08c3bdfSopenharmony_ci	char *segname = NULL, *nextarg;
655f08c3bdfSopenharmony_ci
656f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
657f08c3bdfSopenharmony_ci	if (*args != '\0')
658f08c3bdfSopenharmony_ci		segname = strtok_r(args, whitespace, &nextarg);
659f08c3bdfSopenharmony_ci
660f08c3bdfSopenharmony_ci	if (!segment_show(segname))
661f08c3bdfSopenharmony_ci		return CMD_ERROR;
662f08c3bdfSopenharmony_ci
663f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
664f08c3bdfSopenharmony_ci}
665f08c3bdfSopenharmony_ci
666f08c3bdfSopenharmony_ci/*
667f08c3bdfSopenharmony_ci * anon_seg:  <seg-name> <size>[kmgp] [private|shared]
668f08c3bdfSopenharmony_ci */
669f08c3bdfSopenharmony_cistatic int anon_seg(char *args)
670f08c3bdfSopenharmony_ci{
671f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
672f08c3bdfSopenharmony_ci
673f08c3bdfSopenharmony_ci	char *segname, *nextarg;
674f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
675f08c3bdfSopenharmony_ci	int segflag = 0;
676f08c3bdfSopenharmony_ci
677f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
678f08c3bdfSopenharmony_ci
679f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
680f08c3bdfSopenharmony_ci		return CMD_ERROR;
681f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
682f08c3bdfSopenharmony_ci	args = nextarg + strspn(nextarg, whitespace);
683f08c3bdfSopenharmony_ci
684f08c3bdfSopenharmony_ci	if (!required_arg(args, "<size>"))
685f08c3bdfSopenharmony_ci		return CMD_ERROR;
686f08c3bdfSopenharmony_ci	args = strtok_r(args, whitespace, &nextarg);
687f08c3bdfSopenharmony_ci	range.length = get_scaled_value(args, "size");
688f08c3bdfSopenharmony_ci	if (range.length == BOGUS_SIZE)
689f08c3bdfSopenharmony_ci		return CMD_ERROR;
690f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
691f08c3bdfSopenharmony_ci
692f08c3bdfSopenharmony_ci	if (*args != '\0') {
693f08c3bdfSopenharmony_ci		segflag = get_shared(args);
694f08c3bdfSopenharmony_ci		if (segflag == -1)
695f08c3bdfSopenharmony_ci			return CMD_ERROR;
696f08c3bdfSopenharmony_ci	}
697f08c3bdfSopenharmony_ci
698f08c3bdfSopenharmony_ci	if (!segment_register(SEGT_ANON, segname, &range, segflag))
699f08c3bdfSopenharmony_ci		return CMD_ERROR;
700f08c3bdfSopenharmony_ci
701f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
702f08c3bdfSopenharmony_ci}
703f08c3bdfSopenharmony_ci
704f08c3bdfSopenharmony_ci/*
705f08c3bdfSopenharmony_ci * file_seg:  <path-name> [<offset>[kmgp] <length>[kmgp]  [private|shared]]
706f08c3bdfSopenharmony_ci */
707f08c3bdfSopenharmony_cistatic int file_seg(char *args)
708f08c3bdfSopenharmony_ci{
709f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
710f08c3bdfSopenharmony_ci
711f08c3bdfSopenharmony_ci	char *pathname, *nextarg;
712f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
713f08c3bdfSopenharmony_ci	int segflag = MAP_PRIVATE;
714f08c3bdfSopenharmony_ci
715f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
716f08c3bdfSopenharmony_ci
717f08c3bdfSopenharmony_ci	if (!required_arg(args, "<path-name>"))
718f08c3bdfSopenharmony_ci		return CMD_ERROR;
719f08c3bdfSopenharmony_ci	pathname = strtok_r(args, whitespace, &nextarg);
720f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
721f08c3bdfSopenharmony_ci
722f08c3bdfSopenharmony_ci	/*
723f08c3bdfSopenharmony_ci	 * offset, length are optional
724f08c3bdfSopenharmony_ci	 */
725f08c3bdfSopenharmony_ci	if (get_range(args, &range, &nextarg) == CMD_ERROR)
726f08c3bdfSopenharmony_ci		return CMD_ERROR;
727f08c3bdfSopenharmony_ci	args = nextarg;
728f08c3bdfSopenharmony_ci
729f08c3bdfSopenharmony_ci	if (*args != '\0') {
730f08c3bdfSopenharmony_ci		segflag = get_shared(args);
731f08c3bdfSopenharmony_ci		if (segflag == -1)
732f08c3bdfSopenharmony_ci			return CMD_ERROR;
733f08c3bdfSopenharmony_ci	}
734f08c3bdfSopenharmony_ci
735f08c3bdfSopenharmony_ci	if (!segment_register(SEGT_FILE, pathname, &range, segflag))
736f08c3bdfSopenharmony_ci		return CMD_ERROR;
737f08c3bdfSopenharmony_ci
738f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
739f08c3bdfSopenharmony_ci}
740f08c3bdfSopenharmony_ci
741f08c3bdfSopenharmony_ci/*
742f08c3bdfSopenharmony_ci * deletefile <file-name>
743f08c3bdfSopenharmony_ci */
744f08c3bdfSopenharmony_cistatic int delete_file(char *args)
745f08c3bdfSopenharmony_ci{
746f08c3bdfSopenharmony_ci       glctx_t *gcp = &glctx;
747f08c3bdfSopenharmony_ci       char *filename, *nextarg;
748f08c3bdfSopenharmony_ci
749f08c3bdfSopenharmony_ci       args += strspn(args, whitespace);
750f08c3bdfSopenharmony_ci       if (!required_arg(args, "<file-name>"))
751f08c3bdfSopenharmony_ci               return CMD_ERROR;
752f08c3bdfSopenharmony_ci       filename = strtok_r(args, whitespace, &nextarg);
753f08c3bdfSopenharmony_ci
754f08c3bdfSopenharmony_ci       if (remove(filename)) {
755f08c3bdfSopenharmony_ci               fprintf(stderr, "%s: deletefile failed - %s\n",
756f08c3bdfSopenharmony_ci                       gcp->program_name, strerror(errno));
757f08c3bdfSopenharmony_ci               return CMD_ERROR;
758f08c3bdfSopenharmony_ci       }
759f08c3bdfSopenharmony_ci
760f08c3bdfSopenharmony_ci       return CMD_SUCCESS;
761f08c3bdfSopenharmony_ci}
762f08c3bdfSopenharmony_ci
763f08c3bdfSopenharmony_ci/*
764f08c3bdfSopenharmony_ci * createfile <file-name> <size>[k|m|g|p]]
765f08c3bdfSopenharmony_ci */
766f08c3bdfSopenharmony_cistatic int create_file(char *args)
767f08c3bdfSopenharmony_ci{
768f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
769f08c3bdfSopenharmony_ci	char *filename, *nextarg;
770f08c3bdfSopenharmony_ci	size_t len;
771f08c3bdfSopenharmony_ci	int fd;
772f08c3bdfSopenharmony_ci
773f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
774f08c3bdfSopenharmony_ci	if (!required_arg(args, "<file-name>"))
775f08c3bdfSopenharmony_ci		return CMD_ERROR;
776f08c3bdfSopenharmony_ci	filename = strtok_r(args, whitespace, &nextarg);
777f08c3bdfSopenharmony_ci	args = nextarg + strspn(nextarg, whitespace);
778f08c3bdfSopenharmony_ci
779f08c3bdfSopenharmony_ci	if (!required_arg(args, "<size>"))
780f08c3bdfSopenharmony_ci		return CMD_ERROR;
781f08c3bdfSopenharmony_ci	args = strtok_r(args, whitespace, &nextarg);
782f08c3bdfSopenharmony_ci	len = get_scaled_value(args, "size");
783f08c3bdfSopenharmony_ci	if (len == BOGUS_SIZE)
784f08c3bdfSopenharmony_ci		return CMD_ERROR;
785f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
786f08c3bdfSopenharmony_ci
787f08c3bdfSopenharmony_ci	fd = open(filename, O_RDWR | O_CREAT, 0600);
788f08c3bdfSopenharmony_ci	if (fd < 0) {
789f08c3bdfSopenharmony_ci		fprintf(stderr, "%s: createfile failed - %s\n",
790f08c3bdfSopenharmony_ci			gcp->program_name, strerror(errno));
791f08c3bdfSopenharmony_ci		return CMD_ERROR;
792f08c3bdfSopenharmony_ci	}
793f08c3bdfSopenharmony_ci
794f08c3bdfSopenharmony_ci	if (posix_fallocate(fd, 0, len)) {
795f08c3bdfSopenharmony_ci		fprintf(stderr, "%s: createfile failed - %s\n",
796f08c3bdfSopenharmony_ci			gcp->program_name, strerror(errno));
797f08c3bdfSopenharmony_ci		return CMD_ERROR;
798f08c3bdfSopenharmony_ci	}
799f08c3bdfSopenharmony_ci	close(fd);
800f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
801f08c3bdfSopenharmony_ci}
802f08c3bdfSopenharmony_ci
803f08c3bdfSopenharmony_ci/*
804f08c3bdfSopenharmony_ci * remove_seg:  <seg-name> [<seg-name> ...]
805f08c3bdfSopenharmony_ci */
806f08c3bdfSopenharmony_cistatic int remove_seg(char *args)
807f08c3bdfSopenharmony_ci{
808f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
809f08c3bdfSopenharmony_ci
810f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
811f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
812f08c3bdfSopenharmony_ci		return CMD_ERROR;
813f08c3bdfSopenharmony_ci
814f08c3bdfSopenharmony_ci	while (*args != '\0') {
815f08c3bdfSopenharmony_ci		char *segname, *nextarg;
816f08c3bdfSopenharmony_ci
817f08c3bdfSopenharmony_ci		segname = strtok_r(args, whitespace, &nextarg);
818f08c3bdfSopenharmony_ci		args = nextarg + strspn(nextarg, whitespace);
819f08c3bdfSopenharmony_ci
820f08c3bdfSopenharmony_ci		segment_remove(segname);
821f08c3bdfSopenharmony_ci	}
822f08c3bdfSopenharmony_ci	return 0;
823f08c3bdfSopenharmony_ci}
824f08c3bdfSopenharmony_ci
825f08c3bdfSopenharmony_ci/*
826f08c3bdfSopenharmony_ci * touch_seg:  <seg-name> [<offset> <length>] [read|write]
827f08c3bdfSopenharmony_ci */
828f08c3bdfSopenharmony_cistatic int touch_seg(char *args)
829f08c3bdfSopenharmony_ci{
830f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
831f08c3bdfSopenharmony_ci
832f08c3bdfSopenharmony_ci	char *segname, *nextarg;
833f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
834f08c3bdfSopenharmony_ci	int axcs;
835f08c3bdfSopenharmony_ci
836f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
837f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
838f08c3bdfSopenharmony_ci		return CMD_ERROR;
839f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
840f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
841f08c3bdfSopenharmony_ci
842f08c3bdfSopenharmony_ci	/*
843f08c3bdfSopenharmony_ci	 * offset, length are optional
844f08c3bdfSopenharmony_ci	 */
845f08c3bdfSopenharmony_ci	if (get_range(args, &range, &nextarg) == CMD_ERROR)
846f08c3bdfSopenharmony_ci		return CMD_ERROR;
847f08c3bdfSopenharmony_ci	args = nextarg;
848f08c3bdfSopenharmony_ci
849f08c3bdfSopenharmony_ci	axcs = get_access(args);
850f08c3bdfSopenharmony_ci	if (axcs == 0)
851f08c3bdfSopenharmony_ci		return CMD_ERROR;
852f08c3bdfSopenharmony_ci
853f08c3bdfSopenharmony_ci	if (!segment_touch(segname, &range, axcs - 1))
854f08c3bdfSopenharmony_ci		return CMD_ERROR;
855f08c3bdfSopenharmony_ci
856f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
857f08c3bdfSopenharmony_ci}
858f08c3bdfSopenharmony_ci
859f08c3bdfSopenharmony_ci/*
860f08c3bdfSopenharmony_ci * unmap <seg-name> - unmap specified segment, but remember name/size/...
861f08c3bdfSopenharmony_ci */
862f08c3bdfSopenharmony_cistatic int unmap_seg(char *args)
863f08c3bdfSopenharmony_ci{
864f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
865f08c3bdfSopenharmony_ci	char *segname, *nextarg;
866f08c3bdfSopenharmony_ci
867f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
868f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
869f08c3bdfSopenharmony_ci		return CMD_ERROR;
870f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
871f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
872f08c3bdfSopenharmony_ci
873f08c3bdfSopenharmony_ci	if (!segment_unmap(segname))
874f08c3bdfSopenharmony_ci		return CMD_ERROR;
875f08c3bdfSopenharmony_ci
876f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
877f08c3bdfSopenharmony_ci}
878f08c3bdfSopenharmony_ci
879f08c3bdfSopenharmony_ci/*
880f08c3bdfSopenharmony_ci * map <seg-name> [<offset>[k|m|g|p] <length>[k|m|g|p]] [<seg-share>]
881f08c3bdfSopenharmony_ci */
882f08c3bdfSopenharmony_cistatic int map_seg(char *args)
883f08c3bdfSopenharmony_ci{
884f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
885f08c3bdfSopenharmony_ci
886f08c3bdfSopenharmony_ci	char *segname, *nextarg;
887f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
888f08c3bdfSopenharmony_ci	range_t *rangep = NULL;
889f08c3bdfSopenharmony_ci	int segflag = MAP_PRIVATE;
890f08c3bdfSopenharmony_ci
891f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
892f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
893f08c3bdfSopenharmony_ci		return CMD_ERROR;
894f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
895f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
896f08c3bdfSopenharmony_ci
897f08c3bdfSopenharmony_ci	/*
898f08c3bdfSopenharmony_ci	 * offset, length are optional
899f08c3bdfSopenharmony_ci	 */
900f08c3bdfSopenharmony_ci	if (get_range(args, &range, &nextarg) == CMD_ERROR)
901f08c3bdfSopenharmony_ci		return CMD_ERROR;
902f08c3bdfSopenharmony_ci	if (args != nextarg) {
903f08c3bdfSopenharmony_ci		rangep = &range;	/* override any registered range */
904f08c3bdfSopenharmony_ci		args = nextarg;
905f08c3bdfSopenharmony_ci	}
906f08c3bdfSopenharmony_ci
907f08c3bdfSopenharmony_ci	if (*args != '\0') {
908f08c3bdfSopenharmony_ci		segflag = get_shared(args);
909f08c3bdfSopenharmony_ci		if (segflag == -1)
910f08c3bdfSopenharmony_ci			return CMD_ERROR;
911f08c3bdfSopenharmony_ci	}
912f08c3bdfSopenharmony_ci
913f08c3bdfSopenharmony_ci	if (!segment_map(segname, rangep, segflag))
914f08c3bdfSopenharmony_ci		return CMD_ERROR;
915f08c3bdfSopenharmony_ci
916f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
917f08c3bdfSopenharmony_ci}
918f08c3bdfSopenharmony_ci
919f08c3bdfSopenharmony_ci/*
920f08c3bdfSopenharmony_ci * mbind <seg-name> [<offset>[kmgp] <length>[kmgp]] <policy> <node-list>
921f08c3bdfSopenharmony_ci */
922f08c3bdfSopenharmony_cistatic int mbind_seg(char *args)
923f08c3bdfSopenharmony_ci{
924f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
925f08c3bdfSopenharmony_ci
926f08c3bdfSopenharmony_ci	char *segname, *nextarg;
927f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
928f08c3bdfSopenharmony_ci	nodemask_t *nodemask = NULL;
929f08c3bdfSopenharmony_ci	int policy, flags = 0;
930f08c3bdfSopenharmony_ci	int ret;
931f08c3bdfSopenharmony_ci
932f08c3bdfSopenharmony_ci	if (!numa_supported())
933f08c3bdfSopenharmony_ci		return CMD_ERROR;
934f08c3bdfSopenharmony_ci
935f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
936f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
937f08c3bdfSopenharmony_ci		return CMD_ERROR;
938f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
939f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
940f08c3bdfSopenharmony_ci
941f08c3bdfSopenharmony_ci	/*
942f08c3bdfSopenharmony_ci	 * offset, length are optional
943f08c3bdfSopenharmony_ci	 */
944f08c3bdfSopenharmony_ci	if (get_range(args, &range, &nextarg) == CMD_ERROR)
945f08c3bdfSopenharmony_ci		return CMD_ERROR;
946f08c3bdfSopenharmony_ci	args = nextarg;
947f08c3bdfSopenharmony_ci
948f08c3bdfSopenharmony_ci	if (!required_arg(args, "<policy>"))
949f08c3bdfSopenharmony_ci		return CMD_ERROR;
950f08c3bdfSopenharmony_ci	policy = get_mbind_policy(args, &nextarg);
951f08c3bdfSopenharmony_ci	if (policy < 0)
952f08c3bdfSopenharmony_ci		return CMD_ERROR;
953f08c3bdfSopenharmony_ci
954f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
955f08c3bdfSopenharmony_ci	if (*args == '+') {
956f08c3bdfSopenharmony_ci		flags = get_mbind_flags(++args, &nextarg);
957f08c3bdfSopenharmony_ci		if (flags == -1)
958f08c3bdfSopenharmony_ci			return CMD_ERROR;
959f08c3bdfSopenharmony_ci	}
960f08c3bdfSopenharmony_ci	args = nextarg + strspn(nextarg, whitespace);
961f08c3bdfSopenharmony_ci
962f08c3bdfSopenharmony_ci	if (policy != MPOL_DEFAULT) {
963f08c3bdfSopenharmony_ci		if (!required_arg(args, "<node/list>"))
964f08c3bdfSopenharmony_ci			return CMD_ERROR;
965f08c3bdfSopenharmony_ci		nodemask = get_nodemask(args);
966f08c3bdfSopenharmony_ci		if (nodemask == NULL)
967f08c3bdfSopenharmony_ci			return CMD_ERROR;
968f08c3bdfSopenharmony_ci	}
969f08c3bdfSopenharmony_ci
970f08c3bdfSopenharmony_ci	ret = CMD_SUCCESS;
971f08c3bdfSopenharmony_ci#if 1				// for testing
972f08c3bdfSopenharmony_ci	if (!segment_mbind(segname, &range, policy, nodemask, flags))
973f08c3bdfSopenharmony_ci		ret = CMD_ERROR;
974f08c3bdfSopenharmony_ci#endif
975f08c3bdfSopenharmony_ci
976f08c3bdfSopenharmony_ci	if (nodemask != NULL)
977f08c3bdfSopenharmony_ci		free(nodemask);
978f08c3bdfSopenharmony_ci	return ret;
979f08c3bdfSopenharmony_ci}
980f08c3bdfSopenharmony_ci
981f08c3bdfSopenharmony_ci/*
982f08c3bdfSopenharmony_ci *  shmem_seg - create [shmget] and register a SysV shared memory segment
983f08c3bdfSopenharmony_ci *              of specified size
984f08c3bdfSopenharmony_ci */
985f08c3bdfSopenharmony_cistatic int shmem_seg(char *args)
986f08c3bdfSopenharmony_ci{
987f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
988f08c3bdfSopenharmony_ci
989f08c3bdfSopenharmony_ci	char *segname, *nextarg;
990f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
991f08c3bdfSopenharmony_ci
992f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
993f08c3bdfSopenharmony_ci
994f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
995f08c3bdfSopenharmony_ci		return CMD_ERROR;
996f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
997f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
998f08c3bdfSopenharmony_ci
999f08c3bdfSopenharmony_ci	if (!required_arg(args, "<size>"))
1000f08c3bdfSopenharmony_ci		return CMD_ERROR;
1001f08c3bdfSopenharmony_ci	args = strtok_r(args, whitespace, &nextarg);
1002f08c3bdfSopenharmony_ci	range.length = get_scaled_value(args, "size");
1003f08c3bdfSopenharmony_ci	if (range.length == BOGUS_SIZE)
1004f08c3bdfSopenharmony_ci		return CMD_ERROR;
1005f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
1006f08c3bdfSopenharmony_ci
1007f08c3bdfSopenharmony_ci	if (!segment_register(SEGT_SHM, segname, &range, MAP_SHARED))
1008f08c3bdfSopenharmony_ci		return CMD_ERROR;
1009f08c3bdfSopenharmony_ci
1010f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
1011f08c3bdfSopenharmony_ci}
1012f08c3bdfSopenharmony_ci
1013f08c3bdfSopenharmony_ci/*
1014f08c3bdfSopenharmony_ci * where <seg-name> [<offset>[kmgp] <length>[kmgp]]  - show node location
1015f08c3bdfSopenharmony_ci * of specified range of segment.
1016f08c3bdfSopenharmony_ci *
1017f08c3bdfSopenharmony_ci * NOTE: if neither <offset> nor <length> specified, <offset> defaults
1018f08c3bdfSopenharmony_ci * to 0 [start of segment], as usual, and length defaults to 64 pages
1019f08c3bdfSopenharmony_ci * rather than the entire segment.  Suitable for a "quick look" at where
1020f08c3bdfSopenharmony_ci * segment resides.
1021f08c3bdfSopenharmony_ci */
1022f08c3bdfSopenharmony_cistatic int where_seg(char *args)
1023f08c3bdfSopenharmony_ci{
1024f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
1025f08c3bdfSopenharmony_ci
1026f08c3bdfSopenharmony_ci	char *segname, *nextarg;
1027f08c3bdfSopenharmony_ci	range_t range = { 0L, 0L };
1028f08c3bdfSopenharmony_ci	int ret;
1029f08c3bdfSopenharmony_ci
1030f08c3bdfSopenharmony_ci	if (!numa_supported())
1031f08c3bdfSopenharmony_ci		return CMD_ERROR;
1032f08c3bdfSopenharmony_ci
1033f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
1034f08c3bdfSopenharmony_ci	if (!required_arg(args, "<seg-name>"))
1035f08c3bdfSopenharmony_ci		return CMD_ERROR;
1036f08c3bdfSopenharmony_ci	segname = strtok_r(args, whitespace, &nextarg);
1037f08c3bdfSopenharmony_ci	args = get_next_arg(args, nextarg);
1038f08c3bdfSopenharmony_ci
1039f08c3bdfSopenharmony_ci	/*
1040f08c3bdfSopenharmony_ci	 * offset, length are optional
1041f08c3bdfSopenharmony_ci	 */
1042f08c3bdfSopenharmony_ci	if (get_range(args, &range, &nextarg) == CMD_ERROR)
1043f08c3bdfSopenharmony_ci		return CMD_ERROR;
1044f08c3bdfSopenharmony_ci	if (args == nextarg)
1045f08c3bdfSopenharmony_ci		range.length = 64 * gcp->pagesize;	/* default length */
1046f08c3bdfSopenharmony_ci
1047f08c3bdfSopenharmony_ci	if (!segment_location(segname, &range))
1048f08c3bdfSopenharmony_ci		return CMD_ERROR;
1049f08c3bdfSopenharmony_ci
1050f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
1051f08c3bdfSopenharmony_ci}
1052f08c3bdfSopenharmony_ci
1053f08c3bdfSopenharmony_ci#if 0
1054f08c3bdfSopenharmony_cistatic int command(char *args)
1055f08c3bdfSopenharmony_ci{
1056f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
1057f08c3bdfSopenharmony_ci
1058f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
1059f08c3bdfSopenharmony_ci}
1060f08c3bdfSopenharmony_ci
1061f08c3bdfSopenharmony_ci#endif
1062f08c3bdfSopenharmony_ci/*
1063f08c3bdfSopenharmony_ci * =========================================================================
1064f08c3bdfSopenharmony_ci */
1065f08c3bdfSopenharmony_citypedef int (*cmd_func_t) (char *);
1066f08c3bdfSopenharmony_ci
1067f08c3bdfSopenharmony_cistruct command {
1068f08c3bdfSopenharmony_ci	char *cmd_name;
1069f08c3bdfSopenharmony_ci	cmd_func_t cmd_func;	/* */
1070f08c3bdfSopenharmony_ci	char *cmd_help;
1071f08c3bdfSopenharmony_ci
1072f08c3bdfSopenharmony_ci} cmd_table[] = {
1073f08c3bdfSopenharmony_ci	{
1074f08c3bdfSopenharmony_ci	.cmd_name = "quit",.cmd_func = quit,.cmd_help =
1075f08c3bdfSopenharmony_ci		    "quit           - just what you think\n"
1076f08c3bdfSopenharmony_ci		    "\tEOF on stdin has the same effect\n"}, {
1077f08c3bdfSopenharmony_ci	.cmd_name = "help",.cmd_func = help_me,.cmd_help =
1078f08c3bdfSopenharmony_ci		    "help           - show this help\n"
1079f08c3bdfSopenharmony_ci		    "help <command> - display help for just <command>\n"}, {
1080f08c3bdfSopenharmony_ci	.cmd_name = "pid",.cmd_func = show_pid,.cmd_help =
1081f08c3bdfSopenharmony_ci		    "pid            - show process id of this session\n"}, {
1082f08c3bdfSopenharmony_ci	.cmd_name = "pause",.cmd_func = pause_me,.cmd_help =
1083f08c3bdfSopenharmony_ci		    "pause          - pause program until signal"
1084f08c3bdfSopenharmony_ci		    " -- e.g., INT, USR1\n"}, {
1085f08c3bdfSopenharmony_ci	.cmd_name = "numa",.cmd_func = numa_info,.cmd_help =
1086f08c3bdfSopenharmony_ci		    "numa          - display numa info as seen by this program.\n"
1087f08c3bdfSopenharmony_ci		    "\tshows nodes from which program may allocate memory\n"
1088f08c3bdfSopenharmony_ci		    "\twith total and free memory.\n"}, {
1089f08c3bdfSopenharmony_ci	.cmd_name = "migrate",.cmd_func = migrate_process,.cmd_help =
1090f08c3bdfSopenharmony_ci		    "migrate <to-node-id[s]> [<from-node-id[s]>] - \n"
1091f08c3bdfSopenharmony_ci		    "\tmigrate this process' memory from <from-node-id[s]>\n"
1092f08c3bdfSopenharmony_ci		    "\tto <to-node-id[s]>.  Specify multiple node ids as a\n"
1093f08c3bdfSopenharmony_ci		    "\tcomma-separated list. TODO - more info\n"}, {
1094f08c3bdfSopenharmony_ci	.cmd_name = "show",.cmd_func = show_seg,.cmd_help =
1095f08c3bdfSopenharmony_ci		    "show [<name>]  - show info for segment[s]; default all\n"},
1096f08c3bdfSopenharmony_ci	{
1097f08c3bdfSopenharmony_ci	.cmd_name = "anon",.cmd_func = anon_seg,.cmd_help =
1098f08c3bdfSopenharmony_ci		    "anon <seg-name> <seg-size>[k|m|g|p] [<seg-share>] -\n"
1099f08c3bdfSopenharmony_ci		    "\tdefine a MAP_ANONYMOUS segment of specified size\n"
1100f08c3bdfSopenharmony_ci		    "\t<seg-share> := private|shared - default = private\n"}, {
1101f08c3bdfSopenharmony_ci	.cmd_name = "file",.cmd_func = file_seg,.cmd_help =
1102f08c3bdfSopenharmony_ci		    "file <pathname> [<offset>[k|m|g|p] <length>[k|m|g|p]] [<seg-share>] -\n"
1103f08c3bdfSopenharmony_ci		    "\tdefine a mapped file segment of specified length starting at the\n"
1104f08c3bdfSopenharmony_ci		    "\tspecified offset into the file.  <offset> and <length> may be\n"
1105f08c3bdfSopenharmony_ci		    "\tomitted and specified on the map command.\n"
1106f08c3bdfSopenharmony_ci		    "\t<seg-share> := private|shared - default = private\n"}, {
1107f08c3bdfSopenharmony_ci	.cmd_name = "createfile", .cmd_func = create_file, .cmd_help =
1108f08c3bdfSopenharmony_ci			"createfile <file-name> <size>[k|m|g|p]]",}, {
1109f08c3bdfSopenharmony_ci	.cmd_name = "deletefile", .cmd_func = delete_file, .cmd_help =
1110f08c3bdfSopenharmony_ci			"deletefile <file-name>"}, {
1111f08c3bdfSopenharmony_ci	.cmd_name = "shm",.cmd_func = shmem_seg,.cmd_help =
1112f08c3bdfSopenharmony_ci		    "shm <seg-name> <seg-size>[k|m|g|p] - \n"
1113f08c3bdfSopenharmony_ci		    "\tdefine a shared memory segment of specified size.\n"
1114f08c3bdfSopenharmony_ci		    "\tYou may need to increase limits [/proc/sys/kernel/shmmax].\n"
1115f08c3bdfSopenharmony_ci		    "\tUse map/unmap to attach/detach\n"}, {
1116f08c3bdfSopenharmony_ci	.cmd_name = "remove",.cmd_func = remove_seg,.cmd_help =
1117f08c3bdfSopenharmony_ci		    "remove <seg-name> [<seg-name> ...] - remove the named segment[s]\n"},
1118f08c3bdfSopenharmony_ci	{
1119f08c3bdfSopenharmony_ci	.cmd_name = "map",.cmd_func = map_seg,.cmd_help =
1120f08c3bdfSopenharmony_ci		    "map <seg-name> [<offset>[k|m|g|p] <length>[k|m|g|p]] [<seg-share>] - \n"
1121f08c3bdfSopenharmony_ci		    "\tmmap()/shmat() a previously defined, currently unmapped() segment.\n"
1122f08c3bdfSopenharmony_ci		    "\t<offset> and <length> apply only to mapped files.\n"
1123f08c3bdfSopenharmony_ci		    "\tUse <length> of '*' or '0' to map to the end of the file.\n"},
1124f08c3bdfSopenharmony_ci	{
1125f08c3bdfSopenharmony_ci	.cmd_name = "unmap",.cmd_func = unmap_seg,.cmd_help =
1126f08c3bdfSopenharmony_ci		    "unmap <seg-name> - unmap specified segment, but remember name/size/...\n"},
1127f08c3bdfSopenharmony_ci	{
1128f08c3bdfSopenharmony_ci	.cmd_name = "touch",.cmd_func = touch_seg,.cmd_help =
1129f08c3bdfSopenharmony_ci		    "touch <seg-name> [<offset>[k|m|g|p] <length>[k|m|g|p]] [read|write] - \n"
1130f08c3bdfSopenharmony_ci		    "\tread [default] or write the named segment from <offset> through\n"
1131f08c3bdfSopenharmony_ci		    "\t<offset>+<length>.  If <offset> and <length> omitted, touches all\n"
1132f08c3bdfSopenharmony_ci		    "\t of mapped segment.\n"}, {
1133f08c3bdfSopenharmony_ci	.cmd_name = "mbind",.cmd_func = mbind_seg,.cmd_help =
1134f08c3bdfSopenharmony_ci		    "mbind <seg-name> [<offset>[k|m|g|p] <length>[k|m|g|p]]\n"
1135f08c3bdfSopenharmony_ci		    "      <policy>[+move[+wait]] [<node/list>] - \n"
1136f08c3bdfSopenharmony_ci		    "\tset the numa policy for the specified range of the name segment\n"
1137f08c3bdfSopenharmony_ci		    "\tto policy --  one of {default, bind, preferred, interleaved}.\n"
1138f08c3bdfSopenharmony_ci		    "\t<node/list> specifies a node id or a comma separated list of\n"
1139f08c3bdfSopenharmony_ci		    "\tnode ids.  <node> is ignored for 'default' policy, and only\n"
1140f08c3bdfSopenharmony_ci		    "\tthe first node is used for 'preferred' policy.\n"
1141f08c3bdfSopenharmony_ci		    "\t'+move' specifies that currently allocated pages be prepared\n"
1142f08c3bdfSopenharmony_ci		    "\t        for migration on next touch\n"
1143f08c3bdfSopenharmony_ci		    "\t'+wait' [valid only with +move] specifies that pages mbind()\n"
1144f08c3bdfSopenharmony_ci		    "          touch the pages and wait for migration before returning.\n"},
1145f08c3bdfSopenharmony_ci	{
1146f08c3bdfSopenharmony_ci	.cmd_name = "where",.cmd_func = where_seg,.cmd_help =
1147f08c3bdfSopenharmony_ci		    "where <seg-name> [<offset>[k|m|g|p] <length>[k|m|g|p]] - \n"
1148f08c3bdfSopenharmony_ci		    "\tshow the node location of pages in the specified range\n"
1149f08c3bdfSopenharmony_ci		    "\tof the specified segment.  <offset> defaults to start of\n"
1150f08c3bdfSopenharmony_ci		    "\tsegment; <length> defaults to 64 pages.\n"},
1151f08c3bdfSopenharmony_ci#if 0				/* template for new commands */
1152f08c3bdfSopenharmony_ci	{
1153f08c3bdfSopenharmony_ci	.cmd_name = "",.cmd_func =,.cmd_help =},
1154f08c3bdfSopenharmony_ci#endif
1155f08c3bdfSopenharmony_ci	{
1156f08c3bdfSopenharmony_ci	.cmd_name = NULL}
1157f08c3bdfSopenharmony_ci};
1158f08c3bdfSopenharmony_ci
1159f08c3bdfSopenharmony_cistatic int help_me(char *args)
1160f08c3bdfSopenharmony_ci{
1161f08c3bdfSopenharmony_ci	struct command *cmdp = cmd_table;
1162f08c3bdfSopenharmony_ci	char *cmd, *nextarg;
1163f08c3bdfSopenharmony_ci	int cmdlen;
1164f08c3bdfSopenharmony_ci	bool match = false;
1165f08c3bdfSopenharmony_ci
1166f08c3bdfSopenharmony_ci	args += strspn(args, whitespace);
1167f08c3bdfSopenharmony_ci	if (*args != '\0') {
1168f08c3bdfSopenharmony_ci		cmd = strtok_r(args, whitespace, &nextarg);
1169f08c3bdfSopenharmony_ci		cmdlen = strlen(cmd);
1170f08c3bdfSopenharmony_ci	} else {
1171f08c3bdfSopenharmony_ci		cmd = NULL;
1172f08c3bdfSopenharmony_ci		cmdlen = 0;
1173f08c3bdfSopenharmony_ci	}
1174f08c3bdfSopenharmony_ci
1175f08c3bdfSopenharmony_ci	for (cmdp = cmd_table; cmdp->cmd_name != NULL; ++cmdp) {
1176f08c3bdfSopenharmony_ci		if (cmd == NULL || !strncmp(cmd, cmdp->cmd_name, cmdlen)) {
1177f08c3bdfSopenharmony_ci			printf("%s\n", cmdp->cmd_help);
1178f08c3bdfSopenharmony_ci			match = true;
1179f08c3bdfSopenharmony_ci		}
1180f08c3bdfSopenharmony_ci	}
1181f08c3bdfSopenharmony_ci
1182f08c3bdfSopenharmony_ci	if (!match) {
1183f08c3bdfSopenharmony_ci		printf("unrecognized command:  %s\n", cmd);
1184f08c3bdfSopenharmony_ci		printf("\tuse 'help' for a complete list of commands\n");
1185f08c3bdfSopenharmony_ci		return CMD_ERROR;
1186f08c3bdfSopenharmony_ci	}
1187f08c3bdfSopenharmony_ci
1188f08c3bdfSopenharmony_ci	return CMD_SUCCESS;
1189f08c3bdfSopenharmony_ci}
1190f08c3bdfSopenharmony_ci
1191f08c3bdfSopenharmony_ci/*
1192f08c3bdfSopenharmony_ci * =========================================================================
1193f08c3bdfSopenharmony_ci */
1194f08c3bdfSopenharmony_ci
1195f08c3bdfSopenharmony_cistatic bool unique_abbrev(char *cmd, size_t clen, struct command *cmdp)
1196f08c3bdfSopenharmony_ci{
1197f08c3bdfSopenharmony_ci	for (; cmdp->cmd_name != NULL; ++cmdp) {
1198f08c3bdfSopenharmony_ci		if (!strncmp(cmd, cmdp->cmd_name, clen))
1199f08c3bdfSopenharmony_ci			return false;	/* match: not unique */
1200f08c3bdfSopenharmony_ci	}
1201f08c3bdfSopenharmony_ci	return true;
1202f08c3bdfSopenharmony_ci}
1203f08c3bdfSopenharmony_ci
1204f08c3bdfSopenharmony_cistatic int parse_command(char *cmdline)
1205f08c3bdfSopenharmony_ci{
1206f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
1207f08c3bdfSopenharmony_ci	char *cmd, *args;
1208f08c3bdfSopenharmony_ci	struct command *cmdp;
1209f08c3bdfSopenharmony_ci
1210f08c3bdfSopenharmony_ci	cmdline += strspn(cmdline, whitespace);	/* possibly redundant */
1211f08c3bdfSopenharmony_ci
1212f08c3bdfSopenharmony_ci	cmd = strtok_r(cmdline, whitespace, &args);
1213f08c3bdfSopenharmony_ci
1214f08c3bdfSopenharmony_ci	for (cmdp = cmd_table; cmdp->cmd_name != NULL; ++cmdp) {
1215f08c3bdfSopenharmony_ci		size_t clen = strlen(cmd);
1216f08c3bdfSopenharmony_ci		int ret;
1217f08c3bdfSopenharmony_ci
1218f08c3bdfSopenharmony_ci		if (strncmp(cmd, cmdp->cmd_name, clen))
1219f08c3bdfSopenharmony_ci			continue;
1220f08c3bdfSopenharmony_ci		if (!unique_abbrev(cmd, clen, cmdp + 1)) {
1221f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  ambiguous command:  %s\n",
1222f08c3bdfSopenharmony_ci				gcp->program_name, cmd);
1223f08c3bdfSopenharmony_ci			return CMD_ERROR;
1224f08c3bdfSopenharmony_ci		}
1225f08c3bdfSopenharmony_ci		gcp->cmd_name = cmdp->cmd_name;
1226f08c3bdfSopenharmony_ci		ret = cmdp->cmd_func(args);
1227f08c3bdfSopenharmony_ci		gcp->cmd_name = NULL;
1228f08c3bdfSopenharmony_ci		return ret;
1229f08c3bdfSopenharmony_ci	}
1230f08c3bdfSopenharmony_ci
1231f08c3bdfSopenharmony_ci	fprintf(stderr, "%s:  unrecognized command %s\n", __FUNCTION__, cmd);
1232f08c3bdfSopenharmony_ci	return CMD_ERROR;
1233f08c3bdfSopenharmony_ci}
1234f08c3bdfSopenharmony_ci
1235f08c3bdfSopenharmony_civoid process_commands()
1236f08c3bdfSopenharmony_ci{
1237f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
1238f08c3bdfSopenharmony_ci
1239f08c3bdfSopenharmony_ci	char cmdbuf[CMDBUFSZ];
1240f08c3bdfSopenharmony_ci
1241f08c3bdfSopenharmony_ci	do {
1242f08c3bdfSopenharmony_ci		char *cmdline;
1243f08c3bdfSopenharmony_ci		size_t cmdlen;
1244f08c3bdfSopenharmony_ci
1245f08c3bdfSopenharmony_ci		if (is_option(INTERACTIVE))
1246f08c3bdfSopenharmony_ci			printf("%s>", gcp->program_name);
1247f08c3bdfSopenharmony_ci
1248f08c3bdfSopenharmony_ci		cmdline = fgets(cmdbuf, CMDBUFSZ, stdin);
1249f08c3bdfSopenharmony_ci		if (cmdline == NULL) {
1250f08c3bdfSopenharmony_ci			printf("%s\n",
1251f08c3bdfSopenharmony_ci			       is_option(INTERACTIVE) ? "" : "EOF on stdin");
1252f08c3bdfSopenharmony_ci			exit(0);	/* EOF */
1253f08c3bdfSopenharmony_ci		}
1254f08c3bdfSopenharmony_ci		if (cmdline[0] == '\n')
1255f08c3bdfSopenharmony_ci			continue;
1256f08c3bdfSopenharmony_ci
1257f08c3bdfSopenharmony_ci		/*
1258f08c3bdfSopenharmony_ci		 * trim trailing newline, if any
1259f08c3bdfSopenharmony_ci		 */
1260f08c3bdfSopenharmony_ci		cmdlen = strlen(cmdline);
1261f08c3bdfSopenharmony_ci		if (cmdline[cmdlen - 1] == '\n')
1262f08c3bdfSopenharmony_ci			cmdline[--cmdlen] = '\0';
1263f08c3bdfSopenharmony_ci
1264f08c3bdfSopenharmony_ci		cmdline += strspn(cmdline, whitespace);
1265f08c3bdfSopenharmony_ci		cmdlen -= (cmdline - cmdbuf);
1266f08c3bdfSopenharmony_ci
1267f08c3bdfSopenharmony_ci		if (cmdlen == 0) {
1268f08c3bdfSopenharmony_ci			//TODO:  interactive help?
1269f08c3bdfSopenharmony_ci			continue;	/* ignore blank lines */
1270f08c3bdfSopenharmony_ci		}
1271f08c3bdfSopenharmony_ci
1272f08c3bdfSopenharmony_ci		if (*cmdline == '#')
1273f08c3bdfSopenharmony_ci			continue;	/* comments */
1274f08c3bdfSopenharmony_ci
1275f08c3bdfSopenharmony_ci		/*
1276f08c3bdfSopenharmony_ci		 * trim trailing whitespace for ease of parsing
1277f08c3bdfSopenharmony_ci		 */
1278f08c3bdfSopenharmony_ci		while (strchr(whitespace, cmdline[cmdlen - 1]))
1279f08c3bdfSopenharmony_ci			cmdline[--cmdlen] = '\0';
1280f08c3bdfSopenharmony_ci
1281f08c3bdfSopenharmony_ci		if (cmdlen == 0)
1282f08c3bdfSopenharmony_ci			continue;
1283f08c3bdfSopenharmony_ci
1284f08c3bdfSopenharmony_ci		/*
1285f08c3bdfSopenharmony_ci		 * reset signals just before parsing a command.
1286f08c3bdfSopenharmony_ci		 * non-interactive:  exit on SIGQUIT
1287f08c3bdfSopenharmony_ci		 */
1288f08c3bdfSopenharmony_ci		if (signalled(gcp)) {
1289f08c3bdfSopenharmony_ci			if (!is_option(INTERACTIVE) &&
1290f08c3bdfSopenharmony_ci			    gcp->siginfo->si_signo == SIGQUIT)
1291f08c3bdfSopenharmony_ci				exit(0);
1292f08c3bdfSopenharmony_ci			reset_signal();
1293f08c3bdfSopenharmony_ci		}
1294f08c3bdfSopenharmony_ci
1295f08c3bdfSopenharmony_ci		/*
1296f08c3bdfSopenharmony_ci		 * non-interactive:  errors are fatal
1297f08c3bdfSopenharmony_ci		 */
1298f08c3bdfSopenharmony_ci		if (!is_option(INTERACTIVE)) {
1299f08c3bdfSopenharmony_ci			vprint("%s>%s\n", gcp->program_name, cmdline);
1300f08c3bdfSopenharmony_ci			if (parse_command(cmdline) == CMD_ERROR) {
1301f08c3bdfSopenharmony_ci				fprintf(stderr, "%s:  command error\n",
1302f08c3bdfSopenharmony_ci					gcp->program_name);
1303f08c3bdfSopenharmony_ci				exit(4);
1304f08c3bdfSopenharmony_ci			}
1305f08c3bdfSopenharmony_ci		} else
1306f08c3bdfSopenharmony_ci			parse_command(cmdline);
1307f08c3bdfSopenharmony_ci
1308f08c3bdfSopenharmony_ci	} while (1);
1309f08c3bdfSopenharmony_ci}
1310f08c3bdfSopenharmony_ci#endif
1311