readdir() and readdir_r() (XCC)
[akaros.git] / kern / src / syscall.c
index 194252e..0eadc4f 100644 (file)
@@ -307,12 +307,15 @@ static int sys_proc_yield(struct proc *p, bool being_nice)
 static ssize_t sys_fork(env_t* e)
 {
        // TODO: right now we only support fork for single-core processes
-       if(e->state != PROC_RUNNING_S)
-       {
+       if (e->state != PROC_RUNNING_S) {
+               set_errno(EINVAL);
+               return -1;
+       }
+       /* Can't really fork if we don't have a current_tf to fork */
+       if (!current_tf) {
                set_errno(EINVAL);
                return -1;
        }
-
        env_t* env;
        assert(!proc_alloc(&env, current));
        assert(env != NULL);
@@ -398,9 +401,15 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
        struct file *program;
 
        /* We probably want it to never be allowed to exec if it ever was _M */
-       if(p->state != PROC_RUNNING_S)
+       if (p->state != PROC_RUNNING_S) {
+               set_errno(EINVAL);
                return -1;
-
+       }
+       /* Can't really exec if we don't have a current_tf to reset */
+       if (!current_tf) {
+               set_errno(EINVAL);
+               return -1;
+       }
        /* Copy in the path.  Consider putting an upper bound on path_l. */
        t_path = user_strdup_errno(p, path, path_l);
        if (!t_path)
@@ -775,6 +784,7 @@ static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
                set_errno(EBADF);
                return -1;
        }
+       assert(file->f_op->read);
        /* TODO: (UMEM) currently, read() handles user memcpy issues, but we
         * probably should user_mem_check and pin the region here, so read doesn't
         * worry about it */
@@ -800,6 +810,11 @@ static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
                set_errno(EBADF);
                return -1;
        }
+       if (!file->f_op->write) {
+               kref_put(&file->f_kref);
+               set_errno(EINVAL);
+               return -1;
+       }
        /* TODO: (UMEM) */
        ret = file->f_op->write(file, buf, len, &file->f_pos);
        kref_put(&file->f_kref);
