kernel/elf: structures must be packed
[meinos.git] / apps / devfs / devfs.c
blob74793269b0ca06e3d906abfde07a724d4c2f07dc
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;
35 llist_t devlist;
36 int nextdevid;
38 #define getnew_devid() (nextdevid++)
40 /**
41 * Gets ListID by DevID
42 * @param devid DevID
43 * @return ListID
45 int getlid_devid(int devid) {
46 struct devlist_item *dev;
47 int i;
48 for (i=0;(dev = llist_get(devlist,i));i++) {
49 if (dev->id==devid) return i;
51 return -1;
54 /**
55 * Gets device by name
56 * @param name Device name
57 * @return Device
59 struct devlist_item *getdev_name(char *name) {
60 struct devlist_item *dev;
61 int i;
63 for (i=0;(dev = llist_get(devlist,i));i++) {
64 if (strcmp(dev->name,name)==0) return dev;
66 return NULL;
69 /**
70 * Opens a file
71 * @param path Path to file
72 * @param fi File Info
73 * @return Filehandle
75 int devfs_open(const char *path,struct fuse_file_info *fi) {
76 struct devlist_item *dev = getdev_name((char*)path+1);
77 if (dev!=NULL) return 0;
78 else return -ENOENT;
81 /**
82 * Closes a file
83 * @param path Path to file
84 * @param fi File Info
85 * @return Success?
87 int devfs_close(const char *path,struct fuse_file_info *fi) {
88 return 0;
91 /**
92 * Reads from file
93 * @param path Path to file
94 * @param buf Buffer to store read data in
95 * @param count How many bytes to read
96 * @param offset Offset to start at
97 * @param fi File info
98 * @return How many bytes read (-Errorcode)
100 int devfs_read(const char *path,char *buf,size_t count,off_t offset,struct fuse_file_info *fi) {
101 struct devlist_item *dev = getdev_name((char*)path+1);
102 char *func;
103 if (dev!=NULL) {
104 asprintf(&func,"devfs_read_%x",dev->owner);
105 int ret = rpc_call(func,0,dev->id,count,offset);
106 memcpy(buf,dev->shmbuf,count);
107 free(func);
108 return ret;
110 else return -ENOENT;
114 * Writes to file
115 * @param path Path to file
116 * @param buf Buffer to get data from
117 * @param count How many bytes to write
118 * @param offset Offset to start at
119 * @param fi File info
120 * @return How many bytes written (-Errorcode)
122 int devfs_write(const char *path,const char *buf,size_t count,off_t offset,struct fuse_file_info *fi) {
123 struct devlist_item *dev = getdev_name((char*)path+1);
124 char *func;
125 if (dev!=NULL) {
126 asprintf(&func,"devfs_write_%x",dev->owner);
127 memcpy(dev->shmbuf,buf,count);
128 int ret = rpc_call(func,0,dev->id,count,offset);
129 free(func);
130 return ret;
132 else return -ENOENT;
136 * Reads from dir
137 * @param path Path to dir
138 * @param buf Buffer for dir entries
139 * @param filler Filler function
140 * @param off Dir offset
141 * @param fi File info
142 * @return 0=success (-Errorcode)
144 int devfs_readdir(const char *path,void *buf,fuse_fill_dir_t filler,off_t off,struct fuse_file_info *fi) {
145 if (strcmp(path,"/")==0) {
146 size_t i;
147 struct devlist_item *dev;
148 filler(buf,".",NULL,0);
149 filler(buf,"..",NULL,0);
150 for (i=0;(dev = llist_get(devlist,i));i++) filler(buf,dev->name,NULL,0);
151 return 0;
153 else return -ENOENT;
157 * Gets informations about files
158 * @param path Path to file
159 * @param stbuf Buffer to store informations in
160 * @return 0=success (-Errorcode)
162 int devfs_getattr(const char *path,struct stat *stbuf) {
163 struct devlist_item *dev;
164 memset(stbuf,0,sizeof(struct stat));
165 if (strcmp(path,"/") == 0) {
166 stbuf->st_mode = S_IFDIR|0755;
167 stbuf->st_nlink = 2;
169 else if ((dev = getdev_name((char*)path+1))!=NULL) {
170 stbuf->st_mode = (dev->type==DT_BLOCK?S_IFBLK:S_IFCHR)|0744;
171 stbuf->st_nlink = 1;
172 stbuf->st_size = 0;
174 else return -ENOENT;
175 return 0;
179 * Creates a new device
180 * @param name Device name
181 * @return DevID
183 int devfs_createdev(char *name,int shmid) {
184 int devid = getnew_devid();
185 if (devid>=0 && getdev_name(name)==NULL) {
186 struct devlist_item *new = malloc(sizeof(struct devlist_item));
187 new->id = devid;
188 new->name = strdup(name);
189 new->owner = rpc_curpid;
190 new->shmbuf = shmat(shmid,NULL,0);
191 llist_push(devlist,new);
192 return devid;
194 else {
195 fprintf(stderr,"devfs: Could not create device: %s\n",name);
196 return -1;
201 * Removes a device
202 * @param id DevID
203 * @return 0=success; -1=failure
205 int devfs_removedev(int id) {
206 struct devlist_item *dev = llist_get(devlist,getlid_devid(id));
207 if (dev!=NULL && dev->owner==rpc_curpid) {
208 llist_remove(devlist,getlid_devid(id));
209 shmdt(dev->shmbuf);
210 free(dev->name);
211 free(dev);
212 return 0;
214 return -1;
218 * Initializes DevFS
219 * @param argc Number of arguments
220 * @param argv Values of arguments
221 * @return Return value
223 int main(int argc,char *argv[]) {
224 devlist = llist_create();
225 nextdevid = 1;
227 rpc_func(devfs_createdev,"$i",NAME_MAX+sizeof(int));
228 rpc_func(devfs_removedev,"i",sizeof(int));
230 struct fuse_operations devfs_oper = {
231 .open = devfs_open,
232 .release = devfs_close,
233 .read = devfs_read,
234 .write = devfs_write,
235 .readdir = devfs_readdir,
236 .getattr = devfs_getattr
239 // fake argc/argv
240 int fake_argc = 2;
241 char *fake_argv[2] = { "devfs","/dev" };
242 fuse_main(fake_argc,fake_argv,&devfs_oper,NULL);
244 return 0;