Import changeset
[linux-flexiantxendom0-3.2.10.git] / arch / parisc / hpux / sys_hpux.c
1 /*
2  * linux/arch/parisc/kernel/sys_hpux.c
3  *
4  * implements HPUX syscalls.
5  */
6
7 #include <linux/sched.h>
8 #include <linux/smp_lock.h>
9 #include <linux/utsname.h>
10 #include <asm/errno.h>
11 #include <asm/uaccess.h>
12
13 unsigned long sys_brk(unsigned long addr);
14  
15 unsigned long hpux_brk(unsigned long addr)
16 {
17         /* Sigh.  Looks like HP/UX libc relies on kernel bugs. */
18         return sys_brk(addr + PAGE_SIZE);
19 }
20
21 int hpux_sbrk(void)
22 {
23         return -ENOSYS;
24 }
25
26 /* Random other syscalls */
27
28 int hpux_nice(int priority_change)
29 {
30         return -ENOSYS;
31 }
32
33 int hpux_ptrace(void)
34 {
35         return -ENOSYS;
36 }
37
38 int hpux_wait(int *stat_loc)
39 {
40         extern int sys_waitpid(int, int *, int);
41         return sys_waitpid(-1, stat_loc, 0);
42 }
43
44 #define _SC_CPU_VERSION 10001
45 #define _SC_OPEN_MAX    4
46 #define CPU_PA_RISC1_1  0x210
47
48 int hpux_sysconf(int which)
49 {
50         switch (which) {
51         case _SC_CPU_VERSION:
52                 return CPU_PA_RISC1_1;
53         case _SC_OPEN_MAX:
54                 return INT_MAX;
55         default:
56                 return -EINVAL;
57         }
58 }
59
60 /*****************************************************************************/
61
62 #define HPUX_UTSLEN 9
63 #define HPUX_SNLEN 15
64
65 struct hpux_utsname {
66         char sysname[HPUX_UTSLEN];
67         char nodename[HPUX_UTSLEN];
68         char release[HPUX_UTSLEN];
69         char version[HPUX_UTSLEN];
70         char machine[HPUX_UTSLEN];
71         char idnumber[HPUX_SNLEN];
72 } ;
73
74 struct hpux_ustat {
75         int32_t         f_tfree;        /* total free (daddr_t)  */
76         u_int32_t       f_tinode;       /* total inodes free (ino_t)  */
77         char            f_fname[6];     /* filsys name */
78         char            f_fpack[6];     /* filsys pack name */
79         u_int32_t       f_blksize;      /* filsys block size (int) */
80 };
81
82 /*
83  * HPUX's utssys() call.  It's a collection of miscellaneous functions,
84  * alas, so there's no nice way of splitting them up.
85  */
86
87 /*  This function is called from hpux_utssys(); HP-UX implements
88  *  ustat() as an option to utssys().
89  *
90  *  Now, struct ustat on HP-UX is exactly the same as on Linux, except
91  *  that it contains one addition field on the end, int32_t f_blksize.
92  *  So, we could have written this function to just call the Linux
93  *  sys_ustat(), (defined in linux/fs/super.c), and then just
94  *  added this additional field to the user's structure.  But I figure
95  *  if we're gonna be digging through filesystem structures to get
96  *  this, we might as well just do the whole enchilada all in one go.
97  *
98  *  So, most of this function is almost identical to sys_ustat().
99  *  I have placed comments at the few lines changed or added, to
100  *  aid in porting forward if and when sys_ustat() is changed from
101  *  its form in kernel 2.2.5.
102  */
103 static int hpux_ustat(dev_t dev, struct hpux_ustat *ubuf)
104 {
105         struct super_block *s;
106         struct hpux_ustat tmp;  /* Changed to hpux_ustat */
107         struct statfs sbuf;
108         int err = -EINVAL;
109
110         lock_kernel();
111         s = get_super(to_kdev_t(dev));
112         if (s == NULL)
113                 goto out;
114         err = vfs_statfs(s, &sbuf);
115         if (err)
116                 goto out;
117
118         memset(&tmp,0,sizeof(struct hpux_ustat));  /* Changed to hpux_ustat */
119
120         tmp.f_tfree = (int32_t)sbuf.f_bfree;
121         tmp.f_tinode = (u_int32_t)sbuf.f_ffree;
122         tmp.f_blksize = (u_int32_t)sbuf.f_bsize;  /*  Added this line  */
123
124         /* Changed to hpux_ustat:  */
125         err = copy_to_user(ubuf,&tmp,sizeof(struct hpux_ustat)) ? -EFAULT : 0;
126 out:
127         unlock_kernel();
128         return err;
129 }
130
131
132 /*  This function is called from hpux_utssys(); HP-UX implements
133  *  uname() as an option to utssys().
134  *
135  *  The form of this function is pretty much copied from sys_olduname(),
136  *  defined in linux/arch/i386/kernel/sys_i386.c.
137  */
138 /*  TODO: Are these put_user calls OK?  Should they pass an int?
139  *        (I copied it from sys_i386.c like this.)
140  */
141 static int hpux_uname(struct hpux_utsname *name)
142 {
143         int error;
144
145         if (!name)
146                 return -EFAULT;
147         if (!access_ok(VERIFY_WRITE,name,sizeof(struct hpux_utsname)))
148                 return -EFAULT;
149
150         down_read(&uts_sem);
151
152         error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1);
153         error |= __put_user(0,name->sysname+HPUX_UTSLEN-1);
154         error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1);
155         error |= __put_user(0,name->nodename+HPUX_UTSLEN-1);
156         error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1);
157         error |= __put_user(0,name->release+HPUX_UTSLEN-1);
158         error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1);
159         error |= __put_user(0,name->version+HPUX_UTSLEN-1);
160         error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1);
161         error |= __put_user(0,name->machine+HPUX_UTSLEN-1);
162
163         up_read(&uts_sem);
164
165         /*  HP-UX  utsname has no domainname field.  */
166
167         /*  TODO:  Implement idnumber!!!  */
168 #if 0
169         error |= __put_user(0,name->idnumber);
170         error |= __put_user(0,name->idnumber+HPUX_SNLEN-1);
171 #endif
172
173         error = error ? -EFAULT : 0;
174
175         return error;
176 }
177
178 int sys_sethostname(char *, int);
179 int sys_gethostname(char *, int);
180
181 /*  Note: HP-UX just uses the old suser() function to check perms
182  *  in this system call.  We'll use capable(CAP_SYS_ADMIN).
183  */
184 int hpux_utssys(char *ubuf, int n, int type)
185 {
186         int len;
187         int error;
188         switch( type ) {
189         case 0:
190                 /*  uname():  */
191                 return( hpux_uname( (struct hpux_utsname *)ubuf ) );
192                 break ;
193         case 1:
194                 /*  Obsolete (used to be umask().)  */
195                 return -EFAULT ;
196                 break ;
197         case 2:
198                 /*  ustat():  */
199                 return( hpux_ustat((dev_t)n, (struct hpux_ustat *)ubuf) );
200                 break ;
201         case 3:
202                 /*  setuname():
203                  *
204                  *  On linux (unlike HP-UX), utsname.nodename
205                  *  is the same as the hostname.
206                  *
207                  *  sys_sethostname() is defined in linux/kernel/sys.c.
208                  */
209                 if (!capable(CAP_SYS_ADMIN))
210                         return -EPERM;
211                 /*  Unlike Linux, HP-UX returns an error if n==0:  */
212                 if ( n <= 0 )
213                         return -EINVAL ;
214                 /*  Unlike Linux, HP-UX truncates it if n is too big:  */
215                 len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
216                 return( sys_sethostname(ubuf, len) );
217                 break ;
218         case 4:
219                 /*  sethostname():
220                  *
221                  *  sys_sethostname() is defined in linux/kernel/sys.c.
222                  */
223                 if (!capable(CAP_SYS_ADMIN))
224                         return -EPERM;
225                 /*  Unlike Linux, HP-UX returns an error if n==0:  */
226                 if ( n <= 0 )
227                         return -EINVAL ;
228                 /*  Unlike Linux, HP-UX truncates it if n is too big:  */
229                 len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
230                 return( sys_sethostname(ubuf, len) );
231                 break ;
232         case 5:
233                 /*  gethostname():
234                  *
235                  *  sys_gethostname() is defined in linux/kernel/sys.c.
236                  */
237                 /*  Unlike Linux, HP-UX returns an error if n==0:  */
238                 if ( n <= 0 )
239                         return -EINVAL ;
240                 return( sys_gethostname(ubuf, n) );
241                 break ;
242         case 6:
243                 /*  Supposedly called from setuname() in libc.
244                  *  TODO: When and why is this called?
245                  *        Is it ever even called?
246                  *
247                  *  This code should look a lot like sys_sethostname(),
248                  *  defined in linux/kernel/sys.c.  If that gets updated,
249                  *  update this code similarly.
250                  */
251                 if (!capable(CAP_SYS_ADMIN))
252                         return -EPERM;
253                 /*  Unlike Linux, HP-UX returns an error if n==0:  */
254                 if ( n <= 0 )
255                         return -EINVAL ;
256                 /*  Unlike Linux, HP-UX truncates it if n is too big:  */
257                 len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
258                 /**/
259                 /*  TODO:  print a warning about using this?  */
260                 down_write(&uts_sem);
261                 error = -EFAULT;
262                 if (!copy_from_user(system_utsname.sysname, ubuf, len)) {
263                         system_utsname.sysname[len] = 0;
264                         error = 0;
265                 }
266                 up_write(&uts_sem);
267                 return error;
268                 break ;
269         case 7:
270                 /*  Sets utsname.release, if you're allowed.
271                  *  Undocumented.  Used by swinstall to change the
272                  *  OS version, during OS updates.  Yuck!!!
273                  *
274                  *  This code should look a lot like sys_sethostname()
275                  *  in linux/kernel/sys.c.  If that gets updated, update
276                  *  this code similarly.
277                  */
278                 if (!capable(CAP_SYS_ADMIN))
279                         return -EPERM;
280                 /*  Unlike Linux, HP-UX returns an error if n==0:  */
281                 if ( n <= 0 )
282                         return -EINVAL ;
283                 /*  Unlike Linux, HP-UX truncates it if n is too big:  */
284                 len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
285                 /**/
286                 /*  TODO:  print a warning about this?  */
287                 down_write(&uts_sem);
288                 error = -EFAULT;
289                 if (!copy_from_user(system_utsname.release, ubuf, len)) {
290                         system_utsname.release[len] = 0;
291                         error = 0;
292                 }
293                 up_write(&uts_sem);
294                 return error;
295                 break ;
296         default:
297                 /*  This system call returns -EFAULT if given an unknown type.
298                  *  Why not -EINVAL?  I don't know, it's just not what they did.
299                  */
300                 return -EFAULT ;
301         }
302 }
303
304 int hpux_getdomainname(char *name, int len)
305 {
306         int nlen;
307         int err = -EFAULT;
308         
309         down_read(&uts_sem);
310         
311         nlen = strlen(system_utsname.domainname) + 1;
312
313         if (nlen < len)
314                 len = nlen;
315         if(len > __NEW_UTS_LEN)
316                 goto done;
317         if(copy_to_user(name, system_utsname.domainname, len))
318                 goto done;
319         err = 0;
320 done:
321         up_read(&uts_sem);
322         return err;
323         
324 }
325
326 int hpux_pipe(int *kstack_fildes)
327 {
328         int error;
329
330         lock_kernel();
331         error = do_pipe(kstack_fildes);
332         unlock_kernel();
333         return error;
334 }