/* * Implements HPUX syscalls. * * Copyright (C) 1999 Matthew Wilcox * Copyright (C) 2000 Michael Ang * Copyright (C) 2000 John Marvin * 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 #include #include #include #include #include #include #include int hpux_execve(struct pt_regs *regs) { int error; char *filename; filename = getname((char __user *) regs->gr[26]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = do_execve(filename, (char __user * __user *) regs->gr[25], (char __user * __user *) regs->gr[24], regs); if (error == 0) { task_lock(current); current->ptrace &= ~PT_DTRACE; task_unlock(current); } 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) return -EOVERFLOW; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; buf->previous = dirent; 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); dirent = (void __user *)dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; } #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) goto out_putf; error = buf.error; lastdirent = buf.previous; if (lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = count - buf.count; } out_putf: 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(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(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; }