MFC (4 of X):

- don't limit number of syscalls to 255
 - handle more socket options
 - bug-/compatibility-fixes to linux
   * file related (includes fixes which prevent creation of strange files
     which can only be removed with a fsck)
   * make ping work
   * ...
 - add devfs to the file system type handling/translation

Compile tested by:	scf (i386, as part of a mega-MFC-patch)
Tested by:		Arno J. Klaassen <arno@heho.snv.jussieu.fr> (amd64)
This commit is contained in:
netchild 2007-07-08 09:04:44 +00:00
parent 47a37c3274
commit 962e1e6836
6 changed files with 117 additions and 32 deletions

View File

@ -974,7 +974,7 @@ linux32_fixlimit(struct rlimit *rl, int which)
struct sysentvec elf_linux_sysvec = {
LINUX_SYS_MAXSYSCALL,
linux_sysent,
0xff,
0,
LINUX_SIGTBLSZ,
bsd_to_linux_signal,
ELAST + 1,

View File

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
#include <sys/unistd.h>
#include <sys/tty.h>
#include <sys/vnode.h>
@ -268,7 +269,17 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args,
struct l_dirent64 linux_dirent64;
int buflen, error, eofflag, nbytes, justone;
u_long *cookies = NULL, *cookiep;
int ncookies;
int ncookies, vfslocked;
nbytes = args->count;
if (nbytes == 1) {
/* readdir(2) case. Always struct dirent. */
if (is64bit)
return (EINVAL);
nbytes = sizeof(linux_dirent);
justone = 1;
} else
justone = 0;
if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
return (error);
@ -279,23 +290,13 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args,
}
vp = fp->f_vnode;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
if (vp->v_type != VDIR) {
VFS_UNLOCK_GIANT(vfslocked);
fdrop(fp, td);
return (EINVAL);
}
nbytes = args->count;
if (nbytes == 1) {
/* readdir(2) case. Always struct dirent. */
if (is64bit) {
fdrop(fp, td);
return (EINVAL);
}
nbytes = sizeof(linux_dirent);
justone = 1;
} else
justone = 0;
off = fp->f_offset;
buflen = max(LINUX_DIRBLKSIZ, nbytes);
@ -448,6 +449,7 @@ out:
free(cookies, M_TEMP);
VOP_UNLOCK(vp, 0, td);
VFS_UNLOCK_GIANT(vfslocked);
fdrop(fp, td);
free(buf, M_TEMP);
return (error);
@ -487,6 +489,10 @@ linux_access(struct thread *td, struct linux_access_args *args)
char *path;
int error;
/* linux convention */
if (args->flags & ~(F_OK | X_OK | W_OK | R_OK))
return (EINVAL);
LCONVPATHEXIST(td, args->path, &path);
#ifdef DEBUG
@ -719,12 +725,28 @@ linux_pread(td, uap)
struct linux_pread_args *uap;
{
struct pread_args bsd;
struct vnode *vp;
int error;
bsd.fd = uap->fd;
bsd.buf = uap->buf;
bsd.nbyte = uap->nbyte;
bsd.offset = uap->offset;
return pread(td, &bsd);
error = pread(td, &bsd);
if (error == 0) {
/* This seems to violate POSIX but linux does it */
if ((error = fgetvp(td, uap->fd, &vp)) != 0)
return (error);
if (vp->v_type == VDIR) {
vrele(vp);
return (EISDIR);
}
vrele(vp);
}
return (error);
}
int

View File

@ -812,6 +812,12 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
printf(ARGS(waitpid, "%d, %p, %d"),
args->pid, (void *)args->status, args->options);
#endif
/*
* this is necessary because the test in kern_wait doesn't work
* because we mess with the options here
*/
if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE))
return (EINVAL);
options = (args->options & (WNOHANG | WUNTRACED));
/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
@ -898,11 +904,34 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args)
printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
#endif
if (args->mode & S_IFIFO)
switch (args->mode & S_IFMT) {
case S_IFIFO:
case S_IFSOCK:
error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
else
break;
case S_IFCHR:
case S_IFBLK:
error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
args->dev);
break;
case S_IFDIR:
error = EPERM;
break;
case 0:
args->mode |= S_IFREG;
/* FALLTHROUGH */
case S_IFREG:
error = kern_open(td, path, UIO_SYSSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
break;
default:
error = EINVAL;
break;
}
LFREEPATH(path);
return (error);
}

View File

