+ exec* functions
[meinos.git] / apps / devfs / devfs.c
blob13b3b71564ace45824434571259781597e08f845
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
20 #include <sys/shm.h>
21 #include <rpc.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <llist.h>
25 #include <fuse.h>
27 struct devlist_item {
28 int id;
29 char *name;
30 pid_t owner;
31 enum { DT_CHAR,DT_BLOCK } type;
32 void *shmbuf;
33 size_t bufsz;
36 static llist_t devlist;
37 static int nextdevid;
39 #define getnew_devid() (nextdevid++)
41 /**
42 * Gets ListID by DevID
43 * @param devid DevID
44 * @return ListID
46 static int getlid_devid(int devid) {
47 struct devlist_item *dev;
48 int i;
49 for (i=0;(dev = llist_get(devlist,i));i++) {
50 if (dev->id==devid) return i;
52 return -1;
55 /**
56 * Gets device by name
57 * @param name Device name
58 * @return Device
60 static struct devlist_item *getdev_name(char *name) {
61 struct devlist_item *dev;
62 int i;
64 for (i=0;(dev = llist_get(devlist,i));i++) {
65 if (strcmp(dev->name,name)==0) return dev;
67 return NULL;
70 /**
71 * Opens a file
72 * @param path Path to file
73 * @param fi File Info
74 * @return Filehandle
76 static int devfs_open(const char *path,struct fuse_file_info *fi) {
77 struct devlist_item *dev = getdev_name((char*)path+1);
78 if (dev!=NULL) return 0;
79 else return -ENOENT;
82 /**
83 * Closes a file
84 * @param path Path to file
85 * @param fi File Info
86 * @return Success?
88 static int devfs_close(const char *path,struct fuse_file_info *fi) {
89 return 0;
92 /**
93 * Reads from file
94 * @param path Path to file
95 * @param buf Buffer to store read data in
96 * @param count How many bytes to read
97 * @param offset Offset to start at
98 * @param fi File info
99 * @return How many bytes read (-Errorcode)
101 static int devfs_read(const char *path,char *buf,size_t count,off_t offset,struct fuse_file_info *fi) {
102 struct devlist_item *dev = getdev_name((char*)path+1);
103 if (dev!=NULL) {
104 if (count>dev->bufsz) count = dev->bufsz;
105 //dbgmsg("devfs:\tdevfs_read(%s,0x%x,0x%x,0x%x)\n",path,buf,count,offset);
106 int ret = rpc_call("devfs_read",RPC_FLAG_SENDTO,dev->owner,dev->id,count,offset);
107 //dbgmsg("devfs:\tret = 0x%x\n",ret);
108 memcpy(buf,dev->shmbuf,ret);
109 return ret;
111 else return -ENOENT;
115 * Writes to file
116 * @param path Path to file
117 * @param buf Buffer to get data from
118 * @param count How many bytes to write
119 * @param offset Offset to start at
120 * @param fi File info
121 * @return How many bytes written (-Errorcode)
123 static int devfs_write(const char *path,const char *buf,size_t count,off_t offset,struct fuse_file_info *fi) {
124 struct devlist_item *dev = getdev_name((char*)path+1);
125 if (dev!=NULL) {
126 if (count>dev->bufsz) count = dev->bufsz;
127 memcpy(dev->shmbuf,buf,count);
128 return rpc_call("devfs_write",RPC_FLAG_SENDTO,dev->owner,dev->id,count,offset);
130 else return -ENOENT;
134 * Reads from dir
135 * @param path Path to dir
136 * @param buf Buffer for dir entries
137 * @param filler Filler function
138 * @param off Dir offset
139 * @param fi File info
140 * @return 0=success (-Errorcode)
142 static int devfs_readdir(const char *path,void *buf,fuse_fill_dir_t filler,off_t off,struct fuse_file_info *fi) {
143 if (strcmp(path,"/")==0) {
144 size_t i;
145 struct devlist_item *dev;
146 filler(buf,".",NULL,0);
147 filler(buf,"..",NULL,0);
148 for (i=0;(dev = llist_get(devlist,i));i++) filler(buf,dev->name,NULL,0);
149 return 0;
151 else return -ENOENT;
155 * Gets informations about files
156 * @param path Path to file
157 * @param stbuf Buffer to store informations in
158 * @return 0=success (-Errorcode)
160 static int devfs_getattr(const char *path,struct stat *stbuf) {
161 struct devlist_item *dev;
162 memset(stbuf,0,sizeof(struct stat));
163 if (strcmp(path,"/") == 0) {
164 stbuf->st_mode = S_IFDIR|0755;
165 stbuf->st_nlink = 2;
167 else if ((dev = getdev_name((char*)path+1))!=NULL) {
168 stbuf->st_mode = (dev->type==DT_BLOCK?S_IFBLK:S_IFCHR)|0744;
169 stbuf->st_nlink = 1;
170 stbuf->st_size = 0;
172 else return -ENOENT;
173 return 0;
177 * Creates a new device
178 * @param name Device name
179 * @return DevID
181 static int devfs_createdev(char *name,int shmid) {
182 int devid = getnew_devid();
183 if (devid>=0 && getdev_name(name)==NULL) {
184 struct devlist_item *new = malloc(sizeof(struct devlist_item));
185 struct shmid_ds shmid_ds;
186 shmctl(shmid,IPC_STAT,&shmid_ds);
187 new->id = devid;
188 new->name = strdup(name);
189 new->owner = rpc_curpid;
190 new->shmbuf = shmat(shmid,NULL,0);
191 new->bufsz = shmid_ds.shm_segsz;
192 llist_push(devlist,new);
193 return devid;
195 else {
196 fprintf(stderr,"devfs: Could not create device: %s\n",name);
197 return -1;
202 * Removes a device
203 * @param id DevID
204 * @return 0=success; -1=failure
206 static int devfs_removedev(int id) {
207 struct devlist_item *dev = llist_get(devlist,getlid_devid(id));
208 if (dev!=NULL && dev->owner==rpc_curpid) {
209 llist_remove(devlist,getlid_devid(id));
210 shmdt(dev->shmbuf);
211 free(dev->name);
212 free(dev);
213 return 0;
215 return -1;
219 * Initializes DevFS
220 * @param argc Number of arguments
221 * @param argv Values of arguments
222 * @return Return value
224 int main(int argc,char *argv[]) {
225 devlist = llist_create();
226 nextdevid = 1;
228 rpc_func(devfs_createdev,"$ii",NAME_MAX+sizeof(int));
229 rpc_func(devfs_removedev,"i",sizeof(int));
231 struct fuse_operations devfs_oper = {
232 .open = devfs_open,
233 .release = devfs_close,
234 .read = devfs_read,
235 .write = devfs_write,
236 .readdir = devfs_readdir,
237 .getattr = devfs_getattr
240 // fake argc/argv
241 int fake_argc = 2;
242 char *fake_argv[2] = { "devfs","/dev" };
243 fuse_main(fake_argc,fake_argv,&devfs_oper,NULL);
245 return 0;