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__ */
Cache object: bf37910748f9878e83b3c65d6a86642c
|