Merge master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-drm-fsl-dcu.git] / arch / um / os-Linux / mem.c
index 71bb90a7606d0ebf8dab332fd874aa0e0f6d707b..c6378c6d10d2821f2d4da93a7618d5ce1935302d 100644 (file)
@@ -8,9 +8,9 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <sys/statfs.h>
 #include "kern_util.h"
 #include "user.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "init.h"
 #include "os.h"
 
 #include <sys/param.h>
 
+/* Modified by which_tmpdir, which is called during early boot */
+static char *default_tmpdir = "/tmp";
+
+/*
+ *  Modified when creating the physical memory file and when checking
+ * the tmp filesystem for usability, both happening during early boot.
+ */
 static char *tempdir = NULL;
 
 static void __init find_tempdir(void)
@@ -27,14 +34,15 @@ static void __init find_tempdir(void)
        int i;
        char *dir = NULL;
 
-       if(tempdir != NULL) return;     /* We've already been called */
+       if(tempdir != NULL) /* We've already been called */
+               return;
        for(i = 0; dirs[i]; i++){
                dir = getenv(dirs[i]);
                if((dir != NULL) && (*dir != '\0'))
                        break;
        }
        if((dir == NULL) || (*dir == '\0'))
-               dir = "/tmp";
+               dir = default_tmpdir;
 
        tempdir = malloc(strlen(dir) + 2);
        if(tempdir == NULL){
@@ -46,16 +54,123 @@ static void __init find_tempdir(void)
        strcat(tempdir, "/");
 }
 
+/* This will return 1, with the first character in buf being the
+ * character following the next instance of c in the file.  This will
+ * read the file as needed.  If there's an error, -errno is returned;
+ * if the end of the file is reached, 0 is returned.
+ */
+static int next(int fd, char *buf, int size, char c)
+{
+       int n, len;
+       char *ptr;
+
+       while((ptr = strchr(buf, c)) == NULL){
+               n = read(fd, buf, size - 1);
+               if(n == 0)
+                       return 0;
+               else if(n < 0)
+                       return -errno;
+
+               buf[n] = '\0';
+       }
+
+       ptr++;
+       len = strlen(ptr);
+       memmove(buf, ptr, len + 1);
+
+       /* Refill the buffer so that if there's a partial string that we care
+        * about, it will be completed, and we can recognize it.
+        */
+       n = read(fd, &buf[len], size - len - 1);
+       if(n < 0)
+               return -errno;
+
+       buf[len + n] = '\0';
+       return 1;
+}
+
+/* which_tmpdir is called only during early boot */
+static int checked_tmpdir = 0;
+
+/* Look for a tmpfs mounted at /dev/shm.  I couldn't find a cleaner
+ * way to do this than to parse /proc/mounts.  statfs will return the
+ * same filesystem magic number and fs id for both /dev and /dev/shm
+ * when they are both tmpfs, so you can't tell if they are different
+ * filesystems.  Also, there seems to be no other way of finding the
+ * mount point of a filesystem from within it.
+ *
+ * If a /dev/shm tmpfs entry is found, then we switch to using it.
+ * Otherwise, we stay with the default /tmp.
+ */
+static void which_tmpdir(void)
+{
+       int fd, found;
+       char buf[128] = { '\0' };
+
+       if(checked_tmpdir)
+               return;
+
+       checked_tmpdir = 1;
+
+       printf("Checking for tmpfs mount on /dev/shm...");
+
+       fd = open("/proc/mounts", O_RDONLY);
+       if(fd < 0){
+               printf("failed to open /proc/mounts, errno = %d\n", errno);
+               return;
+       }
+
+       while(1){
+               found = next(fd, buf, ARRAY_SIZE(buf), ' ');
+               if(found != 1)
+                       break;
+
+               if(!strncmp(buf, "/dev/shm", strlen("/dev/shm")))
+                       goto found;
+
+               found = next(fd, buf, ARRAY_SIZE(buf), '\n');
+               if(found != 1)
+                       break;
+       }
+
+err:
+       if(found == 0)
+               printf("nothing mounted on /dev/shm\n");
+       else if(found < 0)
+               printf("read returned errno %d\n", -found);
+
+out:
+       close(fd);
+
+       return;
+
+found:
+       found = next(fd, buf, ARRAY_SIZE(buf), ' ');
+       if(found != 1)
+               goto err;
+
+       if(strncmp(buf, "tmpfs", strlen("tmpfs"))){
+               printf("not tmpfs\n");
+               goto out;
+       }
+
+       printf("OK\n");
+       default_tmpdir = "/dev/shm";
+       goto out;
+}
+
 /*
  * This proc still used in tt-mode
  * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger).
  * So it isn't 'static' yet.
  */
-int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+int __init make_tempfile(const char *template, char **out_tempname,
+                        int do_unlink)
 {
        char *tempname;
        int fd;
 
+       which_tmpdir();
        tempname = malloc(MAXPATHLEN);
 
        find_tempdir();
@@ -79,7 +194,7 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink)
        } else {
                free(tempname);
        }
-       return(fd);
+       return fd;
 out:
        free(tempname);
        return -1;
@@ -91,7 +206,7 @@ out:
  * This proc is used in start_up.c
  * So it isn't 'static'.
  */
-int create_tmp_file(unsigned long long len)
+int __init create_tmp_file(unsigned long long len)
 {
        int fd, err;
        char zero;
@@ -107,24 +222,26 @@ int create_tmp_file(unsigned long long len)
                exit(1);
        }
 
-        if (lseek64(fd, len, SEEK_SET) < 0) {
-               perror("os_seek_file");
+       /* Seek to len - 1 because writing a character there will
+        * increase the file size by one byte, to the desired length.
+        */
+       if (lseek64(fd, len - 1, SEEK_SET) < 0) {
+               perror("os_seek_file");
                exit(1);
        }
 
        zero = 0;
 
-       err = os_write_file(fd, &zero, 1);
+       err = write(fd, &zero, 1);
        if(err != 1){
-               errno = -err;
-               perror("os_write_file");
+               perror("write");
                exit(1);
        }
 
-       return(fd);
+       return fd;
 }
 
-int create_mem_file(unsigned long long len)
+int __init create_mem_file(unsigned long long len)
 {
        int err, fd;
 
@@ -135,5 +252,28 @@ int create_mem_file(unsigned long long len)
                errno = -err;
                perror("exec_close");
        }
-       return(fd);
+       return fd;
+}
+
+
+void __init check_tmpexec(void)
+{
+       void *addr;
+       int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
+
+       addr = mmap(NULL, UM_KERN_PAGE_SIZE,
+                   PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
+       printf("Checking PROT_EXEC mmap in %s...",tempdir);
+       fflush(stdout);
+       if(addr == MAP_FAILED){
+               err = errno;
+               perror("failed");
+               if(err == EPERM)
+                       printf("%s must be not mounted noexec\n",tempdir);
+               exit(1);
+       }
+       printf("OK\n");
+       munmap(addr, UM_KERN_PAGE_SIZE);
+
+       close(fd);
 }