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 Lesser 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
33 #include <fcntl.h> // open,close
34 #include <unistd.h> // read,write,seek,truncate
35 #include <dirent.h> // *dir
36 #include <sys/stat.h> // stat
37 #include <sys/statvfs.h> // statvfs
38 #include <utime.h> // utime
40 #include <sys/socket.h> // Socket stuff
42 #define getnew_fh() (nextfh++)
44 #define SHMMEM_SIZE (2*PAGE_SIZE)
53 struct filelist_item
{
54 struct fslist_item
*fs
;
56 struct dirent dir_cur
;
63 enum { FL_FILE
,FL_DIR
,FL_PIPE
,FL_SOCK
} type
;
64 /// @todo Check for right file types (e.g. in read()/write()) and set them in open()/opendir()/socket()
67 static llist_t filelist
;
68 static llist_t fslist
;
75 static mode_t creation_mask
;
76 struct process_data
*_process_data
;
79 * Initializes File I/O
81 void _fs_init(char *_stdin
,char *_stdout
,char *_stderr
) {
82 filelist
= llist_create();
83 fslist
= llist_create();
86 // Init current workdir
87 char *path
= getenv("PATH");
88 if (path
==NULL
) path
= "/";
89 memset(&workdir
,0,sizeof(workdir
));
92 // Create stdin, stdout, stderr
93 nextfh
= STDIN_FILENO
;
94 if (_stdin
!=NULL
) open(_stdin
,O_RDONLY
);
95 nextfh
= STDOUT_FILENO
;
96 if (_stdout
!=NULL
) open(_stdout
,O_WRONLY
);
97 nextfh
= STDERR_FILENO
;
98 if (_stderr
!=NULL
) open(_stderr
,O_WRONLY
);
99 nextfh
= STDERR_FILENO
+1;
104 * @param file Path to file
105 * @param parent If FS of parent directory of file is needed
106 * @return FS List item
108 static struct fslist_item
*mp_match(char *file
,int parent
) {
111 struct fslist_item
*fs
;
112 struct fslist_item
*maxfs
= NULL
;
113 path_t
*path
= path_parse(file
);
115 if (parent
) path_parent(path
);
117 for (i
=0;(fs
= llist_get(fslist
,i
));i
++) {
118 curcmp
= path_compare(path
,fs
->mountpoint
);
125 if (maxfs
!=NULL
) memmove(file
,file
+strlen(maxfs
->mountpoint_str
),strlen(file
)-strlen(maxfs
->mountpoint_str
)+1);
126 if (file
[0]==0) strcpy(file
,"/");
132 * Gets FSID and PID by path and cuts path to relative path for FS
133 * @param path Path to file
134 * @param parent If FS of parent directory of file is needed
137 static struct fslist_item
*fsbypath(char *path
,int parent
) {
138 if (path
==NULL
|| path
[0]==0) return NULL
;
139 struct fslist_item
*fs
= mp_match(path
,parent
);
141 fs
= malloc(sizeof(struct fslist_item
));
142 char *mountpoint
= strdup(path
);
143 fs
->id
= rpc_call("vfs_getfsid",1,path
,parent
);
149 mountpoint
[strlen(mountpoint
)-strlen(path
)] = 0;
150 fs
->mountpoint
= path_parse(mountpoint
);
151 fs
->mountpoint_str
= path_output(fs
->mountpoint
,NULL
);
153 fs
->pid
= rpc_call("vfs_getpid",0,fs
->id
);
158 llist_push(fslist
,fs
);
165 * Gets list index by filehandle
166 * @param fh filehandle
169 static int lidxbyfh(int fh
) {
170 struct filelist_item
*file
;
172 for (i
=0;(file
= llist_get(filelist
,i
));i
++) {
173 if (file
->fh
==fh
) return i
;
178 static struct filelist_item
*filebyfh(int fh
) {
180 int idx
= lidxbyfh(fh
);
181 if (idx
>=0) return llist_get(filelist
,idx
);
187 * Gets absolute path by relative path
188 * @param relative Relative or absolute path
189 * @return Absolute path (Can be passed to free())
191 static char *getabsolutepath(const char *relative
) {
192 path_t
*path
= path_parse(relative
);
194 path_t
*newpath
= path_cat(workdir
.path
,path
);
198 path_reject_dots(path
);
199 return path_output(path
,NULL
);
203 * Gets current workdir
204 * @param buf Buffer to store path in
205 * @param size Size of buffer
206 * @return Current workdir
208 char *getcwd(char *buf
,size_t size
) {
210 size
= workdir
.strlen
+1;
217 else if (workdir
.strlen
+1>size
) {
221 return strncpy(buf
,workdir
.str
,size
);
225 * Change current workdir
226 * @param new New workdir
227 * @return 0=success; -1=failure
229 int chdir(const char *new) {
230 new = getabsolutepath((char*)new);
231 if (new==NULL
) new = "/";
233 DIR *dir
= opendir(new);
237 path_destroy(workdir
.path
);
238 workdir
.path
= path_parse(new);
239 path_reject_dots(workdir
.path
);
240 workdir
.str
= path_output(workdir
.path
,NULL
);
241 workdir
.strlen
= strlen(workdir
.str
);
242 setenv("PATH",workdir
.str
,1);
249 * Change current workdir
250 * @param new Filedescriptor of new workdir
251 * @return 0=success; -1=failure
253 int fchdir(int fildes
) {
255 struct filelist_item
*file
= filebyfh(fildes
);
256 if (file
!=NULL
) res
= chdir(file
->path
);
258 errno
= res
<0?-res
:0;
264 * @param path Path to new node
265 * @param mode Mode of new node
266 * @param dev DeviceID (not used)
267 * @return 0=success; -1=failure
269 int mknod(const char *path
,mode_t mode
,dev_t dev
) {
271 char *cpath
= getabsolutepath((char*)path
);
272 struct fslist_item
*fs
= fsbypath(cpath
,1);
276 asprintf(&func
,"fs_mknod_%x",fs
->pid
);
277 res
= rpc_call(func
,0,fs
->id
,cpath
,mode
&(~creation_mask
),dev
);
282 errno
= res
<0?-res
:0;
287 * Checks whether file can be opened with mode
288 * @param path Path to file
290 * @return 0=success; -1=failure
292 int access(const char *path
,int amode
) {
294 char *cpath
= getabsolutepath((char*)path
);
295 struct fslist_item
*fs
= fsbypath(cpath
,0);
299 asprintf(&func
,"fs_access_%x",fs
->pid
);
300 res
= rpc_call(func
,0,fs
->id
,cpath
,amode
);
305 errno
= res
<0?-res
:0;
311 * @param path Path to file
314 int open(const char *path
,int oflag
,...) {
319 char *cpath
= getabsolutepath(path
);
320 struct fslist_item
*fs
= fsbypath(cpath
,0);
321 if (fs
==NULL
) fh
= -errno
;
323 va_start(args
,oflag
);
328 int res
= mknod(path
,va_arg(args
,mode_t
)|S_IFREG
,0);
329 if (res
==-1 && errno
!=EEXIST
) fh
= -errno
;
331 int shmid
= shmget(IPC_PRIVATE
,SHMMEM_SIZE
,0);
332 shmbuf
= shmat(shmid
,NULL
,0);
334 strncpy(shmbuf
,cpath
,SHMMEM_SIZE
);
335 asprintf(&func
,"fs_open_%x",fs
->pid
);
336 fh
= rpc_call(func
,0,fs
->id
,oflag
,shmid
);
339 struct filelist_item
*new = malloc(sizeof(struct filelist_item
));
344 new->fh
= getnew_fh();
345 new->path
= strdup(cpath
);
347 new->shmbuf
= shmbuf
;
349 llist_push(filelist
,new);
360 * Closes all filehandles
362 void _close_all_filehandles() {
363 struct filelist_item
*file
;
364 while ((file
= llist_pop(filelist
))!=NULL
) {
365 if (S_ISREG(file
->mode
)) close(file
->fh
);
366 else if (S_ISDIR(file
->mode
)) closedir(file
);
372 * @param fildes File descriptor
373 * @return 0=success; -1=failure
375 int close(int fildes
) {
378 struct filelist_item
*file
= filebyfh(fildes
);
380 asprintf(&func
,"fs_close_%x",file
->fs
->pid
);
381 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
);
385 shmctl(file
->shmid
,IPC_RMID
,NULL
);
386 llist_remove(filelist
,lidxbyfh(fildes
));
392 errno
= res
<0?-res
:0;
398 * Duplicates a file descriptor
399 * @param fildes File descriptor
400 * @param fildes2 New file descriptor
401 * @return New file desciptor
403 int dup2(int fildes
,int fildes2
) {
406 struct filelist_item
*file
= filebyfh(fildes
);
408 asprintf(&func
,"fs_close_%x",file
->fs
->pid
);
409 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
);
412 struct filelist_item
*new = malloc(sizeof(struct filelist_item
));
413 memcpy(new,file
,sizeof(struct filelist_item
));
414 if (fildes2
==0) new->fh
= getnew_fh();
420 new->shmid
= shmget(IPC_PRIVATE
,SHMMEM_SIZE
,0);
421 new->shmbuf
= shmat(new->shmid
,NULL
,0);
422 llist_push(filelist
,new);
431 * @param fildes File descriptor
432 * @param buf Buffer to store read data in
433 * @param count How many bytes to read
434 * @return How many bytes read
436 static ssize_t
_read(struct filelist_item
*file
,void *buf
,size_t count
) {
439 asprintf(&func
,"fs_read_%x",file
->fs
->pid
);
440 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
,count
);
442 if (res
>0) memcpy(buf
,file
->shmbuf
,res
);
445 ssize_t
read(int fildes
,void *buf
,size_t count
) {
446 struct filelist_item
*file
= filebyfh(fildes
);
448 ssize_t count_rem
= count
;
451 while (count_rem
>0) {
452 size_t count_cur
= count_rem
;
453 if (count_cur
>SHMMEM_SIZE
) count_cur
= SHMMEM_SIZE
;
454 count_cur
= _read(file
,buf
+off
,count_cur
);
455 if (count_cur
==-1) return -1;
456 count_rem
-= count_cur
;
457 if (count_cur
==0) break;
461 return count
-count_rem
;
471 * @param fildes File descriptor
472 * @param buf Data to write to file
473 * @param count How many bytes to write
474 * @return How many bytes written
476 static ssize_t
_write(struct filelist_item
*file
,const void *buf
,size_t count
) {
479 memcpy(file
->shmbuf
,buf
,count
);
480 asprintf(&func
,"fs_write_%x",file
->fs
->pid
);
481 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
,count
);
485 ssize_t
write(int fildes
,const void *buf
,size_t count
) {
486 struct filelist_item
*file
= filebyfh(fildes
);
488 ssize_t count_rem
= count
;
490 while (count_rem
>0) {
491 size_t count_cur
= count_rem
;
492 if (count_cur
>SHMMEM_SIZE
) count_cur
= SHMMEM_SIZE
;
493 count_cur
= _write(file
,buf
+off
,count_cur
);
494 if (count_cur
==-1) return -1;
495 count_rem
-= count_cur
;
496 if (count_cur
==0) break;
499 return count
-count_rem
;
509 * @param fildes File descriptor
510 * @param offset Offset
511 * @param whence SEEK_SET, SEEK_CUR, SEEK_END
512 * @return New position
514 off_t
lseek(int fildes
,off_t offset
,int whence
) {
517 struct filelist_item
*file
= filebyfh(fildes
);
519 asprintf(&func
,"fs_seek_%x",file
->fs
->pid
);
520 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
,offset
,whence
);
524 errno
= res
<0?-res
:0;
530 * @param path Path to file
531 * @return 0=success; -1=failure
533 int unlink(const char *path
) {
535 char *cpath
= getabsolutepath((char*)path
);
536 struct fslist_item
*fs
= fsbypath(cpath
,1);
540 asprintf(&func
,"fs_unlink_%x",fs
->pid
);
541 res
= rpc_call(func
,0,fs
->id
,cpath
);
546 errno
= res
<0?-res
:0;
551 * Removes a directory
552 * @param path Path to directory
553 * @return 0=success; -1=failure
555 int rmdir(const char *path
) {
557 char *cpath
= getabsolutepath((char*)path
);
558 struct fslist_item
*fs
= fsbypath(cpath
,1);
562 asprintf(&func
,"fs_rmdir_%x",fs
->pid
);
563 res
= rpc_call(func
,0,fs
->id
,cpath
);
568 errno
= res
<0?-res
:0;
574 * @param path Path to directory
575 * @return 0=success; -1=failure
577 int rename(const char *old
, const char *new) {
579 char *cold
= getabsolutepath((char*)old
);
580 char *cnew
= getabsolutepath((char*)new);
581 struct fslist_item
*fs
= fsbypath(cold
,1);
582 struct fslist_item
*fsnew
= fsbypath(cnew
,1);
585 if (fs
!=NULL
&& fs
==fsnew
) {
586 asprintf(&func
,"fs_rename_%x",fs
->pid
);
587 res
= rpc_call(func
,0,fs
->id
,old
,new);
591 errno
= res
<0?-res
:0;
598 * @param length New length
599 * @return 0=success; -1=failure
601 int truncate(const char *path
,off_t length
) {
604 if ((fh
= open(path
,O_WRONLY
))!=-1) {
605 if (ftruncate(fh
,length
)!=-1) res
= 0;
613 * @param fildes File descriptor
614 * @param length New length
615 * @return 0=success; -1=failure
617 int ftruncate(int fildes
,off_t length
) {
620 struct filelist_item
*file
= filebyfh(fildes
);
622 asprintf(&func
,"fs_ftruncate_%x",file
->fs
->pid
);
623 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
,length
);
627 errno
= res
<0?-res
:0;
634 * @param path Path to directory
635 * @return Pointer to dir handle
637 DIR *opendir(const char *path
) {
641 char *cpath
= getabsolutepath(path
);
642 struct fslist_item
*fs
= fsbypath(cpath
,0);
644 struct filelist_item
*new;
646 int shmid
= shmget(IPC_PRIVATE
,SHMMEM_SIZE
,0);
647 shmbuf
= shmat(shmid
,NULL
,0);
649 strncpy(shmbuf
,cpath
,SHMMEM_SIZE
);
650 asprintf(&func
,"fs_opendir_%x",fs
->pid
);
651 dh
= rpc_call(func
,0,fs
->id
,shmid
);
654 new = malloc(sizeof(struct filelist_item
));
659 new->fh
= 0; // Dir handles don't need IDs
660 new->path
= strdup(cpath
);
662 new->shmbuf
= shmbuf
;
663 new->dir_cur
.d_name
= NULL
;
664 llist_push(filelist
,new);
673 errno
= res
<0?-res
:0;
674 return res
<0?NULL
:((DIR*)new);
679 * @param file Dirhandle
682 int closedir(DIR *file
) {
686 asprintf(&func
,"fs_closedir_%x",file
->fs
->pid
);
687 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
);
691 shmctl(file
->shmid
,IPC_RMID
,NULL
);
694 llist_remove(filelist
,llist_find(filelist
,file
));
698 errno
= res
<0?-res
:0;
703 * Reads an entry from an opened dir
704 * @param dh Dirhandle
707 struct dirent
*readdir(DIR *file
) {
711 asprintf(&func
,"fs_readdir_%x",file
->fs
->pid
);
712 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
);
715 if (file
->dir_cur
.d_name
!=NULL
) free(file
->dir_cur
.d_name
);
716 file
->dir_cur
.d_name
= strdup(file
->shmbuf
);
720 errno
= res
<0 && res
!=-ENOENT
?-res
:0;
721 return res
<0?NULL
:&(file
->dir_cur
);
726 * @param dh Dirhandle
727 * @param loc Location to seek to
729 void seekdir(DIR *file
,long loc
) {
733 asprintf(&func
,"fs_seekdir_%x",file
->fs
->pid
);
734 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
,loc
);
738 errno
= res
<0?-res
:0;
742 * Gets location in dir
743 * @param dh Dirhandle
744 * @return Location in dir
746 long telldir(DIR *file
) {
750 asprintf(&func
,"fs_seekdir_%x",file
->fs
->pid
);
751 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
,-1);
755 errno
= res
<0?-res
:0;
760 * Gets informations about a file
761 * @param path Path to file
762 * @param buf Pointer to stat structure
763 * @return 0=success; -1=failure
765 int stat(const char *path
,struct stat
*buf
) {
768 if ((fh
= open(path
,O_RDONLY
))!=-1) {
773 struct filelist_item
*dir
= opendir(path
);
775 ret
= fstat(dir
->fh
,buf
);
783 * Gets informations about a filedescriptor
784 * @param fildes Filedescriptor
785 * @param buf Pointer to stat structure
786 * @return 0=success; -1=failure
788 int fstat(int fildes
,struct stat
*buf
) {
791 struct filelist_item
*file
= filebyfh(fildes
);
793 asprintf(&func
,"fs_fstat_%x",file
->fs
->pid
);
794 res
= rpc_call(func
,0,file
->fs
->id
,file
->fs_fh
);
795 memcpy(buf
,file
->shmbuf
,sizeof(struct stat
));
799 errno
= res
<0?-res
:0;
804 * Gets informations about a filesystem
805 * @param path File included in FS of that information is wanted
806 * @param buf Pointer to statvfs structure
809 int statvfs(const char *path
,struct statvfs
*buf
) {
813 char *cpath
= getabsolutepath(path
);
814 struct fslist_item
*fs
= fsbypath(cpath
,0);
817 int shmid
= shmget(IPC_PRIVATE
,SHMMEM_SIZE
,0);
818 shmbuf
= shmat(shmid
,NULL
,0);
820 asprintf(&func
,"fs_statvfs_%x",fs
->pid
);
821 memset(buf
,0,sizeof(struct statvfs
));
822 strncpy(shmbuf
,cpath
,SHMMEM_SIZE
);
823 res
= rpc_call(func
,0,fs
->id
,shmid
);
824 memcpy(buf
,shmbuf
,sizeof(struct statvfs
));
827 shmctl(shmid
,IPC_RMID
,NULL
);
833 errno
= res
<0?-res
:0;
839 * @param path Path to link
840 * @param buf Buffer for path
841 * @param bufsize Size of buffer
842 * @return Bytes written to buffer
844 ssize_t
readlink(const char *path
,char *buf
,size_t bufsize
) {
848 char *cpath
= getabsolutepath(path
);
849 struct fslist_item
*fs
= fsbypath(cpath
,0);
852 int shmid
= shmget(IPC_PRIVATE
,SHMMEM_SIZE
,0);
853 shmbuf
= shmat(shmid
,NULL
,0);
855 asprintf(&func
,"fs_readlink_%x",fs
->pid
);
856 strncpy(shmbuf
,cpath
,SHMMEM_SIZE
);
857 res
= rpc_call(func
,0,fs
->id
,shmid
,bufsize
);
858 strncpy(buf
,shmbuf
,bufsize
);
861 shmctl(shmid
,IPC_RMID
,NULL
);
867 errno
= res
<0?-res
:0;
872 * Creates a symoblic link
873 * @param src Source file
874 * @param dest Destination (name of symlink)
875 * @return 0=success; -1=failure
877 int symlink(const char *dest
,const char *src
) {
879 char *csrc
= getabsolutepath((char*)src
);
880 char *cdest
= getabsolutepath((char*)dest
);
881 struct fslist_item
*fs
= fsbypath(csrc
,1);
885 asprintf(&func
,"fs_symlink_%x",fs
->pid
);
886 res
= rpc_call(func
,0,fs
->id
,csrc
,cdest
);
890 errno
= res
<0?-res
:0;
896 * @param src Source file
897 * @param dest Destination (name of hardlink)
898 * @return 0=success; -1=failure
900 int link(const char *src
,const char *dest
) {
902 char *csrc
= getabsolutepath((char*)src
);
903 char *cdest
= getabsolutepath((char*)dest
);
904 struct fslist_item
*fs
= fsbypath(csrc
,1);
905 struct fslist_item
*fsdest
= fsbypath(cdest
,0);
908 if (fs
!=NULL
&& fs
==fsdest
) {
909 asprintf(&func
,"fs_link_%x",fs
->pid
);
910 res
= rpc_call(func
,0,fs
->id
,src
,dest
);
914 errno
= res
<0?-res
:0;
918 int chown(const char *path
,uid_t uid
,gid_t gid
) {
920 char *cpath
= getabsolutepath((char*)path
);
921 struct fslist_item
*fs
= fsbypath(cpath
,0);
925 asprintf(&func
,"fs_chown_%x",fs
->pid
);
926 res
= rpc_call(func
,0,fs
->id
,cpath
,uid
,gid
);
931 errno
= res
<0?-res
:0;
935 int fchown(int fildes
,uid_t uid
,gid_t gid
) {
937 struct filelist_item
*file
= filebyfh(fildes
);
938 if (file
) res
= chown(file
->path
,uid
,gid
);
940 errno
= res
<0?-res
:0;
944 int chmod(const char *path
,mode_t mode
) {
946 char *cpath
= getabsolutepath((char*)path
);
947 struct fslist_item
*fs
= fsbypath(cpath
,0);
951 asprintf(&func
,"fs_chmod_%x",fs
->pid
);
952 res
= rpc_call(func
,0,fs
->id
,cpath
,mode
);
957 errno
= res
<0?-res
:0;
961 int fchmod(int fildes
,mode_t mode
) {
963 struct filelist_item
*file
= filebyfh(fildes
);
965 res
= chmod(file
->path
,mode
);
966 if (res
==0) file
->mode
= mode
;
969 errno
= res
<0?-res
:0;
973 int utime(const char *path
,const struct utimbuf
*times
) {
977 char *cpath
= getabsolutepath(path
);
978 struct fslist_item
*fs
= fsbypath(cpath
,0);
981 int shmid
= shmget(IPC_PRIVATE
,SHMMEM_SIZE
,0);
982 shmbuf
= shmat(shmid
,NULL
,0);
984 asprintf(&func
,"fs_utime_%x",fs
->pid
);
985 strncpy(shmbuf
,path
,SHMMEM_SIZE
);
986 memcpy(shmbuf
+strlen(shmbuf
)+1,times
,sizeof(struct utimbuf
));
987 res
= rpc_call(func
,0,fs
->id
,shmid
);
990 shmctl(shmid
,IPC_RMID
,NULL
);
996 errno
= res
<0?-res
:0;
1000 mode_t
umask(mode_t cmask
) {
1001 mode_t ret
= creation_mask
;
1002 creation_mask
= cmask
&0777;
1006 ///////// SOCKET STUFF /////////////////////
1008 int socket(int domain
,int type
, int protocol
) {