1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/conf.h> 33 #include <sys/dirent.h> 34 #include <sys/file.h> 35 #include <sys/filedesc.h> 36 #include <sys/proc.h> 37 #include <sys/mount.h> 38 #include <sys/namei.h> 39 #include <sys/stat.h> 40 #include <sys/systm.h> 41 #include <sys/vnode.h> 42 43 #include <machine/../linux/linux.h> 44 #ifdef __alpha__ 45 #include <linux_proto.h> 46 #else 47 #include <machine/../linux/linux_proto.h> 48 #endif 49 #include <compat/linux/linux_util.h> 50 51 struct linux_newstat { 52 #ifdef __alpha__ 53 u_int stat_dev; 54 u_int stat_ino; 55 u_int stat_mode; 56 u_int stat_nlink; 57 u_int stat_uid; 58 u_int stat_gid; 59 u_int stat_rdev; 60 long stat_size; 61 u_long stat_atime; 62 u_long stat_mtime; 63 u_long stat_ctime; 64 u_int stat_blksize; 65 int stat_blocks; 66 u_int stat_flags; 67 u_int stat_gen; 68 #else 69 u_short stat_dev; 70 u_short __pad1; 71 u_long stat_ino; 72 u_short stat_mode; 73 u_short stat_nlink; 74 u_short stat_uid; 75 u_short stat_gid; 76 u_short stat_rdev; 77 u_short __pad2; 78 u_long stat_size; 79 u_long stat_blksize; 80 u_long stat_blocks; 81 u_long stat_atime; 82 u_long __unused1; 83 u_long stat_mtime; 84 u_long __unused2; 85 u_long stat_ctime; 86 u_long __unused3; 87 u_long __unused4; 88 u_long __unused5; 89 #endif 90 }; 91 92 93 struct linux_ustat 94 { 95 int f_tfree; 96 u_long f_tinode; 97 char f_fname[6]; 98 char f_fpack[6]; 99 }; 100 101 static int 102 newstat_copyout(struct stat *buf, void *ubuf) 103 { 104 struct linux_newstat tbuf; 105 106 tbuf.stat_dev = uminor(buf->st_dev) | (umajor(buf->st_dev) << 8); 107 tbuf.stat_ino = buf->st_ino; 108 tbuf.stat_mode = buf->st_mode; 109 tbuf.stat_nlink = buf->st_nlink; 110 tbuf.stat_uid = buf->st_uid; 111 tbuf.stat_gid = buf->st_gid; 112 tbuf.stat_rdev = buf->st_rdev; 113 tbuf.stat_size = buf->st_size; 114 tbuf.stat_atime = buf->st_atime; 115 tbuf.stat_mtime = buf->st_mtime; 116 tbuf.stat_ctime = buf->st_ctime; 117 tbuf.stat_blksize = buf->st_blksize; 118 tbuf.stat_blocks = buf->st_blocks; 119 120 return (copyout(&tbuf, ubuf, sizeof(tbuf))); 121 } 122 123 int 124 linux_newstat(struct proc *p, struct linux_newstat_args *args) 125 { 126 struct stat buf; 127 struct nameidata nd; 128 int error; 129 caddr_t sg; 130 131 sg = stackgap_init(); 132 CHECKALTEXIST(p, &sg, args->path); 133 134 #ifdef DEBUG 135 printf("Linux-emul(%ld): newstat(%s, *)\n", (long)p->p_pid, 136 args->path); 137 #endif 138 139 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 140 args->path, p); 141 error = namei(&nd); 142 if (error) 143 return (error); 144 NDFREE(&nd, NDF_ONLY_PNBUF); 145 146 error = vn_stat(nd.ni_vp, &buf, p); 147 vput(nd.ni_vp); 148 if (error) 149 return (error); 150 151 return (newstat_copyout(&buf, args->buf)); 152 } 153 154 /* 155 * Get file status; this version does not follow links. 156 */ 157 int 158 linux_newlstat(p, uap) 159 struct proc *p; 160 struct linux_newlstat_args *uap; 161 { 162 int error; 163 struct vnode *vp; 164 struct stat sb; 165 struct nameidata nd; 166 caddr_t sg; 167 168 sg = stackgap_init(); 169 CHECKALTEXIST(p, &sg, uap->path); 170 171 #ifdef DEBUG 172 printf("Linux-emul(%ld): newlstat(%s, *)\n", (long)p->p_pid, 173 uap->path); 174 #endif 175 176 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 177 uap->path, p); 178 error = namei(&nd); 179 if (error) 180 return (error); 181 NDFREE(&nd, NDF_ONLY_PNBUF); 182 183 vp = nd.ni_vp; 184 error = vn_stat(vp, &sb, p); 185 vput(vp); 186 if (error) 187 return (error); 188 189 return (newstat_copyout(&sb, uap->buf)); 190 } 191 192 int 193 linux_newfstat(struct proc *p, struct linux_newfstat_args *args) 194 { 195 struct filedesc *fdp; 196 struct file *fp; 197 struct stat buf; 198 int error; 199 200 fdp = p->p_fd; 201 202 #ifdef DEBUG 203 printf("Linux-emul(%ld): newfstat(%d, *)\n", (long)p->p_pid, args->fd); 204 #endif 205 206 if ((unsigned)args->fd >= fdp->fd_nfiles || 207 (fp = fdp->fd_ofiles[args->fd]) == NULL) 208 return (EBADF); 209 210 error = fo_stat(fp, &buf, p); 211 if (!error) 212 error = newstat_copyout(&buf, args->buf); 213 214 return (error); 215 } 216 217 struct linux_statfs_buf { 218 int ftype; 219 int fbsize; 220 int fblocks; 221 int fbfree; 222 int fbavail; 223 int ffiles; 224 int fffree; 225 linux_fsid_t ffsid; 226 int fnamelen; 227 int fspare[6]; 228 }; 229 230 #ifndef VT_NWFS 231 #define VT_NWFS VT_TFS /* XXX - bug compatibility with sys/nwfs/nwfs_node.h */ 232 #endif 233 234 #define LINUX_CODA_SUPER_MAGIC 0x73757245L 235 #define LINUX_EXT2_SUPER_MAGIC 0xEF53L 236 #define LINUX_HPFS_SUPER_MAGIC 0xf995e849L 237 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L 238 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L 239 #define LINUX_NCP_SUPER_MAGIC 0x564cL 240 #define LINUX_NFS_SUPER_MAGIC 0x6969L 241 #define LINUX_NTFS_SUPER_MAGIC 0x5346544EL 242 #define LINUX_PROC_SUPER_MAGIC 0x9fa0L 243 #define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ 244 245 /* 246 * ext2fs uses the VT_UFS tag. A mounted ext2 filesystem will therefore 247 * be seen as an ufs/mfs filesystem. 248 */ 249 static long 250 bsd_to_linux_ftype(int tag) 251 { 252 253 switch (tag) { 254 case VT_CODA: 255 return (LINUX_CODA_SUPER_MAGIC); 256 case VT_HPFS: 257 return (LINUX_HPFS_SUPER_MAGIC); 258 case VT_ISOFS: 259 return (LINUX_ISOFS_SUPER_MAGIC); 260 case VT_MFS: 261 return (LINUX_UFS_SUPER_MAGIC); 262 case VT_MSDOSFS: 263 return (LINUX_MSDOS_SUPER_MAGIC); 264 case VT_NFS: 265 return (LINUX_NFS_SUPER_MAGIC); 266 case VT_NTFS: 267 return (LINUX_NTFS_SUPER_MAGIC); 268 case VT_NWFS: 269 return (LINUX_NCP_SUPER_MAGIC); 270 case VT_PROCFS: 271 return (LINUX_PROC_SUPER_MAGIC); 272 case VT_UFS: 273 return (LINUX_UFS_SUPER_MAGIC); 274 } 275 276 return (0L); 277 } 278 279 int 280 linux_statfs(struct proc *p, struct linux_statfs_args *args) 281 { 282 struct mount *mp; 283 struct nameidata *ndp; 284 struct statfs *bsd_statfs; 285 struct nameidata nd; 286 struct linux_statfs_buf linux_statfs_buf; 287 int error; 288 caddr_t sg; 289 290 sg = stackgap_init(); 291 CHECKALTEXIST(p, &sg, args->path); 292 293 #ifdef DEBUG 294 printf("Linux-emul(%d): statfs(%s, *)\n", p->p_pid, args->path); 295 #endif 296 ndp = &nd; 297 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args->path, curproc); 298 error = namei(ndp); 299 if (error) 300 return error; 301 NDFREE(ndp, NDF_ONLY_PNBUF); 302 mp = ndp->ni_vp->v_mount; 303 bsd_statfs = &mp->mnt_stat; 304 vrele(ndp->ni_vp); 305 error = VFS_STATFS(mp, bsd_statfs, p); 306 if (error) 307 return error; 308 bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 309 linux_statfs_buf.ftype = bsd_to_linux_ftype(bsd_statfs->f_type); 310 linux_statfs_buf.fbsize = bsd_statfs->f_bsize; 311 linux_statfs_buf.fblocks = bsd_statfs->f_blocks; 312 linux_statfs_buf.fbfree = bsd_statfs->f_bfree; 313 linux_statfs_buf.fbavail = bsd_statfs->f_bavail; 314 linux_statfs_buf.fffree = bsd_statfs->f_ffree; 315 linux_statfs_buf.ffiles = bsd_statfs->f_files; 316 linux_statfs_buf.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; 317 linux_statfs_buf.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; 318 linux_statfs_buf.fnamelen = MAXNAMLEN; 319 return copyout((caddr_t)&linux_statfs_buf, (caddr_t)args->buf, 320 sizeof(struct linux_statfs_buf)); 321 } 322 323 int 324 linux_fstatfs(struct proc *p, struct linux_fstatfs_args *args) 325 { 326 struct file *fp; 327 struct mount *mp; 328 struct statfs *bsd_statfs; 329 struct linux_statfs_buf linux_statfs_buf; 330 int error; 331 332 #ifdef DEBUG 333 printf("Linux-emul(%d): fstatfs(%d, *)\n", p->p_pid, args->fd); 334 #endif 335 error = getvnode(p->p_fd, args->fd, &fp); 336 if (error) 337 return error; 338 mp = ((struct vnode *)fp->f_data)->v_mount; 339 bsd_statfs = &mp->mnt_stat; 340 error = VFS_STATFS(mp, bsd_statfs, p); 341 if (error) 342 return error; 343 bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 344 linux_statfs_buf.ftype = bsd_to_linux_ftype(bsd_statfs->f_type); 345 linux_statfs_buf.fbsize = bsd_statfs->f_bsize; 346 linux_statfs_buf.fblocks = bsd_statfs->f_blocks; 347 linux_statfs_buf.fbfree = bsd_statfs->f_bfree; 348 linux_statfs_buf.fbavail = bsd_statfs->f_bavail; 349 linux_statfs_buf.fffree = bsd_statfs->f_ffree; 350 linux_statfs_buf.ffiles = bsd_statfs->f_files; 351 linux_statfs_buf.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; 352 linux_statfs_buf.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; 353 linux_statfs_buf.fnamelen = MAXNAMLEN; 354 return copyout((caddr_t)&linux_statfs_buf, (caddr_t)args->buf, 355 sizeof(struct linux_statfs_buf)); 356 } 357 358 int 359 linux_ustat(p, uap) 360 struct proc *p; 361 struct linux_ustat_args *uap; 362 { 363 struct linux_ustat lu; 364 dev_t dev; 365 struct vnode *vp; 366 struct statfs *stat; 367 int error; 368 369 #ifdef DEBUG 370 printf("Linux-emul(%ld): ustat(%d, *)\n", (long)p->p_pid, uap->dev); 371 #endif 372 373 /* 374 * lu.f_fname and lu.f_fpack are not used. They are always zeroed. 375 * lu.f_tinode and lu.f_tfree are set from the device's super block. 376 */ 377 bzero(&lu, sizeof(lu)); 378 379 /* 380 * XXX - Don't return an error if we can't find a vnode for the 381 * device. Our dev_t is 32-bits whereas Linux only has a 16-bits 382 * dev_t. The dev_t that is used now may as well be a truncated 383 * dev_t returned from previous syscalls. Just return a bzeroed 384 * ustat in that case. 385 */ 386 dev = makedev(uap->dev >> 8, uap->dev & 0xFF); 387 if (vfinddev(dev, VCHR, &vp)) { 388 if (vp->v_mount == NULL) 389 return (EINVAL); 390 stat = &(vp->v_mount->mnt_stat); 391 error = VFS_STATFS(vp->v_mount, stat, p); 392 if (error) 393 return (error); 394 395 lu.f_tfree = stat->f_bfree; 396 lu.f_tinode = stat->f_ffree; 397 } 398 399 return (copyout(&lu, uap->ubuf, sizeof(lu))); 400 } 401