2005-04-16 15:20:36 -07:00
/* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
* sys_sparc32 . c : Conversion between 32 bit and 64 bit native syscalls .
*
* Copyright ( C ) 1997 , 1998 Jakub Jelinek ( jj @ sunsite . mff . cuni . cz )
* Copyright ( C ) 1997 David S . Miller ( davem @ caip . rutgers . edu )
*
* These routines maintain argument size conversion between 32 bit and 64 bit
* environment .
*/
# include <linux/kernel.h>
# include <linux/sched.h>
2006-01-11 12:17:48 -08:00
# include <linux/capability.h>
2005-04-16 15:20:36 -07:00
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/file.h>
# include <linux/signal.h>
# include <linux/resource.h>
# include <linux/times.h>
# include <linux/utsname.h>
# include <linux/smp.h>
# include <linux/smp_lock.h>
# include <linux/sem.h>
# include <linux/msg.h>
# include <linux/shm.h>
# include <linux/slab.h>
# include <linux/uio.h>
# include <linux/nfs_fs.h>
# include <linux/quota.h>
# include <linux/module.h>
# include <linux/sunrpc/svc.h>
# include <linux/nfsd/nfsd.h>
# include <linux/nfsd/cache.h>
# include <linux/nfsd/xdr.h>
# include <linux/nfsd/syscall.h>
# include <linux/poll.h>
# include <linux/personality.h>
# include <linux/stat.h>
# include <linux/filter.h>
# include <linux/highmem.h>
# include <linux/highuid.h>
# include <linux/mman.h>
# include <linux/ipv6.h>
# include <linux/in.h>
# include <linux/icmpv6.h>
# include <linux/syscalls.h>
# include <linux/sysctl.h>
# include <linux/binfmts.h>
# include <linux/dnotify.h>
# include <linux/security.h>
# include <linux/compat.h>
# include <linux/vfs.h>
# include <linux/netfilter_ipv4/ip_tables.h>
# include <linux/ptrace.h>
# include <linux/highuid.h>
# include <asm/types.h>
# include <asm/ipc.h>
# include <asm/uaccess.h>
# include <asm/fpumacro.h>
# include <asm/semaphore.h>
# include <asm/mmu_context.h>
2006-03-17 17:33:56 -08:00
# include <asm/a.out.h>
2006-10-02 14:17:57 -07:00
# include <asm/compat_signal.h>
2005-04-16 15:20:36 -07:00
asmlinkage long sys32_chown16 ( const char __user * filename , u16 user , u16 group )
{
return sys_chown ( filename , low2highuid ( user ) , low2highgid ( group ) ) ;
}
asmlinkage long sys32_lchown16 ( const char __user * filename , u16 user , u16 group )
{
return sys_lchown ( filename , low2highuid ( user ) , low2highgid ( group ) ) ;
}
asmlinkage long sys32_fchown16 ( unsigned int fd , u16 user , u16 group )
{
return sys_fchown ( fd , low2highuid ( user ) , low2highgid ( group ) ) ;
}
asmlinkage long sys32_setregid16 ( u16 rgid , u16 egid )
{
return sys_setregid ( low2highgid ( rgid ) , low2highgid ( egid ) ) ;
}
asmlinkage long sys32_setgid16 ( u16 gid )
{
return sys_setgid ( ( gid_t ) gid ) ;
}
asmlinkage long sys32_setreuid16 ( u16 ruid , u16 euid )
{
return sys_setreuid ( low2highuid ( ruid ) , low2highuid ( euid ) ) ;
}
asmlinkage long sys32_setuid16 ( u16 uid )
{
return sys_setuid ( ( uid_t ) uid ) ;
}
asmlinkage long sys32_setresuid16 ( u16 ruid , u16 euid , u16 suid )
{
return sys_setresuid ( low2highuid ( ruid ) , low2highuid ( euid ) ,
low2highuid ( suid ) ) ;
}
asmlinkage long sys32_getresuid16 ( u16 __user * ruid , u16 __user * euid , u16 __user * suid )
{
int retval ;
if ( ! ( retval = put_user ( high2lowuid ( current - > uid ) , ruid ) ) & &
! ( retval = put_user ( high2lowuid ( current - > euid ) , euid ) ) )
retval = put_user ( high2lowuid ( current - > suid ) , suid ) ;
return retval ;
}
asmlinkage long sys32_setresgid16 ( u16 rgid , u16 egid , u16 sgid )
{
return sys_setresgid ( low2highgid ( rgid ) , low2highgid ( egid ) ,
low2highgid ( sgid ) ) ;
}
asmlinkage long sys32_getresgid16 ( u16 __user * rgid , u16 __user * egid , u16 __user * sgid )
{
int retval ;
if ( ! ( retval = put_user ( high2lowgid ( current - > gid ) , rgid ) ) & &
! ( retval = put_user ( high2lowgid ( current - > egid ) , egid ) ) )
retval = put_user ( high2lowgid ( current - > sgid ) , sgid ) ;
return retval ;
}
asmlinkage long sys32_setfsuid16 ( u16 uid )
{
return sys_setfsuid ( ( uid_t ) uid ) ;
}
asmlinkage long sys32_setfsgid16 ( u16 gid )
{
return sys_setfsgid ( ( gid_t ) gid ) ;
}
static int groups16_to_user ( u16 __user * grouplist , struct group_info * group_info )
{
int i ;
u16 group ;
for ( i = 0 ; i < group_info - > ngroups ; i + + ) {
group = ( u16 ) GROUP_AT ( group_info , i ) ;
if ( put_user ( group , grouplist + i ) )
return - EFAULT ;
}
return 0 ;
}
static int groups16_from_user ( struct group_info * group_info , u16 __user * grouplist )
{
int i ;
u16 group ;
for ( i = 0 ; i < group_info - > ngroups ; i + + ) {
if ( get_user ( group , grouplist + i ) )
return - EFAULT ;
GROUP_AT ( group_info , i ) = ( gid_t ) group ;
}
return 0 ;
}
asmlinkage long sys32_getgroups16 ( int gidsetsize , u16 __user * grouplist )
{
int i ;
if ( gidsetsize < 0 )
return - EINVAL ;
get_group_info ( current - > group_info ) ;
i = current - > group_info - > ngroups ;
if ( gidsetsize ) {
if ( i > gidsetsize ) {
i = - EINVAL ;
goto out ;
}
if ( groups16_to_user ( grouplist , current - > group_info ) ) {
i = - EFAULT ;
goto out ;
}
}
out :
put_group_info ( current - > group_info ) ;
return i ;
}
asmlinkage long sys32_setgroups16 ( int gidsetsize , u16 __user * grouplist )
{
struct group_info * group_info ;
int retval ;
if ( ! capable ( CAP_SETGID ) )
return - EPERM ;
if ( ( unsigned ) gidsetsize > NGROUPS_MAX )
return - EINVAL ;
group_info = groups_alloc ( gidsetsize ) ;
if ( ! group_info )
return - ENOMEM ;
retval = groups16_from_user ( group_info , grouplist ) ;
if ( retval ) {
put_group_info ( group_info ) ;
return retval ;
}
retval = set_current_groups ( group_info ) ;
put_group_info ( group_info ) ;
return retval ;
}
asmlinkage long sys32_getuid16 ( void )
{
return high2lowuid ( current - > uid ) ;
}
asmlinkage long sys32_geteuid16 ( void )
{
return high2lowuid ( current - > euid ) ;
}
asmlinkage long sys32_getgid16 ( void )
{
return high2lowgid ( current - > gid ) ;
}
asmlinkage long sys32_getegid16 ( void )
{
return high2lowgid ( current - > egid ) ;
}
/* 32-bit timeval and related flotsam. */
static long get_tv32 ( struct timeval * o , struct compat_timeval __user * i )
{
return ( ! access_ok ( VERIFY_READ , i , sizeof ( * i ) ) | |
( __get_user ( o - > tv_sec , & i - > tv_sec ) |
__get_user ( o - > tv_usec , & i - > tv_usec ) ) ) ;
}
static inline long put_tv32 ( struct compat_timeval __user * o , struct timeval * i )
{
return ( ! access_ok ( VERIFY_WRITE , o , sizeof ( * o ) ) | |
( __put_user ( i - > tv_sec , & o - > tv_sec ) |
__put_user ( i - > tv_usec , & o - > tv_usec ) ) ) ;
}
# ifdef CONFIG_SYSVIPC
asmlinkage long compat_sys_ipc ( u32 call , u32 first , u32 second , u32 third , compat_uptr_t ptr , u32 fifth )
{
int version ;
version = call > > 16 ; /* hack for backward compatibility */
call & = 0xffff ;
switch ( call ) {
case SEMTIMEDOP :
if ( fifth )
/* sign extend semid */
return compat_sys_semtimedop ( ( int ) first ,
compat_ptr ( ptr ) , second ,
compat_ptr ( fifth ) ) ;
/* else fall through for normal semop() */
case SEMOP :
/* struct sembuf is the same on 32 and 64bit :)) */
/* sign extend semid */
return sys_semtimedop ( ( int ) first , compat_ptr ( ptr ) , second ,
NULL ) ;
case SEMGET :
/* sign extend key, nsems */
return sys_semget ( ( int ) first , ( int ) second , third ) ;
case SEMCTL :
/* sign extend semid, semnum */
return compat_sys_semctl ( ( int ) first , ( int ) second , third ,
compat_ptr ( ptr ) ) ;
case MSGSND :
/* sign extend msqid */
return compat_sys_msgsnd ( ( int ) first , ( int ) second , third ,
compat_ptr ( ptr ) ) ;
case MSGRCV :
/* sign extend msqid, msgtyp */
return compat_sys_msgrcv ( ( int ) first , second , ( int ) fifth ,
third , version , compat_ptr ( ptr ) ) ;
case MSGGET :
/* sign extend key */
return sys_msgget ( ( int ) first , second ) ;
case MSGCTL :
/* sign extend msqid */
return compat_sys_msgctl ( ( int ) first , second , compat_ptr ( ptr ) ) ;
case SHMAT :
/* sign extend shmid */
return compat_sys_shmat ( ( int ) first , second , third , version ,
compat_ptr ( ptr ) ) ;
case SHMDT :
return sys_shmdt ( compat_ptr ( ptr ) ) ;
case SHMGET :
/* sign extend key_t */
return sys_shmget ( ( int ) first , second , third ) ;
case SHMCTL :
/* sign extend shmid */
return compat_sys_shmctl ( ( int ) first , second , compat_ptr ( ptr ) ) ;
default :
return - ENOSYS ;
} ;
return - ENOSYS ;
}
# endif
asmlinkage long sys32_truncate64 ( const char __user * path , unsigned long high , unsigned long low )
{
if ( ( int ) high < 0 )
return - EINVAL ;
else
return sys_truncate ( path , ( high < < 32 ) | low ) ;
}
asmlinkage long sys32_ftruncate64 ( unsigned int fd , unsigned long high , unsigned long low )
{
if ( ( int ) high < 0 )
return - EINVAL ;
else
return sys_ftruncate ( fd , ( high < < 32 ) | low ) ;
}
int cp_compat_stat ( struct kstat * stat , struct compat_stat __user * statbuf )
{
2006-10-03 01:13:46 -07:00
compat_ino_t ino ;
2005-04-16 15:20:36 -07:00
int err ;
if ( stat - > size > MAX_NON_LFS | | ! old_valid_dev ( stat - > dev ) | |
! old_valid_dev ( stat - > rdev ) )
return - EOVERFLOW ;
2006-10-03 01:13:46 -07:00
ino = stat - > ino ;
if ( sizeof ( ino ) < sizeof ( stat - > ino ) & & ino ! = stat - > ino )
return - EOVERFLOW ;
2005-04-16 15:20:36 -07:00
err = put_user ( old_encode_dev ( stat - > dev ) , & statbuf - > st_dev ) ;
err | = put_user ( stat - > ino , & statbuf - > st_ino ) ;
err | = put_user ( stat - > mode , & statbuf - > st_mode ) ;
err | = put_user ( stat - > nlink , & statbuf - > st_nlink ) ;
err | = put_user ( high2lowuid ( stat - > uid ) , & statbuf - > st_uid ) ;
err | = put_user ( high2lowgid ( stat - > gid ) , & statbuf - > st_gid ) ;
err | = put_user ( old_encode_dev ( stat - > rdev ) , & statbuf - > st_rdev ) ;
err | = put_user ( stat - > size , & statbuf - > st_size ) ;
err | = put_user ( stat - > atime . tv_sec , & statbuf - > st_atime ) ;
2005-04-18 15:13:15 -07:00
err | = put_user ( stat - > atime . tv_nsec , & statbuf - > st_atime_nsec ) ;
2005-04-16 15:20:36 -07:00
err | = put_user ( stat - > mtime . tv_sec , & statbuf - > st_mtime ) ;
2005-04-18 15:13:15 -07:00
err | = put_user ( stat - > mtime . tv_nsec , & statbuf - > st_mtime_nsec ) ;
2005-04-16 15:20:36 -07:00
err | = put_user ( stat - > ctime . tv_sec , & statbuf - > st_ctime ) ;
2005-04-18 15:13:15 -07:00
err | = put_user ( stat - > ctime . tv_nsec , & statbuf - > st_ctime_nsec ) ;
2005-04-16 15:20:36 -07:00
err | = put_user ( stat - > blksize , & statbuf - > st_blksize ) ;
err | = put_user ( stat - > blocks , & statbuf - > st_blocks ) ;
err | = put_user ( 0 , & statbuf - > __unused4 [ 0 ] ) ;
err | = put_user ( 0 , & statbuf - > __unused4 [ 1 ] ) ;
return err ;
}
2005-04-18 15:13:15 -07:00
int cp_compat_stat64 ( struct kstat * stat , struct compat_stat64 __user * statbuf )
{
int err ;
err = put_user ( huge_encode_dev ( stat - > dev ) , & statbuf - > st_dev ) ;
err | = put_user ( stat - > ino , & statbuf - > st_ino ) ;
err | = put_user ( stat - > mode , & statbuf - > st_mode ) ;
err | = put_user ( stat - > nlink , & statbuf - > st_nlink ) ;
err | = put_user ( stat - > uid , & statbuf - > st_uid ) ;
err | = put_user ( stat - > gid , & statbuf - > st_gid ) ;
err | = put_user ( huge_encode_dev ( stat - > rdev ) , & statbuf - > st_rdev ) ;
err | = put_user ( 0 , ( unsigned long __user * ) & statbuf - > __pad3 [ 0 ] ) ;
err | = put_user ( stat - > size , & statbuf - > st_size ) ;
err | = put_user ( stat - > blksize , & statbuf - > st_blksize ) ;
err | = put_user ( 0 , ( unsigned int __user * ) & statbuf - > __pad4 [ 0 ] ) ;
err | = put_user ( 0 , ( unsigned int __user * ) & statbuf - > __pad4 [ 4 ] ) ;
err | = put_user ( stat - > blocks , & statbuf - > st_blocks ) ;
err | = put_user ( stat - > atime . tv_sec , & statbuf - > st_atime ) ;
err | = put_user ( stat - > atime . tv_nsec , & statbuf - > st_atime_nsec ) ;
err | = put_user ( stat - > mtime . tv_sec , & statbuf - > st_mtime ) ;
err | = put_user ( stat - > mtime . tv_nsec , & statbuf - > st_mtime_nsec ) ;
err | = put_user ( stat - > ctime . tv_sec , & statbuf - > st_ctime ) ;
err | = put_user ( stat - > ctime . tv_nsec , & statbuf - > st_ctime_nsec ) ;
err | = put_user ( 0 , & statbuf - > __unused4 ) ;
err | = put_user ( 0 , & statbuf - > __unused5 ) ;
return err ;
}
asmlinkage long compat_sys_stat64 ( char __user * filename ,
struct compat_stat64 __user * statbuf )
{
struct kstat stat ;
int error = vfs_stat ( filename , & stat ) ;
if ( ! error )
error = cp_compat_stat64 ( & stat , statbuf ) ;
return error ;
}
asmlinkage long compat_sys_lstat64 ( char __user * filename ,
struct compat_stat64 __user * statbuf )
{
struct kstat stat ;
int error = vfs_lstat ( filename , & stat ) ;
if ( ! error )
error = cp_compat_stat64 ( & stat , statbuf ) ;
return error ;
}
asmlinkage long compat_sys_fstat64 ( unsigned int fd ,
struct compat_stat64 __user * statbuf )
{
struct kstat stat ;
int error = vfs_fstat ( fd , & stat ) ;
if ( ! error )
error = cp_compat_stat64 ( & stat , statbuf ) ;
return error ;
}
2006-02-12 23:30:11 -08:00
asmlinkage long compat_sys_fstatat64 ( unsigned int dfd , char __user * filename ,
struct compat_stat64 __user * statbuf , int flag )
{
struct kstat stat ;
int error = - EINVAL ;
if ( ( flag & ~ AT_SYMLINK_NOFOLLOW ) ! = 0 )
goto out ;
if ( flag & AT_SYMLINK_NOFOLLOW )
error = vfs_lstat_fd ( dfd , filename , & stat ) ;
else
error = vfs_stat_fd ( dfd , filename , & stat ) ;
if ( ! error )
error = cp_compat_stat64 ( & stat , statbuf ) ;
out :
return error ;
}
2005-04-16 15:20:36 -07:00
asmlinkage long compat_sys_sysfs ( int option , u32 arg1 , u32 arg2 )
{
return sys_sysfs ( option , arg1 , arg2 ) ;
}
asmlinkage long compat_sys_sched_rr_get_interval ( compat_pid_t pid , struct compat_timespec __user * interval )
{
struct timespec t ;
int ret ;
mm_segment_t old_fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
ret = sys_sched_rr_get_interval ( pid , ( struct timespec __user * ) & t ) ;
set_fs ( old_fs ) ;
if ( put_compat_timespec ( & t , interval ) )
return - EFAULT ;
return ret ;
}
asmlinkage long compat_sys_rt_sigprocmask ( int how ,
compat_sigset_t __user * set ,
compat_sigset_t __user * oset ,
compat_size_t sigsetsize )
{
sigset_t s ;
compat_sigset_t s32 ;
int ret ;
mm_segment_t old_fs = get_fs ( ) ;
if ( set ) {
if ( copy_from_user ( & s32 , set , sizeof ( compat_sigset_t ) ) )
return - EFAULT ;
switch ( _NSIG_WORDS ) {
case 4 : s . sig [ 3 ] = s32 . sig [ 6 ] | ( ( ( long ) s32 . sig [ 7 ] ) < < 32 ) ;
case 3 : s . sig [ 2 ] = s32 . sig [ 4 ] | ( ( ( long ) s32 . sig [ 5 ] ) < < 32 ) ;
case 2 : s . sig [ 1 ] = s32 . sig [ 2 ] | ( ( ( long ) s32 . sig [ 3 ] ) < < 32 ) ;
case 1 : s . sig [ 0 ] = s32 . sig [ 0 ] | ( ( ( long ) s32 . sig [ 1 ] ) < < 32 ) ;
}
}
set_fs ( KERNEL_DS ) ;
ret = sys_rt_sigprocmask ( how ,
set ? ( sigset_t __user * ) & s : NULL ,
oset ? ( sigset_t __user * ) & s : NULL ,
sigsetsize ) ;
set_fs ( old_fs ) ;
if ( ret ) return ret ;
if ( oset ) {
switch ( _NSIG_WORDS ) {
case 4 : s32 . sig [ 7 ] = ( s . sig [ 3 ] > > 32 ) ; s32 . sig [ 6 ] = s . sig [ 3 ] ;
case 3 : s32 . sig [ 5 ] = ( s . sig [ 2 ] > > 32 ) ; s32 . sig [ 4 ] = s . sig [ 2 ] ;
case 2 : s32 . sig [ 3 ] = ( s . sig [ 1 ] > > 32 ) ; s32 . sig [ 2 ] = s . sig [ 1 ] ;
case 1 : s32 . sig [ 1 ] = ( s . sig [ 0 ] > > 32 ) ; s32 . sig [ 0 ] = s . sig [ 0 ] ;
}
if ( copy_to_user ( oset , & s32 , sizeof ( compat_sigset_t ) ) )
return - EFAULT ;
}
return 0 ;
}
asmlinkage long sys32_rt_sigpending ( compat_sigset_t __user * set ,
compat_size_t sigsetsize )
{
sigset_t s ;
compat_sigset_t s32 ;
int ret ;
mm_segment_t old_fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
ret = sys_rt_sigpending ( ( sigset_t __user * ) & s , sigsetsize ) ;
set_fs ( old_fs ) ;
if ( ! ret ) {
switch ( _NSIG_WORDS ) {
case 4 : s32 . sig [ 7 ] = ( s . sig [ 3 ] > > 32 ) ; s32 . sig [ 6 ] = s . sig [ 3 ] ;
case 3 : s32 . sig [ 5 ] = ( s . sig [ 2 ] > > 32 ) ; s32 . sig [ 4 ] = s . sig [ 2 ] ;
case 2 : s32 . sig [ 3 ] = ( s . sig [ 1 ] > > 32 ) ; s32 . sig [ 2 ] = s . sig [ 1 ] ;
case 1 : s32 . sig [ 1 ] = ( s . sig [ 0 ] > > 32 ) ; s32 . sig [ 0 ] = s . sig [ 0 ] ;
}
if ( copy_to_user ( set , & s32 , sizeof ( compat_sigset_t ) ) )
return - EFAULT ;
}
return ret ;
}
asmlinkage long compat_sys_rt_sigqueueinfo ( int pid , int sig ,
struct compat_siginfo __user * uinfo )
{
siginfo_t info ;
int ret ;
mm_segment_t old_fs = get_fs ( ) ;
if ( copy_siginfo_from_user32 ( & info , uinfo ) )
return - EFAULT ;
set_fs ( KERNEL_DS ) ;
ret = sys_rt_sigqueueinfo ( pid , sig , ( siginfo_t __user * ) & info ) ;
set_fs ( old_fs ) ;
return ret ;
}
asmlinkage long compat_sys_sigaction ( int sig , struct old_sigaction32 __user * act ,
struct old_sigaction32 __user * oact )
{
struct k_sigaction new_ka , old_ka ;
int ret ;
if ( sig < 0 ) {
set_thread_flag ( TIF_NEWSIGNALS ) ;
sig = - sig ;
}
if ( act ) {
compat_old_sigset_t mask ;
u32 u_handler , u_restorer ;
ret = get_user ( u_handler , & act - > sa_handler ) ;
new_ka . sa . sa_handler = compat_ptr ( u_handler ) ;
ret | = __get_user ( u_restorer , & act - > sa_restorer ) ;
new_ka . sa . sa_restorer = compat_ptr ( u_restorer ) ;
ret | = __get_user ( new_ka . sa . sa_flags , & act - > sa_flags ) ;
ret | = __get_user ( mask , & act - > sa_mask ) ;
if ( ret )
return ret ;
new_ka . ka_restorer = NULL ;
siginitset ( & new_ka . sa . sa_mask , mask ) ;
}
ret = do_sigaction ( sig , act ? & new_ka : NULL , oact ? & old_ka : NULL ) ;
if ( ! ret & & oact ) {
ret = put_user ( ptr_to_compat ( old_ka . sa . sa_handler ) , & oact - > sa_handler ) ;
ret | = __put_user ( ptr_to_compat ( old_ka . sa . sa_restorer ) , & oact - > sa_restorer ) ;
ret | = __put_user ( old_ka . sa . sa_flags , & oact - > sa_flags ) ;
ret | = __put_user ( old_ka . sa . sa_mask . sig [ 0 ] , & oact - > sa_mask ) ;
}
return ret ;
}
asmlinkage long compat_sys_rt_sigaction ( int sig ,
struct sigaction32 __user * act ,
struct sigaction32 __user * oact ,
void __user * restorer ,
compat_size_t sigsetsize )
{
struct k_sigaction new_ka , old_ka ;
int ret ;
compat_sigset_t set32 ;
/* XXX: Don't preclude handling different sized sigset_t's. */
if ( sigsetsize ! = sizeof ( compat_sigset_t ) )
return - EINVAL ;
/* All tasks which use RT signals (effectively) use
* new style signals .
*/
set_thread_flag ( TIF_NEWSIGNALS ) ;
if ( act ) {
u32 u_handler , u_restorer ;
new_ka . ka_restorer = restorer ;
ret = get_user ( u_handler , & act - > sa_handler ) ;
new_ka . sa . sa_handler = compat_ptr ( u_handler ) ;
ret | = __copy_from_user ( & set32 , & act - > sa_mask , sizeof ( compat_sigset_t ) ) ;
switch ( _NSIG_WORDS ) {
case 4 : new_ka . sa . sa_mask . sig [ 3 ] = set32 . sig [ 6 ] | ( ( ( long ) set32 . sig [ 7 ] ) < < 32 ) ;
case 3 : new_ka . sa . sa_mask . sig [ 2 ] = set32 . sig [ 4 ] | ( ( ( long ) set32 . sig [ 5 ] ) < < 32 ) ;
case 2 : new_ka . sa . sa_mask . sig [ 1 ] = set32 . sig [ 2 ] | ( ( ( long ) set32 . sig [ 3 ] ) < < 32 ) ;
case 1 : new_ka . sa . sa_mask . sig [ 0 ] = set32 . sig [ 0 ] | ( ( ( long ) set32 . sig [ 1 ] ) < < 32 ) ;
}
ret | = __get_user ( new_ka . sa . sa_flags , & act - > sa_flags ) ;
ret | = __get_user ( u_restorer , & act - > sa_restorer ) ;
new_ka . sa . sa_restorer = compat_ptr ( u_restorer ) ;
if ( ret )
return - EFAULT ;
}
ret = do_sigaction ( sig , act ? & new_ka : NULL , oact ? & old_ka : NULL ) ;
if ( ! ret & & oact ) {
switch ( _NSIG_WORDS ) {
case 4 : set32 . sig [ 7 ] = ( old_ka . sa . sa_mask . sig [ 3 ] > > 32 ) ; set32 . sig [ 6 ] = old_ka . sa . sa_mask . sig [ 3 ] ;
case 3 : set32 . sig [ 5 ] = ( old_ka . sa . sa_mask . sig [ 2 ] > > 32 ) ; set32 . sig [ 4 ] = old_ka . sa . sa_mask . sig [ 2 ] ;
case 2 : set32 . sig [ 3 ] = ( old_ka . sa . sa_mask . sig [ 1 ] > > 32 ) ; set32 . sig [ 2 ] = old_ka . sa . sa_mask . sig [ 1 ] ;
case 1 : set32 . sig [ 1 ] = ( old_ka . sa . sa_mask . sig [ 0 ] > > 32 ) ; set32 . sig [ 0 ] = old_ka . sa . sa_mask . sig [ 0 ] ;
}
ret = put_user ( ptr_to_compat ( old_ka . sa . sa_handler ) , & oact - > sa_handler ) ;
ret | = __copy_to_user ( & oact - > sa_mask , & set32 , sizeof ( compat_sigset_t ) ) ;
ret | = __put_user ( old_ka . sa . sa_flags , & oact - > sa_flags ) ;
ret | = __put_user ( ptr_to_compat ( old_ka . sa . sa_restorer ) , & oact - > sa_restorer ) ;
if ( ret )
ret = - EFAULT ;
}
return ret ;
}
/*
* sparc32_execve ( ) executes a new program after the asm stub has set
* things up for us . This should basically do what I want it to .
*/
asmlinkage long sparc32_execve ( struct pt_regs * regs )
{
int error , base = 0 ;
char * filename ;
/* User register window flush is done by entry.S */
/* Check for indirect call. */
if ( ( u32 ) regs - > u_regs [ UREG_G1 ] = = 0 )
base = 1 ;
filename = getname ( compat_ptr ( regs - > u_regs [ base + UREG_I0 ] ) ) ;
error = PTR_ERR ( filename ) ;
if ( IS_ERR ( filename ) )
goto out ;
error = compat_do_execve ( filename ,
compat_ptr ( regs - > u_regs [ base + UREG_I1 ] ) ,
compat_ptr ( regs - > u_regs [ base + UREG_I2 ] ) , regs ) ;
putname ( filename ) ;
if ( ! error ) {
fprs_write ( 0 ) ;
current_thread_info ( ) - > xfsr [ 0 ] = 0 ;
current_thread_info ( ) - > fpsaved [ 0 ] = 0 ;
regs - > tstate & = ~ TSTATE_PEF ;
task_lock ( current ) ;
current - > ptrace & = ~ PT_DTRACE ;
task_unlock ( current ) ;
}
out :
return error ;
}
# ifdef CONFIG_MODULES
asmlinkage long sys32_init_module ( void __user * umod , u32 len ,
const char __user * uargs )
{
return sys_init_module ( umod , len , uargs ) ;
}
asmlinkage long sys32_delete_module ( const char __user * name_user ,
unsigned int flags )
{
return sys_delete_module ( name_user , flags ) ;
}
# else /* CONFIG_MODULES */
asmlinkage long sys32_init_module ( const char __user * name_user ,
struct module __user * mod_user )
{
return - ENOSYS ;
}
asmlinkage long sys32_delete_module ( const char __user * name_user )
{
return - ENOSYS ;
}
# endif /* CONFIG_MODULES */
/* Translations due to time_t size differences. Which affects all
sorts of things , like timeval and itimerval . */
extern struct timezone sys_tz ;
asmlinkage long sys32_gettimeofday ( struct compat_timeval __user * tv ,
struct timezone __user * tz )
{
if ( tv ) {
struct timeval ktv ;
do_gettimeofday ( & ktv ) ;
if ( put_tv32 ( tv , & ktv ) )
return - EFAULT ;
}
if ( tz ) {
if ( copy_to_user ( tz , & sys_tz , sizeof ( sys_tz ) ) )
return - EFAULT ;
}
return 0 ;
}
static inline long get_ts32 ( struct timespec * o , struct compat_timeval __user * i )
{
long usec ;
if ( ! access_ok ( VERIFY_READ , i , sizeof ( * i ) ) )
return - EFAULT ;
if ( __get_user ( o - > tv_sec , & i - > tv_sec ) )
return - EFAULT ;
if ( __get_user ( usec , & i - > tv_usec ) )
return - EFAULT ;
o - > tv_nsec = usec * 1000 ;
return 0 ;
}
asmlinkage long sys32_settimeofday ( struct compat_timeval __user * tv ,
struct timezone __user * tz )
{
struct timespec kts ;
struct timezone ktz ;
if ( tv ) {
if ( get_ts32 ( & kts , tv ) )
return - EFAULT ;
}
if ( tz ) {
if ( copy_from_user ( & ktz , tz , sizeof ( ktz ) ) )
return - EFAULT ;
}
return do_sys_settimeofday ( tv ? & kts : NULL , tz ? & ktz : NULL ) ;
}
asmlinkage long sys32_utimes ( char __user * filename ,
struct compat_timeval __user * tvs )
{
utimensat implementation
Implement utimensat(2) which is an extension to futimesat(2) in that it
a) supports nano-second resolution for the timestamps
b) allows to selectively ignore the atime/mtime value
c) allows to selectively use the current time for either atime or mtime
d) supports changing the atime/mtime of a symlink itself along the lines
of the BSD lutimes(3) functions
For this change the internally used do_utimes() functions was changed to
accept a timespec time value and an additional flags parameter.
Additionally the sys_utime function was changed to match compat_sys_utime
which already use do_utimes instead of duplicating the work.
Also, the completely missing futimensat() functionality is added. We have
such a function in glibc but we have to resort to using /proc/self/fd/* which
not everybody likes (chroot etc).
Test application (the syscall number will need per-arch editing):
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <stddef.h>
#include <syscall.h>
#define __NR_utimensat 280
#define UTIME_NOW ((1l << 30) - 1l)
#define UTIME_OMIT ((1l << 30) - 2l)
int
main(void)
{
int status = 0;
int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666);
if (fd == -1)
error (1, errno, "failed to create test file \"ttt\"");
struct stat64 st1;
if (fstat64 (fd, &st1) != 0)
error (1, errno, "fstat failed");
struct timespec t[2];
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
struct stat64 st2;
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;
t[0] = st1.st_atim;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_OMIT;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("atim not set");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim changed from zero");
status = 1;
}
if (status != 0)
goto out;
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_OMIT;
t[1] = st1.st_mtim;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("mtim changed from original time");
status = 1;
}
if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec
|| st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec)
{
puts ("mtim not set");
status = 1;
}
if (status != 0)
goto out;
sleep (2);
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_NOW;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_NOW;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
struct timeval tv;
gettimeofday(&tv,NULL);
if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec
|| st2.st_atim.tv_sec > tv.tv_sec)
{
puts ("atim not set to NOW");
status = 1;
}
if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec
|| st2.st_mtim.tv_sec > tv.tv_sec)
{
puts ("mtim not set to NOW");
status = 1;
}
if (symlink ("ttt", "tttsym") != 0)
error (1, errno, "cannot create symlink");
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, AT_FDCWD, "tttsym", t, AT_SYMLINK_NOFOLLOW) != 0)
error (1, errno, "utimensat failed");
if (lstat64 ("tttsym", &st2) != 0)
error (1, errno, "lstat failed");
if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("symlink atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("symlink mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;
t[0].tv_sec = 1;
t[0].tv_nsec = 0;
t[1].tv_sec = 1;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, fd, NULL, t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != 1 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to one");
status = 1;
}
if (st2.st_mtim.tv_sec != 1 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to one");
status = 1;
}
if (status == 0)
puts ("all OK");
out:
close (fd);
unlink ("ttt");
unlink ("tttsym");
return status;
}
[akpm@linux-foundation.org: add missing i386 syscall table entry]
Signed-off-by: Ulrich Drepper <drepper@redhat.com>
Cc: Alexey Dobriyan <adobriyan@openvz.org>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: <linux-arch@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-08 00:33:25 -07:00
struct timespec tv [ 2 ] ;
2005-04-16 15:20:36 -07:00
if ( tvs ) {
utimensat implementation
Implement utimensat(2) which is an extension to futimesat(2) in that it
a) supports nano-second resolution for the timestamps
b) allows to selectively ignore the atime/mtime value
c) allows to selectively use the current time for either atime or mtime
d) supports changing the atime/mtime of a symlink itself along the lines
of the BSD lutimes(3) functions
For this change the internally used do_utimes() functions was changed to
accept a timespec time value and an additional flags parameter.
Additionally the sys_utime function was changed to match compat_sys_utime
which already use do_utimes instead of duplicating the work.
Also, the completely missing futimensat() functionality is added. We have
such a function in glibc but we have to resort to using /proc/self/fd/* which
not everybody likes (chroot etc).
Test application (the syscall number will need per-arch editing):
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <stddef.h>
#include <syscall.h>
#define __NR_utimensat 280
#define UTIME_NOW ((1l << 30) - 1l)
#define UTIME_OMIT ((1l << 30) - 2l)
int
main(void)
{
int status = 0;
int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666);
if (fd == -1)
error (1, errno, "failed to create test file \"ttt\"");
struct stat64 st1;
if (fstat64 (fd, &st1) != 0)
error (1, errno, "fstat failed");
struct timespec t[2];
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
struct stat64 st2;
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;
t[0] = st1.st_atim;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_OMIT;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("atim not set");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim changed from zero");
status = 1;
}
if (status != 0)
goto out;
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_OMIT;
t[1] = st1.st_mtim;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("mtim changed from original time");
status = 1;
}
if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec
|| st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec)
{
puts ("mtim not set");
status = 1;
}
if (status != 0)
goto out;
sleep (2);
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_NOW;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_NOW;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
struct timeval tv;
gettimeofday(&tv,NULL);
if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec
|| st2.st_atim.tv_sec > tv.tv_sec)
{
puts ("atim not set to NOW");
status = 1;
}
if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec
|| st2.st_mtim.tv_sec > tv.tv_sec)
{
puts ("mtim not set to NOW");
status = 1;
}
if (symlink ("ttt", "tttsym") != 0)
error (1, errno, "cannot create symlink");
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, AT_FDCWD, "tttsym", t, AT_SYMLINK_NOFOLLOW) != 0)
error (1, errno, "utimensat failed");
if (lstat64 ("tttsym", &st2) != 0)
error (1, errno, "lstat failed");
if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("symlink atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("symlink mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;
t[0].tv_sec = 1;
t[0].tv_nsec = 0;
t[1].tv_sec = 1;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, fd, NULL, t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != 1 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to one");
status = 1;
}
if (st2.st_mtim.tv_sec != 1 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to one");
status = 1;
}
if (status == 0)
puts ("all OK");
out:
close (fd);
unlink ("ttt");
unlink ("tttsym");
return status;
}
[akpm@linux-foundation.org: add missing i386 syscall table entry]
Signed-off-by: Ulrich Drepper <drepper@redhat.com>
Cc: Alexey Dobriyan <adobriyan@openvz.org>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: <linux-arch@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-08 00:33:25 -07:00
struct timeval ktvs [ 2 ] ;
2005-04-16 15:20:36 -07:00
if ( get_tv32 ( & ktvs [ 0 ] , tvs ) | |
get_tv32 ( & ktvs [ 1 ] , 1 + tvs ) )
return - EFAULT ;
utimensat implementation
Implement utimensat(2) which is an extension to futimesat(2) in that it
a) supports nano-second resolution for the timestamps
b) allows to selectively ignore the atime/mtime value
c) allows to selectively use the current time for either atime or mtime
d) supports changing the atime/mtime of a symlink itself along the lines
of the BSD lutimes(3) functions
For this change the internally used do_utimes() functions was changed to
accept a timespec time value and an additional flags parameter.
Additionally the sys_utime function was changed to match compat_sys_utime
which already use do_utimes instead of duplicating the work.
Also, the completely missing futimensat() functionality is added. We have
such a function in glibc but we have to resort to using /proc/self/fd/* which
not everybody likes (chroot etc).
Test application (the syscall number will need per-arch editing):
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <stddef.h>
#include <syscall.h>
#define __NR_utimensat 280
#define UTIME_NOW ((1l << 30) - 1l)
#define UTIME_OMIT ((1l << 30) - 2l)
int
main(void)
{
int status = 0;
int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666);
if (fd == -1)
error (1, errno, "failed to create test file \"ttt\"");
struct stat64 st1;
if (fstat64 (fd, &st1) != 0)
error (1, errno, "fstat failed");
struct timespec t[2];
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
struct stat64 st2;
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;
t[0] = st1.st_atim;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_OMIT;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("atim not set");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim changed from zero");
status = 1;
}
if (status != 0)
goto out;
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_OMIT;
t[1] = st1.st_mtim;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
|| st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
{
puts ("mtim changed from original time");
status = 1;
}
if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec
|| st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec)
{
puts ("mtim not set");
status = 1;
}
if (status != 0)
goto out;
sleep (2);
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_NOW;
t[1].tv_sec = 0;
t[1].tv_nsec = UTIME_NOW;
if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
struct timeval tv;
gettimeofday(&tv,NULL);
if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec
|| st2.st_atim.tv_sec > tv.tv_sec)
{
puts ("atim not set to NOW");
status = 1;
}
if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec
|| st2.st_mtim.tv_sec > tv.tv_sec)
{
puts ("mtim not set to NOW");
status = 1;
}
if (symlink ("ttt", "tttsym") != 0)
error (1, errno, "cannot create symlink");
t[0].tv_sec = 0;
t[0].tv_nsec = 0;
t[1].tv_sec = 0;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, AT_FDCWD, "tttsym", t, AT_SYMLINK_NOFOLLOW) != 0)
error (1, errno, "utimensat failed");
if (lstat64 ("tttsym", &st2) != 0)
error (1, errno, "lstat failed");
if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
{
puts ("symlink atim not reset to zero");
status = 1;
}
if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
{
puts ("symlink mtim not reset to zero");
status = 1;
}
if (status != 0)
goto out;
t[0].tv_sec = 1;
t[0].tv_nsec = 0;
t[1].tv_sec = 1;
t[1].tv_nsec = 0;
if (syscall(__NR_utimensat, fd, NULL, t, 0) != 0)
error (1, errno, "utimensat failed");
if (fstat64 (fd, &st2) != 0)
error (1, errno, "fstat failed");
if (st2.st_atim.tv_sec != 1 || st2.st_atim.tv_nsec != 0)
{
puts ("atim not reset to one");
status = 1;
}
if (st2.st_mtim.tv_sec != 1 || st2.st_mtim.tv_nsec != 0)
{
puts ("mtim not reset to one");
status = 1;
}
if (status == 0)
puts ("all OK");
out:
close (fd);
unlink ("ttt");
unlink ("tttsym");
return status;
}
[akpm@linux-foundation.org: add missing i386 syscall table entry]
Signed-off-by: Ulrich Drepper <drepper@redhat.com>
Cc: Alexey Dobriyan <adobriyan@openvz.org>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: <linux-arch@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-08 00:33:25 -07:00
if ( ktvs [ 0 ] . tv_usec < 0 | | ktvs [ 0 ] . tv_usec > = 1000000 | |
ktvs [ 1 ] . tv_usec < 0 | | ktvs [ 1 ] . tv_usec > = 1000000 )
return - EINVAL ;
tv [ 0 ] . tv_sec = ktvs [ 0 ] . tv_sec ;
tv [ 0 ] . tv_nsec = 1000 * ktvs [ 0 ] . tv_usec ;
tv [ 1 ] . tv_sec = ktvs [ 1 ] . tv_sec ;
tv [ 1 ] . tv_nsec = 1000 * ktvs [ 1 ] . tv_usec ;
2005-04-16 15:20:36 -07:00
}
2007-05-08 17:50:14 -07:00
return do_utimes ( AT_FDCWD , filename , tvs ? tv : NULL , 0 ) ;
2005-04-16 15:20:36 -07:00
}
/* These are here just in case some old sparc32 binary calls it. */
asmlinkage long sys32_pause ( void )
{
current - > state = TASK_INTERRUPTIBLE ;
schedule ( ) ;
return - ERESTARTNOHAND ;
}
asmlinkage compat_ssize_t sys32_pread64 ( unsigned int fd ,
char __user * ubuf ,
compat_size_t count ,
unsigned long poshi ,
unsigned long poslo )
{
return sys_pread64 ( fd , ubuf , count , ( poshi < < 32 ) | poslo ) ;
}
asmlinkage compat_ssize_t sys32_pwrite64 ( unsigned int fd ,
char __user * ubuf ,
compat_size_t count ,
unsigned long poshi ,
unsigned long poslo )
{
return sys_pwrite64 ( fd , ubuf , count , ( poshi < < 32 ) | poslo ) ;
}
asmlinkage long compat_sys_readahead ( int fd ,
unsigned long offhi ,
unsigned long offlo ,
compat_size_t count )
{
return sys_readahead ( fd , ( offhi < < 32 ) | offlo , count ) ;
}
long compat_sys_fadvise64 ( int fd ,
unsigned long offhi ,
unsigned long offlo ,
compat_size_t len , int advice )
{
return sys_fadvise64_64 ( fd , ( offhi < < 32 ) | offlo , len , advice ) ;
}
long compat_sys_fadvise64_64 ( int fd ,
unsigned long offhi , unsigned long offlo ,
unsigned long lenhi , unsigned long lenlo ,
int advice )
{
return sys_fadvise64_64 ( fd ,
( offhi < < 32 ) | offlo ,
( lenhi < < 32 ) | lenlo ,
advice ) ;
}
asmlinkage long compat_sys_sendfile ( int out_fd , int in_fd ,
compat_off_t __user * offset ,
compat_size_t count )
{
mm_segment_t old_fs = get_fs ( ) ;
int ret ;
off_t of ;
if ( offset & & get_user ( of , offset ) )
return - EFAULT ;
set_fs ( KERNEL_DS ) ;
ret = sys_sendfile ( out_fd , in_fd ,
offset ? ( off_t __user * ) & of : NULL ,
count ) ;
set_fs ( old_fs ) ;
if ( offset & & put_user ( of , offset ) )
return - EFAULT ;
return ret ;
}
asmlinkage long compat_sys_sendfile64 ( int out_fd , int in_fd ,
compat_loff_t __user * offset ,
compat_size_t count )
{
mm_segment_t old_fs = get_fs ( ) ;
int ret ;
loff_t lof ;
if ( offset & & get_user ( lof , offset ) )
return - EFAULT ;
set_fs ( KERNEL_DS ) ;
ret = sys_sendfile64 ( out_fd , in_fd ,
offset ? ( loff_t __user * ) & lof : NULL ,
count ) ;
set_fs ( old_fs ) ;
if ( offset & & put_user ( lof , offset ) )
return - EFAULT ;
return ret ;
}
/* This is just a version for 32-bit applications which does
* not force O_LARGEFILE on .
*/
asmlinkage long sparc32_open ( const char __user * filename ,
int flags , int mode )
{
2006-01-18 17:43:53 -08:00
return do_sys_open ( AT_FDCWD , filename , flags , mode ) ;
2005-04-16 15:20:36 -07:00
}
extern unsigned long do_mremap ( unsigned long addr ,
unsigned long old_len , unsigned long new_len ,
unsigned long flags , unsigned long new_addr ) ;
asmlinkage unsigned long sys32_mremap ( unsigned long addr ,
unsigned long old_len , unsigned long new_len ,
unsigned long flags , u32 __new_addr )
{
struct vm_area_struct * vma ;
unsigned long ret = - EINVAL ;
unsigned long new_addr = __new_addr ;
2006-03-17 17:33:56 -08:00
if ( old_len > STACK_TOP32 | | new_len > STACK_TOP32 )
2005-04-16 15:20:36 -07:00
goto out ;
2006-03-17 17:33:56 -08:00
if ( addr > STACK_TOP32 - old_len )
2005-04-16 15:20:36 -07:00
goto out ;
down_write ( & current - > mm - > mmap_sem ) ;
if ( flags & MREMAP_FIXED ) {
2006-03-17 17:33:56 -08:00
if ( new_addr > STACK_TOP32 - new_len )
2005-04-16 15:20:36 -07:00
goto out_sem ;
2006-03-17 17:33:56 -08:00
} else if ( addr > STACK_TOP32 - new_len ) {
2005-04-16 15:20:36 -07:00
unsigned long map_flags = 0 ;
struct file * file = NULL ;
ret = - ENOMEM ;
if ( ! ( flags & MREMAP_MAYMOVE ) )
goto out_sem ;
vma = find_vma ( current - > mm , addr ) ;
if ( vma ) {
if ( vma - > vm_flags & VM_SHARED )
map_flags | = MAP_SHARED ;
file = vma - > vm_file ;
}
/* MREMAP_FIXED checked above. */
new_addr = get_unmapped_area ( file , addr , new_len ,
vma ? vma - > vm_pgoff : 0 ,
map_flags ) ;
ret = new_addr ;
if ( new_addr & ~ PAGE_MASK )
goto out_sem ;
flags | = MREMAP_FIXED ;
}
ret = do_mremap ( addr , old_len , new_len , flags , new_addr ) ;
out_sem :
up_write ( & current - > mm - > mmap_sem ) ;
out :
return ret ;
}
struct __sysctl_args32 {
u32 name ;
int nlen ;
u32 oldval ;
u32 oldlenp ;
u32 newval ;
u32 newlen ;
u32 __unused [ 4 ] ;
} ;
asmlinkage long sys32_sysctl ( struct __sysctl_args32 __user * args )
{
2006-09-27 01:51:04 -07:00
# ifndef CONFIG_SYSCTL_SYSCALL
2005-04-16 15:20:36 -07:00
return - ENOSYS ;
# else
struct __sysctl_args32 tmp ;
int error ;
size_t oldlen , __user * oldlenp = NULL ;
unsigned long addr = ( ( ( unsigned long ) & args - > __unused [ 0 ] ) + 7UL ) & ~ 7UL ;
if ( copy_from_user ( & tmp , args , sizeof ( tmp ) ) )
return - EFAULT ;
if ( tmp . oldval & & tmp . oldlenp ) {
/* Duh, this is ugly and might not work if sysctl_args
is in read - only memory , but do_sysctl does indirectly
a lot of uaccess in both directions and we ' d have to
basically copy the whole sysctl . c here , and
glibc ' s __sysctl uses rw memory for the structure
anyway . */
if ( get_user ( oldlen , ( u32 __user * ) ( unsigned long ) tmp . oldlenp ) | |
put_user ( oldlen , ( size_t __user * ) addr ) )
return - EFAULT ;
oldlenp = ( size_t __user * ) addr ;
}
lock_kernel ( ) ;
error = do_sysctl ( ( int __user * ) ( unsigned long ) tmp . name ,
tmp . nlen ,
( void __user * ) ( unsigned long ) tmp . oldval ,
oldlenp ,
( void __user * ) ( unsigned long ) tmp . newval ,
tmp . newlen ) ;
unlock_kernel ( ) ;
if ( oldlenp ) {
if ( ! error ) {
if ( get_user ( oldlen , ( size_t __user * ) addr ) | |
put_user ( oldlen , ( u32 __user * ) ( unsigned long ) tmp . oldlenp ) )
error = - EFAULT ;
}
if ( copy_to_user ( args - > __unused , tmp . __unused , sizeof ( tmp . __unused ) ) )
error = - EFAULT ;
}
return error ;
# endif
}
long sys32_lookup_dcookie ( unsigned long cookie_high ,
unsigned long cookie_low ,
char __user * buf , size_t len )
{
return sys_lookup_dcookie ( ( cookie_high < < 32 ) | cookie_low ,
buf , len ) ;
}
2006-03-31 23:49:34 -08:00
long compat_sync_file_range ( int fd , unsigned long off_high , unsigned long off_low , unsigned long nb_high , unsigned long nb_low , int flags )
{
return sys_sync_file_range ( fd ,
( off_high < < 32 ) | off_low ,
( nb_high < < 32 ) | nb_low ,
flags ) ;
}