File: /usr/src/linux/arch/sparc64/kernel/sys_sunos32.c

1     /* $Id: sys_sunos32.c,v 1.61 2001/08/13 14:40:07 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     }
1361