linux/arch/um/os-Linux/mem.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include <stdio.h>
   7#include <stddef.h>
   8#include <stdlib.h>
   9#include <unistd.h>
  10#include <errno.h>
  11#include <fcntl.h>
  12#include <string.h>
  13#include <sys/mman.h>
  14#include <sys/param.h>
  15#include "init.h"
  16#include "kern_constants.h"
  17#include "os.h"
  18#include "user.h"
  19
  20/* Modified by which_tmpdir, which is called during early boot */
  21static char *default_tmpdir = "/tmp";
  22
  23/*
  24 *  Modified when creating the physical memory file and when checking
  25 * the tmp filesystem for usability, both happening during early boot.
  26 */
  27static char *tempdir = NULL;
  28
  29static void __init find_tempdir(void)
  30{
  31        const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
  32        int i;
  33        char *dir = NULL;
  34
  35        if (tempdir != NULL)
  36                /* We've already been called */
  37                return;
  38        for (i = 0; dirs[i]; i++) {
  39                dir = getenv(dirs[i]);
  40                if ((dir != NULL) && (*dir != '\0'))
  41                        break;
  42        }
  43        if ((dir == NULL) || (*dir == '\0'))
  44                dir = default_tmpdir;
  45
  46        tempdir = malloc(strlen(dir) + 2);
  47        if (tempdir == NULL) {
  48                fprintf(stderr, "Failed to malloc tempdir, "
  49                        "errno = %d\n", errno);
  50                return;
  51        }
  52        strcpy(tempdir, dir);
  53        strcat(tempdir, "/");
  54}
  55
  56/*
  57 * This will return 1, with the first character in buf being the
  58 * character following the next instance of c in the file.  This will
  59 * read the file as needed.  If there's an error, -errno is returned;
  60 * if the end of the file is reached, 0 is returned.
  61 */
  62static int next(int fd, char *buf, size_t size, char c)
  63{
  64        ssize_t n;
  65        size_t len;
  66        char *ptr;
  67
  68        while ((ptr = strchr(buf, c)) == NULL) {
  69                n = read(fd, buf, size - 1);
  70                if (n == 0)
  71                        return 0;
  72                else if (n < 0)
  73                        return -errno;
  74
  75                buf[n] = '\0';
  76        }
  77
  78        ptr++;
  79        len = strlen(ptr);
  80        memmove(buf, ptr, len + 1);
  81
  82        /*
  83         * Refill the buffer so that if there's a partial string that we care
  84         * about, it will be completed, and we can recognize it.
  85         */
  86        n = read(fd, &buf[len], size - len - 1);
  87        if (n < 0)
  88                return -errno;
  89
  90        buf[len + n] = '\0';
  91        return 1;
  92}
  93
  94/* which_tmpdir is called only during early boot */
  95static int checked_tmpdir = 0;
  96
  97/*
  98 * Look for a tmpfs mounted at /dev/shm.  I couldn't find a cleaner
  99 * way to do this than to parse /proc/mounts.  statfs will return the
 100 * same filesystem magic number and fs id for both /dev and /dev/shm
 101 * when they are both tmpfs, so you can't tell if they are different
 102 * filesystems.  Also, there seems to be no other way of finding the
 103 * mount point of a filesystem from within it.
 104 *
 105 * If a /dev/shm tmpfs entry is found, then we switch to using it.
 106 * Otherwise, we stay with the default /tmp.
 107 */
 108static void which_tmpdir(void)
 109{
 110        int fd, found;
 111        char buf[128] = { '\0' };
 112
 113        if (checked_tmpdir)
 114                return;
 115
 116        checked_tmpdir = 1;
 117
 118        printf("Checking for tmpfs mount on /dev/shm...");
 119
 120        fd = open("/proc/mounts", O_RDONLY);
 121        if (fd < 0) {
 122                printf("failed to open /proc/mounts, errno = %d\n", errno);
 123                return;
 124        }
 125
 126        while (1) {
 127                found = next(fd, buf, ARRAY_SIZE(buf), ' ');
 128                if (found != 1)
 129                        break;
 130
 131                if (!strncmp(buf, "/dev/shm", strlen("/dev/shm")))
 132                        goto found;
 133
 134                found = next(fd, buf, ARRAY_SIZE(buf), '\n');
 135                if (found != 1)
 136                        break;
 137        }
 138
 139err:
 140        if (found == 0)
 141                printf("nothing mounted on /dev/shm\n");
 142        else if (found < 0)
 143                printf("read returned errno %d\n", -found);
 144
 145out:
 146        close(fd);
 147
 148        return;
 149
 150found:
 151        found = next(fd, buf, ARRAY_SIZE(buf), ' ');
 152        if (found != 1)
 153                goto err;
 154
 155        if (strncmp(buf, "tmpfs", strlen("tmpfs"))) {
 156                printf("not tmpfs\n");
 157                goto out;
 158        }
 159
 160        printf("OK\n");
 161        default_tmpdir = "/dev/shm";
 162        goto out;
 163}
 164
 165static int __init make_tempfile(const char *template, char **out_tempname,
 166                                int do_unlink)
 167{
 168        char *tempname;
 169        int fd;
 170
 171        which_tmpdir();
 172        tempname = malloc(MAXPATHLEN);
 173        if (tempname == NULL)
 174                return -1;
 175
 176        find_tempdir();
 177        if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN))
 178                return -1;
 179
 180        if (template[0] != '/')
 181                strcpy(tempname, tempdir);
 182        else
 183                tempname[0] = '\0';
 184        strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
 185        fd = mkstemp(tempname);
 186        if (fd < 0) {
 187                fprintf(stderr, "open - cannot create %s: %s\n", tempname,
 188                        strerror(errno));
 189                goto out;
 190        }
 191        if (do_unlink && (unlink(tempname) < 0)) {
 192                perror("unlink");
 193                goto out;
 194        }
 195        if (out_tempname) {
 196                *out_tempname = tempname;
 197        } else
 198                free(tempname);
 199        return fd;
 200out:
 201        free(tempname);
 202        return -1;
 203}
 204
 205#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
 206
 207static int __init create_tmp_file(unsigned long long len)
 208{
 209        int fd, err;
 210        char zero;
 211
 212        fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
 213        if (fd < 0)
 214                exit(1);
 215
 216        err = fchmod(fd, 0777);
 217        if (err < 0) {
 218                perror("fchmod");
 219                exit(1);
 220        }
 221
 222        /*
 223         * Seek to len - 1 because writing a character there will
 224         * increase the file size by one byte, to the desired length.
 225         */
 226        if (lseek64(fd, len - 1, SEEK_SET) < 0) {
 227                perror("lseek64");
 228                exit(1);
 229        }
 230
 231        zero = 0;
 232
 233        err = write(fd, &zero, 1);
 234        if (err != 1) {
 235                perror("write");
 236                exit(1);
 237        }
 238
 239        return fd;
 240}
 241
 242int __init create_mem_file(unsigned long long len)
 243{
 244        int err, fd;
 245
 246        fd = create_tmp_file(len);
 247
 248        err = os_set_exec_close(fd);
 249        if (err < 0) {
 250                errno = -err;
 251                perror("exec_close");
 252        }
 253        return fd;
 254}
 255
 256
 257void __init check_tmpexec(void)
 258{
 259        void *addr;
 260        int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
 261
 262        addr = mmap(NULL, UM_KERN_PAGE_SIZE,
 263                    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
 264        printf("Checking PROT_EXEC mmap in %s...",tempdir);
 265        fflush(stdout);
 266        if (addr == MAP_FAILED) {
 267                err = errno;
 268                perror("failed");
 269                close(fd);
 270                if (err == EPERM)
 271                        printf("%s must be not mounted noexec\n",tempdir);
 272                exit(1);
 273        }
 274        printf("OK\n");
 275        munmap(addr, UM_KERN_PAGE_SIZE);
 276
 277        close(fd);
 278}
 279