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