1 /* $Id: sys_sunos.c,v 1.135 2001/08/13 14:40:10 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/errno.h>
34 #include <linux/smp.h>
35 #include <linux/smp_lock.h>
37 #include <asm/uaccess.h>
39 #include <linux/segment.h>
43 #include <asm/pgtable.h>
44 #include <asm/pconf.h>
45 #include <asm/idprom.h> /* for gethostid() */
46 #include <asm/unistd.h>
47 #include <asm/system.h>
49 /* For the nfs mount emulation */
50 #include <linux/socket.h>
52 #include <linux/nfs.h>
53 #include <linux/nfs2.h>
54 #include <linux/nfs_mount.h>
56 /* for sunos_select */
57 #include <linux/time.h>
58 #include <linux/personality.h>
60 /* NR_OPEN is now larger and dynamic in recent kernels. */
61 #define SUNOS_NR_OPEN 256
63 /* We use the SunOS mmap() semantics. */
64 asmlinkage
unsigned long sunos_mmap(unsigned long addr
, unsigned long len
,
65 unsigned long prot
, unsigned long flags
,
66 unsigned long fd
, unsigned long off
)
68 struct file
* file
= NULL
;
69 unsigned long retval
, ret_type
;
71 if(flags
& MAP_NORESERVE
) {
74 printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
76 flags
&= ~MAP_NORESERVE
;
79 if(!(flags
& MAP_ANONYMOUS
)) {
80 if (fd
>= SUNOS_NR_OPEN
)
88 /* If this is ld.so or a shared library doing an mmap
89 * of /dev/zero, transform it into an anonymous mapping.
90 * SunOS is so stupid some times... hmph!
93 if(MAJOR(file
->f_dentry
->d_inode
->i_rdev
) == MEM_MAJOR
&&
94 MINOR(file
->f_dentry
->d_inode
->i_rdev
) == 5) {
95 flags
|= MAP_ANONYMOUS
;
100 ret_type
= flags
& _MAP_NEW
;
103 if(!(flags
& MAP_FIXED
))
106 if (ARCH_SUN4C_SUN4
&&
108 ((flags
& MAP_FIXED
) &&
109 addr
< 0xe0000000 && addr
+ len
> 0x20000000)))
112 /* See asm-sparc/uaccess.h */
113 if (len
> TASK_SIZE
- PAGE_SIZE
||
114 addr
+ len
> TASK_SIZE
- PAGE_SIZE
)
118 flags
&= ~(MAP_EXECUTABLE
| MAP_DENYWRITE
);
119 down_write(¤t
->mm
->mmap_sem
);
120 retval
= do_mmap(file
, addr
, len
, prot
, flags
, off
);
121 up_write(¤t
->mm
->mmap_sem
);
123 retval
= ((retval
< PAGE_OFFSET
) ? 0 : retval
);
132 /* lmbench calls this, just say "yeah, ok" */
133 asmlinkage
int sunos_mctl(unsigned long addr
, unsigned long len
, int function
, char *arg
)
138 /* SunOS is completely broken... it returns 0 on success, otherwise
139 * ENOMEM. For sys_sbrk() it wants the old brk value as a return
140 * on success and ENOMEM as before on failure.
142 asmlinkage
int sunos_brk(unsigned long brk
)
144 int freepages
, retval
= -ENOMEM
;
146 unsigned long newbrk
, oldbrk
;
148 down_write(¤t
->mm
->mmap_sem
);
149 if(ARCH_SUN4C_SUN4
) {
150 if(brk
>= 0x20000000 && brk
< 0xe0000000) {
155 if (brk
< current
->mm
->end_code
)
158 newbrk
= PAGE_ALIGN(brk
);
159 oldbrk
= PAGE_ALIGN(current
->mm
->brk
);
161 if (oldbrk
== newbrk
) {
162 current
->mm
->brk
= brk
;
167 * Always allow shrinking brk
169 if (brk
<= current
->mm
->brk
) {
170 current
->mm
->brk
= brk
;
171 do_munmap(current
->mm
, newbrk
, oldbrk
-newbrk
);
175 * Check against rlimit and stack..
178 rlim
= current
->rlim
[RLIMIT_DATA
].rlim_cur
;
179 if (rlim
>= RLIM_INFINITY
)
181 if (brk
- current
->mm
->end_code
> rlim
)
185 * Check against existing mmap mappings.
187 if (find_vma_intersection(current
->mm
, oldbrk
, newbrk
+PAGE_SIZE
))
191 * stupid algorithm to decide if we have enough memory: while
192 * simple, it hopefully works in most obvious cases.. Easy to
193 * fool it, but this should catch most mistakes.
195 freepages
= atomic_read(&buffermem_pages
) >> PAGE_SHIFT
;
196 freepages
+= page_cache_size
;
198 freepages
+= nr_free_pages();
199 freepages
+= nr_swap_pages
;
200 freepages
-= num_physpages
>> 4;
201 freepages
-= (newbrk
-oldbrk
) >> PAGE_SHIFT
;
205 * Ok, we have probably got enough memory - let it rip.
207 current
->mm
->brk
= brk
;
208 do_brk(oldbrk
, newbrk
-oldbrk
);
211 up_write(¤t
->mm
->mmap_sem
);
215 asmlinkage
unsigned long sunos_sbrk(int increment
)
218 unsigned long oldbrk
;
220 /* This should do it hopefully... */
222 oldbrk
= current
->mm
->brk
;
223 error
= sunos_brk(((int) current
->mm
->brk
) + increment
);
230 /* XXX Completely undocumented, and completely magic...
231 * XXX I believe it is to increase the size of the stack by
232 * XXX argument 'increment' and return the new end of stack
235 asmlinkage
unsigned long sunos_sstk(int increment
)
238 printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
239 current
->comm
, increment
);
244 /* Give hints to the kernel as to what paging strategy to use...
245 * Completely bogus, don't remind me.
247 #define VA_NORMAL 0 /* Normal vm usage expected */
248 #define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */
249 #define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
250 #define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
251 static char *vstrings
[] = {
258 asmlinkage
void sunos_vadvise(unsigned long strategy
)
260 /* I wanna see who uses this... */
262 printk("%s: Advises us to use %s paging strategy\n",
264 strategy
<= 3 ? vstrings
[strategy
] : "BOGUS");
268 /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
269 * resource limit and is for backwards compatibility with older sunos
272 asmlinkage
long sunos_getdtablesize(void)
274 return SUNOS_NR_OPEN
;
277 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
279 asmlinkage
unsigned long sunos_sigblock(unsigned long blk_mask
)
283 spin_lock_irq(¤t
->sigmask_lock
);
284 old
= current
->blocked
.sig
[0];
285 current
->blocked
.sig
[0] |= (blk_mask
& _BLOCKABLE
);
286 recalc_sigpending(current
);
287 spin_unlock_irq(¤t
->sigmask_lock
);
291 asmlinkage
unsigned long sunos_sigsetmask(unsigned long newmask
)
293 unsigned long retval
;
295 spin_lock_irq(¤t
->sigmask_lock
);
296 retval
= current
->blocked
.sig
[0];
297 current
->blocked
.sig
[0] = (newmask
& _BLOCKABLE
);
298 recalc_sigpending(current
);
299 spin_unlock_irq(¤t
->sigmask_lock
);
303 /* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) */
304 /* getdents system call, the format of the structure just has a different */
305 /* layout (d_off+d_ino instead of d_ino+d_off) */
306 struct sunos_dirent
{
309 unsigned short d_reclen
;
310 unsigned short d_namlen
;
314 struct sunos_dirent_callback
{
315 struct sunos_dirent
*curr
;
316 struct sunos_dirent
*previous
;
321 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
322 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
324 static int sunos_filldir(void * __buf
, const char * name
, int namlen
,
325 loff_t offset
, ino_t ino
, unsigned int d_type
)
327 struct sunos_dirent
* dirent
;
328 struct sunos_dirent_callback
* buf
= (struct sunos_dirent_callback
*) __buf
;
329 int reclen
= ROUND_UP(NAME_OFFSET(dirent
) + namlen
+ 1);
331 buf
->error
= -EINVAL
; /* only used if we fail.. */
332 if (reclen
> buf
->count
)
334 dirent
= buf
->previous
;
336 put_user(offset
, &dirent
->d_off
);
338 buf
->previous
= dirent
;
339 put_user(ino
, &dirent
->d_ino
);
340 put_user(namlen
, &dirent
->d_namlen
);
341 put_user(reclen
, &dirent
->d_reclen
);
342 copy_to_user(dirent
->d_name
, name
, namlen
);
343 put_user(0, dirent
->d_name
+ namlen
);
344 ((char *) dirent
) += reclen
;
346 buf
->count
-= reclen
;
350 asmlinkage
int sunos_getdents(unsigned int fd
, void * dirent
, int cnt
)
353 struct sunos_dirent
* lastdirent
;
354 struct sunos_dirent_callback buf
;
357 if (fd
>= SUNOS_NR_OPEN
)
365 if (cnt
< (sizeof(struct sunos_dirent
) + 255))
368 buf
.curr
= (struct sunos_dirent
*) dirent
;
373 error
= vfs_readdir(file
, sunos_filldir
, &buf
);
377 lastdirent
= buf
.previous
;
380 put_user(file
->f_pos
, &lastdirent
->d_off
);
381 error
= cnt
- buf
.count
;
390 /* Old sunos getdirentries, severely broken compatibility stuff here. */
391 struct sunos_direntry
{
393 unsigned short d_reclen
;
394 unsigned short d_namlen
;
398 struct sunos_direntry_callback
{
399 struct sunos_direntry
*curr
;
400 struct sunos_direntry
*previous
;
405 static int sunos_filldirentry(void * __buf
, const char * name
, int namlen
,
406 loff_t offset
, ino_t ino
, unsigned int d_type
)
408 struct sunos_direntry
* dirent
;
409 struct sunos_direntry_callback
* buf
= (struct sunos_direntry_callback
*) __buf
;
410 int reclen
= ROUND_UP(NAME_OFFSET(dirent
) + namlen
+ 1);
412 buf
->error
= -EINVAL
; /* only used if we fail.. */
413 if (reclen
> buf
->count
)
415 dirent
= buf
->previous
;
417 buf
->previous
= dirent
;
418 put_user(ino
, &dirent
->d_ino
);
419 put_user(namlen
, &dirent
->d_namlen
);
420 put_user(reclen
, &dirent
->d_reclen
);
421 copy_to_user(dirent
->d_name
, name
, namlen
);
422 put_user(0, dirent
->d_name
+ namlen
);
423 ((char *) dirent
) += reclen
;
425 buf
->count
-= reclen
;
429 asmlinkage
int sunos_getdirentries(unsigned int fd
, void * dirent
, int cnt
, unsigned int *basep
)
432 struct sunos_direntry
* lastdirent
;
433 struct sunos_direntry_callback buf
;
436 if (fd
>= SUNOS_NR_OPEN
)
444 if(cnt
< (sizeof(struct sunos_direntry
) + 255))
447 buf
.curr
= (struct sunos_direntry
*) dirent
;
452 error
= vfs_readdir(file
, sunos_filldirentry
, &buf
);
456 lastdirent
= buf
.previous
;
459 put_user(file
->f_pos
, basep
);
460 error
= cnt
- buf
.count
;
469 struct sunos_utsname
{
478 asmlinkage
int sunos_uname(struct sunos_utsname
*name
)
482 ret
= copy_to_user(&name
->sname
[0], &system_utsname
.sysname
[0], sizeof(name
->sname
) - 1);
484 ret
|= __copy_to_user(&name
->nname
[0], &system_utsname
.nodename
[0], sizeof(name
->nname
) - 1);
485 ret
|= __put_user('\0', &name
->nname
[8]);
486 ret
|= __copy_to_user(&name
->rel
[0], &system_utsname
.release
[0], sizeof(name
->rel
) - 1);
487 ret
|= __copy_to_user(&name
->ver
[0], &system_utsname
.version
[0], sizeof(name
->ver
) - 1);
488 ret
|= __copy_to_user(&name
->mach
[0], &system_utsname
.machine
[0], sizeof(name
->mach
) - 1);
492 return (ret
? -EFAULT
: 0);
495 asmlinkage
int sunos_nosys(void)
497 struct pt_regs
*regs
;
502 regs
= current
->thread
.kregs
;
503 info
.si_signo
= SIGSYS
;
505 info
.si_code
= __SI_FAULT
|0x100;
506 info
.si_addr
= (void *)regs
->pc
;
507 info
.si_trapno
= regs
->u_regs
[UREG_G1
];
508 send_sig_info(SIGSYS
, &info
, current
);
510 printk("Process makes ni_syscall number %d, register dump:\n",
511 (int) regs
->u_regs
[UREG_G1
]);
518 /* This is not a real and complete implementation yet, just to keep
519 * the easy SunOS binaries happy.
521 asmlinkage
int sunos_fpathconf(int fd
, int name
)
544 case _PCONF_CHRESTRICT
: /* XXX Investigate XXX */
547 case _PCONF_NOTRUNC
: /* XXX Investigate XXX */
548 case _PCONF_VDISABLE
:
558 asmlinkage
int sunos_pathconf(char *path
, int name
)
562 ret
= sunos_fpathconf(0, name
); /* XXX cheese XXX */
566 /* SunOS mount system call emulation */
567 extern asmlinkage
int
568 sys_select(int n
, fd_set
*inp
, fd_set
*outp
, fd_set
*exp
, struct timeval
*tvp
);
570 asmlinkage
int sunos_select(int width
, fd_set
*inp
, fd_set
*outp
, fd_set
*exp
, struct timeval
*tvp
)
574 /* SunOS binaries expect that select won't change the tvp contents */
575 ret
= sys_select (width
, inp
, outp
, exp
, tvp
);
576 if (ret
== -EINTR
&& tvp
) {
579 __get_user(sec
, &tvp
->tv_sec
);
580 __get_user(usec
, &tvp
->tv_usec
);
582 if (sec
== 0 && usec
== 0)
588 asmlinkage
void sunos_nop(void)
593 /* SunOS mount/umount. */
594 #define SMNT_RDONLY 1
595 #define SMNT_NOSUID 2
596 #define SMNT_NEWTYPE 4
598 #define SMNT_REMOUNT 16
599 #define SMNT_NOSUB 32
600 #define SMNT_MULTI 64
601 #define SMNT_SYS5 128
604 char fh_data
[NFS_FHSIZE
];
607 struct sunos_nfs_mount_args
{
608 struct sockaddr_in
*addr
; /* file server address */
609 struct nfs_fh
*fh
; /* File handle to be mounted */
610 int flags
; /* flags */
611 int wsize
; /* write size in bytes */
612 int rsize
; /* read size in bytes */
613 int timeo
; /* initial timeout in .1 secs */
614 int retrans
; /* times to retry send */
615 char *hostname
; /* server's hostname */
616 int acregmin
; /* attr cache file min secs */
617 int acregmax
; /* attr cache file max secs */
618 int acdirmin
; /* attr cache dir min secs */
619 int acdirmax
; /* attr cache dir max secs */
620 char *netname
; /* server's netname */
624 extern asmlinkage
int sys_connect(int fd
, struct sockaddr
*uservaddr
, int addrlen
);
625 extern asmlinkage
int sys_socket(int family
, int type
, int protocol
);
626 extern asmlinkage
int sys_bind(int fd
, struct sockaddr
*umyaddr
, int addrlen
);
629 /* Bind the socket on a local reserved port and connect it to the
630 * remote server. This on Linux/i386 is done by the mount program,
634 sunos_nfs_get_server_fd (int fd
, struct sockaddr_in
*addr
)
636 struct sockaddr_in local
;
637 struct sockaddr_in server
;
639 struct socket
*socket
;
648 inode
= file
->f_dentry
->d_inode
;
650 socket
= &inode
->u
.socket_i
;
651 local
.sin_family
= AF_INET
;
652 local
.sin_addr
.s_addr
= INADDR_ANY
;
654 /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */
657 local
.sin_port
= htons (--try_port
);
658 ret
= socket
->ops
->bind(socket
, (struct sockaddr
*)&local
,
660 } while (ret
&& try_port
> (1024 / 2));
665 server
.sin_family
= AF_INET
;
666 server
.sin_addr
= addr
->sin_addr
;
667 server
.sin_port
= NFS_PORT
;
669 /* Call sys_connect */
670 ret
= socket
->ops
->connect (socket
, (struct sockaddr
*) &server
,
671 sizeof (server
), file
->f_flags
);
681 static int get_default (int value
, int def_value
)
689 static int sunos_nfs_mount(char *dir_name
, int linux_flags
, void *data
)
692 char *the_name
, *mount_page
;
693 struct nfs_mount_data linux_nfs_mount
;
694 struct sunos_nfs_mount_args sunos_mount
;
696 /* Ok, here comes the fun part: Linux's nfs mount needs a
697 * socket connection to the server, but SunOS mount does not
698 * require this, so we use the information on the destination
699 * address to create a socket and bind it to a reserved
700 * port on this system
702 if (copy_from_user(&sunos_mount
, data
, sizeof(sunos_mount
)))
705 server_fd
= sys_socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
709 if (copy_from_user(&linux_nfs_mount
.addr
,sunos_mount
.addr
,
710 sizeof(*sunos_mount
.addr
)) ||
711 copy_from_user(&linux_nfs_mount
.root
,sunos_mount
.fh
,
712 sizeof(*sunos_mount
.fh
))) {
713 sys_close (server_fd
);
717 if (!sunos_nfs_get_server_fd (server_fd
, &linux_nfs_mount
.addr
)){
718 sys_close (server_fd
);
722 /* Now, bind it to a locally reserved port */
723 linux_nfs_mount
.version
= NFS_MOUNT_VERSION
;
724 linux_nfs_mount
.flags
= sunos_mount
.flags
;
725 linux_nfs_mount
.fd
= server_fd
;
727 linux_nfs_mount
.rsize
= get_default (sunos_mount
.rsize
, 8192);
728 linux_nfs_mount
.wsize
= get_default (sunos_mount
.wsize
, 8192);
729 linux_nfs_mount
.timeo
= get_default (sunos_mount
.timeo
, 10);
730 linux_nfs_mount
.retrans
= sunos_mount
.retrans
;
732 linux_nfs_mount
.acregmin
= sunos_mount
.acregmin
;
733 linux_nfs_mount
.acregmax
= sunos_mount
.acregmax
;
734 linux_nfs_mount
.acdirmin
= sunos_mount
.acdirmin
;
735 linux_nfs_mount
.acdirmax
= sunos_mount
.acdirmax
;
737 the_name
= getname(sunos_mount
.hostname
);
739 return PTR_ERR(the_name
);
741 strncpy (linux_nfs_mount
.hostname
, the_name
, 254);
742 linux_nfs_mount
.hostname
[255] = 0;
745 mount_page
= (char *) get_zeroed_page(GFP_KERNEL
);
749 memcpy(mount_page
, &linux_nfs_mount
, sizeof(linux_nfs_mount
));
751 err
= do_mount("", dir_name
, "nfs", linux_flags
, mount_page
);
753 free_page((unsigned long) mount_page
);
758 sunos_mount(char *type
, char *dir
, int flags
, void *data
)
763 char *dir_page
, *type_page
;
765 if (!capable (CAP_SYS_ADMIN
))
769 /* We don't handle the integer fs type */
770 if ((flags
& SMNT_NEWTYPE
) == 0)
773 /* Do not allow for those flags we don't support */
774 if (flags
& (SMNT_GRPID
|SMNT_NOSUB
|SMNT_MULTI
|SMNT_SYS5
))
777 if(flags
& SMNT_REMOUNT
)
778 linux_flags
|= MS_REMOUNT
;
779 if(flags
& SMNT_RDONLY
)
780 linux_flags
|= MS_RDONLY
;
781 if(flags
& SMNT_NOSUID
)
782 linux_flags
|= MS_NOSUID
;
784 dir_page
= getname(dir
);
785 ret
= PTR_ERR(dir_page
);
786 if (IS_ERR(dir_page
))
789 type_page
= getname(type
);
790 ret
= PTR_ERR(type_page
);
791 if (IS_ERR(type_page
))
794 if(strcmp(type_page
, "ext2") == 0) {
795 dev_fname
= getname(data
);
796 } else if(strcmp(type_page
, "iso9660") == 0) {
797 dev_fname
= getname(data
);
798 } else if(strcmp(type_page
, "minix") == 0) {
799 dev_fname
= getname(data
);
800 } else if(strcmp(type_page
, "nfs") == 0) {
801 ret
= sunos_nfs_mount (dir_page
, flags
, data
);
803 } else if(strcmp(type_page
, "ufs") == 0) {
804 printk("Warning: UFS filesystem mounts unsupported.\n");
807 } else if(strcmp(type_page
, "proc")) {
811 ret
= PTR_ERR(dev_fname
);
812 if (IS_ERR(dev_fname
))
814 ret
= do_mount(dev_fname
, dir_page
, type_page
, linux_flags
, NULL
);
826 extern asmlinkage
int sys_setsid(void);
827 extern asmlinkage
int sys_setpgid(pid_t
, pid_t
);
829 asmlinkage
int sunos_setpgrp(pid_t pid
, pid_t pgid
)
834 if((!pid
|| pid
== current
->pid
) &&
839 ret
= sys_setpgid(pid
, pgid
);
845 asmlinkage
int sunos_wait4(pid_t pid
, unsigned int *stat_addr
, int options
, struct rusage
*ru
)
849 ret
= sys_wait4((pid
? pid
: -1), stat_addr
, options
, ru
);
853 extern int kill_pg(int, int, int);
854 asmlinkage
int sunos_killpg(int pgrp
, int sig
)
859 ret
= kill_pg(pgrp
, sig
, 0);
864 asmlinkage
int sunos_audit(void)
867 printk ("sys_audit\n");
872 extern asmlinkage
unsigned long sunos_gethostid(void)
877 ret
= ((unsigned long)idprom
->id_machtype
<< 24) |
878 (unsigned long)idprom
->id_sernum
;
883 /* sysconf options, for SunOS compatibility */
884 #define _SC_ARG_MAX 1
885 #define _SC_CHILD_MAX 2
886 #define _SC_CLK_TCK 3
887 #define _SC_NGROUPS_MAX 4
888 #define _SC_OPEN_MAX 5
889 #define _SC_JOB_CONTROL 6
890 #define _SC_SAVED_IDS 7
891 #define _SC_VERSION 8
893 extern asmlinkage
long sunos_sysconf (int name
)
907 case _SC_NGROUPS_MAX
:
913 case _SC_JOB_CONTROL
:
914 ret
= 1; /* yes, we do support job control */
917 ret
= 1; /* yes, we do support saved uids */
920 /* mhm, POSIX_VERSION is in /usr/include/unistd.h
921 * should it go on /usr/include/linux?
932 asmlinkage
int sunos_semsys(int op
, unsigned long arg1
, unsigned long arg2
,
933 unsigned long arg3
, void *ptr
)
940 /* Most arguments match on a 1:1 basis but cmd doesn't */
958 arg4
.__pad
=ptr
; /* value to modify semaphore to */
959 ret
= sys_semctl((int)arg1
, (int)arg2
, (int)arg3
, arg4
);
963 ret
= sys_semget((key_t
)arg1
, (int)arg2
, (int)arg3
);
967 ret
= sys_semop((int)arg1
, (struct sembuf
*)arg2
, (unsigned)arg3
);
976 asmlinkage
int sunos_msgsys(int op
, unsigned long arg1
, unsigned long arg2
,
977 unsigned long arg3
, unsigned long arg4
)
979 struct sparc_stackf
*sp
;
985 rval
= sys_msgget((key_t
)arg1
, (int)arg2
);
988 rval
= sys_msgctl((int)arg1
, (int)arg2
,
989 (struct msqid_ds
*)arg3
);
993 sp
= (struct sparc_stackf
*)current
->thread
.kregs
->u_regs
[UREG_FP
];
994 arg5
= sp
->xxargs
[0];
996 rval
= sys_msgrcv((int)arg1
, (struct msgbuf
*)arg2
,
997 (size_t)arg3
, (long)arg4
, (int)arg5
);
1000 rval
= sys_msgsnd((int)arg1
, (struct msgbuf
*)arg2
,
1001 (size_t)arg3
, (int)arg4
);
1010 asmlinkage
int sunos_shmsys(int op
, unsigned long arg1
, unsigned long arg2
,
1013 unsigned long raddr
;
1018 /* sys_shmat(): attach a shared memory area */
1019 rval
= sys_shmat((int)arg1
,(char *)arg2
,(int)arg3
,&raddr
);
1024 /* sys_shmctl(): modify shared memory area attr. */
1025 rval
= sys_shmctl((int)arg1
,(int)arg2
,(struct shmid_ds
*)arg3
);
1028 /* sys_shmdt(): detach a shared memory area */
1029 rval
= sys_shmdt((char *)arg1
);
1032 /* sys_shmget(): get a shared memory area */
1033 rval
= sys_shmget((key_t
)arg1
,(int)arg2
,(int)arg3
);
1042 #define SUNOS_EWOULDBLOCK 35
1044 /* see the sunos man page read(2v) for an explanation
1045 of this garbage. We use O_NDELAY to mark
1046 file descriptors that have been set non-blocking
1047 using 4.2BSD style calls. (tridge) */
1049 static inline int check_nonblock(int ret
, int fd
)
1051 if (ret
== -EAGAIN
) {
1052 struct file
* file
= fget(fd
);
1054 if (file
->f_flags
& O_NDELAY
)
1055 ret
= -SUNOS_EWOULDBLOCK
;
1062 extern asmlinkage ssize_t
sys_read(unsigned int fd
,char *buf
,int count
);
1063 extern asmlinkage ssize_t
sys_write(unsigned int fd
,char *buf
,int count
);
1064 extern asmlinkage
int sys_recv(int fd
, void * ubuf
, int size
, unsigned flags
);
1065 extern asmlinkage
int sys_send(int fd
, void * buff
, int len
, unsigned flags
);
1066 extern asmlinkage
int sys_accept(int fd
, struct sockaddr
*sa
, int *addrlen
);
1067 extern asmlinkage
int sys_readv(unsigned long fd
, const struct iovec
* vector
, long count
);
1068 extern asmlinkage
int sys_writev(unsigned long fd
, const struct iovec
* vector
, long count
);
1071 asmlinkage
int sunos_read(unsigned int fd
,char *buf
,int count
)
1075 ret
= check_nonblock(sys_read(fd
,buf
,count
),fd
);
1079 asmlinkage
int sunos_readv(unsigned long fd
, const struct iovec
* vector
, long count
)
1083 ret
= check_nonblock(sys_readv(fd
,vector
,count
),fd
);
1087 asmlinkage
int sunos_write(unsigned int fd
,char *buf
,int count
)
1091 ret
= check_nonblock(sys_write(fd
,buf
,count
),fd
);
1095 asmlinkage
int sunos_writev(unsigned long fd
, const struct iovec
* vector
, long count
)
1099 ret
= check_nonblock(sys_writev(fd
,vector
,count
),fd
);
1103 asmlinkage
int sunos_recv(int fd
, void * ubuf
, int size
, unsigned flags
)
1107 ret
= check_nonblock(sys_recv(fd
,ubuf
,size
,flags
),fd
);
1111 asmlinkage
int sunos_send(int fd
, void * buff
, int len
, unsigned flags
)
1115 ret
= check_nonblock(sys_send(fd
,buff
,len
,flags
),fd
);
1119 extern asmlinkage
int sys_setsockopt(int fd
, int level
, int optname
,
1120 char *optval
, int optlen
);
1122 asmlinkage
int sunos_socket(int family
, int type
, int protocol
)
1126 ret
= sys_socket(family
, type
, protocol
);
1130 sys_setsockopt(ret
, SOL_SOCKET
, SO_BSDCOMPAT
,
1131 (char *)&one
, sizeof(one
));
1136 asmlinkage
int sunos_accept(int fd
, struct sockaddr
*sa
, int *addrlen
)
1141 ret
= check_nonblock(sys_accept(fd
,sa
,addrlen
),fd
);
1142 if (ret
!= -ENETUNREACH
&& ret
!= -EHOSTUNREACH
)
1148 sys_setsockopt(ret
, SOL_SOCKET
, SO_BSDCOMPAT
,
1149 (char *)&one
, sizeof(one
));
1154 #define SUNOS_SV_INTERRUPT 2
1157 sunos_sigaction(int sig
, const struct old_sigaction
*act
,
1158 struct old_sigaction
*oact
)
1160 struct k_sigaction new_ka
, old_ka
;
1166 if (verify_area(VERIFY_READ
, act
, sizeof(*act
)) ||
1167 __get_user(new_ka
.sa
.sa_handler
, &act
->sa_handler
) ||
1168 __get_user(new_ka
.sa
.sa_flags
, &act
->sa_flags
))
1170 __get_user(mask
, &act
->sa_mask
);
1171 new_ka
.sa
.sa_restorer
= NULL
;
1172 new_ka
.ka_restorer
= NULL
;
1173 siginitset(&new_ka
.sa
.sa_mask
, mask
);
1174 new_ka
.sa
.sa_flags
^= SUNOS_SV_INTERRUPT
;
1177 ret
= do_sigaction(sig
, act
? &new_ka
: NULL
, oact
? &old_ka
: NULL
);
1180 /* In the clone() case we could copy half consistant
1181 * state to the user, however this could sleep and
1182 * deadlock us if we held the signal lock on SMP. So for
1183 * now I take the easy way out and do no locking.
1184 * But then again we don't support SunOS lwp's anyways ;-)
1186 old_ka
.sa
.sa_flags
^= SUNOS_SV_INTERRUPT
;
1187 if (verify_area(VERIFY_WRITE
, oact
, sizeof(*oact
)) ||
1188 __put_user(old_ka
.sa
.sa_handler
, &oact
->sa_handler
) ||
1189 __put_user(old_ka
.sa
.sa_flags
, &oact
->sa_flags
))
1191 __put_user(old_ka
.sa
.sa_mask
.sig
[0], &oact
->sa_mask
);
1198 extern asmlinkage
int sys_setsockopt(int fd
, int level
, int optname
, char *optval
, int optlen
);
1199 extern asmlinkage
int sys_getsockopt(int fd
, int level
, int optname
, char *optval
, int *optlen
);
1201 asmlinkage
int sunos_setsockopt(int fd
, int level
, int optname
, char *optval
,
1204 int tr_opt
= optname
;
1207 if (level
== SOL_IP
) {
1208 /* Multicast socketopts (ttl, membership) */
1209 if (tr_opt
>=2 && tr_opt
<= 6)
1212 ret
= sys_setsockopt(fd
, level
, tr_opt
, optval
, optlen
);
1216 asmlinkage
int sunos_getsockopt(int fd
, int level
, int optname
, char *optval
,
1219 int tr_opt
= optname
;
1222 if (level
== SOL_IP
) {
1223 /* Multicast socketopts (ttl, membership) */
1224 if (tr_opt
>=2 && tr_opt
<= 6)
1227 ret
= sys_getsockopt(fd
, level
, tr_opt
, optval
, optlen
);