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