1/* $Id: sys_sunos32.c,v 1.1.1.1 2007/08/03 18:52:18 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
66asmlinkage 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);
111out_putf:
112	if (file)
113		fput(file);
114out:
115	return (u32) retval;
116}
117
118asmlinkage int sunos_mctl(u32 addr, u32 len, int function, u32 arg)
119{
120	return 0;
121}
122
123asmlinkage 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;
171out:
172	up_write(&current->mm->mmap_sem);
173	return retval;
174}
175
176asmlinkage 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
188asmlinkage 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 ??? */
203static char *vstrings[] = {
204	"VA_NORMAL",
205	"VA_ABNORMAL",
206	"VA_SEQUENTIAL",
207	"VA_INVALIDATE",
208};
209
210asmlinkage 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 */
225asmlinkage int sunos_getdtablesize(void)
226{
227	return SUNOS_NR_OPEN;
228}
229
230
231#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
232
233asmlinkage 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
245asmlinkage 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) */
260struct 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
268struct 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
278static 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
309asmlinkage 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
343out_putf:
344	fput(file);
345out:
346	return error;
347}
348
349/* Old sunos getdirentries, severely broken compatibility stuff here. */
350struct sunos_direntry {
351    u32		d_ino;
352    u16		d_reclen;
353    u16		d_namlen;
354    char	d_name[1];
355};
356
357struct sunos_direntry_callback {
358    struct sunos_direntry __user *curr;
359    struct sunos_direntry __user *previous;
360    int count;
361    int error;
362};
363
364static 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
394asmlinkage 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
431out_putf:
432	fput(file);
433out:
434	return error;
435}
436
437struct 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
446asmlinkage 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
466asmlinkage 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 */
494asmlinkage 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:
518		ret = 1;
519		break;
520	case _PCONF_NOTRUNC:
521	case _PCONF_VDISABLE:
522		ret = 0;
523		break;
524	default:
525		ret = -EINVAL;
526		break;
527	}
528	return ret;
529}
530
531asmlinkage int sunos_pathconf(u32 u_path, int name)
532{
533	int ret;
534
535	ret = sunos_fpathconf(0, name);
536	return ret;
537}
538
539asmlinkage 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
558asmlinkage 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
577struct sunos_fh_t {
578	char fh_data [NFS_FHSIZE];
579};
580
581struct 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 */
603static int
604sunos_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 */
651static 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 */
660static 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 */
729asmlinkage int
730sunos_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);
790out2:
791	putname(type_page);
792out1:
793	putname(dir_page);
794out:
795	return ret;
796}
797#endif
798
799asmlinkage 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... */
815extern long compat_sys_wait4(compat_pid_t, compat_uint_t __user *, int,
816			     struct compat_rusage __user *);
817
818asmlinkage 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
827asmlinkage 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
840asmlinkage int sunos_audit(void)
841{
842	printk ("sys_audit\n");
843	return -1;
844}
845
846asmlinkage 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
865asmlinkage 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
904asmlinkage 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
949struct msgbuf32 {
950	s32 mtype;
951	char mtext[1];
952};
953
954struct 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
965struct 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
982static 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
1002static 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
1022static 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
1030static 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
1038asmlinkage 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
1106struct 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
1117static 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
1136static 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
1155asmlinkage 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
1197extern asmlinkage long sparc32_open(const char __user * filename, int flags, int mode);
1198
1199asmlinkage 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
1213static 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
1226asmlinkage 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
1234asmlinkage 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
1242asmlinkage 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
1250asmlinkage 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
1258asmlinkage 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
1266asmlinkage 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
1274asmlinkage 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
1288asmlinkage 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
1323asmlinkage 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
1343asmlinkage 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}
1361