xref: /openbmc/linux/arch/um/os-Linux/mem.c (revision 7473534130c3156d199512c99ff1b796233e8547)
15134d8feSJeff Dike /*
25134d8feSJeff Dike  * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
35134d8feSJeff Dike  * Licensed under the GPL
45134d8feSJeff Dike  */
55134d8feSJeff Dike 
60f80bc85SJeff Dike #include <stdio.h>
70f80bc85SJeff Dike #include <stddef.h>
85134d8feSJeff Dike #include <stdlib.h>
90f80bc85SJeff Dike #include <unistd.h>
100f80bc85SJeff Dike #include <errno.h>
110f80bc85SJeff Dike #include <fcntl.h>
125134d8feSJeff Dike #include <string.h>
13fb967eccSLiu Aleaxander #include <sys/stat.h>
140f80bc85SJeff Dike #include <sys/mman.h>
150f80bc85SJeff Dike #include <sys/param.h>
1637185b33SAl Viro #include <init.h>
1737185b33SAl Viro #include <os.h>
180f80bc85SJeff Dike 
196bf79482SJeff Dike /* Modified by which_tmpdir, which is called during early boot */
20966a082fSRob Landley static char *default_tmpdir = "/tmp";
216bf79482SJeff Dike 
226bf79482SJeff Dike /*
236bf79482SJeff Dike  *  Modified when creating the physical memory file and when checking
246bf79482SJeff Dike  * the tmp filesystem for usability, both happening during early boot.
256bf79482SJeff Dike  */
260f80bc85SJeff Dike static char *tempdir = NULL;
270f80bc85SJeff Dike 
280f80bc85SJeff Dike static void __init find_tempdir(void)
290f80bc85SJeff Dike {
30c0a9290eSWANG Cong 	const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
310f80bc85SJeff Dike 	int i;
320f80bc85SJeff Dike 	char *dir = NULL;
330f80bc85SJeff Dike 
345134d8feSJeff Dike 	if (tempdir != NULL)
355134d8feSJeff Dike 		/* We've already been called */
3681999a01SJeff Dike 		return;
370f80bc85SJeff Dike 	for (i = 0; dirs[i]; i++) {
380f80bc85SJeff Dike 		dir = getenv(dirs[i]);
390f80bc85SJeff Dike 		if ((dir != NULL) && (*dir != '\0'))
400f80bc85SJeff Dike 			break;
410f80bc85SJeff Dike 	}
420f80bc85SJeff Dike 	if ((dir == NULL) || (*dir == '\0'))
43966a082fSRob Landley 		dir = default_tmpdir;
440f80bc85SJeff Dike 
450f80bc85SJeff Dike 	tempdir = malloc(strlen(dir) + 2);
460f80bc85SJeff Dike 	if (tempdir == NULL) {
470f80bc85SJeff Dike 		fprintf(stderr, "Failed to malloc tempdir, "
480f80bc85SJeff Dike 			"errno = %d\n", errno);
490f80bc85SJeff Dike 		return;
500f80bc85SJeff Dike 	}
510f80bc85SJeff Dike 	strcpy(tempdir, dir);
520f80bc85SJeff Dike 	strcat(tempdir, "/");
530f80bc85SJeff Dike }
540f80bc85SJeff Dike 
555134d8feSJeff Dike /*
56*74735341STristan Schmelcher  * Remove bytes from the front of the buffer and refill it so that if there's a
57*74735341STristan Schmelcher  * partial string that we care about, it will be completed, and we can recognize
58*74735341STristan Schmelcher  * it.
59*74735341STristan Schmelcher  */
60*74735341STristan Schmelcher static int pop(int fd, char *buf, size_t size, size_t npop)
61*74735341STristan Schmelcher {
62*74735341STristan Schmelcher 	ssize_t n;
63*74735341STristan Schmelcher 	size_t len = strlen(&buf[npop]);
64*74735341STristan Schmelcher 
65*74735341STristan Schmelcher 	memmove(buf, &buf[npop], len + 1);
66*74735341STristan Schmelcher 	n = read(fd, &buf[len], size - len - 1);
67*74735341STristan Schmelcher 	if (n < 0)
68*74735341STristan Schmelcher 		return -errno;
69*74735341STristan Schmelcher 
70*74735341STristan Schmelcher 	buf[len + n] = '\0';
71*74735341STristan Schmelcher 	return 1;
72*74735341STristan Schmelcher }
73*74735341STristan Schmelcher 
74*74735341STristan Schmelcher /*
755134d8feSJeff Dike  * This will return 1, with the first character in buf being the
76966a082fSRob Landley  * character following the next instance of c in the file.  This will
77966a082fSRob Landley  * read the file as needed.  If there's an error, -errno is returned;
78966a082fSRob Landley  * if the end of the file is reached, 0 is returned.
79966a082fSRob Landley  */
80c0a9290eSWANG Cong static int next(int fd, char *buf, size_t size, char c)
81966a082fSRob Landley {
82c0a9290eSWANG Cong 	ssize_t n;
83966a082fSRob Landley 	char *ptr;
84966a082fSRob Landley 
85966a082fSRob Landley 	while ((ptr = strchr(buf, c)) == NULL) {
86966a082fSRob Landley 		n = read(fd, buf, size - 1);
87966a082fSRob Landley 		if (n == 0)
88966a082fSRob Landley 			return 0;
89966a082fSRob Landley 		else if (n < 0)
90966a082fSRob Landley 			return -errno;
91966a082fSRob Landley 
92966a082fSRob Landley 		buf[n] = '\0';
93966a082fSRob Landley 	}
94966a082fSRob Landley 
95*74735341STristan Schmelcher 	return pop(fd, buf, size, ptr - buf + 1);
96*74735341STristan Schmelcher }
97c2b7a4bbSJeff Dike 
985134d8feSJeff Dike /*
99*74735341STristan Schmelcher  * Decode an octal-escaped and space-terminated path of the form used by
100*74735341STristan Schmelcher  * /proc/mounts. May be used to decode a path in-place. "out" must be at least
101*74735341STristan Schmelcher  * as large as the input. The output is always null-terminated. "len" gets the
102*74735341STristan Schmelcher  * length of the output, excluding the trailing null. Returns 0 if a full path
103*74735341STristan Schmelcher  * was successfully decoded, otherwise an error.
104c2b7a4bbSJeff Dike  */
105*74735341STristan Schmelcher static int decode_path(const char *in, char *out, size_t *len)
106*74735341STristan Schmelcher {
107*74735341STristan Schmelcher 	char *first = out;
108*74735341STristan Schmelcher 	int c;
109*74735341STristan Schmelcher 	int i;
110*74735341STristan Schmelcher 	int ret = -EINVAL;
111*74735341STristan Schmelcher 	while (1) {
112*74735341STristan Schmelcher 		switch (*in) {
113*74735341STristan Schmelcher 		case '\0':
114*74735341STristan Schmelcher 			goto out;
115c2b7a4bbSJeff Dike 
116*74735341STristan Schmelcher 		case ' ':
117*74735341STristan Schmelcher 			ret = 0;
118*74735341STristan Schmelcher 			goto out;
119*74735341STristan Schmelcher 
120*74735341STristan Schmelcher 		case '\\':
121*74735341STristan Schmelcher 			in++;
122*74735341STristan Schmelcher 			c = 0;
123*74735341STristan Schmelcher 			for (i = 0; i < 3; i++) {
124*74735341STristan Schmelcher 				if (*in < '0' || *in > '7')
125*74735341STristan Schmelcher 					goto out;
126*74735341STristan Schmelcher 				c = (c << 3) | (*in++ - '0');
127*74735341STristan Schmelcher 			}
128*74735341STristan Schmelcher 			*(unsigned char *)out++ = (unsigned char) c;
129*74735341STristan Schmelcher 			break;
130*74735341STristan Schmelcher 
131*74735341STristan Schmelcher 		default:
132*74735341STristan Schmelcher 			*out++ = *in++;
133*74735341STristan Schmelcher 			break;
134*74735341STristan Schmelcher 		}
135*74735341STristan Schmelcher 	}
136*74735341STristan Schmelcher 
137*74735341STristan Schmelcher out:
138*74735341STristan Schmelcher 	*out = '\0';
139*74735341STristan Schmelcher 	*len = out - first;
140*74735341STristan Schmelcher 	return ret;
141*74735341STristan Schmelcher }
142*74735341STristan Schmelcher 
143*74735341STristan Schmelcher /*
144*74735341STristan Schmelcher  * Computes the length of s when encoded with three-digit octal escape sequences
145*74735341STristan Schmelcher  * for the characters in chars.
146*74735341STristan Schmelcher  */
147*74735341STristan Schmelcher static size_t octal_encoded_length(const char *s, const char *chars)
148*74735341STristan Schmelcher {
149*74735341STristan Schmelcher 	size_t len = strlen(s);
150*74735341STristan Schmelcher 	while ((s = strpbrk(s, chars)) != NULL) {
151*74735341STristan Schmelcher 		len += 3;
152*74735341STristan Schmelcher 		s++;
153*74735341STristan Schmelcher 	}
154*74735341STristan Schmelcher 
155*74735341STristan Schmelcher 	return len;
156*74735341STristan Schmelcher }
157*74735341STristan Schmelcher 
158*74735341STristan Schmelcher enum {
159*74735341STristan Schmelcher 	OUTCOME_NOTHING_MOUNTED,
160*74735341STristan Schmelcher 	OUTCOME_TMPFS_MOUNT,
161*74735341STristan Schmelcher 	OUTCOME_NON_TMPFS_MOUNT,
162*74735341STristan Schmelcher };
163*74735341STristan Schmelcher 
164*74735341STristan Schmelcher /* Read a line of /proc/mounts data looking for a tmpfs mount at "path". */
165*74735341STristan Schmelcher static int read_mount(int fd, char *buf, size_t bufsize, const char *path,
166*74735341STristan Schmelcher 		      int *outcome)
167*74735341STristan Schmelcher {
168*74735341STristan Schmelcher 	int found;
169*74735341STristan Schmelcher 	int match;
170*74735341STristan Schmelcher 	char *space;
171*74735341STristan Schmelcher 	size_t len;
172*74735341STristan Schmelcher 
173*74735341STristan Schmelcher 	enum {
174*74735341STristan Schmelcher 		MATCH_NONE,
175*74735341STristan Schmelcher 		MATCH_EXACT,
176*74735341STristan Schmelcher 		MATCH_PARENT,
177*74735341STristan Schmelcher 	};
178*74735341STristan Schmelcher 
179*74735341STristan Schmelcher 	found = next(fd, buf, bufsize, ' ');
180*74735341STristan Schmelcher 	if (found != 1)
181*74735341STristan Schmelcher 		return found;
182*74735341STristan Schmelcher 
183*74735341STristan Schmelcher 	/*
184*74735341STristan Schmelcher 	 * If there's no following space in the buffer, then this path is
185*74735341STristan Schmelcher 	 * truncated, so it can't be the one we're looking for.
186*74735341STristan Schmelcher 	 */
187*74735341STristan Schmelcher 	space = strchr(buf, ' ');
188*74735341STristan Schmelcher 	if (space) {
189*74735341STristan Schmelcher 		match = MATCH_NONE;
190*74735341STristan Schmelcher 		if (!decode_path(buf, buf, &len)) {
191*74735341STristan Schmelcher 			if (!strcmp(buf, path))
192*74735341STristan Schmelcher 				match = MATCH_EXACT;
193*74735341STristan Schmelcher 			else if (!strncmp(buf, path, len)
194*74735341STristan Schmelcher 				 && (path[len] == '/' || !strcmp(buf, "/")))
195*74735341STristan Schmelcher 				match = MATCH_PARENT;
196*74735341STristan Schmelcher 		}
197*74735341STristan Schmelcher 
198*74735341STristan Schmelcher 		found = pop(fd, buf, bufsize, space - buf + 1);
199*74735341STristan Schmelcher 		if (found != 1)
200*74735341STristan Schmelcher 			return found;
201*74735341STristan Schmelcher 
202*74735341STristan Schmelcher 		switch (match) {
203*74735341STristan Schmelcher 		case MATCH_EXACT:
204*74735341STristan Schmelcher 			if (!strncmp(buf, "tmpfs", strlen("tmpfs")))
205*74735341STristan Schmelcher 				*outcome = OUTCOME_TMPFS_MOUNT;
206*74735341STristan Schmelcher 			else
207*74735341STristan Schmelcher 				*outcome = OUTCOME_NON_TMPFS_MOUNT;
208*74735341STristan Schmelcher 			break;
209*74735341STristan Schmelcher 
210*74735341STristan Schmelcher 		case MATCH_PARENT:
211*74735341STristan Schmelcher 			/* This mount obscures any previous ones. */
212*74735341STristan Schmelcher 			*outcome = OUTCOME_NOTHING_MOUNTED;
213*74735341STristan Schmelcher 			break;
214*74735341STristan Schmelcher 		}
215*74735341STristan Schmelcher 	}
216*74735341STristan Schmelcher 
217*74735341STristan Schmelcher 	return next(fd, buf, bufsize, '\n');
218966a082fSRob Landley }
219966a082fSRob Landley 
2206bf79482SJeff Dike /* which_tmpdir is called only during early boot */
221966a082fSRob Landley static int checked_tmpdir = 0;
222966a082fSRob Landley 
2235134d8feSJeff Dike /*
2245134d8feSJeff Dike  * Look for a tmpfs mounted at /dev/shm.  I couldn't find a cleaner
225966a082fSRob Landley  * way to do this than to parse /proc/mounts.  statfs will return the
226966a082fSRob Landley  * same filesystem magic number and fs id for both /dev and /dev/shm
227966a082fSRob Landley  * when they are both tmpfs, so you can't tell if they are different
228966a082fSRob Landley  * filesystems.  Also, there seems to be no other way of finding the
229966a082fSRob Landley  * mount point of a filesystem from within it.
230966a082fSRob Landley  *
231966a082fSRob Landley  * If a /dev/shm tmpfs entry is found, then we switch to using it.
232966a082fSRob Landley  * Otherwise, we stay with the default /tmp.
233966a082fSRob Landley  */
234966a082fSRob Landley static void which_tmpdir(void)
235966a082fSRob Landley {
236*74735341STristan Schmelcher 	int fd;
237*74735341STristan Schmelcher 	int found;
238*74735341STristan Schmelcher 	int outcome;
239*74735341STristan Schmelcher 	char *path;
240*74735341STristan Schmelcher 	char *buf;
241*74735341STristan Schmelcher 	size_t bufsize;
242966a082fSRob Landley 
243966a082fSRob Landley 	if (checked_tmpdir)
244966a082fSRob Landley 		return;
245966a082fSRob Landley 
246966a082fSRob Landley 	checked_tmpdir = 1;
247966a082fSRob Landley 
248966a082fSRob Landley 	printf("Checking for tmpfs mount on /dev/shm...");
249966a082fSRob Landley 
250*74735341STristan Schmelcher 	path = realpath("/dev/shm", NULL);
251*74735341STristan Schmelcher 	if (!path) {
252*74735341STristan Schmelcher 		printf("failed to check real path, errno = %d\n", errno);
253*74735341STristan Schmelcher 		return;
254*74735341STristan Schmelcher 	}
255*74735341STristan Schmelcher 	printf("%s...", path);
256*74735341STristan Schmelcher 
257*74735341STristan Schmelcher 	/*
258*74735341STristan Schmelcher 	 * The buffer needs to be able to fit the full octal-escaped path, a
259*74735341STristan Schmelcher 	 * space, and a trailing null in order to successfully decode it.
260*74735341STristan Schmelcher 	 */
261*74735341STristan Schmelcher 	bufsize = octal_encoded_length(path, " \t\n\\") + 2;
262*74735341STristan Schmelcher 
263*74735341STristan Schmelcher 	if (bufsize < 128)
264*74735341STristan Schmelcher 		bufsize = 128;
265*74735341STristan Schmelcher 
266*74735341STristan Schmelcher 	buf = malloc(bufsize);
267*74735341STristan Schmelcher 	if (!buf) {
268*74735341STristan Schmelcher 		printf("malloc failed, errno = %d\n", errno);
269*74735341STristan Schmelcher 		goto out;
270*74735341STristan Schmelcher 	}
271*74735341STristan Schmelcher 	buf[0] = '\0';
272*74735341STristan Schmelcher 
273966a082fSRob Landley 	fd = open("/proc/mounts", O_RDONLY);
274966a082fSRob Landley 	if (fd < 0) {
275966a082fSRob Landley 		printf("failed to open /proc/mounts, errno = %d\n", errno);
276*74735341STristan Schmelcher 		goto out1;
277966a082fSRob Landley 	}
278966a082fSRob Landley 
279*74735341STristan Schmelcher 	outcome = OUTCOME_NOTHING_MOUNTED;
280966a082fSRob Landley 	while (1) {
281*74735341STristan Schmelcher 		found = read_mount(fd, buf, bufsize, path, &outcome);
282966a082fSRob Landley 		if (found != 1)
283966a082fSRob Landley 			break;
284966a082fSRob Landley 	}
285966a082fSRob Landley 
286*74735341STristan Schmelcher 	if (found < 0) {
287966a082fSRob Landley 		printf("read returned errno %d\n", -found);
288*74735341STristan Schmelcher 	} else {
289*74735341STristan Schmelcher 		switch (outcome) {
290*74735341STristan Schmelcher 		case OUTCOME_TMPFS_MOUNT:
291966a082fSRob Landley 			printf("OK\n");
292966a082fSRob Landley 			default_tmpdir = "/dev/shm";
293*74735341STristan Schmelcher 			break;
294*74735341STristan Schmelcher 
295*74735341STristan Schmelcher 		case OUTCOME_NON_TMPFS_MOUNT:
296*74735341STristan Schmelcher 			printf("not tmpfs\n");
297*74735341STristan Schmelcher 			break;
298*74735341STristan Schmelcher 
299*74735341STristan Schmelcher 		default:
300*74735341STristan Schmelcher 			printf("nothing mounted on /dev/shm\n");
301*74735341STristan Schmelcher 			break;
302*74735341STristan Schmelcher 		}
303*74735341STristan Schmelcher 	}
304*74735341STristan Schmelcher 
305*74735341STristan Schmelcher 	close(fd);
306*74735341STristan Schmelcher out1:
307*74735341STristan Schmelcher 	free(buf);
308*74735341STristan Schmelcher out:
309*74735341STristan Schmelcher 	free(path);
310966a082fSRob Landley }
311966a082fSRob Landley 
3125134d8feSJeff Dike static int __init make_tempfile(const char *template, char **out_tempname,
31336e45463SJeff Dike 				int do_unlink)
3140f80bc85SJeff Dike {
31587276f72SPaolo 'Blaisorblade' Giarrusso 	char *tempname;
3160f80bc85SJeff Dike 	int fd;
3170f80bc85SJeff Dike 
318966a082fSRob Landley 	which_tmpdir();
31987276f72SPaolo 'Blaisorblade' Giarrusso 	tempname = malloc(MAXPATHLEN);
32011a7ac23SJim Meyering 	if (tempname == NULL)
32111a7ac23SJim Meyering 		return -1;
32287276f72SPaolo 'Blaisorblade' Giarrusso 
3230f80bc85SJeff Dike 	find_tempdir();
32411a7ac23SJim Meyering 	if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN))
3252a6d0ac1SDavidlohr Bueso 		goto out;
32611a7ac23SJim Meyering 
32787276f72SPaolo 'Blaisorblade' Giarrusso 	if (template[0] != '/')
3280f80bc85SJeff Dike 		strcpy(tempname, tempdir);
3290f80bc85SJeff Dike 	else
33087276f72SPaolo 'Blaisorblade' Giarrusso 		tempname[0] = '\0';
331c9a3072dSWANG Cong 	strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
3320f80bc85SJeff Dike 	fd = mkstemp(tempname);
3330f80bc85SJeff Dike 	if (fd < 0) {
3340f80bc85SJeff Dike 		fprintf(stderr, "open - cannot create %s: %s\n", tempname,
3350f80bc85SJeff Dike 			strerror(errno));
33687276f72SPaolo 'Blaisorblade' Giarrusso 		goto out;
3370f80bc85SJeff Dike 	}
3380f80bc85SJeff Dike 	if (do_unlink && (unlink(tempname) < 0)) {
3390f80bc85SJeff Dike 		perror("unlink");
3402a6d0ac1SDavidlohr Bueso 		goto close;
3410f80bc85SJeff Dike 	}
3420f80bc85SJeff Dike 	if (out_tempname) {
34387276f72SPaolo 'Blaisorblade' Giarrusso 		*out_tempname = tempname;
34411a7ac23SJim Meyering 	} else
34587276f72SPaolo 'Blaisorblade' Giarrusso 		free(tempname);
34681999a01SJeff Dike 	return fd;
3472a6d0ac1SDavidlohr Bueso close:
3482a6d0ac1SDavidlohr Bueso 	close(fd);
34987276f72SPaolo 'Blaisorblade' Giarrusso out:
35087276f72SPaolo 'Blaisorblade' Giarrusso 	free(tempname);
35187276f72SPaolo 'Blaisorblade' Giarrusso 	return -1;
3520f80bc85SJeff Dike }
3530f80bc85SJeff Dike 
3540f80bc85SJeff Dike #define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
3550f80bc85SJeff Dike 
3565134d8feSJeff Dike static int __init create_tmp_file(unsigned long long len)
3570f80bc85SJeff Dike {
3580f80bc85SJeff Dike 	int fd, err;
3590f80bc85SJeff Dike 	char zero;
3600f80bc85SJeff Dike 
3610f80bc85SJeff Dike 	fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
3625134d8feSJeff Dike 	if (fd < 0)
3630f80bc85SJeff Dike 		exit(1);
3640f80bc85SJeff Dike 
3650f80bc85SJeff Dike 	err = fchmod(fd, 0777);
3660f80bc85SJeff Dike 	if (err < 0) {
367512b6fb1SJeff Dike 		perror("fchmod");
3680f80bc85SJeff Dike 		exit(1);
3690f80bc85SJeff Dike 	}
3700f80bc85SJeff Dike 
3715134d8feSJeff Dike 	/*
3725134d8feSJeff Dike 	 * Seek to len - 1 because writing a character there will
373190f4939SJeff Dike 	 * increase the file size by one byte, to the desired length.
374190f4939SJeff Dike 	 */
375190f4939SJeff Dike 	if (lseek64(fd, len - 1, SEEK_SET) < 0) {
376512b6fb1SJeff Dike 		perror("lseek64");
3770f80bc85SJeff Dike 		exit(1);
3780f80bc85SJeff Dike 	}
3790f80bc85SJeff Dike 
3800f80bc85SJeff Dike 	zero = 0;
3810f80bc85SJeff Dike 
382a61f334fSJeff Dike 	err = write(fd, &zero, 1);
3830f80bc85SJeff Dike 	if (err != 1) {
384a61f334fSJeff Dike 		perror("write");
3850f80bc85SJeff Dike 		exit(1);
3860f80bc85SJeff Dike 	}
3870f80bc85SJeff Dike 
38881999a01SJeff Dike 	return fd;
3890f80bc85SJeff Dike }
3900f80bc85SJeff Dike 
39136e45463SJeff Dike int __init create_mem_file(unsigned long long len)
3920f80bc85SJeff Dike {
3930f80bc85SJeff Dike 	int err, fd;
3940f80bc85SJeff Dike 
39502dea087SJeff Dike 	fd = create_tmp_file(len);
3960f80bc85SJeff Dike 
397512b6fb1SJeff Dike 	err = os_set_exec_close(fd);
3980f80bc85SJeff Dike 	if (err < 0) {
3990f80bc85SJeff Dike 		errno = -err;
4000f80bc85SJeff Dike 		perror("exec_close");
4010f80bc85SJeff Dike 	}
40281999a01SJeff Dike 	return fd;
4030f80bc85SJeff Dike }
404966a082fSRob Landley 
405966a082fSRob Landley 
40636e45463SJeff Dike void __init check_tmpexec(void)
407966a082fSRob Landley {
408966a082fSRob Landley 	void *addr;
409966a082fSRob Landley 	int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
410966a082fSRob Landley 
411966a082fSRob Landley 	addr = mmap(NULL, UM_KERN_PAGE_SIZE,
412966a082fSRob Landley 		    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
413966a082fSRob Landley 	printf("Checking PROT_EXEC mmap in %s...",tempdir);
414966a082fSRob Landley 	fflush(stdout);
415966a082fSRob Landley 	if (addr == MAP_FAILED) {
416966a082fSRob Landley 		err = errno;
417966a082fSRob Landley 		perror("failed");
418c9a3072dSWANG Cong 		close(fd);
419966a082fSRob Landley 		if (err == EPERM)
420966a082fSRob Landley 			printf("%s must be not mounted noexec\n",tempdir);
421966a082fSRob Landley 		exit(1);
422966a082fSRob Landley 	}
423966a082fSRob Landley 	printf("OK\n");
424966a082fSRob Landley 	munmap(addr, UM_KERN_PAGE_SIZE);
425966a082fSRob Landley 
426966a082fSRob Landley 	close(fd);
427966a082fSRob Landley }
428