1 /* $Id: sys_sunos.c,v 1.137 2002/02/08 03:57:14 davem Exp $
2 * sys_sunos.c: SunOS specific syscall compatibility support.
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
7 * Based upon preliminary work which is:
9 * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/types.h>
16 #include <linux/mman.h>
18 #include <linux/swap.h>
20 #include <linux/file.h>
21 #include <linux/resource.h>
22 #include <linux/ipc.h>
23 #include <linux/shm.h>
24 #include <linux/msg.h>
25 #include <linux/sem.h>
26 #include <linux/signal.h>
27 #include <linux/uio.h>
28 #include <linux/utsname.h>
29 #include <linux/major.h>
30 #include <linux/stat.h>
31 #include <linux/slab.h>
32 #include <linux/pagemap.h>
33 #include <linux/capability.h>
34 #include <linux/errno.h>
35 #include <linux/smp.h>
36 #include <linux/smp_lock.h>
37 #include <linux/syscalls.h>
41 #include <asm/uaccess.h>
43 #include <linux/segment.h>
47 #include <asm/pgtable.h>
48 #include <asm/pconf.h>
49 #include <asm/idprom.h> /* for gethostid() */
50 #include <asm/unistd.h>
51 #include <asm/system.h>
53 /* For the nfs mount emulation */
54 #include <linux/socket.h>
56 #include <linux/nfs.h>
57 #include <linux/nfs2.h>
58 #include <linux/nfs_mount.h>
60 /* for sunos_select */
61 #include <linux/time.h>
62 #include <linux/personality.h>
64 /* NR_OPEN is now larger and dynamic in recent kernels. */
65 #define SUNOS_NR_OPEN 256
67 /* We use the SunOS mmap() semantics. */
68 asmlinkage
unsigned long sunos_mmap(unsigned long addr
, unsigned long len
,
69 unsigned long prot
, unsigned long flags
,
70 unsigned long fd
, unsigned long off
)
72 struct file
* file
= NULL
;
73 unsigned long retval
, ret_type
;
75 if (flags
& MAP_NORESERVE
) {
78 printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
80 flags
&= ~MAP_NORESERVE
;
83 if (!(flags
& MAP_ANONYMOUS
)) {
84 if (fd
>= SUNOS_NR_OPEN
)
92 /* If this is ld.so or a shared library doing an mmap
93 * of /dev/zero, transform it into an anonymous mapping.
94 * SunOS is so stupid some times... hmph!
97 if (imajor(file
->f_path
.dentry
->d_inode
) == MEM_MAJOR
&&
98 iminor(file
->f_path
.dentry
->d_inode
) == 5) {
99 flags
|= MAP_ANONYMOUS
;
104 ret_type
= flags
& _MAP_NEW
;
107 if (!(flags
& MAP_FIXED
))
110 if (ARCH_SUN4C_SUN4
&&
112 ((flags
& MAP_FIXED
) &&
113 addr
< 0xe0000000 && addr
+ len
> 0x20000000)))
116 /* See asm-sparc/uaccess.h */
117 if (len
> TASK_SIZE
- PAGE_SIZE
||
118 addr
+ len
> TASK_SIZE
- PAGE_SIZE
)
122 flags
&= ~(MAP_EXECUTABLE
| MAP_DENYWRITE
);
123 down_write(¤t
->mm
->mmap_sem
);
124 retval
= do_mmap(file
, addr
, len
, prot
, flags
, off
);
125 up_write(¤t
->mm
->mmap_sem
);
127 retval
= ((retval
< PAGE_OFFSET
) ? 0 : retval
);
136 /* lmbench calls this, just say "yeah, ok" */
137 asmlinkage
int sunos_mctl(unsigned long addr
, unsigned long len
, int function
, char *arg
)
142 /* SunOS is completely broken... it returns 0 on success, otherwise
143 * ENOMEM. For sys_sbrk() it wants the old brk value as a return
144 * on success and ENOMEM as before on failure.
146 asmlinkage
int sunos_brk(unsigned long brk
)
148 int freepages
, retval
= -ENOMEM
;
150 unsigned long newbrk
, oldbrk
;
152 down_write(¤t
->mm
->mmap_sem
);
153 if (ARCH_SUN4C_SUN4
) {
154 if (brk
>= 0x20000000 && brk
< 0xe0000000) {
159 if (brk
< current
->mm
->end_code
)
162 newbrk
= PAGE_ALIGN(brk
);
163 oldbrk
= PAGE_ALIGN(current
->mm
->brk
);
165 if (oldbrk
== newbrk
) {
166 current
->mm
->brk
= brk
;
171 * Always allow shrinking brk
173 if (brk
<= current
->mm
->brk
) {
174 current
->mm
->brk
= brk
;
175 do_munmap(current
->mm
, newbrk
, oldbrk
-newbrk
);
179 * Check against rlimit and stack..
182 rlim
= current
->signal
->rlim
[RLIMIT_DATA
].rlim_cur
;
183 if (rlim
>= RLIM_INFINITY
)
185 if (brk
- current
->mm
->end_code
> rlim
)
189 * Check against existing mmap mappings.
191 if (find_vma_intersection(current
->mm
, oldbrk
, newbrk
+PAGE_SIZE
))
195 * stupid algorithm to decide if we have enough memory: while
196 * simple, it hopefully works in most obvious cases.. Easy to
197 * fool it, but this should catch most mistakes.
199 freepages
= global_page_state(NR_FILE_PAGES
);
201 freepages
+= nr_free_pages();
202 freepages
+= nr_swap_pages
;
203 freepages
-= num_physpages
>> 4;
204 freepages
-= (newbrk
-oldbrk
) >> PAGE_SHIFT
;
208 * Ok, we have probably got enough memory - let it rip.
210 current
->mm
->brk
= brk
;
211 do_brk(oldbrk
, newbrk
-oldbrk
);
214 up_write(¤t
->mm
->mmap_sem
);
218 asmlinkage
unsigned long sunos_sbrk(int increment
)
221 unsigned long oldbrk
;
223 /* This should do it hopefully... */
225 oldbrk
= current
->mm
->brk
;
226 error
= sunos_brk(((int) current
->mm
->brk
) + increment
);
233 /* XXX Completely undocumented, and completely magic...
234 * XXX I believe it is to increase the size of the stack by
235 * XXX argument 'increment' and return the new end of stack
238 asmlinkage
unsigned long sunos_sstk(int increment
)
241 printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
242 current
->comm
, increment
);
247 /* Give hints to the kernel as to what paging strategy to use...
248 * Completely bogus, don't remind me.
250 #define VA_NORMAL 0 /* Normal vm usage expected */
251 #define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */
252 #define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
253 #define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
254 static char *vstrings
[] = {
261 asmlinkage
void sunos_vadvise(unsigned long strategy
)
263 /* I wanna see who uses this... */
265 printk("%s: Advises us to use %s paging strategy\n",
267 strategy
<= 3 ? vstrings
[strategy
] : "BOGUS");
271 /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
272 * resource limit and is for backwards compatibility with older sunos
275 asmlinkage
long sunos_getdtablesize(void)
277 return SUNOS_NR_OPEN
;
280 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
282 asmlinkage
unsigned long sunos_sigblock(unsigned long blk_mask
)
286 spin_lock_irq(¤t
->sighand
->siglock
);
287 old
= current
->blocked
.sig
[0];
288 current
->blocked
.sig
[0] |= (blk_mask
& _BLOCKABLE
);
290 spin_unlock_irq(¤t
->sighand
->siglock
);
294 asmlinkage
unsigned long sunos_sigsetmask(unsigned long newmask
)
296 unsigned long retval
;
298 spin_lock_irq(¤t
->sighand
->siglock
);
299 retval
= current
->blocked
.sig
[0];
300 current
->blocked
.sig
[0] = (newmask
& _BLOCKABLE
);
302 spin_unlock_irq(¤t
->sighand
->siglock
);
306 /* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) */
307 /* getdents system call, the format of the structure just has a different */
308 /* layout (d_off+d_ino instead of d_ino+d_off) */
309 struct sunos_dirent
{
312 unsigned short d_reclen
;
313 unsigned short d_namlen
;
317 struct sunos_dirent_callback
{
318 struct sunos_dirent __user
*curr
;
319 struct sunos_dirent __user
*previous
;
324 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
325 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
327 static int sunos_filldir(void * __buf
, const char * name
, int namlen
,
328 loff_t offset
, u64 ino
, unsigned int d_type
)
330 struct sunos_dirent __user
*dirent
;
331 struct sunos_dirent_callback
* buf
= __buf
;
333 int reclen
= ROUND_UP(NAME_OFFSET(dirent
) + namlen
+ 1);
335 buf
->error
= -EINVAL
; /* only used if we fail.. */
336 if (reclen
> buf
->count
)
339 if (sizeof(d_ino
) < sizeof(ino
) && d_ino
!= ino
)
341 dirent
= buf
->previous
;
343 put_user(offset
, &dirent
->d_off
);
345 buf
->previous
= dirent
;
346 put_user(d_ino
, &dirent
->d_ino
);
347 put_user(namlen
, &dirent
->d_namlen
);
348 put_user(reclen
, &dirent
->d_reclen
);
349 copy_to_user(dirent
->d_name
, name
, namlen
);
350 put_user(0, dirent
->d_name
+ namlen
);
351 dirent
= (void __user
*) dirent
+ reclen
;
353 buf
->count
-= reclen
;
357 asmlinkage
int sunos_getdents(unsigned int fd
, void __user
*dirent
, int cnt
)
360 struct sunos_dirent __user
*lastdirent
;
361 struct sunos_dirent_callback buf
;
364 if (fd
>= SUNOS_NR_OPEN
)
372 if (cnt
< (sizeof(struct sunos_dirent
) + 255))
375 buf
.curr
= (struct sunos_dirent __user
*) dirent
;
380 error
= vfs_readdir(file
, sunos_filldir
, &buf
);
384 lastdirent
= buf
.previous
;
387 put_user(file
->f_pos
, &lastdirent
->d_off
);
388 error
= cnt
- buf
.count
;
397 /* Old sunos getdirentries, severely broken compatibility stuff here. */
398 struct sunos_direntry
{
400 unsigned short d_reclen
;
401 unsigned short d_namlen
;
405 struct sunos_direntry_callback
{
406 struct sunos_direntry __user
*curr
;
407 struct sunos_direntry __user
*previous
;
412 static int sunos_filldirentry(void * __buf
, const char * name
, int namlen
,
413 loff_t offset
, u64 ino
, unsigned int d_type
)
415 struct sunos_direntry __user
*dirent
;
416 struct sunos_direntry_callback
*buf
= __buf
;
418 int reclen
= ROUND_UP(NAME_OFFSET(dirent
) + namlen
+ 1);
420 buf
->error
= -EINVAL
; /* only used if we fail.. */
421 if (reclen
> buf
->count
)
424 if (sizeof(d_ino
) < sizeof(ino
) && d_ino
!= ino
)
426 dirent
= buf
->previous
;
428 buf
->previous
= dirent
;
429 put_user(d_ino
, &dirent
->d_ino
);
430 put_user(namlen
, &dirent
->d_namlen
);
431 put_user(reclen
, &dirent
->d_reclen
);
432 copy_to_user(dirent
->d_name
, name
, namlen
);
433 put_user(0, dirent
->d_name
+ namlen
);
434 dirent
= (void __user
*) dirent
+ reclen
;
436 buf
->count
-= reclen
;
440 asmlinkage
int sunos_getdirentries(unsigned int fd
, void __user
*dirent
,
441 int cnt
, unsigned int __user
*basep
)
444 struct sunos_direntry __user
*lastdirent
;
445 struct sunos_direntry_callback buf
;
448 if (fd
>= SUNOS_NR_OPEN
)
456 if (cnt
< (sizeof(struct sunos_direntry
) + 255))
459 buf
.curr
= (struct sunos_direntry __user
*) dirent
;
464 error
= vfs_readdir(file
, sunos_filldirentry
, &buf
);
468 lastdirent
= buf
.previous
;
471 put_user(file
->f_pos
, basep
);
472 error
= cnt
- buf
.count
;
481 struct sunos_utsname
{
490 asmlinkage
int sunos_uname(struct sunos_utsname __user
*name
)
494 ret
= copy_to_user(&name
->sname
[0], &utsname()->sysname
[0],
495 sizeof(name
->sname
) - 1);
497 ret
|= __copy_to_user(&name
->nname
[0], &utsname()->nodename
[0],
498 sizeof(name
->nname
) - 1);
499 ret
|= __put_user('\0', &name
->nname
[8]);
500 ret
|= __copy_to_user(&name
->rel
[0], &utsname()->release
[0],
501 sizeof(name
->rel
) - 1);
502 ret
|= __copy_to_user(&name
->ver
[0], &utsname()->version
[0],
503 sizeof(name
->ver
) - 1);
504 ret
|= __copy_to_user(&name
->mach
[0], &utsname()->machine
[0],
505 sizeof(name
->mach
) - 1);
508 return ret
? -EFAULT
: 0;
511 asmlinkage
int sunos_nosys(void)
513 struct pt_regs
*regs
;
518 regs
= current
->thread
.kregs
;
519 info
.si_signo
= SIGSYS
;
521 info
.si_code
= __SI_FAULT
|0x100;
522 info
.si_addr
= (void __user
*)regs
->pc
;
523 info
.si_trapno
= regs
->u_regs
[UREG_G1
];
524 send_sig_info(SIGSYS
, &info
, current
);
526 printk("Process makes ni_syscall number %d, register dump:\n",
527 (int) regs
->u_regs
[UREG_G1
]);
534 /* This is not a real and complete implementation yet, just to keep
535 * the easy SunOS binaries happy.
537 asmlinkage
int sunos_fpathconf(int fd
, int name
)
560 case _PCONF_CHRESTRICT
: /* XXX Investigate XXX */
563 case _PCONF_NOTRUNC
: /* XXX Investigate XXX */
564 case _PCONF_VDISABLE
:
574 asmlinkage
int sunos_pathconf(char __user
*path
, int name
)
578 ret
= sunos_fpathconf(0, name
); /* XXX cheese XXX */
582 /* SunOS mount system call emulation */
584 asmlinkage
int sunos_select(int width
, fd_set __user
*inp
, fd_set __user
*outp
,
585 fd_set __user
*exp
, struct timeval __user
*tvp
)
589 /* SunOS binaries expect that select won't change the tvp contents */
590 ret
= sys_select (width
, inp
, outp
, exp
, tvp
);
591 if (ret
== -EINTR
&& tvp
) {
594 __get_user(sec
, &tvp
->tv_sec
);
595 __get_user(usec
, &tvp
->tv_usec
);
597 if (sec
== 0 && usec
== 0)
603 asmlinkage
void sunos_nop(void)
608 /* SunOS mount/umount. */
609 #define SMNT_RDONLY 1
610 #define SMNT_NOSUID 2
611 #define SMNT_NEWTYPE 4
613 #define SMNT_REMOUNT 16
614 #define SMNT_NOSUB 32
615 #define SMNT_MULTI 64
616 #define SMNT_SYS5 128
619 char fh_data
[NFS_FHSIZE
];
622 struct sunos_nfs_mount_args
{
623 struct sockaddr_in __user
*addr
; /* file server address */
624 struct nfs_fh __user
*fh
; /* File handle to be mounted */
625 int flags
; /* flags */
626 int wsize
; /* write size in bytes */
627 int rsize
; /* read size in bytes */
628 int timeo
; /* initial timeout in .1 secs */
629 int retrans
; /* times to retry send */
630 char __user
*hostname
; /* server's hostname */
631 int acregmin
; /* attr cache file min secs */
632 int acregmax
; /* attr cache file max secs */
633 int acdirmin
; /* attr cache dir min secs */
634 int acdirmax
; /* attr cache dir max secs */
635 char __user
*netname
; /* server's netname */
639 /* Bind the socket on a local reserved port and connect it to the
640 * remote server. This on Linux/i386 is done by the mount program,
644 sunos_nfs_get_server_fd (int fd
, struct sockaddr_in
*addr
)
646 struct sockaddr_in local
;
647 struct sockaddr_in server
;
649 struct socket
*socket
;
658 inode
= file
->f_path
.dentry
->d_inode
;
660 socket
= SOCKET_I(inode
);
661 local
.sin_family
= AF_INET
;
662 local
.sin_addr
.s_addr
= INADDR_ANY
;
664 /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */
667 local
.sin_port
= htons (--try_port
);
668 ret
= socket
->ops
->bind(socket
, (struct sockaddr
*)&local
,
670 } while (ret
&& try_port
> (1024 / 2));
675 server
.sin_family
= AF_INET
;
676 server
.sin_addr
= addr
->sin_addr
;
677 server
.sin_port
= NFS_PORT
;
679 /* Call sys_connect */
680 ret
= socket
->ops
->connect (socket
, (struct sockaddr
*) &server
,
681 sizeof (server
), file
->f_flags
);
691 static int get_default (int value
, int def_value
)
699 static int sunos_nfs_mount(char *dir_name
, int linux_flags
, void __user
*data
)
702 char *the_name
, *mount_page
;
703 struct nfs_mount_data linux_nfs_mount
;
704 struct sunos_nfs_mount_args sunos_mount
;
706 /* Ok, here comes the fun part: Linux's nfs mount needs a
707 * socket connection to the server, but SunOS mount does not
708 * require this, so we use the information on the destination
709 * address to create a socket and bind it to a reserved
710 * port on this system
712 if (copy_from_user(&sunos_mount
, data
, sizeof(sunos_mount
)))
715 server_fd
= sys_socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
719 if (copy_from_user(&linux_nfs_mount
.addr
,sunos_mount
.addr
,
720 sizeof(*sunos_mount
.addr
)) ||
721 copy_from_user(&linux_nfs_mount
.root
,sunos_mount
.fh
,
722 sizeof(*sunos_mount
.fh
))) {
723 sys_close (server_fd
);
727 if (!sunos_nfs_get_server_fd (server_fd
, &linux_nfs_mount
.addr
)){
728 sys_close (server_fd
);
732 /* Now, bind it to a locally reserved port */
733 linux_nfs_mount
.version
= NFS_MOUNT_VERSION
;
734 linux_nfs_mount
.flags
= sunos_mount
.flags
;
735 linux_nfs_mount
.fd
= server_fd
;
737 linux_nfs_mount
.rsize
= get_default (sunos_mount
.rsize
, 8192);
738 linux_nfs_mount
.wsize
= get_default (sunos_mount
.wsize
, 8192);
739 linux_nfs_mount
.timeo
= get_default (sunos_mount
.timeo
, 10);
740 linux_nfs_mount
.retrans
= sunos_mount
.retrans
;
742 linux_nfs_mount
.acregmin
= sunos_mount
.acregmin
;
743 linux_nfs_mount
.acregmax
= sunos_mount
.acregmax
;
744 linux_nfs_mount
.acdirmin
= sunos_mount
.acdirmin
;
745 linux_nfs_mount
.acdirmax
= sunos_mount
.acdirmax
;
747 the_name
= getname(sunos_mount
.hostname
);
748 if (IS_ERR(the_name
))
749 return PTR_ERR(the_name
);
751 strlcpy(linux_nfs_mount
.hostname
, the_name
,
752 sizeof(linux_nfs_mount
.hostname
));
755 mount_page
= (char *) get_zeroed_page(GFP_KERNEL
);
759 memcpy(mount_page
, &linux_nfs_mount
, sizeof(linux_nfs_mount
));
761 err
= do_mount("", dir_name
, "nfs", linux_flags
, mount_page
);
763 free_page((unsigned long) mount_page
);
768 sunos_mount(char __user
*type
, char __user
*dir
, int flags
, void __user
*data
)
772 char *dev_fname
= NULL
;
773 char *dir_page
, *type_page
;
775 if (!capable (CAP_SYS_ADMIN
))
779 /* We don't handle the integer fs type */
780 if ((flags
& SMNT_NEWTYPE
) == 0)
783 /* Do not allow for those flags we don't support */
784 if (flags
& (SMNT_GRPID
|SMNT_NOSUB
|SMNT_MULTI
|SMNT_SYS5
))
787 if (flags
& SMNT_REMOUNT
)
788 linux_flags
|= MS_REMOUNT
;
789 if (flags
& SMNT_RDONLY
)
790 linux_flags
|= MS_RDONLY
;
791 if (flags
& SMNT_NOSUID
)
792 linux_flags
|= MS_NOSUID
;
794 dir_page
= getname(dir
);
795 ret
= PTR_ERR(dir_page
);
796 if (IS_ERR(dir_page
))
799 type_page
= getname(type
);
800 ret
= PTR_ERR(type_page
);
801 if (IS_ERR(type_page
))
804 if (strcmp(type_page
, "ext2") == 0) {
805 dev_fname
= getname(data
);
806 } else if (strcmp(type_page
, "iso9660") == 0) {
807 dev_fname
= getname(data
);
808 } else if (strcmp(type_page
, "minix") == 0) {
809 dev_fname
= getname(data
);
810 } else if (strcmp(type_page
, "nfs") == 0) {
811 ret
= sunos_nfs_mount (dir_page
, flags
, data
);
813 } else if (strcmp(type_page
, "ufs") == 0) {
814 printk("Warning: UFS filesystem mounts unsupported.\n");
817 } else if (strcmp(type_page
, "proc")) {
821 ret
= PTR_ERR(dev_fname
);
822 if (IS_ERR(dev_fname
))
824 ret
= do_mount(dev_fname
, dir_page
, type_page
, linux_flags
, NULL
);
837 asmlinkage
int sunos_setpgrp(pid_t pid
, pid_t pgid
)
842 if ((!pid
|| pid
== current
->pid
) &&
847 ret
= sys_setpgid(pid
, pgid
);
853 asmlinkage
int sunos_wait4(pid_t pid
, unsigned int __user
*stat_addr
,
854 int options
, struct rusage __user
*ru
)
858 ret
= sys_wait4((pid
? pid
: -1), stat_addr
, options
, ru
);
862 asmlinkage
int sunos_killpg(int pgrp
, int sig
)
869 ret
= kill_pgrp(find_vpid(pgrp
), sig
, 0);
875 asmlinkage
int sunos_audit(void)
878 printk ("sys_audit\n");
883 asmlinkage
unsigned long sunos_gethostid(void)
888 ret
= ((unsigned long)idprom
->id_machtype
<< 24) |
889 (unsigned long)idprom
->id_sernum
;
894 /* sysconf options, for SunOS compatibility */
895 #define _SC_ARG_MAX 1
896 #define _SC_CHILD_MAX 2
897 #define _SC_CLK_TCK 3
898 #define _SC_NGROUPS_MAX 4
899 #define _SC_OPEN_MAX 5
900 #define _SC_JOB_CONTROL 6
901 #define _SC_SAVED_IDS 7
902 #define _SC_VERSION 8
904 asmlinkage
long sunos_sysconf (int name
)
913 ret
= current
->signal
->rlim
[RLIMIT_NPROC
].rlim_cur
;
918 case _SC_NGROUPS_MAX
:
922 ret
= current
->signal
->rlim
[RLIMIT_NOFILE
].rlim_cur
;
924 case _SC_JOB_CONTROL
:
925 ret
= 1; /* yes, we do support job control */
928 ret
= 1; /* yes, we do support saved uids */
931 /* mhm, POSIX_VERSION is in /usr/include/unistd.h
932 * should it go on /usr/include/linux?
943 asmlinkage
int sunos_semsys(int op
, unsigned long arg1
, unsigned long arg2
,
944 unsigned long arg3
, void *ptr
)
951 /* Most arguments match on a 1:1 basis but cmd doesn't */
969 /* value to modify semaphore to */
970 arg4
.__pad
= (void __user
*) ptr
;
971 ret
= sys_semctl((int)arg1
, (int)arg2
, (int)arg3
, arg4
);
975 ret
= sys_semget((key_t
)arg1
, (int)arg2
, (int)arg3
);
979 ret
= sys_semop((int)arg1
, (struct sembuf __user
*)arg2
, (unsigned)arg3
);
988 asmlinkage
int sunos_msgsys(int op
, unsigned long arg1
, unsigned long arg2
,
989 unsigned long arg3
, unsigned long arg4
)
991 struct sparc_stackf
*sp
;
997 rval
= sys_msgget((key_t
)arg1
, (int)arg2
);
1000 rval
= sys_msgctl((int)arg1
, (int)arg2
,
1001 (struct msqid_ds __user
*)arg3
);
1005 sp
= (struct sparc_stackf
*)current
->thread
.kregs
->u_regs
[UREG_FP
];
1006 arg5
= sp
->xxargs
[0];
1008 rval
= sys_msgrcv((int)arg1
, (struct msgbuf __user
*)arg2
,
1009 (size_t)arg3
, (long)arg4
, (int)arg5
);
1012 rval
= sys_msgsnd((int)arg1
, (struct msgbuf __user
*)arg2
,
1013 (size_t)arg3
, (int)arg4
);
1022 asmlinkage
int sunos_shmsys(int op
, unsigned long arg1
, unsigned long arg2
,
1025 unsigned long raddr
;
1030 /* do_shmat(): attach a shared memory area */
1031 rval
= do_shmat((int)arg1
,(char __user
*)arg2
,(int)arg3
,&raddr
);
1036 /* sys_shmctl(): modify shared memory area attr. */
1037 rval
= sys_shmctl((int)arg1
,(int)arg2
,(struct shmid_ds __user
*)arg3
);
1040 /* sys_shmdt(): detach a shared memory area */
1041 rval
= sys_shmdt((char __user
*)arg1
);
1044 /* sys_shmget(): get a shared memory area */
1045 rval
= sys_shmget((key_t
)arg1
,(int)arg2
,(int)arg3
);
1054 #define SUNOS_EWOULDBLOCK 35
1056 /* see the sunos man page read(2v) for an explanation
1057 of this garbage. We use O_NDELAY to mark
1058 file descriptors that have been set non-blocking
1059 using 4.2BSD style calls. (tridge) */
1061 static inline int check_nonblock(int ret
, int fd
)
1063 if (ret
== -EAGAIN
) {
1064 struct file
* file
= fget(fd
);
1066 if (file
->f_flags
& O_NDELAY
)
1067 ret
= -SUNOS_EWOULDBLOCK
;
1074 asmlinkage
int sunos_read(unsigned int fd
, char __user
*buf
, int count
)
1078 ret
= check_nonblock(sys_read(fd
,buf
,count
),fd
);
1082 asmlinkage
int sunos_readv(unsigned long fd
, const struct iovec __user
*vector
,
1087 ret
= check_nonblock(sys_readv(fd
,vector
,count
),fd
);
1091 asmlinkage
int sunos_write(unsigned int fd
, char __user
*buf
, int count
)
1095 ret
= check_nonblock(sys_write(fd
,buf
,count
),fd
);
1099 asmlinkage
int sunos_writev(unsigned long fd
,
1100 const struct iovec __user
*vector
, long count
)
1104 ret
= check_nonblock(sys_writev(fd
,vector
,count
),fd
);
1108 asmlinkage
int sunos_recv(int fd
, void __user
*ubuf
, int size
, unsigned flags
)
1112 ret
= check_nonblock(sys_recv(fd
,ubuf
,size
,flags
),fd
);
1116 asmlinkage
int sunos_send(int fd
, void __user
*buff
, int len
, unsigned flags
)
1120 ret
= check_nonblock(sys_send(fd
,buff
,len
,flags
),fd
);
1124 asmlinkage
int sunos_accept(int fd
, struct sockaddr __user
*sa
,
1125 int __user
*addrlen
)
1130 ret
= check_nonblock(sys_accept(fd
,sa
,addrlen
),fd
);
1131 if (ret
!= -ENETUNREACH
&& ret
!= -EHOSTUNREACH
)
1138 #define SUNOS_SV_INTERRUPT 2
1141 sunos_sigaction(int sig
, const struct old_sigaction __user
*act
,
1142 struct old_sigaction __user
*oact
)
1144 struct k_sigaction new_ka
, old_ka
;
1150 if (!access_ok(VERIFY_READ
, act
, sizeof(*act
)) ||
1151 __get_user(new_ka
.sa
.sa_handler
, &act
->sa_handler
) ||
1152 __get_user(new_ka
.sa
.sa_flags
, &act
->sa_flags
))
1154 __get_user(mask
, &act
->sa_mask
);
1155 new_ka
.sa
.sa_restorer
= NULL
;
1156 new_ka
.ka_restorer
= NULL
;
1157 siginitset(&new_ka
.sa
.sa_mask
, mask
);
1158 new_ka
.sa
.sa_flags
^= SUNOS_SV_INTERRUPT
;
1161 ret
= do_sigaction(sig
, act
? &new_ka
: NULL
, oact
? &old_ka
: NULL
);
1164 /* In the clone() case we could copy half consistent
1165 * state to the user, however this could sleep and
1166 * deadlock us if we held the signal lock on SMP. So for
1167 * now I take the easy way out and do no locking.
1168 * But then again we don't support SunOS lwp's anyways ;-)
1170 old_ka
.sa
.sa_flags
^= SUNOS_SV_INTERRUPT
;
1171 if (!access_ok(VERIFY_WRITE
, oact
, sizeof(*oact
)) ||
1172 __put_user(old_ka
.sa
.sa_handler
, &oact
->sa_handler
) ||
1173 __put_user(old_ka
.sa
.sa_flags
, &oact
->sa_flags
))
1175 __put_user(old_ka
.sa
.sa_mask
.sig
[0], &oact
->sa_mask
);
1182 asmlinkage
int sunos_setsockopt(int fd
, int level
, int optname
,
1183 char __user
*optval
, int optlen
)
1185 int tr_opt
= optname
;
1188 if (level
== SOL_IP
) {
1189 /* Multicast socketopts (ttl, membership) */
1190 if (tr_opt
>=2 && tr_opt
<= 6)
1193 ret
= sys_setsockopt(fd
, level
, tr_opt
, optval
, optlen
);
1197 asmlinkage
int sunos_getsockopt(int fd
, int level
, int optname
,
1198 char __user
*optval
, int __user
*optlen
)
1200 int tr_opt
= optname
;
1203 if (level
== SOL_IP
) {
1204 /* Multicast socketopts (ttl, membership) */
1205 if (tr_opt
>=2 && tr_opt
<= 6)
1208 ret
= sys_getsockopt(fd
, level
, tr_opt
, optval
, optlen
);