sys_read() from /dev/stdin
[akaros.git] / kern / src / devfs.c
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Devfs: filesystem interfaces to devices.  For now, we just create the
6  * needed/discovered devices in KFS in its /dev/ folder, and only do this for
7  * stdin and stdout. */
8
9 #include <devfs.h>
10 #include <kfs.h>
11 #include <error.h>
12 #include <syscall.h>
13 #include <process.h>
14 #include <smp.h>
15 #include <umem.h>
16 #include <kmalloc.h>
17
18 /* These structs are declared again and initialized farther down */
19 struct file_operations dev_f_op_stdin;
20 struct file_operations dev_f_op_stdout;
21
22 struct file *dev_stdin, *dev_stdout, *dev_stderr;
23
24 /* Helper to build stdin, stdout, and stderr */
25 static struct file *get_stdinout(char *name, int mode,
26                                  struct file_operations *fop)
27 {
28         struct file *f_char_dev = do_file_open(name, O_CREAT, mode);
29         assert(f_char_dev);
30         /* Overwrite the f_op with our own f_ops */
31         f_char_dev->f_dentry->d_inode->i_fop = fop;
32         f_char_dev->f_op = fop;
33         SET_FTYPE(f_char_dev->f_dentry->d_inode->i_mode, __S_IFCHR);
34         return f_char_dev;
35 }
36
37 void devfs_init(void)
38 {
39         int mode;
40         /* Make sure there is a dev directory */
41         struct dentry *dentry = lookup_dentry("/dev/", 0);      
42         if (!dentry) {
43                 assert(!do_mkdir("/dev/", S_IRWXU | S_IRWXG | S_IRWXO));
44         } else {
45                 kref_put(&dentry->d_kref);
46         }
47         /* Notice we don't kref_put().  We're storing the refs globally */
48         dev_stdin = get_stdinout("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
49                                  &dev_f_op_stdin);
50         dev_stdout = get_stdinout("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
51                                   &dev_f_op_stdout);
52         /* Note stderr uses the same f_op as stdout */
53         dev_stderr = get_stdinout("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
54                                   &dev_f_op_stdout);
55 }
56
57 /* We provide a separate set of f_ops and pm_ops for devices (char for now), and
58  * this is the only thing that differs from the regular KFS.  We need to do some
59  * ghetto-overriding of these ops after we create them. */
60
61 off_t dev_c_llseek(struct file *file, off_t offset, int whence)
62 {
63         set_errno(EINVAL);
64         return -1;
65 }
66
67 ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
68                        off_t *offset)
69 {
70         int read_amt;
71         char *kbuf = kmalloc(count, 0);
72         memset(kbuf, 0, count);// TODO REMOVE ME
73         read_amt = readline(kbuf, count, 0);
74         assert(read_amt <= count);
75         /* applications (ash) expect a \n instead of a \r */
76         if (kbuf[read_amt - 1] == '\r')
77                 kbuf[read_amt - 1] = '\n';
78         /* TODO UMEM */
79         if (current)
80                 memcpy_to_user_errno(current, buf, kbuf, read_amt);
81         else
82                 memcpy(buf, kbuf, read_amt);
83         return read_amt;
84 }
85
86 ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
87                          off_t *offset)
88 {
89         char *t_buf;
90         struct proc *p = current;
91         if (p)
92                 t_buf = user_strdup_errno(p, buf, count);
93         else
94                 t_buf = (char*)buf;
95         if (!t_buf)
96                 return -1;
97         printk("%s", t_buf);
98         return count;
99 }
100
101 /* we don't allow mmapping of any device file */
102 int dev_mmap(struct file *file, struct vm_region *vmr)
103 {
104         set_errno(EINVAL);
105         return -1;
106 }
107
108 /* Character device file ops */
109 struct file_operations dev_f_op_stdin = {
110         dev_c_llseek,
111         dev_stdin_read,
112         0,      /* write - can't write to stdin */
113         kfs_readdir,    /* this will fail gracefully */
114         dev_mmap,
115         kfs_open,
116         kfs_flush,
117         kfs_release,
118         0,      /* fsync - makes no sense */
119         kfs_poll,
120         0,      /* readv */
121         0,      /* writev */
122         kfs_sendpage,
123         kfs_check_flags,
124 };
125
126 struct file_operations dev_f_op_stdout = {
127         dev_c_llseek,
128         0,      /* read - can't read stdout */
129         dev_stdout_write,
130         kfs_readdir,    /* this will fail gracefully */
131         dev_mmap,
132         kfs_open,
133         kfs_flush,
134         kfs_release,
135         0,      /* fsync - makes no sense */
136         kfs_poll,
137         0,      /* readv */
138         0,      /* writev */
139         kfs_sendpage,
140         kfs_check_flags,
141 };