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 "os.h"
  18
  19/* Modified by which_tmpdir, which is called during early boot */
  20static char *default_tmpdir = "/tmp";
  21
  22/*
  23 *  Modified when creating the physical memory file and when checking
  24 * the tmp filesystem for usability, both happening during early boot.
  25 */
  26static char *tempdir = NULL;
  27
  28static void __init find_tempdir(void)
  29{
  30        const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
  31        int i;
  32        char *dir = NULL;
  33
  34        if (tempdir != NULL)
  35                /* We've already been called */
  36                return;
  37        for (i = 0; dirs[i]; i++) {
  38                dir = getenv(dirs[i]);
  39                if ((dir != NULL) && (*dir != '\0'))
  40                        break;
  41        }
  42        if ((dir == NULL) || (*dir == '\0'))
  43                dir = default_tmpdir;
  44
  45        tempdir = malloc(strlen(dir) + 2);
  46        if (tempdir == NULL) {
  47                fprintf(stderr, "Failed to malloc tempdir, "
  48                        "errno = %d\n", errno);
  49                return;
  50        }
  51        strcpy(tempdir, dir);
  52        strcat(tempdir, "/");
  53}
  54
  55/*
  56 * This will return 1, with the first character in buf being the
  57 * character following the next instance of c in the file.  This will
  58 * read the file as needed.  If there's an error, -errno is returned;
  59 * if the end of the file is reached, 0 is returned.
  60 */
  61static int next(int fd, char *buf, size_t size, char c)
  62{
  63        ssize_t n;
  64        size_t len;
  65        char *ptr;
  66
  67        while ((ptr = strchr(buf, c)) == NULL) {
  68                n = read(fd, buf, size - 1);
  69                if (n == 0)
  70                        return 0;
  71                else if (n < 0)
  72                        return -errno;
  73
  74                buf[n] = '\0';
  75        }
  76
  77        ptr++;
  78        len = strlen(ptr);
  79        memmove(buf, ptr, len + 1);
  80
  81        /*
  82         * Refill the buffer so that if there's a partial string that we care
  83         * about, it will be completed, and we can recognize it.
  84         */
  85        n = read(fd, &buf[len], size - len - 1);
  86        if (n < 0)
  87                return -errno;
  88
  89        buf[len + n] = '\0';
  90        return 1;
  91}
  92
  93/* which_tmpdir is called only during early boot */
  94static int checked_tmpdir = 0;
  95
  96/*
  97 * Look for a tmpfs mounted at /dev/shm.  I couldn't find a cleaner
  98 * way to do this than to parse /proc/mounts.  statfs will return the
  99 * same filesystem magic number and fs id for both /dev and /dev/shm
 100 * when they are both tmpfs, so you can't tell if they are different
 101 * filesystems.  Also, there seems to be no other way of finding the
 102 * mount point of a filesystem from within it.
 103 *
 104 * If a /dev/shm tmpfs entry is found, then we switch to using it.
 105 * Otherwise, we stay with the default /tmp.
 106 */
 107static void which_tmpdir(void)
 108{
 109        int fd, found;
 110        char buf[128] = { '\0' };
 111
 112        if (checked_tmpdir)
 113                return;
 114
 115        checked_tmpdir = 1;
 116
 117        printf("Checking for tmpfs mount on /dev/shm...");
 118
 119        fd = open("/proc/mounts", O_RDONLY);
 120        if (fd < 0) {
 121                printf("failed to open /proc/mounts, errno = %d\n", errno);
 122                return;
 123        }
 124
 125        while (1) {
 126                found = next(fd, buf, ARRAY_SIZE(buf), ' ');
 127                if (found != 1)
 128                        break;
 129
 130                if (!strncmp(buf, "/dev/shm", strlen("/dev/shm")))
 131                        goto found;
 132
 133                found = next(fd, buf, ARRAY_SIZE(buf), '\n');
 134                if (found != 1)
 135                        break;
 136        }
 137
 138err:
 139        if (found == 0)
 140                printf("nothing mounted on /dev/shm\n");
 141        else if (found < 0)
 142                printf("read returned errno %d\n", -found);
 143
 144out:
 145        close(fd);
 146
 147        return;
 148
 149found:
 150        found = next(fd, buf, ARRAY_SIZE(buf), ' ');
 151        if (found != 1)
 152                goto err;
 153
 154        if (strncmp(buf, "tmpfs", strlen("tmpfs"))) {
 155                printf("not tmpfs\n");
 156                goto out;
 157        }
 158
 159        printf("OK\n");
 160        default_tmpdir = "/dev/shm";
 161        goto out;
 162}
 163
 164static int __init make_tempfile(const char *template, char **out_tempname,
 165                                int do_unlink)
 166{
 167        char *tempname;
 168        int fd;
 169
 170        which_tmpdir();
 171        tempname = malloc(MAXPATHLEN);
 172        if (tempname == NULL)
 173                return -1;
 174
 175        find_tempdir();
 176        if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN))
 177                goto out;
 178
 179        if (template[0] != '/')
 180                strcpy(tempname, tempdir);
 181        else
 182                tempname[0] = '\0';
 183        strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
 184        fd = mkstemp(tempname);
 185        if (fd < 0) {
 186                fprintf(stderr, "open - cannot create %s: %s\n", tempname,
 187                        strerror(errno));
 188                goto out;
 189        }
 190        if (do_unlink && (unlink(tempname) < 0)) {
 191                perror("unlink");
 192                goto close;
 193        }
 194        if (out_tempname) {
 195                *out_tempname = tempname;
 196        } else
 197                free(tempname);
 198        return fd;
 199close:
 200        close(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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.