Convert files to UTF-8
[dragonfly.git] / sys / emulation / linux / linux_stats.c
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 without 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: src/sys/compat/linux/linux_stats.c,v 1.22.2.3 2001/11/05 19:08:23 marcel Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/conf.h>
34 #include <sys/dirent.h>
35 #include <sys/file.h>
36 #include <sys/filedesc.h>
37 #include <sys/proc.h>
38 #include <sys/mount.h>
39 #include <sys/nlookup.h>
40 #include <sys/stat.h>
41 #include <sys/sysctl.h>
42 #include <sys/systm.h>
43 #include <sys/unistd.h>
44 #include <sys/vnode.h>
45 #include <sys/device.h>
46 #include <sys/kern_syscall.h>
47 #include <emulation/43bsd/stat.h>
48
49 #include <sys/file2.h>
50 #include <sys/mplock2.h>
51
52 #include <arch_linux/linux.h>
53 #include <arch_linux/linux_proto.h>
54 #include "linux_util.h"
55
56 static int
57 newstat_copyout(struct stat *buf, void *ubuf)
58 {
59         struct l_newstat tbuf;
60         int error;
61
62         bzero(&tbuf, sizeof(tbuf));
63         tbuf.st_dev = uminor(buf->st_dev) | (umajor(buf->st_dev) << 8);
64         tbuf.st_ino = INO64TO32(buf->st_ino);
65         tbuf.st_mode = buf->st_mode;
66         tbuf.st_nlink = buf->st_nlink;
67         tbuf.st_uid = buf->st_uid;
68         tbuf.st_gid = buf->st_gid;
69         tbuf.st_rdev = buf->st_rdev;
70         tbuf.st_size = buf->st_size;
71         tbuf.st_atime = buf->st_atime;
72         tbuf.st_mtime = buf->st_mtime;
73         tbuf.st_ctime = buf->st_ctime;
74         tbuf.st_blksize = buf->st_blksize;
75         tbuf.st_blocks = buf->st_blocks;
76
77         error = copyout(&tbuf, ubuf, sizeof(tbuf));
78         return (error);
79 }
80
81 static int
82 ostat_copyout(struct stat *st, struct ostat *uaddr)
83 {
84         struct ostat ost;
85         int error;
86
87         ost.st_dev = st->st_dev;
88         ost.st_ino = st->st_ino;
89         ost.st_mode = st->st_mode;
90         ost.st_nlink = st->st_nlink;
91         ost.st_uid = st->st_uid;
92         ost.st_gid = st->st_gid;
93         ost.st_rdev = st->st_rdev;
94         if (st->st_size < (quad_t)1 << 32)
95                 ost.st_size = st->st_size;
96         else
97                 ost.st_size = -2;
98         ost.st_atime = st->st_atime;
99         ost.st_mtime = st->st_mtime;
100         ost.st_ctime = st->st_ctime;
101         ost.st_blksize = st->st_blksize;
102         ost.st_blocks = st->st_blocks;
103         ost.st_flags = st->st_flags;
104         ost.st_gen = st->st_gen;
105
106         error = copyout(&ost, uaddr, sizeof(ost));
107         return (error);
108 }
109
110 /*
111  * MPALMOSTSAFE
112  */
113 int
114 sys_linux_newstat(struct linux_newstat_args *args)
115 {
116         struct stat buf;
117         struct nlookupdata nd;
118         char *path;
119         int error;
120
121         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
122         if (error)
123                 return (error);
124 #ifdef DEBUG
125         if (ldebug(newstat))
126                 kprintf(ARGS(newstat, "%s, *"), path);
127 #endif
128         get_mplock();
129         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
130         if (error == 0) {
131                 error = kern_stat(&nd, &buf);
132                 if (error == 0)
133                         error = newstat_copyout(&buf, args->buf);
134                 nlookup_done(&nd);
135         }
136         rel_mplock();
137         linux_free_path(&path);
138         return (error);
139 }
140
141 /*
142  * MPALMOSTSAFE
143  */
144 int
145 sys_linux_newlstat(struct linux_newlstat_args *args)
146 {
147         struct stat sb;
148         struct nlookupdata nd;
149         char *path;
150         int error;
151
152         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
153         if (error)
154                 return (error);
155 #ifdef DEBUG
156         if (ldebug(newlstat))
157                 kprintf(ARGS(newlstat, "%s, *"), path);
158 #endif
159         get_mplock();
160         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
161         if (error == 0) {
162                 error = kern_stat(&nd, &sb);
163                 if (error == 0)
164                         error = newstat_copyout(&sb, args->buf);
165                 nlookup_done(&nd);
166         }
167         rel_mplock();
168         linux_free_path(&path);
169         return (error);
170 }
171
172 /*
173  * MPALMOSTSAFE
174  */
175 int
176 sys_linux_newfstat(struct linux_newfstat_args *args)
177 {
178         struct stat buf;
179         int error;
180
181 #ifdef DEBUG
182         if (ldebug(newfstat))
183                 kprintf(ARGS(newfstat, "%d, *"), args->fd);
184 #endif
185         get_mplock();
186         error = kern_fstat(args->fd, &buf);
187         rel_mplock();
188
189         if (error == 0)
190                 error = newstat_copyout(&buf, args->buf);
191         return (error);
192 }
193
194 /* XXX - All fields of type l_int are defined as l_long on i386 */
195 struct l_statfs {
196         l_int           f_type;
197         l_int           f_bsize;
198         l_int           f_blocks;
199         l_int           f_bfree;
200         l_int           f_bavail;
201         l_int           f_files;
202         l_int           f_ffree;
203         l_fsid_t        f_fsid;
204         l_int           f_namelen;
205         l_int           f_spare[6];
206 };
207
208 #define LINUX_CODA_SUPER_MAGIC  0x73757245L
209 #define LINUX_EXT2_SUPER_MAGIC  0xEF53L
210 #define LINUX_HPFS_SUPER_MAGIC  0xf995e849L
211 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L
212 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L
213 #define LINUX_NCP_SUPER_MAGIC   0x564cL
214 #define LINUX_NFS_SUPER_MAGIC   0x6969L
215 #define LINUX_NTFS_SUPER_MAGIC  0x5346544EL
216 #define LINUX_PROC_SUPER_MAGIC  0x9fa0L
217 #define LINUX_UFS_SUPER_MAGIC   0x00011954L     /* XXX - UFS_MAGIC in Linux */
218
219 static long
220 bsd_to_linux_ftype(const char *fstypename)
221 {
222         int i;
223         static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
224                 {"ufs",     LINUX_UFS_SUPER_MAGIC},
225                 {"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
226                 {"nfs",     LINUX_NFS_SUPER_MAGIC},
227                 {"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
228                 {"procfs",  LINUX_PROC_SUPER_MAGIC},
229                 {"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
230                 {"ntfs",    LINUX_NTFS_SUPER_MAGIC},
231                 {"hpfs",    LINUX_HPFS_SUPER_MAGIC},
232                 {NULL,      0L}};
233
234         for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
235                 if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
236                         return (b2l_tbl[i].linux_type);
237
238         return (0L);
239 }
240
241 static int
242 statfs_copyout(struct statfs *statfs, struct l_statfs_buf *buf, l_int namelen)
243 {
244         struct l_statfs linux_statfs;
245         int error;
246
247         linux_statfs.f_type = bsd_to_linux_ftype(statfs->f_fstypename);
248         linux_statfs.f_bsize = statfs->f_bsize;
249         linux_statfs.f_blocks = statfs->f_blocks;
250         linux_statfs.f_bfree = statfs->f_bfree;
251         linux_statfs.f_bavail = statfs->f_bavail;
252         linux_statfs.f_ffree = statfs->f_ffree;
253         linux_statfs.f_files = statfs->f_files;
254         linux_statfs.f_fsid.val[0] = statfs->f_fsid.val[0];
255         linux_statfs.f_fsid.val[1] = statfs->f_fsid.val[1];
256         linux_statfs.f_namelen = namelen;
257
258         error = copyout(&linux_statfs, buf, sizeof(linux_statfs));
259         return (error);
260 }
261
262 /*
263  * MPALMOSTSAFE
264  */
265 int
266 sys_linux_statfs(struct linux_statfs_args *args)
267 {
268         struct statfs statfs;
269         struct nlookupdata nd;
270         char *path;
271         int error, namelen;
272
273         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
274         if (error)
275                 return (error);
276 #ifdef DEBUG
277         if (ldebug(statfs))
278                 kprintf(ARGS(statfs, "%s, *"), path);
279 #endif
280         get_mplock();
281         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
282         if (error == 0)
283                 error = kern_statfs(&nd, &statfs);
284         if (error == 0) {
285                 if (nd.nl_nch.ncp->nc_vp != NULL)
286                         error = vn_get_namelen(nd.nl_nch.ncp->nc_vp, &namelen);
287                 else
288                         error = EINVAL;
289         }
290         nlookup_done(&nd);
291         rel_mplock();
292         if (error == 0)
293                 error = statfs_copyout(&statfs, args->buf, (l_int)namelen);
294         linux_free_path(&path);
295         return (error);
296 }
297
298 /*
299  * MPALMOSTSAFE
300  */
301 int
302 sys_linux_fstatfs(struct linux_fstatfs_args *args)
303 {
304         struct proc *p = curthread->td_proc;
305         struct file *fp;
306         struct statfs statfs;
307         int error, namelen;
308
309 #ifdef DEBUG
310         if (ldebug(fstatfs))
311                 kprintf(ARGS(fstatfs, "%d, *"), args->fd);
312 #endif
313         get_mplock();
314         if ((error = kern_fstatfs(args->fd, &statfs)) != 0)
315                 return (error);
316         if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
317                 return (error);
318         error = vn_get_namelen((struct vnode *)fp->f_data, &namelen);
319         rel_mplock();
320         fdrop(fp);
321         if (error == 0)
322                 error = statfs_copyout(&statfs, args->buf, (l_int)namelen);
323         return (error);
324 }
325
326 struct l_ustat 
327 {
328         l_daddr_t       f_tfree;
329         l_ino_t         f_tinode;
330         char            f_fname[6];
331         char            f_fpack[6];
332 };
333
334 /*
335  * MPALMOSTSAFE
336  */
337 int
338 sys_linux_ustat(struct linux_ustat_args *args)
339 {
340         struct thread *td = curthread;
341         struct l_ustat lu;
342         cdev_t dev;
343         struct vnode *vp;
344         struct statfs *stat;
345         int error;
346
347 #ifdef DEBUG
348         if (ldebug(ustat))
349                 kprintf(ARGS(ustat, "%d, *"), args->dev);
350 #endif
351
352         /*
353          * lu.f_fname and lu.f_fpack are not used. They are always zeroed.
354          * lu.f_tinode and lu.f_tfree are set from the device's super block.
355          */
356         bzero(&lu, sizeof(lu));
357
358         /*
359          * XXX - Don't return an error if we can't find a vnode for the
360          * device. Our cdev_t is 32-bits whereas Linux only has a 16-bits
361          * cdev_t. The dev_t that is used now may as well be a truncated
362          * cdev_t returned from previous syscalls. Just return a bzeroed
363          * ustat in that case.
364          */
365         get_mplock();
366         dev = udev2dev(makeudev(args->dev >> 8, args->dev & 0xFF), 0);
367         if (dev != NULL && vfinddev(dev, VCHR, &vp)) {
368                 if (vp->v_mount == NULL) {
369                         vrele(vp);
370                         error = EINVAL;
371                         goto done;
372                 }
373                 stat = &(vp->v_mount->mnt_stat);
374                 error = VFS_STATFS(vp->v_mount, stat, td->td_ucred);
375                 vrele(vp);
376                 if (error == 0) {
377                         lu.f_tfree = stat->f_bfree;
378                         lu.f_tinode = stat->f_ffree;
379                 }
380         } else {
381                 error = 0;
382         }
383 done:
384         rel_mplock();
385         if (error == 0)
386                 error = copyout(&lu, args->ubuf, sizeof(lu));
387         return (error);
388 }
389
390 #if defined(__i386__)
391
392 static int
393 stat64_copyout(struct stat *buf, void *ubuf)
394 {
395         struct l_stat64 lbuf;
396         int error;
397
398         bzero(&lbuf, sizeof(lbuf));
399         lbuf.st_dev = uminor(buf->st_dev) | (umajor(buf->st_dev) << 8);
400         lbuf.st_ino = INO64TO32(buf->st_ino);
401         lbuf.st_mode = buf->st_mode;
402         lbuf.st_nlink = buf->st_nlink;
403         lbuf.st_uid = buf->st_uid;
404         lbuf.st_gid = buf->st_gid;
405         lbuf.st_rdev = buf->st_rdev;
406         lbuf.st_size = buf->st_size;
407         lbuf.st_atime = buf->st_atime;
408         lbuf.st_mtime = buf->st_mtime;
409         lbuf.st_ctime = buf->st_ctime;
410         lbuf.st_blksize = buf->st_blksize;
411         lbuf.st_blocks = buf->st_blocks;
412
413         /*
414          * The __st_ino field makes all the difference. In the Linux kernel
415          * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
416          * but without the assignment to __st_ino the runtime linker refuses
417          * to mmap(2) any shared libraries. I guess it's broken alright :-)
418          */
419         lbuf.__st_ino = INO64TO32(buf->st_ino);
420
421         error = copyout(&lbuf, ubuf, sizeof(lbuf));
422         return (error);
423 }
424
425 /*
426  * MPALMOSTSAFE
427  */
428 int
429 sys_linux_stat64(struct linux_stat64_args *args)
430 {
431         struct nlookupdata nd;
432         struct stat buf;
433         char *path;
434         int error;
435
436         error = linux_copyin_path(args->filename, &path, LINUX_PATH_EXISTS);
437         if (error)
438                 return (error);
439 #ifdef DEBUG
440         if (ldebug(stat64))
441                 kprintf(ARGS(stat64, "%s, *"), path);
442 #endif
443         get_mplock();
444         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
445         if (error == 0) {
446                 error = kern_stat(&nd, &buf);
447                 nlookup_done(&nd);
448         }
449         rel_mplock();
450         if (error == 0)
451                 error = stat64_copyout(&buf, args->statbuf);
452         linux_free_path(&path);
453         return (error);
454 }
455
456 /*
457  * MPALMOSTSAFE
458  */
459 int
460 sys_linux_lstat64(struct linux_lstat64_args *args)
461 {
462         struct nlookupdata nd;
463         struct stat sb;
464         char *path;
465         int error;
466
467         error = linux_copyin_path(args->filename, &path, LINUX_PATH_EXISTS);
468         if (error)
469                 return (error);
470 #ifdef DEBUG
471         if (ldebug(lstat64))
472                 kprintf(ARGS(lstat64, "%s, *"), path);
473 #endif
474         get_mplock();
475         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
476         if (error == 0) {
477                 error = kern_stat(&nd, &sb);
478                 nlookup_done(&nd);
479         }
480         rel_mplock();
481         if (error == 0)
482                 error = stat64_copyout(&sb, args->statbuf);
483         linux_free_path(&path);
484         return (error);
485 }
486
487 /*
488  * MPALMOSTSAFE
489  */
490 int
491 sys_linux_fstat64(struct linux_fstat64_args *args)
492 {
493         struct stat buf;
494         int error;
495
496 #ifdef DEBUG
497         if (ldebug(fstat64))
498                 kprintf(ARGS(fstat64, "%d, *"), args->fd);
499 #endif
500         get_mplock();
501         error = kern_fstat(args->fd, &buf);
502         rel_mplock();
503
504         if (error == 0)
505                 error = stat64_copyout(&buf, args->statbuf);
506         return (error);
507 }
508
509 int
510 sys_linux_fstatat64(struct linux_fstatat64_args *args)
511 {
512         struct nlookupdata nd;
513         struct file *fp;
514         struct stat st;
515         char *path;
516         int error, flags, dfd;
517
518         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
519                 return (EINVAL);
520
521         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
522         if (error)
523                 return (error);
524 #ifdef DEBUG
525         if (ldebug(fstatat64))
526                 kprintf(ARGS(fstatat64, "%s"), path);
527 #endif
528         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
529         flags = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 0 : NLC_FOLLOW;
530
531         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, flags);
532         if (error == 0) {
533                 error = kern_stat(&nd, &st);
534                 if (error == 0)
535                         error = stat64_copyout(&st, args->statbuf);
536         }
537         nlookup_done_at(&nd, fp);
538         linux_free_path(&path);
539         return (error);
540 }
541
542 int
543 sys_linux_ostat(struct linux_ostat_args *args)
544 {
545         struct nlookupdata nd;
546         struct stat buf;
547         char *path;
548         int error;
549
550         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
551         if (error)
552                 return (error);
553 #ifdef DEBUG
554         if (ldebug(ostat))
555                 kprintf(ARGS(ostat, "%s, *"), path);
556 #endif
557         get_mplock();
558         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
559         if (error == 0) {
560                 error = kern_stat(&nd, &buf);
561                 nlookup_done(&nd);
562         }
563         rel_mplock();
564         if (error == 0)
565                 error = ostat_copyout(&buf, args->statbuf);
566         linux_free_path(&path);
567         return (error);
568 }
569
570 #endif /* __i386__ */