@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syscallsubr.h>
#include <sys/uio.h>
#include <sys/syslog.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@ -299,6 +300,20 @@ linux_to_bsd_so_sockopt(int opt)
return (SO_OOBINLINE);
case LINUX_SO_LINGER:
return (SO_LINGER);
case LINUX_SO_PEERCRED:
return (LOCAL_PEERCRED);
case LINUX_SO_RCVLOWAT:
return (SO_RCVLOWAT);
case LINUX_SO_SNDLOWAT:
return (SO_SNDLOWAT);
case LINUX_SO_RCVTIMEO:
return (SO_RCVTIMEO);
case LINUX_SO_SNDTIMEO:
return (SO_SNDTIMEO);
case LINUX_SO_TIMESTAMP:
return (SO_TIMESTAMP);
case LINUX_SO_ACCEPTCONN:
return (SO_ACCEPTCONN);
}
return (-1);
}
@ -924,11 +939,15 @@ linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
struct sockaddr * __restrict from;
socklen_t * __restrict fromlenaddr;
} */ bsd_args;
size_t len;
int error;
if ((error = copyin(args, &linux_args, sizeof(linux_args))))
return (error);
if ((error = copyin(PTRIN(linux_args.fromlen), &len, sizeof(size_t))))
return (error);
bsd_args.s = linux_args.s;
bsd_args.buf = PTRIN(linux_args.buf);
bsd_args.len = linux_args.len;
@ -970,6 +989,16 @@ linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
if (error)
return (error);
/*
* Some Linux applications (ping) define a non-NULL control data
* pointer, but a msg_controllen of 0, which is not allowed in the
* FreeBSD system call interface. NULL the msg_control pointer in
* order to handle this case. This should be checked, but allows the
* Linux ping to work.
*/
if (msg.msg_control != NULL && msg.msg_controllen == 0)
msg.msg_control = NULL;
error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
if (error)
return (error);

View File

@ -211,7 +211,8 @@ linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
#endif
error = kern_lstat(td, path, UIO_SYSSPACE, &sb);
translate_path_major_minor(td, path, &sb);
if (!error)
translate_path_major_minor(td, path, &sb);
LFREEPATH(path);
if (error)
return (error);
@ -261,6 +262,7 @@ struct l_statfs {
#define LINUX_NTFS_SUPER_MAGIC 0x5346544EL
#define LINUX_PROC_SUPER_MAGIC 0x9fa0L
#define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */
#define LINUX_DEVFS_SUPER_MAGIC 0x1373L
static long
bsd_to_linux_ftype(const char *fstypename)
@ -277,6 +279,7 @@ bsd_to_linux_ftype(const char *fstypename)
{"nwfs", LINUX_NCP_SUPER_MAGIC},
{"hpfs", LINUX_HPFS_SUPER_MAGIC},
{"coda", LINUX_CODA_SUPER_MAGIC},
{"devfs", LINUX_DEVFS_SUPER_MAGIC},
{NULL, 0L}};
for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
@ -409,18 +412,19 @@ linux_stat64(struct thread *td, struct linux_stat64_args *args)
#endif
error = kern_stat(td, filename, UIO_SYSSPACE, &buf);
if (!error && strlen(filename) > strlen("/dev/pts/") &&
!strncmp(filename, "/dev/pts/", strlen("/dev/pts/"))
&& filename[9] >= '0' && filename[9] <= '9') {
/*
* Linux checks major and minors of the slave device to make
* sure it's a pty deivce, so let's make him believe it is.
*/
buf.st_rdev = (136 << 8);
if (!error) {
if (strlen(filename) > strlen("/dev/pts/") &&
!strncmp(filename, "/dev/pts/", strlen("/dev/pts/")) &&
filename[9] >= '0' && filename[9] <= '9') {
/*
* Linux checks major and minors of the slave device
* to make sure it's a pty deivce, so let's make him
* believe it is.
*/
buf.st_rdev = (136 << 8);
} else
translate_path_major_minor(td, filename, &buf);
}
translate_path_major_minor(td, filename, &buf);
LFREEPATH(filename);
if (error)
return (error);
@ -442,7 +446,8 @@ linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
#endif
error = kern_lstat(td, filename, UIO_SYSSPACE, &sb);
translate_path_major_minor(td, filename, &sb);
if (!error)
translate_path_major_minor(td, filename, &sb);
LFREEPATH(filename);
if (error)
return (error);

View File

@ -797,7 +797,7 @@ exec_linux_setregs(struct thread *td, u_long entry,
struct sysentvec linux_sysvec = {
LINUX_SYS_MAXSYSCALL,
linux_sysent,
0xff,
0,
LINUX_SIGTBLSZ,
bsd_to_linux_signal,
ELAST + 1,
@ -826,7 +826,7 @@ struct sysentvec linux_sysvec = {
struct sysentvec elf_linux_sysvec = {
LINUX_SYS_MAXSYSCALL,
linux_sysent,
0xff,
0,
LINUX_SIGTBLSZ,
bsd_to_linux_signal,
ELAST + 1,