Set errno when only errstr was called
[akaros.git] / kern / src / syscall.c
index 897ec10..e506d76 100644 (file)
@@ -102,6 +102,36 @@ void set_errno(int errno)
                pcpui->cur_sysc->err = errno;
 }
 
+void set_errstr(char *errstr)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       if (!pcpui->cur_sysc)
+               return;
+       strncpy(pcpui->cur_sysc->errstr, errstr, MAX_ERRSTR_LEN);
+       /* enforce null termination */
+       pcpui->cur_sysc->errstr[MAX_ERRSTR_LEN - 1] = '\0';
+}
+
+char *current_errstr(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* no one should call this that doesn't have a sysc */
+       assert(!pcpui->cur_sysc);
+       return pcpui->cur_sysc->errstr;
+}
+
+struct errbuf *get_cur_errbuf(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       return (struct errbuf*)pcpui->cur_errbuf;
+}
+
+void set_cur_errbuf(struct errbuf *ebuf)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       pcpui->cur_errbuf = ebuf;
+}
+
 /************** Utility Syscalls **************/
 
 static int sys_null(void)
@@ -201,7 +231,7 @@ static int sys_cache_buster(struct proc *p, uint32_t num_writes,
 
 static int sys_cache_invalidate(void)
 {
-       #ifdef __i386__
+       #ifdef CONFIG_X86
                wbinvd();
        #endif
        return 0;
@@ -442,7 +472,7 @@ static ssize_t sys_fork(env_t* e)
        memcpy(env->procinfo->argp, e->procinfo->argp, sizeof(e->procinfo->argp));
        memcpy(env->procinfo->argbuf, e->procinfo->argbuf,
               sizeof(e->procinfo->argbuf));
-       #ifdef __i386__
+       #ifdef CONFIG_X86
        /* new guy needs to know about ldt (everything else in procdata is fresh */
        env->procdata->ldt = e->procdata->ldt;
        #endif
@@ -520,7 +550,7 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
                                   sizeof(pi->argbuf)))
                goto mid_error;
        /* This is the point of no return for the process. */
-       #ifdef __i386__
+       #ifdef CONFIG_X86
        /* clear this, so the new program knows to get an LDT */
        p->procdata->ldt = 0;
        #endif
@@ -1460,6 +1490,45 @@ intreg_t sys_rmdir(struct proc *p, const char *path, size_t path_l)
        return retval;
 }
 
+intreg_t sys_pipe(struct proc *p, int *u_pipefd, int flags)
+{
+       int pipefd[2] = {0};
+       int fd;
+       int retval = 0;
+       struct file *pipe_files[2] = {0};
+
+       if (do_pipe(pipe_files, flags))
+               return -1;
+       fd = insert_file(&p->open_files, pipe_files[0], 0);
+       if (!fd) {
+               set_errno(ENFILE);
+               goto failed_first;
+       }
+       pipefd[0] = fd;
+       fd = insert_file(&p->open_files, pipe_files[1], 0);
+       if (!fd) {
+               set_errno(ENFILE);
+               goto failed_second;
+       }
+       pipefd[1] = fd;
+       if (memcpy_to_user_errno(p, u_pipefd, pipefd, sizeof(pipefd))) {
+               set_errno(EFAULT);
+               goto failed_memcpy;
+       }
+       goto all_out;
+
+failed_memcpy:
+       put_file_from_fd(&p->open_files, pipefd[1]);
+failed_second:
+       put_file_from_fd(&p->open_files, pipefd[0]);
+failed_first:
+       retval = -1;
+all_out:
+       kref_put(&pipe_files[0]->f_kref);
+       kref_put(&pipe_files[1]->f_kref);
+       return retval;
+}
+
 intreg_t sys_gettimeofday(struct proc *p, int *buf)
 {
        static spinlock_t gtod_lock = SPINLOCK_INITIALIZER;
@@ -1637,6 +1706,7 @@ const static struct sys_table_entry syscall_table[] = {
        [SYS_getcwd] = {(syscall_t)sys_getcwd, "getcwd"},
        [SYS_mkdir] = {(syscall_t)sys_mkdir, "mkdri"},
        [SYS_rmdir] = {(syscall_t)sys_rmdir, "rmdir"},
+       [SYS_pipe] = {(syscall_t)sys_pipe, "pipe"},
        [SYS_gettimeofday] = {(syscall_t)sys_gettimeofday, "gettime"},
        [SYS_tcgetattr] = {(syscall_t)sys_tcgetattr, "tcgetattr"},
        [SYS_tcsetattr] = {(syscall_t)sys_tcsetattr, "tcsetattr"},
@@ -1702,13 +1772,19 @@ void run_local_syscall(struct syscall *sysc)
 
        /* TODO: (UMEM) assert / pin the memory for the sysc */
        assert(irq_is_enabled());       /* in case we proc destroy */
-       user_mem_assert(pcpui->cur_proc, sysc, sizeof(struct syscall),
-                       sizeof(uintptr_t), PTE_USER_RW);
+       /* Abort on mem check failure, for now */
+       if (!user_mem_check(pcpui->cur_proc, sysc, sizeof(struct syscall),
+                           sizeof(uintptr_t), PTE_USER_RW))
+               return;
        pcpui->cur_sysc = sysc;                 /* let the core know which sysc it is */
        sysc->retval = syscall(pcpui->cur_proc, sysc->num, sysc->arg0, sysc->arg1,
                               sysc->arg2, sysc->arg3, sysc->arg4, sysc->arg5);
        /* Need to re-load pcpui, in case we migrated */
        pcpui = &per_cpu_info[core_id()];
+       /* Some 9ns paths set errstr, but not errno.  glibc will ignore errstr.
+        * this is somewhat hacky, since errno might get set unnecessarily */
+       if ((current_errstr()[0] != 0) && (!sysc->err))
+               sysc->err = EUNSPECIFIED;
        finish_sysc(sysc, pcpui->cur_proc);
        /* Can unpin (UMEM) at this point */
        pcpui->cur_sysc = 0;    /* no longer working on sysc */