d7627467b7
Make do_execve() take a const filename pointer so that kernel_execve() compiles correctly on ARM: arch/arm/kernel/sys_arm.c:88: warning: passing argument 1 of 'do_execve' discards qualifiers from pointer target type This also requires the argv and envp arguments to be consted twice, once for the pointer array and once for the strings the array points to. This is because do_execve() passes a pointer to the filename (now const) to copy_strings_kernel(). A simpler alternative would be to cast the filename pointer in do_execve() when it's passed to copy_strings_kernel(). do_execve() may not change any of the strings it is passed as part of the argv or envp lists as they are some of them in .rodata, so marking these strings as const should be fine. Further kernel_execve() and sys_execve() need to be changed to match. This has been test built on x86_64, frv, arm and mips. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Ralf Baechle <ralf@linux-mips.org> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
207 lines
5.0 KiB
C
207 lines
5.0 KiB
C
/*
|
|
* Implements HPUX syscalls.
|
|
*
|
|
* Copyright (C) 1999 Matthew Wilcox <willy with parisc-linux.org>
|
|
* Copyright (C) 2000 Michael Ang <mang with subcarrier.org>
|
|
* Copyright (C) 2000 John Marvin <jsm with parisc-linux.org>
|
|
* Copyright (C) 2000 Philipp Rumpf
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/file.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/slab.h>
|
|
#include <asm/errno.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
int hpux_execve(struct pt_regs *regs)
|
|
{
|
|
int error;
|
|
char *filename;
|
|
|
|
filename = getname((const char __user *) regs->gr[26]);
|
|
error = PTR_ERR(filename);
|
|
if (IS_ERR(filename))
|
|
goto out;
|
|
|
|
error = do_execve(filename,
|
|
(const char __user *const __user *) regs->gr[25],
|
|
(const char __user *const __user *) regs->gr[24],
|
|
regs);
|
|
|
|
putname(filename);
|
|
|
|
out:
|
|
return error;
|
|
}
|
|
|
|
struct hpux_dirent {
|
|
loff_t d_off;
|
|
ino_t d_ino;
|
|
short d_reclen;
|
|
short d_namlen;
|
|
char d_name[1];
|
|
};
|
|
|
|
struct getdents_callback {
|
|
struct hpux_dirent __user *current_dir;
|
|
struct hpux_dirent __user *previous;
|
|
int count;
|
|
int error;
|
|
};
|
|
|
|
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
|
|
|
|
static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
|
|
u64 ino, unsigned d_type)
|
|
{
|
|
struct hpux_dirent __user * dirent;
|
|
struct getdents_callback * buf = (struct getdents_callback *) __buf;
|
|
ino_t d_ino;
|
|
int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 1, sizeof(long));
|
|
|
|
buf->error = -EINVAL; /* only used if we fail.. */
|
|
if (reclen > buf->count)
|
|
return -EINVAL;
|
|
d_ino = ino;
|
|
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
|
|
buf->error = -EOVERFLOW;
|
|
return -EOVERFLOW;
|
|
}
|
|
dirent = buf->previous;
|
|
if (dirent)
|
|
if (put_user(offset, &dirent->d_off))
|
|
goto Efault;
|
|
dirent = buf->current_dir;
|
|
if (put_user(d_ino, &dirent->d_ino) ||
|
|
put_user(reclen, &dirent->d_reclen) ||
|
|
put_user(namlen, &dirent->d_namlen) ||
|
|
copy_to_user(dirent->d_name, name, namlen) ||
|
|
put_user(0, dirent->d_name + namlen))
|
|
goto Efault;
|
|
buf->previous = dirent;
|
|
buf->current_dir = (void __user *)dirent + reclen;
|
|
buf->count -= reclen;
|
|
return 0;
|
|
Efault:
|
|
buf->error = -EFAULT;
|
|
return -EFAULT;
|
|
}
|
|
|
|
#undef NAME_OFFSET
|
|
|
|
int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned int count)
|
|
{
|
|
struct file * file;
|
|
struct hpux_dirent __user * lastdirent;
|
|
struct getdents_callback buf;
|
|
int error = -EBADF;
|
|
|
|
file = fget(fd);
|
|
if (!file)
|
|
goto out;
|
|
|
|
buf.current_dir = dirent;
|
|
buf.previous = NULL;
|
|
buf.count = count;
|
|
buf.error = 0;
|
|
|
|
error = vfs_readdir(file, filldir, &buf);
|
|
if (error >= 0)
|
|
error = buf.error;
|
|
lastdirent = buf.previous;
|
|
if (lastdirent) {
|
|
if (put_user(file->f_pos, &lastdirent->d_off))
|
|
error = -EFAULT;
|
|
else
|
|
error = count - buf.count;
|
|
}
|
|
|
|
fput(file);
|
|
out:
|
|
return error;
|
|
}
|
|
|
|
int hpux_mount(const char *fs, const char *path, int mflag,
|
|
const char *fstype, const char *dataptr, int datalen)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 __user *statbuf)
|
|
{
|
|
struct hpux_stat64 tmp;
|
|
|
|
/* we probably want a different split here - is hpux 12:20? */
|
|
|
|
if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev))
|
|
return -EOVERFLOW;
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
tmp.st_dev = new_encode_dev(stat->dev);
|
|
tmp.st_ino = stat->ino;
|
|
tmp.st_mode = stat->mode;
|
|
tmp.st_nlink = stat->nlink;
|
|
tmp.st_uid = stat->uid;
|
|
tmp.st_gid = stat->gid;
|
|
tmp.st_rdev = new_encode_dev(stat->rdev);
|
|
tmp.st_size = stat->size;
|
|
tmp.st_atime = stat->atime.tv_sec;
|
|
tmp.st_mtime = stat->mtime.tv_sec;
|
|
tmp.st_ctime = stat->ctime.tv_sec;
|
|
tmp.st_blocks = stat->blocks;
|
|
tmp.st_blksize = stat->blksize;
|
|
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
|
|
}
|
|
|
|
long hpux_stat64(const char __user *filename, struct hpux_stat64 __user *statbuf)
|
|
{
|
|
struct kstat stat;
|
|
int error = vfs_stat(filename, &stat);
|
|
|
|
if (!error)
|
|
error = cp_hpux_stat(&stat, statbuf);
|
|
|
|
return error;
|
|
}
|
|
|
|
long hpux_fstat64(unsigned int fd, struct hpux_stat64 __user *statbuf)
|
|
{
|
|
struct kstat stat;
|
|
int error = vfs_fstat(fd, &stat);
|
|
|
|
if (!error)
|
|
error = cp_hpux_stat(&stat, statbuf);
|
|
|
|
return error;
|
|
}
|
|
|
|
long hpux_lstat64(const char __user *filename,
|
|
struct hpux_stat64 __user *statbuf)
|
|
{
|
|
struct kstat stat;
|
|
int error = vfs_lstat(filename, &stat);
|
|
|
|
if (!error)
|
|
error = cp_hpux_stat(&stat, statbuf);
|
|
|
|
return error;
|
|
}
|