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