Allows no EXT2 block device
[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 struct file_operations dev_f_op_null;
22
23 struct file *dev_stdin, *dev_stdout, *dev_stderr, *dev_null;
24
25 void devfs_init(void)
26 {
27         int mode;
28         /* Make sure there is a dev directory */
29         struct dentry *dentry = lookup_dentry("/dev/", 0);      
30         if (!dentry) {
31                 assert(!do_mkdir("/dev/", S_IRWXU | S_IRWXG | S_IRWXO));
32         } else {
33                 kref_put(&dentry->d_kref);
34         }
35         /* Notice we don't kref_put().  We're storing the refs globally */
36         dev_stdin = make_device("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
37                                 __S_IFCHR, &dev_f_op_stdin);
38         dev_stdout = make_device("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
39                                  __S_IFCHR, &dev_f_op_stdout);
40         /* Note stderr uses the same f_op as stdout */
41         dev_stderr = make_device("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
42                                  __S_IFCHR, &dev_f_op_stdout);
43         dev_null = make_device("/dev/null", S_IWUSR | S_IWGRP | S_IWOTH,
44                                __S_IFCHR, &dev_f_op_null);
45 }
46
47 /* Creates a device node at a given location in the FS-tree */
48 /* TODO: consider making this only deal with the inode */
49 struct file *make_device(char *path, int mode, int type,
50                          struct file_operations *fop)
51 {
52         struct file *f_dev = do_file_open(path, O_CREAT, mode);
53         assert(f_dev);
54         /* Overwrite the f_op with our own f_ops */
55         f_dev->f_dentry->d_inode->i_fop = fop;
56         f_dev->f_op = fop;
57         SET_FTYPE(f_dev->f_dentry->d_inode->i_mode, type);
58         return f_dev;
59 }
60
61 /* We provide a separate set of f_ops for devices (char and block), and the fops
62  * is the only thing that differs from the regular KFS.  We need to do some
63  * ghetto-overriding of these ops after we create them. */
64
65 off_t dev_c_llseek(struct file *file, off_t offset, int whence)
66 {
67         set_errno(EINVAL);
68         return -1;
69 }
70
71 /* we don't allow mmapping of any device file */
72 int dev_mmap(struct file *file, struct vm_region *vmr)
73 {
74         set_errno(EINVAL);
75         return -1;
76 }
77
78 ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
79                        off_t *offset)
80 {
81         int read_amt;
82         char *kbuf = kmalloc(count, 0);
83         memset(kbuf, 0, count);// TODO REMOVE ME
84         read_amt = readline(kbuf, count, 0);
85         assert(read_amt <= count);
86         /* applications (ash) expect a \n instead of a \r */
87         if (kbuf[read_amt - 1] == '\r')
88                 kbuf[read_amt - 1] = '\n';
89         /* TODO UMEM */
90         if (current)
91                 memcpy_to_user_errno(current, buf, kbuf, read_amt);
92         else
93                 memcpy(buf, kbuf, read_amt);
94         return read_amt;
95 }
96
97 ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
98                          off_t *offset)
99 {
100         char *t_buf;
101         struct proc *p = current;
102         if (p)
103                 t_buf = user_strdup_errno(p, buf, count);
104         else
105                 t_buf = (char*)buf;
106         if (!t_buf)
107                 return -1;
108         printk("%s", t_buf);
109         return count;
110 }
111
112 /* stdin/stdout/stderr file ops */
113 struct file_operations dev_f_op_stdin = {
114         dev_c_llseek,
115         dev_stdin_read,
116         0,      /* write - can't write to stdin */
117         kfs_readdir,    /* this will fail gracefully */
118         dev_mmap,
119         kfs_open,
120         kfs_flush,
121         kfs_release,
122         0,      /* fsync - makes no sense */
123         kfs_poll,
124         0,      /* readv */
125         0,      /* writev */
126         kfs_sendpage,
127         kfs_check_flags,
128 };
129
130 struct file_operations dev_f_op_stdout = {
131         dev_c_llseek,
132         0,      /* read - can't read stdout */
133         dev_stdout_write,
134         kfs_readdir,    /* this will fail gracefully */
135         dev_mmap,
136         kfs_open,
137         kfs_flush,
138         kfs_release,
139         0,      /* fsync - makes no sense */
140         kfs_poll,
141         0,      /* readv */
142         0,      /* writev */
143         kfs_sendpage,
144         kfs_check_flags,
145 };
146
147 /* /dev/null: just take whatever was given and pretend it was written */
148 ssize_t dev_null_write(struct file *file, const char *buf, size_t count,
149                        off_t *offset)
150 {
151         return count;
152 }
153
154 struct file_operations dev_f_op_null = {
155         dev_c_llseek,
156         0,      /* read - can't read null */
157         dev_null_write,
158         kfs_readdir,    /* this will fail gracefully */
159         dev_mmap,
160         kfs_open,
161         kfs_flush,
162         kfs_release,
163         0,      /* fsync - makes no sense */
164         kfs_poll,
165         0,      /* readv */
166         0,      /* writev */
167         kfs_sendpage,
168         kfs_check_flags,
169 };