Add check for is_valid_elf() before loading in exec
[akaros.git] / kern / src / devfs.c
index ad3ff14..d63e7f6 100644 (file)
 #include <process.h>
 #include <smp.h>
 #include <umem.h>
+#include <kmalloc.h>
+#include <console.h>
 
 /* These structs are declared again and initialized farther down */
 struct file_operations dev_f_op_stdin;
 struct file_operations dev_f_op_stdout;
+struct file_operations dev_f_op_null;
 
-struct file *dev_stdin, *dev_stdout, *dev_stderr;
-
-/* Helper to build stdin, stdout, and stderr */
-static struct file *get_stdinout(char *name, int mode,
-                                 struct file_operations *fop)
-{
-       struct file *f_char_dev = do_file_open(name, O_CREAT, mode);
-       assert(f_char_dev);
-       /* Overwrite the f_op with our own f_ops */
-       f_char_dev->f_dentry->d_inode->i_fop = fop;
-       f_char_dev->f_op = fop;
-       return f_char_dev;
-}
+struct file *dev_stdin, *dev_stdout, *dev_stderr, *dev_null;
 
 void devfs_init(void)
 {
@@ -43,34 +34,65 @@ void devfs_init(void)
                kref_put(&dentry->d_kref);
        }
        /* Notice we don't kref_put().  We're storing the refs globally */
-       dev_stdin = get_stdinout("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
-                                &dev_f_op_stdin);
-       dev_stdout = get_stdinout("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
-                                 &dev_f_op_stdout);
+       dev_stdin = make_device("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
+                               __S_IFCHR, &dev_f_op_stdin);
+       dev_stdout = make_device("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
+                                __S_IFCHR, &dev_f_op_stdout);
        /* Note stderr uses the same f_op as stdout */
-       dev_stderr = get_stdinout("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
-                                 &dev_f_op_stdout);
+       dev_stderr = make_device("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
+                                __S_IFCHR, &dev_f_op_stdout);
+       dev_null = make_device("/dev/null", S_IWUSR | S_IWGRP | S_IWOTH,
+                              __S_IFCHR, &dev_f_op_null);
+}
+
+/* Creates a device node at a given location in the FS-tree */
+/* TODO: consider making this only deal with the inode */
+struct file *make_device(char *path, int mode, int type,
+                         struct file_operations *fop)
+{
+       struct file *f_dev = do_file_open(path, O_CREAT, mode);
+       assert(f_dev);
+       /* Overwrite the f_op with our own f_ops */
+       f_dev->f_dentry->d_inode->i_fop = fop;
+       f_dev->f_op = fop;
+       SET_FTYPE(f_dev->f_dentry->d_inode->i_mode, type);
+       return f_dev;
 }
 
-/* We provide a separate set of f_ops and pm_ops for devices (char for now), and
- * this is the only thing that differs from the regular KFS.  We need to do some
+/* We provide a separate set of f_ops for devices (char and block), and the fops
+ * is the only thing that differs from the regular KFS.  We need to do some
  * ghetto-overriding of these ops after we create them. */
+int dev_c_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
+{
+       set_errno(EINVAL);
+       return -1;
+}
 
-off_t dev_c_llseek(struct file *file, off_t offset, int whence)
+/* we don't allow mmapping of any device file */
+int dev_mmap(struct file *file, struct vm_region *vmr)
 {
        set_errno(EINVAL);
        return -1;
 }
 
+/* this is really /dev/console, and will need some tty work.  for now, no matter
+ * how much they ask for, we return one character at a time. */
 ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
-                       off_t *offset)
+                       off64_t *offset)
 {
-       printk("[kernel] Tried to read %d bytes from stdin\n", count);
-       return -1;
+       char c;
+       extern struct kb_buffer cons_buf;
+       kb_get_from_buf(&cons_buf, &c, 1);
+       /* TODO UMEM */
+       if (current)
+               memcpy_to_user_errno(current, buf, &c, 1);
+       else
+               memcpy(buf, &c, 1);
+       return 1;
 }
 
 ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
-                         off_t *offset)
+                         off64_t *offset)
 {
        char *t_buf;
        struct proc *p = current;
@@ -80,18 +102,18 @@ ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
                t_buf = (char*)buf;
        if (!t_buf)
                return -1;
-       printk("%s", t_buf);
+       /* TODO: tty hack.  they are sending us an escape sequence, and the keyboard
+        * would try to print it (which it can't do yet).  The hack is even dirtier
+        * in that we only detect it if it is the first char, and we ignore
+        * everything else. */
+       if (t_buf[0] != '\033') /* 0x1b */
+               cputbuf(t_buf, count);
+       if (p)
+               user_memdup_free(p, t_buf);
        return count;
 }
 
-/* we don't allow mmapping of any device file */
-int dev_mmap(struct file *file, struct vm_region *vmr)
-{
-       set_errno(EINVAL);
-       return -1;
-}
-
-/* Character device file ops */
+/* stdin/stdout/stderr file ops */
 struct file_operations dev_f_op_stdin = {
        dev_c_llseek,
        dev_stdin_read,
@@ -125,3 +147,33 @@ struct file_operations dev_f_op_stdout = {
        kfs_sendpage,
        kfs_check_flags,
 };
+
+ssize_t dev_null_read(struct file *file, char *buf, size_t count,
+                      off64_t *offset)
+{
+       return 0;
+}
+
+/* /dev/null: just take whatever was given and pretend it was written */
+ssize_t dev_null_write(struct file *file, const char *buf, size_t count,
+                       off64_t *offset)
+{
+       return count;
+}
+
+struct file_operations dev_f_op_null = {
+       dev_c_llseek,
+       dev_null_read,
+       dev_null_write,
+       kfs_readdir,    /* this will fail gracefully */
+       dev_mmap,
+       kfs_open,
+       kfs_flush,
+       kfs_release,
+       0,      /* fsync - makes no sense */
+       kfs_poll,
+       0,      /* readv */
+       0,      /* writev */
+       kfs_sendpage,
+       kfs_check_flags,
+};