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