@@ -881,22 +896,22 @@ static intreg_t stat_helper(struct proc *p, const char *path, size_t path_l,
                             struct kstat *u_stat, int flags)
 {
        struct kstat *kbuf;
-       struct inode *path_i;
+       struct dentry *path_d;
        char *t_path = user_strdup_errno(p, path, path_l);
        if (!t_path)
                return -1;
-       path_i = lookup_inode(t_path, flags);
+       path_d = lookup_dentry(t_path, flags);
        user_memdup_free(p, t_path);
-       if (!path_i)
+       if (!path_d)
                return -1;
        kbuf = kmalloc(sizeof(struct kstat), 0);
        if (!kbuf) {
                set_errno(ENOMEM);
-               kref_put(&path_i->i_kref);
+               kref_put(&path_d->d_kref);
                return -1;
        }
-       stat_inode(path_i, kbuf);
-       kref_put(&path_i->i_kref);
+       stat_inode(path_d->d_inode, kbuf);
+       kref_put(&path_d->d_kref);
        /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
        if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
                kfree(kbuf);
@@ -923,7 +938,38 @@ static intreg_t sys_lstat(struct proc *p, const char *path, size_t path_l,
 
 intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
 {
-       return ufe(fcntl,fd,cmd,arg,0);
+       int retval = 0;
+       struct file *file = get_file_from_fd(&p->open_files, fd);
+       if (!file) {
+               set_errno(EBADF);
+               return -1;
+       }
+       switch (cmd) {
+               case (F_DUPFD):
+                       printk("[kernel] dup not supported yet\n");
+                       break;
+               case (F_GETFD):
+                       /* GET and SETFD just care about CLOEXEC.  We don't have a separate
+                        * flag variable for the FD (we might need to, technically). */
+                       if (file->f_flags & O_CLOEXEC)
+                               retval = FD_CLOEXEC;
+                       break;
+               case (F_SETFD):
+                       if (arg == FD_CLOEXEC)
+                               file->f_flags |= O_CLOEXEC;
+                       break;
+               case (F_GETFL):
+                       retval = file->f_flags;
+                       break;
+               case (F_SETFL):
+                       /* only allowed to set certain flags. */
+                       arg &= O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK;
+                       break;
+               default:
+                       warn("Unsupported fcntl cmd %d\n", cmd);
+       }
+       kref_put(&file->f_kref);
+       return 0;
 }
 
 static intreg_t sys_access(struct proc *p, const char *path, size_t path_l,
@@ -1002,6 +1048,49 @@ intreg_t sys_unlink(struct proc *p, const char *path, size_t path_l)
        return ret;
 }
 
+intreg_t sys_symlink(struct proc *p, char *old_path, size_t old_l,
+                     char *new_path, size_t new_l)
+{
+       int ret;
+       char *t_oldpath = user_strdup_errno(p, old_path, old_l);
+       if (t_oldpath == NULL)
+               return -1;
+       char *t_newpath = user_strdup_errno(p, new_path, new_l);
+       if (t_newpath == NULL) {
+               user_memdup_free(p, t_oldpath);
+               return -1;
+       }
+       ret = do_symlink(new_path, old_path, S_IRWXU | S_IRWXG | S_IRWXO);
+       user_memdup_free(p, t_oldpath);
+       user_memdup_free(p, t_newpath);
+       return ret;
+}
+
+intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
+                      char *u_buf, size_t buf_l)
+{
+       char *symname;
+       ssize_t copy_amt;
+       struct dentry *path_d;
+       char *t_path = user_strdup_errno(p, path, path_l);
+       if (t_path == NULL)
+               return -1;
+       path_d = lookup_dentry(t_path, 0);
+       user_memdup_free(p, t_path);
+       if (!path_d)
+               return -1;
+       symname = path_d->d_inode->i_op->readlink(path_d);
+       copy_amt = strnlen(symname, buf_l - 1) + 1;
+       if (memcpy_to_user_errno(p, u_buf, symname, copy_amt)) {
+               kref_put(&path_d->d_kref);
+               set_errno(EINVAL);
+               return -1;
+       }
+       kref_put(&path_d->d_kref);
+       printd("READLINK returning %s\n", u_buf);
+       return copy_amt;
+}
+
 intreg_t sys_chdir(struct proc *p, const char *path, size_t path_l)
 {
        char* fn = user_strdup_errno(p,path,PGSIZE);
@@ -1078,19 +1167,13 @@ intreg_t sys_tcsetattr(struct proc *p, int fd, int optional_actions,
  * any silly state.
  * 
  * This syscall function is used by both local syscall and arsc, and should
- * remain oblivious of the caller.
- *
- * TODO: Keep in mind that not every syscall has a user trapframe. 
- * e.g. ARSC
- */
+ * remain oblivious of the caller. */
 intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5)
 {
-       // Initialize the return value and error code returned to 0
-       if(current_tf != NULL){
-               set_retval(ESUCCESS);
-               set_errno(ESUCCESS);
-       }
+       /* Initialize the return value and error code returned to 0 */
+       set_retval(ESUCCESS);
+       set_errno(ESUCCESS);
 
        typedef intreg_t (*syscall_t)(struct proc*,uintreg_t,uintreg_t,
                                      uintreg_t,uintreg_t,uintreg_t);
@@ -1149,6 +1232,8 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                [SYS_lseek] = (syscall_t)sys_lseek,
                [SYS_link] = (syscall_t)sys_link,
                [SYS_unlink] = (syscall_t)sys_unlink,
+               [SYS_symlink] = (syscall_t)sys_symlink,
+               [SYS_readlink] = (syscall_t)sys_readlink,
                [SYS_chdir] = (syscall_t)sys_chdir,
                [SYS_getcwd] = (syscall_t)sys_getcwd,
                [SYS_gettimeofday] = (syscall_t)sys_gettimeofday,