4 * Kernel compatibililty routines for e.g. 32 bit syscall support
7 * Copyright (C) 2002 Stephen Rothwell, IBM Corporation
8 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
9 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
10 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
11 * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
18 #include <linux/linkage.h>
19 #include <linux/compat.h>
20 #include <linux/errno.h>
21 #include <linux/time.h>
23 #include <linux/fcntl.h>
24 #include <linux/namei.h>
25 #include <linux/file.h>
26 #include <linux/vfs.h>
27 #include <linux/ioctl32.h>
28 #include <linux/init.h>
29 #include <linux/sockios.h> /* for SIOCDEVPRIVATE */
31 #include <linux/smp_lock.h>
32 #include <linux/ctype.h>
33 #include <linux/module.h>
34 #include <net/sock.h> /* siocdevprivate_ioctl */
36 #include <asm/uaccess.h>
39 * Not all architectures have sys_utime, so implement this in terms
42 asmlinkage
long compat_sys_utime(char *filename
, struct compat_utimbuf
*t
)
47 if (get_user(tv
[0].tv_sec
, &t
->actime
) ||
48 get_user(tv
[1].tv_sec
, &t
->modtime
))
53 return do_utimes(filename
, t
? tv
: NULL
);
57 asmlinkage
long compat_sys_newstat(char * filename
,
58 struct compat_stat
*statbuf
)
61 int error
= vfs_stat(filename
, &stat
);
64 error
= cp_compat_stat(&stat
, statbuf
);
68 asmlinkage
long compat_sys_newlstat(char * filename
,
69 struct compat_stat
*statbuf
)
72 int error
= vfs_lstat(filename
, &stat
);
75 error
= cp_compat_stat(&stat
, statbuf
);
79 asmlinkage
long compat_sys_newfstat(unsigned int fd
,
80 struct compat_stat
* statbuf
)
83 int error
= vfs_fstat(fd
, &stat
);
86 error
= cp_compat_stat(&stat
, statbuf
);
90 static int put_compat_statfs(struct compat_statfs
*ubuf
, struct kstatfs
*kbuf
)
93 if (sizeof ubuf
->f_blocks
== 4) {
94 if ((kbuf
->f_blocks
| kbuf
->f_bfree
|
95 kbuf
->f_bavail
| kbuf
->f_files
| kbuf
->f_ffree
) &
96 0xffffffff00000000ULL
)
99 if (verify_area(VERIFY_WRITE
, ubuf
, sizeof(*ubuf
)) ||
100 __put_user(kbuf
->f_type
, &ubuf
->f_type
) ||
101 __put_user(kbuf
->f_bsize
, &ubuf
->f_bsize
) ||
102 __put_user(kbuf
->f_blocks
, &ubuf
->f_blocks
) ||
103 __put_user(kbuf
->f_bfree
, &ubuf
->f_bfree
) ||
104 __put_user(kbuf
->f_bavail
, &ubuf
->f_bavail
) ||
105 __put_user(kbuf
->f_files
, &ubuf
->f_files
) ||
106 __put_user(kbuf
->f_ffree
, &ubuf
->f_ffree
) ||
107 __put_user(kbuf
->f_namelen
, &ubuf
->f_namelen
) ||
108 __put_user(kbuf
->f_fsid
.val
[0], &ubuf
->f_fsid
.val
[0]) ||
109 __put_user(kbuf
->f_fsid
.val
[1], &ubuf
->f_fsid
.val
[1]) ||
110 __put_user(kbuf
->f_frsize
, &ubuf
->f_frsize
))
116 * The following statfs calls are copies of code from fs/open.c and
117 * should be checked against those from time to time
119 asmlinkage
long compat_sys_statfs(const char *path
, struct compat_statfs
*buf
)
124 error
= user_path_walk(path
, &nd
);
127 error
= vfs_statfs(nd
.dentry
->d_inode
->i_sb
, &tmp
);
128 if (!error
&& put_compat_statfs(buf
, &tmp
))
135 asmlinkage
long compat_sys_fstatfs(unsigned int fd
, struct compat_statfs
*buf
)
145 error
= vfs_statfs(file
->f_dentry
->d_inode
->i_sb
, &tmp
);
146 if (!error
&& put_compat_statfs(buf
, &tmp
))
154 /* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64 */
156 #define IOCTL_HASHSIZE 256
157 struct ioctl_trans
*ioctl32_hash_table
[IOCTL_HASHSIZE
];
159 extern struct ioctl_trans ioctl_start
[], ioctl_end
[];
161 static inline unsigned long ioctl32_hash(unsigned long cmd
)
163 return (((cmd
>> 6) ^ (cmd
>> 4) ^ cmd
)) % IOCTL_HASHSIZE
;
166 static void ioctl32_insert_translation(struct ioctl_trans
*trans
)
169 struct ioctl_trans
*t
;
171 hash
= ioctl32_hash (trans
->cmd
);
172 if (!ioctl32_hash_table
[hash
])
173 ioctl32_hash_table
[hash
] = trans
;
175 t
= ioctl32_hash_table
[hash
];
183 static int __init
init_sys32_ioctl(void)
187 for (i
= 0; &ioctl_start
[i
] < &ioctl_end
[0]; i
++) {
188 if (ioctl_start
[i
].next
!= 0) {
189 printk("ioctl translation %d bad\n",i
);
193 ioctl32_insert_translation(&ioctl_start
[i
]);
198 __initcall(init_sys32_ioctl
);
200 static struct ioctl_trans
*ioctl_free_list
;
202 /* Never free them really. This avoids SMP races. With a Read-Copy-Update
203 enabled kernel we could just use the RCU infrastructure for this. */
204 static void free_ioctl(struct ioctl_trans
*t
)
208 t
->next
= ioctl_free_list
;
212 int register_ioctl32_conversion(unsigned int cmd
, int (*handler
)(unsigned int, unsigned int, unsigned long, struct file
*))
214 struct ioctl_trans
*t
;
215 unsigned long hash
= ioctl32_hash(cmd
);
218 for (t
= (struct ioctl_trans
*)ioctl32_hash_table
[hash
];
222 printk("Trying to register duplicated ioctl32 handler %x\n", cmd
);
228 if (ioctl_free_list
) {
230 ioctl_free_list
= t
->next
;
232 t
= kmalloc(sizeof(struct ioctl_trans
), GFP_KERNEL
);
241 t
->handler
= handler
;
242 ioctl32_insert_translation(t
);
248 static inline int builtin_ioctl(struct ioctl_trans
*t
)
250 return t
>= (struct ioctl_trans
*)ioctl_start
&&
251 t
< (struct ioctl_trans
*)ioctl_end
;
255 This function cannot unregister duplicate ioctls, because they are not
257 When they happen we need to extend the prototype to pass the handler too. */
259 int unregister_ioctl32_conversion(unsigned int cmd
)
261 unsigned long hash
= ioctl32_hash(cmd
);
262 struct ioctl_trans
*t
, *t1
;
266 t
= (struct ioctl_trans
*)ioctl32_hash_table
[hash
];
273 if (builtin_ioctl(t
)) {
274 printk("%p tried to unregister builtin ioctl %x\n",
275 __builtin_return_address(0), cmd
);
277 ioctl32_hash_table
[hash
] = t
->next
;
284 t1
= (struct ioctl_trans
*)(long)t
->next
;
285 if (t1
->cmd
== cmd
) {
286 if (builtin_ioctl(t1
)) {
287 printk("%p tried to unregister builtin ioctl %x\n",
288 __builtin_return_address(0), cmd
);
299 printk(KERN_ERR
"Trying to free unknown 32bit ioctl handler %x\n", cmd
);
305 EXPORT_SYMBOL(register_ioctl32_conversion
);
306 EXPORT_SYMBOL(unregister_ioctl32_conversion
);
308 asmlinkage
long compat_sys_ioctl(unsigned int fd
, unsigned int cmd
, unsigned long arg
)
312 struct ioctl_trans
*t
;
318 if (!filp
->f_op
|| !filp
->f_op
->ioctl
) {
319 error
= sys_ioctl (fd
, cmd
, arg
);
323 t
= (struct ioctl_trans
*)ioctl32_hash_table
[ioctl32_hash (cmd
)];
325 while (t
&& t
->cmd
!= cmd
)
326 t
= (struct ioctl_trans
*)t
->next
;
329 error
= t
->handler(fd
, cmd
, arg
, filp
);
331 error
= sys_ioctl(fd
, cmd
, arg
);
332 } else if (cmd
>= SIOCDEVPRIVATE
&& cmd
<= (SIOCDEVPRIVATE
+ 15)) {
333 error
= siocdevprivate_ioctl(fd
, cmd
, arg
);
338 char *path
= (char *)__get_free_page(GFP_KERNEL
), *fn
= "?";
340 /* find the name of the device. */
342 fn
= d_path(filp
->f_dentry
, filp
->f_vfsmnt
,
346 sprintf(buf
,"'%c'", (cmd
>>24) & 0x3f);
347 if (!isprint(buf
[1]))
348 sprintf(buf
, "%02x", buf
[1]);
349 printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
350 "cmd(%08x){%s} arg(%08x) on %s\n",
351 current
->comm
, current
->pid
,
352 (int)fd
, (unsigned int)cmd
, buf
, (unsigned int)arg
,
355 free_page((unsigned long)path
);
365 static int get_compat_flock(struct flock
*kfl
, struct compat_flock
*ufl
)
367 if (!access_ok(VERIFY_READ
, ufl
, sizeof(*ufl
)) ||
368 __get_user(kfl
->l_type
, &ufl
->l_type
) ||
369 __get_user(kfl
->l_whence
, &ufl
->l_whence
) ||
370 __get_user(kfl
->l_start
, &ufl
->l_start
) ||
371 __get_user(kfl
->l_len
, &ufl
->l_len
) ||
372 __get_user(kfl
->l_pid
, &ufl
->l_pid
))
377 static int put_compat_flock(struct flock
*kfl
, struct compat_flock
*ufl
)
379 if (!access_ok(VERIFY_WRITE
, ufl
, sizeof(*ufl
)) ||
380 __put_user(kfl
->l_type
, &ufl
->l_type
) ||
381 __put_user(kfl
->l_whence
, &ufl
->l_whence
) ||
382 __put_user(kfl
->l_start
, &ufl
->l_start
) ||
383 __put_user(kfl
->l_len
, &ufl
->l_len
) ||
384 __put_user(kfl
->l_pid
, &ufl
->l_pid
))
389 #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
390 static int get_compat_flock64(struct flock
*kfl
, struct compat_flock64
*ufl
)
392 if (!access_ok(VERIFY_READ
, ufl
, sizeof(*ufl
)) ||
393 __get_user(kfl
->l_type
, &ufl
->l_type
) ||
394 __get_user(kfl
->l_whence
, &ufl
->l_whence
) ||
395 __get_user(kfl
->l_start
, &ufl
->l_start
) ||
396 __get_user(kfl
->l_len
, &ufl
->l_len
) ||
397 __get_user(kfl
->l_pid
, &ufl
->l_pid
))
403 #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
404 static int put_compat_flock64(struct flock
*kfl
, struct compat_flock64
*ufl
)
406 if (!access_ok(VERIFY_WRITE
, ufl
, sizeof(*ufl
)) ||
407 __put_user(kfl
->l_type
, &ufl
->l_type
) ||
408 __put_user(kfl
->l_whence
, &ufl
->l_whence
) ||
409 __put_user(kfl
->l_start
, &ufl
->l_start
) ||
410 __put_user(kfl
->l_len
, &ufl
->l_len
) ||
411 __put_user(kfl
->l_pid
, &ufl
->l_pid
))
417 extern asmlinkage
long sys_fcntl(unsigned int, unsigned int, unsigned long);
419 asmlinkage
long compat_sys_fcntl64(unsigned int fd
, unsigned int cmd
,
430 ret
= get_compat_flock(&f
, compat_ptr(arg
));
435 ret
= sys_fcntl(fd
, cmd
, (unsigned long)&f
);
437 if ((cmd
== F_GETLK
) && (ret
== 0)) {
438 if ((f
.l_start
>= COMPAT_OFF_T_MAX
) ||
439 ((f
.l_start
+ f
.l_len
) >= COMPAT_OFF_T_MAX
))
442 ret
= put_compat_flock(&f
, compat_ptr(arg
));
449 ret
= get_compat_flock64(&f
, compat_ptr(arg
));
454 ret
= sys_fcntl(fd
, (cmd
== F_GETLK64
) ? F_GETLK
:
455 ((cmd
== F_SETLK64
) ? F_SETLK
: F_SETLKW
),
458 if ((cmd
== F_GETLK64
) && (ret
== 0)) {
459 if ((f
.l_start
>= COMPAT_LOFF_T_MAX
) ||
460 ((f
.l_start
+ f
.l_len
) >= COMPAT_LOFF_T_MAX
))
463 ret
= put_compat_flock64(&f
, compat_ptr(arg
));
468 ret
= sys_fcntl(fd
, cmd
, arg
);
474 asmlinkage
long compat_sys_fcntl(unsigned int fd
, unsigned int cmd
,
477 if ((cmd
== F_GETLK64
) || (cmd
== F_SETLK64
) || (cmd
== F_SETLKW64
))
479 return compat_sys_fcntl64(fd
, cmd
, arg
);