ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / sparc64 / kernel / sys_sunos32.c
1 /* $Id: sys_sunos32.c,v 1.64 2002/02/09 19:49:31 davem Exp $
2  * sys_sunos32.c: SunOS binary compatibility layer on sparc64.
3  *
4  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
5  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
6  *
7  * Based upon preliminary work which is:
8  *
9  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/types.h>
15 #include <linux/compat.h>
16 #include <linux/mman.h>
17 #include <linux/mm.h>
18 #include <linux/swap.h>
19 #include <linux/fs.h>
20 #include <linux/file.h>
21 #include <linux/resource.h>
22 #include <linux/ipc.h>
23 #include <linux/shm.h>
24 #include <linux/msg.h>
25 #include <linux/sem.h>
26 #include <linux/signal.h>
27 #include <linux/uio.h>
28 #include <linux/utsname.h>
29 #include <linux/major.h>
30 #include <linux/stat.h>
31 #include <linux/slab.h>
32 #include <linux/pagemap.h>
33 #include <linux/errno.h>
34 #include <linux/smp.h>
35 #include <linux/smp_lock.h>
36 #include <linux/syscalls.h>
37
38 #include <asm/uaccess.h>
39 #include <asm/page.h>
40 #include <asm/pgtable.h>
41 #include <asm/pconf.h>
42 #include <asm/idprom.h> /* for gethostid() */
43 #include <asm/unistd.h>
44 #include <asm/system.h>
45
46 /* For the nfs mount emulation */
47 #include <linux/socket.h>
48 #include <linux/in.h>
49 #include <linux/nfs.h>
50 #include <linux/nfs2.h>
51 #include <linux/nfs_mount.h>
52
53 /* for sunos_select */
54 #include <linux/time.h>
55 #include <linux/personality.h>
56
57 /* For SOCKET_I */
58 #include <linux/socket.h>
59 #include <net/sock.h>
60 #include <net/compat.h>
61
62 /* Use this to get at 32-bit user passed pointers. */
63 #define A(__x)                          \
64 ({      unsigned long __ret;            \
65         __asm__ ("srl   %0, 0, %0"      \
66                  : "=r" (__ret)         \
67                  : "0" (__x));          \
68         __ret;                          \
69 })
70
71 #define SUNOS_NR_OPEN   256
72
73 asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
74 {
75         struct file *file = NULL;
76         unsigned long retval, ret_type;
77
78         if (flags & MAP_NORESERVE) {
79                 static int cnt;
80                 if (cnt++ < 10)
81                         printk("%s:  unimplemented SunOS MAP_NORESERVE mmap() flag\n",
82                                current->comm);
83                 flags &= ~MAP_NORESERVE;
84         }
85         retval = -EBADF;
86         if (!(flags & MAP_ANONYMOUS)) {
87                 struct inode * inode;
88                 if (fd >= SUNOS_NR_OPEN)
89                         goto out;
90                 file = fget(fd);
91                 if (!file)
92                         goto out;
93                 inode = file->f_dentry->d_inode;
94                 if (imajor(inode) == MEM_MAJOR && iminor(inode) == 5) {
95                         flags |= MAP_ANONYMOUS;
96                         fput(file);
97                         file = NULL;
98                 }
99         }
100
101         retval = -EINVAL;
102         if (!(flags & MAP_FIXED))
103                 addr = 0;
104         else if (len > 0xf0000000 || addr > 0xf0000000 - len)
105                 goto out_putf;
106         ret_type = flags & _MAP_NEW;
107         flags &= ~_MAP_NEW;
108
109         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
110         down_write(&current->mm->mmap_sem);
111         retval = do_mmap(file,
112                          (unsigned long) addr, (unsigned long) len,
113                          (unsigned long) prot, (unsigned long) flags,
114                          (unsigned long) off);
115         up_write(&current->mm->mmap_sem);
116         if (!ret_type)
117                 retval = ((retval < 0xf0000000) ? 0 : retval);
118 out_putf:
119         if (file)
120                 fput(file);
121 out:
122         return (u32) retval;
123 }
124
125 asmlinkage int sunos_mctl(u32 addr, u32 len, int function, u32 arg)
126 {
127         return 0;
128 }
129
130 asmlinkage int sunos_brk(u32 baddr)
131 {
132         int freepages, retval = -ENOMEM;
133         unsigned long rlim;
134         unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
135
136         down_write(&current->mm->mmap_sem);
137         if (brk < current->mm->end_code)
138                 goto out;
139         newbrk = PAGE_ALIGN(brk);
140         oldbrk = PAGE_ALIGN(current->mm->brk);
141         retval = 0;
142         if (oldbrk == newbrk) {
143                 current->mm->brk = brk;
144                 goto out;
145         }
146         /* Always allow shrinking brk. */
147         if (brk <= current->mm->brk) {
148                 current->mm->brk = brk;
149                 do_munmap(current->mm, newbrk, oldbrk-newbrk);
150                 goto out;
151         }
152         /* Check against rlimit and stack.. */
153         retval = -ENOMEM;
154         rlim = current->rlim[RLIMIT_DATA].rlim_cur;
155         if (rlim >= RLIM_INFINITY)
156                 rlim = ~0;
157         if (brk - current->mm->end_code > rlim)
158                 goto out;
159         /* Check against existing mmap mappings. */
160         if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE))
161                 goto out;
162         /* stupid algorithm to decide if we have enough memory: while
163          * simple, it hopefully works in most obvious cases.. Easy to
164          * fool it, but this should catch most mistakes.
165          */
166         freepages = get_page_cache_size();
167         freepages >>= 1;
168         freepages += nr_free_pages();
169         freepages += nr_swap_pages;
170         freepages -= num_physpages >> 4;
171         freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
172         if (freepages < 0)
173                 goto out;
174         /* Ok, we have probably got enough memory - let it rip. */
175         current->mm->brk = brk;
176         do_brk(oldbrk, newbrk-oldbrk);
177         retval = 0;
178 out:
179         up_write(&current->mm->mmap_sem);
180         return retval;
181 }
182
183 asmlinkage u32 sunos_sbrk(int increment)
184 {
185         int error, oldbrk;
186
187         /* This should do it hopefully... */
188         oldbrk = (int)current->mm->brk;
189         error = sunos_brk(((int) current->mm->brk) + increment);
190         if(!error)
191                 error = oldbrk;
192         return error;
193 }
194
195 asmlinkage u32 sunos_sstk(int increment)
196 {
197         printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
198                current->comm, increment);
199
200         return (u32)-1;
201 }
202
203 /* Give hints to the kernel as to what paging strategy to use...
204  * Completely bogus, don't remind me.
205  */
206 #define VA_NORMAL     0 /* Normal vm usage expected */
207 #define VA_ABNORMAL   1 /* Abnormal/random vm usage probable */
208 #define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
209 #define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
210 static char *vstrings[] = {
211         "VA_NORMAL",
212         "VA_ABNORMAL",
213         "VA_SEQUENTIAL",
214         "VA_INVALIDATE",
215 };
216
217 asmlinkage void sunos_vadvise(u32 strategy)
218 {
219         static int count;
220
221         /* I wanna see who uses this... */
222         if (count++ < 5)
223                 printk("%s: Advises us to use %s paging strategy\n",
224                        current->comm,
225                        strategy <= 3 ? vstrings[strategy] : "BOGUS");
226 }
227
228 /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
229  * resource limit and is for backwards compatibility with older sunos
230  * revs.
231  */
232 asmlinkage int sunos_getdtablesize(void)
233 {
234         return SUNOS_NR_OPEN;
235 }
236
237
238 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
239
240 asmlinkage u32 sunos_sigblock(u32 blk_mask)
241 {
242         u32 old;
243
244         spin_lock_irq(&current->sighand->siglock);
245         old = (u32) current->blocked.sig[0];
246         current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
247         recalc_sigpending();
248         spin_unlock_irq(&current->sighand->siglock);
249         return old;
250 }
251
252 asmlinkage u32 sunos_sigsetmask(u32 newmask)
253 {
254         u32 retval;
255
256         spin_lock_irq(&current->sighand->siglock);
257         retval = (u32) current->blocked.sig[0];
258         current->blocked.sig[0] = (newmask & _BLOCKABLE);
259         recalc_sigpending();
260         spin_unlock_irq(&current->sighand->siglock);
261         return retval;
262 }
263
264 /* SunOS getdents is very similar to the newer Linux (iBCS2 compliant)    */
265 /* getdents system call, the format of the structure just has a different */
266 /* layout (d_off+d_ino instead of d_ino+d_off) */
267 struct sunos_dirent {
268     s32         d_off;
269     u32         d_ino;
270     u16         d_reclen;
271     u16         d_namlen;
272     char        d_name[1];
273 };
274
275 struct sunos_dirent_callback {
276     struct sunos_dirent *curr;
277     struct sunos_dirent *previous;
278     int count;
279     int error;
280 };
281
282 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
283 #define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1))
284
285 static int sunos_filldir(void * __buf, const char * name, int namlen,
286                          loff_t offset, ino_t ino, unsigned int d_type)
287 {
288         struct sunos_dirent * dirent;
289         struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
290         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
291
292         buf->error = -EINVAL;   /* only used if we fail.. */
293         if (reclen > buf->count)
294                 return -EINVAL;
295         dirent = buf->previous;
296         if (dirent)
297                 put_user(offset, &dirent->d_off);
298         dirent = buf->curr;
299         buf->previous = dirent;
300         put_user(ino, &dirent->d_ino);
301         put_user(namlen, &dirent->d_namlen);
302         put_user(reclen, &dirent->d_reclen);
303         copy_to_user(dirent->d_name, name, namlen);
304         put_user(0, dirent->d_name + namlen);
305         dirent = (void *) dirent + reclen;
306         buf->curr = dirent;
307         buf->count -= reclen;
308         return 0;
309 }
310
311 asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
312 {
313         struct file * file;
314         struct sunos_dirent * lastdirent;
315         struct sunos_dirent_callback buf;
316         int error = -EBADF;
317         void *dirent = (void *)A(u_dirent);
318
319         if(fd >= SUNOS_NR_OPEN)
320                 goto out;
321
322         file = fget(fd);
323         if(!file)
324                 goto out;
325
326         error = -EINVAL;
327         if(cnt < (sizeof(struct sunos_dirent) + 255))
328                 goto out_putf;
329
330         buf.curr = (struct sunos_dirent *) dirent;
331         buf.previous = NULL;
332         buf.count = cnt;
333         buf.error = 0;
334
335         error = vfs_readdir(file, sunos_filldir, &buf);
336         if (error < 0)
337                 goto out_putf;
338
339         lastdirent = buf.previous;
340         error = buf.error;
341         if (lastdirent) {
342                 put_user(file->f_pos, &lastdirent->d_off);
343                 error = cnt - buf.count;
344         }
345
346 out_putf:
347         fput(file);
348 out:
349         return error;
350 }
351
352 /* Old sunos getdirentries, severely broken compatibility stuff here. */
353 struct sunos_direntry {
354     u32         d_ino;
355     u16         d_reclen;
356     u16         d_namlen;
357     char        d_name[1];
358 };
359
360 struct sunos_direntry_callback {
361     struct sunos_direntry *curr;
362     struct sunos_direntry *previous;
363     int count;
364     int error;
365 };
366
367 static int sunos_filldirentry(void * __buf, const char * name, int namlen,
368                               loff_t offset, ino_t ino, unsigned int d_type)
369 {
370         struct sunos_direntry * dirent;
371         struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf;
372         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
373
374         buf->error = -EINVAL;   /* only used if we fail.. */
375         if (reclen > buf->count)
376                 return -EINVAL;
377         dirent = buf->previous;
378         dirent = buf->curr;
379         buf->previous = dirent;
380         put_user(ino, &dirent->d_ino);
381         put_user(namlen, &dirent->d_namlen);
382         put_user(reclen, &dirent->d_reclen);
383         copy_to_user(dirent->d_name, name, namlen);
384         put_user(0, dirent->d_name + namlen);
385         dirent = (void *) dirent + reclen;
386         buf->curr = dirent;
387         buf->count -= reclen;
388         return 0;
389 }
390
391 asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
392                                    int cnt, u32 u_basep)
393 {
394         void *dirent = (void *) A(u_dirent);
395         unsigned int *basep = (unsigned int *)A(u_basep);
396         struct file * file;
397         struct sunos_direntry * lastdirent;
398         int error = -EBADF;
399         struct sunos_direntry_callback buf;
400
401         if(fd >= SUNOS_NR_OPEN)
402                 goto out;
403
404         file = fget(fd);
405         if(!file)
406                 goto out;
407
408         error = -EINVAL;
409         if(cnt < (sizeof(struct sunos_direntry) + 255))
410                 goto out_putf;
411
412         buf.curr = (struct sunos_direntry *) dirent;
413         buf.previous = NULL;
414         buf.count = cnt;
415         buf.error = 0;
416
417         error = vfs_readdir(file, sunos_filldirentry, &buf);
418         if (error < 0)
419                 goto out_putf;
420
421         lastdirent = buf.previous;
422         error = buf.error;
423         if (lastdirent) {
424                 put_user(file->f_pos, basep);
425                 error = cnt - buf.count;
426         }
427
428 out_putf:
429         fput(file);
430 out:
431         return error;
432 }
433
434 struct sunos_utsname {
435         char sname[9];
436         char nname[9];
437         char nnext[56];
438         char rel[9];
439         char ver[9];
440         char mach[9];
441 };
442
443 asmlinkage int sunos_uname(struct sunos_utsname *name)
444 {
445         int ret;
446
447         down_read(&uts_sem);
448         ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
449         ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
450         ret |= put_user('\0', &name->nname[8]);
451         ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
452         ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
453         ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
454         up_read(&uts_sem);
455         return (ret ? -EFAULT : 0);
456 }
457
458 asmlinkage int sunos_nosys(void)
459 {
460         struct pt_regs *regs;
461         siginfo_t info;
462         static int cnt;
463
464         regs = current_thread_info()->kregs;
465         if (test_thread_flag(TIF_32BIT)) {
466                 regs->tpc &= 0xffffffff;
467                 regs->tnpc &= 0xffffffff;
468         }
469         info.si_signo = SIGSYS;
470         info.si_errno = 0;
471         info.si_code = __SI_FAULT|0x100;
472         info.si_addr = (void *)regs->tpc;
473         info.si_trapno = regs->u_regs[UREG_G1];
474         send_sig_info(SIGSYS, &info, current);
475         if (cnt++ < 4) {
476                 printk("Process makes ni_syscall number %d, register dump:\n",
477                        (int) regs->u_regs[UREG_G1]);
478                 show_regs(regs);
479         }
480         return -ENOSYS;
481 }
482
483 /* This is not a real and complete implementation yet, just to keep
484  * the easy SunOS binaries happy.
485  */
486 asmlinkage int sunos_fpathconf(int fd, int name)
487 {
488         int ret;
489
490         switch(name) {
491         case _PCONF_LINK:
492                 ret = LINK_MAX;
493                 break;
494         case _PCONF_CANON:
495                 ret = MAX_CANON;
496                 break;
497         case _PCONF_INPUT:
498                 ret = MAX_INPUT;
499                 break;
500         case _PCONF_NAME:
501                 ret = NAME_MAX;
502                 break;
503         case _PCONF_PATH:
504                 ret = PATH_MAX;
505                 break;
506         case _PCONF_PIPE:
507                 ret = PIPE_BUF;
508                 break;
509         case _PCONF_CHRESTRICT:         /* XXX Investigate XXX */
510                 ret = 1;
511                 break;
512         case _PCONF_NOTRUNC:            /* XXX Investigate XXX */
513         case _PCONF_VDISABLE:
514                 ret = 0;
515                 break;
516         default:
517                 ret = -EINVAL;
518                 break;
519         }
520         return ret;
521 }
522
523 asmlinkage int sunos_pathconf(u32 u_path, int name)
524 {
525         int ret;
526
527         ret = sunos_fpathconf(0, name); /* XXX cheese XXX */
528         return ret;
529 }
530
531 /* SunOS mount system call emulation */
532 extern asmlinkage int
533 sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
534
535 asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
536 {
537         int ret;
538
539         /* SunOS binaries expect that select won't change the tvp contents */
540         ret = sys32_select (width, inp, outp, exp, tvp_x);
541         if (ret == -EINTR && tvp_x) {
542                 struct compat_timeval *tvp = (struct compat_timeval *)A(tvp_x);
543                 time_t sec, usec;
544
545                 __get_user(sec, &tvp->tv_sec);
546                 __get_user(usec, &tvp->tv_usec);
547                 if (sec == 0 && usec == 0)
548                         ret = 0;
549         }
550         return ret;
551 }
552
553 asmlinkage void sunos_nop(void)
554 {
555         return;
556 }
557
558 /* XXXXXXXXXX SunOS mount/umount. XXXXXXXXXXX */
559 #define SMNT_RDONLY       1
560 #define SMNT_NOSUID       2
561 #define SMNT_NEWTYPE      4
562 #define SMNT_GRPID        8
563 #define SMNT_REMOUNT      16
564 #define SMNT_NOSUB        32
565 #define SMNT_MULTI        64
566 #define SMNT_SYS5         128
567
568 struct sunos_fh_t {
569         char fh_data [NFS_FHSIZE];
570 };
571
572 struct sunos_nfs_mount_args {
573         struct sockaddr_in  *addr; /* file server address */
574         struct nfs_fh *fh;     /* File handle to be mounted */
575         int        flags;      /* flags */
576         int        wsize;      /* write size in bytes */
577         int        rsize;      /* read size in bytes */
578         int        timeo;      /* initial timeout in .1 secs */
579         int        retrans;    /* times to retry send */
580         char       *hostname;  /* server's hostname */
581         int        acregmin;   /* attr cache file min secs */
582         int        acregmax;   /* attr cache file max secs */
583         int        acdirmin;   /* attr cache dir min secs */
584         int        acdirmax;   /* attr cache dir max secs */
585         char       *netname;   /* server's netname */
586 };
587
588
589 /* Bind the socket on a local reserved port and connect it to the
590  * remote server.  This on Linux/i386 is done by the mount program,
591  * not by the kernel. 
592  */
593 /* XXXXXXXXXXXXXXXXXXXX */
594 static int
595 sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
596 {
597         struct sockaddr_in local;
598         struct sockaddr_in server;
599         int    try_port;
600         int    ret;
601         struct socket *socket;
602         struct inode  *inode;
603         struct file   *file;
604
605         file = fget(fd);
606         if(!file)
607                 return 0;
608
609         inode = file->f_dentry->d_inode;
610
611         socket = SOCKET_I(inode);
612         local.sin_family = AF_INET;
613         local.sin_addr.s_addr = INADDR_ANY;
614
615         /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */
616         try_port = 1024;
617         do {
618                 local.sin_port = htons (--try_port);
619                 ret = socket->ops->bind(socket, (struct sockaddr*)&local,
620                                         sizeof(local));
621         } while (ret && try_port > (1024 / 2));
622
623         if (ret) {
624                 fput(file);
625                 return 0;
626         }
627
628         server.sin_family = AF_INET;
629         server.sin_addr = addr->sin_addr;
630         server.sin_port = NFS_PORT;
631
632         /* Call sys_connect */
633         ret = socket->ops->connect (socket, (struct sockaddr *) &server,
634                                     sizeof (server), file->f_flags);
635         fput(file);
636         if (ret < 0)
637                 return 0;
638         return 1;
639 }
640
641 /* XXXXXXXXXXXXXXXXXXXX */
642 static int get_default (int value, int def_value)
643 {
644     if (value)
645         return value;
646     else
647         return def_value;
648 }
649
650 /* XXXXXXXXXXXXXXXXXXXX */
651 static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
652 {
653         int  server_fd, err;
654         char *the_name, *mount_page;
655         struct nfs_mount_data linux_nfs_mount;
656         struct sunos_nfs_mount_args sunos_mount;
657
658         /* Ok, here comes the fun part: Linux's nfs mount needs a
659          * socket connection to the server, but SunOS mount does not
660          * require this, so we use the information on the destination
661          * address to create a socket and bind it to a reserved
662          * port on this system
663          */
664         if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount)))
665                 return -EFAULT;
666
667         server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
668         if (server_fd < 0)
669                 return -ENXIO;
670
671         if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr,
672                                 sizeof(*sunos_mount.addr)) ||
673             copy_from_user(&linux_nfs_mount.root,sunos_mount.fh,
674                                 sizeof(*sunos_mount.fh))) {
675                 sys_close (server_fd);
676                 return -EFAULT;
677         }
678
679         if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){
680                 sys_close (server_fd);
681                 return -ENXIO;
682         }
683
684         /* Now, bind it to a locally reserved port */
685         linux_nfs_mount.version  = NFS_MOUNT_VERSION;
686         linux_nfs_mount.flags    = sunos_mount.flags;
687         linux_nfs_mount.fd       = server_fd;
688         
689         linux_nfs_mount.rsize    = get_default (sunos_mount.rsize, 8192);
690         linux_nfs_mount.wsize    = get_default (sunos_mount.wsize, 8192);
691         linux_nfs_mount.timeo    = get_default (sunos_mount.timeo, 10);
692         linux_nfs_mount.retrans  = sunos_mount.retrans;
693         
694         linux_nfs_mount.acregmin = sunos_mount.acregmin;
695         linux_nfs_mount.acregmax = sunos_mount.acregmax;
696         linux_nfs_mount.acdirmin = sunos_mount.acdirmin;
697         linux_nfs_mount.acdirmax = sunos_mount.acdirmax;
698
699         the_name = getname(sunos_mount.hostname);
700         if(IS_ERR(the_name))
701                 return PTR_ERR(the_name);
702
703         strlcpy(linux_nfs_mount.hostname, the_name,
704                 sizeof(linux_nfs_mount.hostname));
705         putname (the_name);
706         
707         mount_page = (char *) get_zeroed_page(GFP_KERNEL);
708         if (!mount_page)
709                 return -ENOMEM;
710
711         memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount));
712
713         err = do_mount("", dir_name, "nfs", linux_flags, mount_page);
714
715         free_page((unsigned long) mount_page);
716         return err;
717 }
718
719 /* XXXXXXXXXXXXXXXXXXXX */
720 asmlinkage int
721 sunos_mount(char *type, char *dir, int flags, void *data)
722 {
723         int linux_flags = 0;
724         int ret = -EINVAL;
725         char *dev_fname = 0;
726         char *dir_page, *type_page;
727
728         if (!capable (CAP_SYS_ADMIN))
729                 return -EPERM;
730
731         /* We don't handle the integer fs type */
732         if ((flags & SMNT_NEWTYPE) == 0)
733                 goto out;
734
735         /* Do not allow for those flags we don't support */
736         if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5))
737                 goto out;
738
739         if(flags & SMNT_REMOUNT)
740                 linux_flags |= MS_REMOUNT;
741         if(flags & SMNT_RDONLY)
742                 linux_flags |= MS_RDONLY;
743         if(flags & SMNT_NOSUID)
744                 linux_flags |= MS_NOSUID;
745
746         dir_page = getname(dir);
747         ret = PTR_ERR(dir_page);
748         if (IS_ERR(dir_page))
749                 goto out;
750
751         type_page = getname(type);
752         ret = PTR_ERR(type_page);
753         if (IS_ERR(type_page))
754                 goto out1;
755
756         if(strcmp(type_page, "ext2") == 0) {
757                 dev_fname = getname(data);
758         } else if(strcmp(type_page, "iso9660") == 0) {
759                 dev_fname = getname(data);
760         } else if(strcmp(type_page, "minix") == 0) {
761                 dev_fname = getname(data);
762         } else if(strcmp(type_page, "nfs") == 0) {
763                 ret = sunos_nfs_mount (dir_page, flags, data);
764                 goto out2;
765         } else if(strcmp(type_page, "ufs") == 0) {
766                 printk("Warning: UFS filesystem mounts unsupported.\n");
767                 ret = -ENODEV;
768                 goto out2;
769         } else if(strcmp(type_page, "proc")) {
770                 ret = -ENODEV;
771                 goto out2;
772         }
773         ret = PTR_ERR(dev_fname);
774         if (IS_ERR(dev_fname))
775                 goto out2;
776         lock_kernel();
777         ret = do_mount(dev_fname, dir_page, type_page, linux_flags, NULL);
778         unlock_kernel();
779         if (dev_fname)
780                 putname(dev_fname);
781 out2:
782         putname(type_page);
783 out1:
784         putname(dir_page);
785 out:
786         return ret;
787 }
788
789
790 asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
791 {
792         int ret;
793
794         /* So stupid... */
795         if((!pid || pid == current->pid) &&
796            !pgid) {
797                 sys_setsid();
798                 ret = 0;
799         } else {
800                 ret = sys_setpgid(pid, pgid);
801         }
802         return ret;
803 }
804
805 /* So stupid... */
806 extern long compat_sys_wait4(compat_pid_t, compat_uint_t *, int,
807                              struct compat_rusage *);
808
809 asmlinkage int sunos_wait4(compat_pid_t pid, u32 stat_addr, int options, u32 ru)
810 {
811         int ret;
812
813         ret = compat_sys_wait4((pid ? pid : ((compat_pid_t)-1)),
814                                (compat_uint_t *)A(stat_addr), options,
815                                (struct compat_rusage *)A(ru));
816         return ret;
817 }
818
819 extern int kill_pg(int, int, int);
820 asmlinkage int sunos_killpg(int pgrp, int sig)
821 {
822         return kill_pg(pgrp, sig, 0);
823 }
824
825 asmlinkage int sunos_audit(void)
826 {
827         printk ("sys_audit\n");
828         return -1;
829 }
830
831 extern asmlinkage u32 sunos_gethostid(void)
832 {
833         u32 ret;
834
835         ret = (((u32)idprom->id_machtype << 24) | ((u32)idprom->id_sernum));
836
837         return ret;
838 }
839
840 /* sysconf options, for SunOS compatibility */
841 #define   _SC_ARG_MAX             1
842 #define   _SC_CHILD_MAX           2
843 #define   _SC_CLK_TCK             3
844 #define   _SC_NGROUPS_MAX         4
845 #define   _SC_OPEN_MAX            5
846 #define   _SC_JOB_CONTROL         6
847 #define   _SC_SAVED_IDS           7
848 #define   _SC_VERSION             8
849
850 extern asmlinkage s32 sunos_sysconf (int name)
851 {
852         s32 ret;
853
854         switch (name){
855         case _SC_ARG_MAX:
856                 ret = ARG_MAX;
857                 break;
858         case _SC_CHILD_MAX:
859                 ret = CHILD_MAX;
860                 break;
861         case _SC_CLK_TCK:
862                 ret = HZ;
863                 break;
864         case _SC_NGROUPS_MAX:
865                 ret = NGROUPS_MAX;
866                 break;
867         case _SC_OPEN_MAX:
868                 ret = OPEN_MAX;
869                 break;
870         case _SC_JOB_CONTROL:
871                 ret = 1;        /* yes, we do support job control */
872                 break;
873         case _SC_SAVED_IDS:
874                 ret = 1;        /* yes, we do support saved uids  */
875                 break;
876         case _SC_VERSION:
877                 /* mhm, POSIX_VERSION is in /usr/include/unistd.h
878                  * should it go on /usr/include/linux?
879                  */
880                 ret = 199009;
881                 break;
882         default:
883                 ret = -1;
884                 break;
885         };
886         return ret;
887 }
888
889 asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 ptr)
890 {
891         union semun arg4;
892         int ret;
893
894         switch (op) {
895         case 0:
896                 /* Most arguments match on a 1:1 basis but cmd doesn't */
897                 switch(arg3) {
898                 case 4:
899                         arg3=GETPID; break;
900                 case 5:
901                         arg3=GETVAL; break;
902                 case 6:
903                         arg3=GETALL; break;
904                 case 3:
905                         arg3=GETNCNT; break;
906                 case 7:
907                         arg3=GETZCNT; break;
908                 case 8:
909                         arg3=SETVAL; break;
910                 case 9:
911                         arg3=SETALL; break;
912                 }
913                 /* sys_semctl(): */
914                 arg4.__pad=(void *)A(ptr); /* value to modify semaphore to */
915                 ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4);
916                 break;
917         case 1:
918                 /* sys_semget(): */
919                 ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3);
920                 break;
921         case 2:
922                 /* sys_semop(): */
923                 ret = sys_semop((int)arg1, (struct sembuf *)A(arg2), (unsigned)arg3);
924                 break;
925         default:
926                 ret = -EINVAL;
927                 break;
928         };
929         return ret;
930 }
931
932 struct msgbuf32 {
933         s32 mtype;
934         char mtext[1];
935 };
936
937 struct ipc_perm32
938 {
939         key_t             key;
940         compat_uid_t  uid;
941         compat_gid_t  gid;
942         compat_uid_t  cuid;
943         compat_gid_t  cgid;
944         compat_mode_t mode;
945         unsigned short  seq;
946 };
947
948 struct msqid_ds32
949 {
950         struct ipc_perm32 msg_perm;
951         u32 msg_first;
952         u32 msg_last;
953         compat_time_t msg_stime;
954         compat_time_t msg_rtime;
955         compat_time_t msg_ctime;
956         u32 wwait;
957         u32 rwait;
958         unsigned short msg_cbytes;
959         unsigned short msg_qnum;  
960         unsigned short msg_qbytes;
961         compat_ipc_pid_t msg_lspid;
962         compat_ipc_pid_t msg_lrpid;
963 };
964
965 static inline int sunos_msqid_get(struct msqid_ds32 *user,
966                                   struct msqid_ds *kern)
967 {
968         if(get_user(kern->msg_perm.key, &user->msg_perm.key)            ||
969            __get_user(kern->msg_perm.uid, &user->msg_perm.uid)          ||
970            __get_user(kern->msg_perm.gid, &user->msg_perm.gid)          ||
971            __get_user(kern->msg_perm.cuid, &user->msg_perm.cuid)        ||
972            __get_user(kern->msg_perm.cgid, &user->msg_perm.cgid)        ||
973            __get_user(kern->msg_stime, &user->msg_stime)                ||
974            __get_user(kern->msg_rtime, &user->msg_rtime)                ||
975            __get_user(kern->msg_ctime, &user->msg_ctime)                ||
976            __get_user(kern->msg_ctime, &user->msg_cbytes)               ||
977            __get_user(kern->msg_ctime, &user->msg_qnum)                 ||
978            __get_user(kern->msg_ctime, &user->msg_qbytes)               ||
979            __get_user(kern->msg_ctime, &user->msg_lspid)                ||
980            __get_user(kern->msg_ctime, &user->msg_lrpid))
981                 return -EFAULT;
982         return 0;
983 }
984
985 static inline int sunos_msqid_put(struct msqid_ds32 *user,
986                                   struct msqid_ds *kern)
987 {
988         if(put_user(kern->msg_perm.key, &user->msg_perm.key)            ||
989            __put_user(kern->msg_perm.uid, &user->msg_perm.uid)          ||
990            __put_user(kern->msg_perm.gid, &user->msg_perm.gid)          ||
991            __put_user(kern->msg_perm.cuid, &user->msg_perm.cuid)        ||
992            __put_user(kern->msg_perm.cgid, &user->msg_perm.cgid)        ||
993            __put_user(kern->msg_stime, &user->msg_stime)                ||
994            __put_user(kern->msg_rtime, &user->msg_rtime)                ||
995            __put_user(kern->msg_ctime, &user->msg_ctime)                ||
996            __put_user(kern->msg_ctime, &user->msg_cbytes)               ||
997            __put_user(kern->msg_ctime, &user->msg_qnum)                 ||
998            __put_user(kern->msg_ctime, &user->msg_qbytes)               ||
999            __put_user(kern->msg_ctime, &user->msg_lspid)                ||
1000            __put_user(kern->msg_ctime, &user->msg_lrpid))
1001                 return -EFAULT;
1002         return 0;
1003 }
1004
1005 static inline int sunos_msgbuf_get(struct msgbuf32 *user, struct msgbuf *kern, int len)
1006 {
1007         if(get_user(kern->mtype, &user->mtype)  ||
1008            __copy_from_user(kern->mtext, &user->mtext, len))
1009                 return -EFAULT;
1010         return 0;
1011 }
1012
1013 static inline int sunos_msgbuf_put(struct msgbuf32 *user, struct msgbuf *kern, int len)
1014 {
1015         if(put_user(kern->mtype, &user->mtype)  ||
1016            __copy_to_user(user->mtext, kern->mtext, len))
1017                 return -EFAULT;
1018         return 0;
1019 }
1020
1021 asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
1022 {
1023         struct sparc_stackf32 *sp;
1024         struct msqid_ds kds;
1025         struct msgbuf *kmbuf;
1026         mm_segment_t old_fs = get_fs();
1027         u32 arg5;
1028         int rval;
1029
1030         switch(op) {
1031         case 0:
1032                 rval = sys_msgget((key_t)arg1, (int)arg2);
1033                 break;
1034         case 1:
1035                 if(!sunos_msqid_get((struct msqid_ds32 *)A(arg3), &kds)) {
1036                         set_fs(KERNEL_DS);
1037                         rval = sys_msgctl((int)arg1, (int)arg2,
1038                                           (struct msqid_ds *)A(arg3));
1039                         set_fs(old_fs);
1040                         if(!rval)
1041                                 rval = sunos_msqid_put((struct msqid_ds32 *)A(arg3),
1042                                                        &kds);
1043                 } else
1044                         rval = -EFAULT;
1045                 break;
1046         case 2:
1047                 rval = -EFAULT;
1048                 kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
1049                                                  GFP_KERNEL);
1050                 if(!kmbuf)
1051                         break;
1052                 sp = (struct sparc_stackf32 *)
1053                         (current_thread_info()->kregs->u_regs[UREG_FP] & 0xffffffffUL);
1054                 if(get_user(arg5, &sp->xxargs[0])) {
1055                         rval = -EFAULT;
1056                         kfree(kmbuf);
1057                         break;
1058                 }
1059                 set_fs(KERNEL_DS);
1060                 rval = sys_msgrcv((int)arg1, kmbuf, (size_t)arg3,
1061                                   (long)arg4, (int)arg5);
1062                 set_fs(old_fs);
1063                 if(!rval)
1064                         rval = sunos_msgbuf_put((struct msgbuf32 *)A(arg2),
1065                                                 kmbuf, arg3);
1066                 kfree(kmbuf);
1067                 break;
1068         case 3:
1069                 rval = -EFAULT;
1070                 kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
1071                                                  GFP_KERNEL);
1072                 if(!kmbuf || sunos_msgbuf_get((struct msgbuf32 *)A(arg2),
1073                                               kmbuf, arg3))
1074                         break;
1075                 set_fs(KERNEL_DS);
1076                 rval = sys_msgsnd((int)arg1, kmbuf, (size_t)arg3, (int)arg4);
1077                 set_fs(old_fs);
1078                 kfree(kmbuf);
1079                 break;
1080         default:
1081                 rval = -EINVAL;
1082                 break;
1083         }
1084         return rval;
1085 }
1086
1087 struct shmid_ds32 {
1088         struct ipc_perm32       shm_perm;
1089         int                     shm_segsz;
1090         compat_time_t         shm_atime;
1091         compat_time_t         shm_dtime;
1092         compat_time_t         shm_ctime;
1093         compat_ipc_pid_t    shm_cpid; 
1094         compat_ipc_pid_t    shm_lpid; 
1095         unsigned short          shm_nattch;
1096 };
1097                                                         
1098 static inline int sunos_shmid_get(struct shmid_ds32 *user,
1099                                   struct shmid_ds *kern)
1100 {
1101         if(get_user(kern->shm_perm.key, &user->shm_perm.key)            ||
1102            __get_user(kern->shm_perm.uid, &user->shm_perm.uid)          ||
1103            __get_user(kern->shm_perm.gid, &user->shm_perm.gid)          ||
1104            __get_user(kern->shm_perm.cuid, &user->shm_perm.cuid)        ||
1105            __get_user(kern->shm_perm.cgid, &user->shm_perm.cgid)        ||
1106            __get_user(kern->shm_segsz, &user->shm_segsz)                ||
1107            __get_user(kern->shm_atime, &user->shm_atime)                ||
1108            __get_user(kern->shm_dtime, &user->shm_dtime)                ||
1109            __get_user(kern->shm_ctime, &user->shm_ctime)                ||
1110            __get_user(kern->shm_cpid, &user->shm_cpid)                  ||
1111            __get_user(kern->shm_lpid, &user->shm_lpid)                  ||
1112            __get_user(kern->shm_nattch, &user->shm_nattch))
1113                 return -EFAULT;
1114         return 0;
1115 }
1116
1117 static inline int sunos_shmid_put(struct shmid_ds32 *user,
1118                                   struct shmid_ds *kern)
1119 {
1120         if(put_user(kern->shm_perm.key, &user->shm_perm.key)            ||
1121            __put_user(kern->shm_perm.uid, &user->shm_perm.uid)          ||
1122            __put_user(kern->shm_perm.gid, &user->shm_perm.gid)          ||
1123            __put_user(kern->shm_perm.cuid, &user->shm_perm.cuid)        ||
1124            __put_user(kern->shm_perm.cgid, &user->shm_perm.cgid)        ||
1125            __put_user(kern->shm_segsz, &user->shm_segsz)                ||
1126            __put_user(kern->shm_atime, &user->shm_atime)                ||
1127            __put_user(kern->shm_dtime, &user->shm_dtime)                ||
1128            __put_user(kern->shm_ctime, &user->shm_ctime)                ||
1129            __put_user(kern->shm_cpid, &user->shm_cpid)                  ||
1130            __put_user(kern->shm_lpid, &user->shm_lpid)                  ||
1131            __put_user(kern->shm_nattch, &user->shm_nattch))
1132                 return -EFAULT;
1133         return 0;
1134 }
1135
1136 asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3)
1137 {
1138         struct shmid_ds ksds;
1139         unsigned long raddr;
1140         mm_segment_t old_fs = get_fs();
1141         int rval;
1142
1143         switch(op) {
1144         case 0:
1145                 /* do_shmat(): attach a shared memory area */
1146                 rval = do_shmat((int)arg1,(char *)A(arg2),(int)arg3,&raddr);
1147                 if(!rval)
1148                         rval = (int) raddr;
1149                 break;
1150         case 1:
1151                 /* sys_shmctl(): modify shared memory area attr. */
1152                 if(!sunos_shmid_get((struct shmid_ds32 *)A(arg3), &ksds)) {
1153                         set_fs(KERNEL_DS);
1154                         rval = sys_shmctl((int)arg1,(int)arg2, &ksds);
1155                         set_fs(old_fs);
1156                         if(!rval)
1157                                 rval = sunos_shmid_put((struct shmid_ds32 *)A(arg3),
1158                                                        &ksds);
1159                 } else
1160                         rval = -EFAULT;
1161                 break;
1162         case 2:
1163                 /* sys_shmdt(): detach a shared memory area */
1164                 rval = sys_shmdt((char *)A(arg1));
1165                 break;
1166         case 3:
1167                 /* sys_shmget(): get a shared memory area */
1168                 rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
1169                 break;
1170         default:
1171                 rval = -EINVAL;
1172                 break;
1173         };
1174         return rval;
1175 }
1176
1177 extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
1178
1179 asmlinkage int sunos_open(u32 fname, int flags, int mode)
1180 {
1181         const char *filename = (const char *)(long)fname;
1182
1183         return sparc32_open(filename, flags, mode);
1184 }
1185
1186 #define SUNOS_EWOULDBLOCK 35
1187
1188 /* see the sunos man page read(2v) for an explanation
1189    of this garbage. We use O_NDELAY to mark
1190    file descriptors that have been set non-blocking 
1191    using 4.2BSD style calls. (tridge) */
1192
1193 static inline int check_nonblock(int ret, int fd)
1194 {
1195         if (ret == -EAGAIN) {
1196                 struct file * file = fget(fd);
1197                 if (file) {
1198                         if (file->f_flags & O_NDELAY)
1199                                 ret = -SUNOS_EWOULDBLOCK;
1200                         fput(file);
1201                 }
1202         }
1203         return ret;
1204 }
1205
1206 extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count);
1207 extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count);
1208
1209 asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count)
1210 {
1211         int ret;
1212
1213         ret = check_nonblock(sys_read(fd, (char *)A(buf), count), fd);
1214         return ret;
1215 }
1216
1217 asmlinkage int sunos_readv(u32 fd, u32 vector, s32 count)
1218 {
1219         int ret;
1220
1221         ret = check_nonblock(sys32_readv(fd, vector, count), fd);
1222         return ret;
1223 }
1224
1225 asmlinkage int sunos_write(unsigned int fd, u32 buf, u32 count)
1226 {
1227         int ret;
1228
1229         ret = check_nonblock(sys_write(fd, (char *)A(buf), count), fd);
1230         return ret;
1231 }
1232
1233 asmlinkage int sunos_writev(u32 fd, u32 vector, s32 count)
1234 {
1235         int ret;
1236
1237         ret = check_nonblock(sys32_writev(fd, vector, count), fd);
1238         return ret;
1239 }
1240
1241 asmlinkage int sunos_recv(int fd, u32 ubuf, int size, unsigned flags)
1242 {
1243         int ret;
1244
1245         ret = check_nonblock(sys_recv(fd, (void *)A(ubuf), size, flags), fd);
1246         return ret;
1247 }
1248
1249 asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags)
1250 {
1251         int ret;
1252
1253         ret = check_nonblock(sys_send(fd, (void *)A(buff), len, flags), fd);
1254         return ret;
1255 }
1256
1257 asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen)
1258 {
1259         int ret;
1260
1261         while (1) {
1262                 ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa),
1263                                                 (int *)A(addrlen)), fd);
1264                 if (ret != -ENETUNREACH && ret != -EHOSTUNREACH)
1265                         break;
1266         }
1267         return ret;
1268 }
1269
1270 #define SUNOS_SV_INTERRUPT 2
1271
1272 asmlinkage int sunos_sigaction (int sig, u32 act, u32 oact)
1273 {
1274         struct k_sigaction new_ka, old_ka;
1275         int ret;
1276
1277         if (act) {
1278                 compat_old_sigset_t mask;
1279                 u32 u_handler;
1280
1281                 if (get_user(u_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
1282                     __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags))
1283                         return -EFAULT;
1284                 new_ka.sa.sa_handler = (void *) (long) u_handler;
1285                 __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask);
1286                 new_ka.sa.sa_restorer = NULL;
1287                 new_ka.ka_restorer = NULL;
1288                 siginitset(&new_ka.sa.sa_mask, mask);
1289                 new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
1290         }
1291
1292         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
1293
1294         if (!ret && oact) {
1295                 old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
1296                 if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) ||
1297                     __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags))
1298                         return -EFAULT;
1299                 __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask);
1300         }
1301
1302         return ret;
1303 }
1304
1305 asmlinkage int sunos_setsockopt(int fd, int level, int optname, u32 optval,
1306                                 int optlen)
1307 {
1308         int tr_opt = optname;
1309         int ret;
1310
1311         if (level == SOL_IP) {
1312                 /* Multicast socketopts (ttl, membership) */
1313                 if (tr_opt >=2 && tr_opt <= 6)
1314                         tr_opt += 30;
1315         }
1316         ret = sys_setsockopt(fd, level, tr_opt, (char *)A(optval), optlen);
1317         return ret;
1318 }
1319
1320 asmlinkage int sunos_getsockopt(int fd, int level, int optname,
1321                                 u32 optval, u32 optlen)
1322 {
1323         int tr_opt = optname;
1324         int ret;
1325
1326         if (level == SOL_IP) {
1327                 /* Multicast socketopts (ttl, membership) */
1328                 if (tr_opt >=2 && tr_opt <= 6)
1329                         tr_opt += 30;
1330         }
1331         ret = compat_sys_getsockopt(fd, level, tr_opt, (void*)(unsigned long)optval, (void*)(unsigned long)optlen);
1332         return ret;
1333 }