blob: ebb29f5259a9dfd59280bb5d5cc9e065d07f52d9 [file] [log] [blame]
Jeff Dike1d3468a2006-07-10 04:45:13 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/file.h"
8#include "linux/smp_lock.h"
9#include "linux/mm.h"
Alexey Dobriyan4e950f62007-07-30 02:36:13 +040010#include "linux/fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include "linux/utsname.h"
12#include "linux/msg.h"
13#include "linux/shm.h"
14#include "linux/sys.h"
15#include "linux/syscalls.h"
16#include "linux/unistd.h"
17#include "linux/slab.h"
18#include "linux/utime.h"
19#include "asm/mman.h"
20#include "asm/uaccess.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include "kern_util.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "sysdep/syscalls.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24/* Unlocked, I don't care if this is a bit off */
25int nsyscalls = 0;
26
27long sys_fork(void)
28{
29 long ret;
30
31 current->thread.forking = 1;
Jeff Dikee0877f02005-06-25 14:55:21 -070032 ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
33 &current->thread.regs, 0, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 current->thread.forking = 0;
35 return(ret);
36}
37
38long sys_vfork(void)
39{
40 long ret;
41
42 current->thread.forking = 1;
Jeff Dikee0877f02005-06-25 14:55:21 -070043 ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
44 UPT_SP(&current->thread.regs.regs),
45 &current->thread.regs, 0, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 current->thread.forking = 0;
47 return(ret);
48}
49
50/* common code for old and new mmaps */
51long sys_mmap2(unsigned long addr, unsigned long len,
52 unsigned long prot, unsigned long flags,
53 unsigned long fd, unsigned long pgoff)
54{
55 long error = -EBADF;
56 struct file * file = NULL;
57
58 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
59 if (!(flags & MAP_ANONYMOUS)) {
60 file = fget(fd);
61 if (!file)
62 goto out;
63 }
64
65 down_write(&current->mm->mmap_sem);
66 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
67 up_write(&current->mm->mmap_sem);
68
69 if (file)
70 fput(file);
71 out:
72 return error;
73}
74
75long old_mmap(unsigned long addr, unsigned long len,
76 unsigned long prot, unsigned long flags,
77 unsigned long fd, unsigned long offset)
78{
79 long err = -EINVAL;
80 if (offset & ~PAGE_MASK)
81 goto out;
82
83 err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
84 out:
85 return err;
86}
87/*
88 * sys_pipe() is the normal C calling standard for creating
89 * a pipe. It's not the way unix traditionally does this, though.
90 */
91long sys_pipe(unsigned long __user * fildes)
92{
93 int fd[2];
94 long error;
95
96 error = do_pipe(fd);
97 if (!error) {
98 if (copy_to_user(fildes, fd, sizeof(fd)))
99 error = -EFAULT;
100 }
101 return error;
102}
103
104
Al Viro4d338e12006-03-31 02:30:15 -0800105long sys_uname(struct old_utsname __user * name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
107 long err;
108 if (!name)
109 return -EFAULT;
110 down_read(&uts_sem);
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700111 err = copy_to_user(name, utsname(), sizeof (*name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 up_read(&uts_sem);
113 return err?-EFAULT:0;
114}
115
Al Viro4d338e12006-03-31 02:30:15 -0800116long sys_olduname(struct oldold_utsname __user * name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
118 long error;
119
120 if (!name)
121 return -EFAULT;
122 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
123 return -EFAULT;
Jeff Dike1d3468a2006-07-10 04:45:13 -0700124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 down_read(&uts_sem);
Jeff Dike1d3468a2006-07-10 04:45:13 -0700126
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700127 error = __copy_to_user(&name->sysname, &utsname()->sysname,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 __OLD_UTS_LEN);
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700129 error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
130 error |= __copy_to_user(&name->nodename, &utsname()->nodename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 __OLD_UTS_LEN);
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700132 error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
133 error |= __copy_to_user(&name->release, &utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 __OLD_UTS_LEN);
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700135 error |= __put_user(0, name->release + __OLD_UTS_LEN);
136 error |= __copy_to_user(&name->version, &utsname()->version,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 __OLD_UTS_LEN);
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700138 error |= __put_user(0, name->version + __OLD_UTS_LEN);
139 error |= __copy_to_user(&name->machine, &utsname()->machine,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 __OLD_UTS_LEN);
Serge E. Hallyne9ff3992006-10-02 02:18:11 -0700141 error |= __put_user(0, name->machine + __OLD_UTS_LEN);
Jeff Dike1d3468a2006-07-10 04:45:13 -0700142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 up_read(&uts_sem);
Jeff Dike1d3468a2006-07-10 04:45:13 -0700144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 error = error ? -EFAULT : 0;
146
147 return error;
148}
149
Arnd Bergmann3db03b42006-10-02 02:18:31 -0700150int kernel_execve(const char *filename, char *const argv[], char *const envp[])
151{
152 mm_segment_t fs;
153 int ret;
154
155 fs = get_fs();
156 set_fs(KERNEL_DS);
157 ret = um_execve(filename, argv, envp);
158 set_fs(fs);
159
160 return ret;
161}