1 /* This file contains the code for performing four system calls relating to
2 * status and directories.
4 * The entry points into this file are
5 * do_chdir: perform the CHDIR system call
6 * do_chroot: perform the CHROOT system call
7 * do_lstat: perform the LSTAT system call
8 * do_stat: perform the STAT system call
9 * do_fstat: perform the FSTAT system call
10 * do_statvfs: perform the STATVFS1 system call
11 * do_fstatvfs: perform the FSTATVFS1 system call
12 * do_getvfsstat: perform the GETVFSSTAT system call
17 #include <minix/com.h>
18 #include <minix/u64.h>
22 #include <minix/vfsif.h>
23 #include <minix/callnr.h>
27 static int change_into(struct vnode
**iip
, struct vnode
*vp
);
29 /*===========================================================================*
31 *===========================================================================*/
34 /* Change directory on already-opened fd. */
38 rfd
= job_m_in
.m_lc_vfs_fchdir
.fd
;
40 /* Is the file descriptor valid? */
41 if ((rfilp
= get_filp(rfd
, VNODE_READ
)) == NULL
) return(err_code
);
42 r
= change_into(&fp
->fp_wd
, rfilp
->filp_vno
);
47 /*===========================================================================*
49 *===========================================================================*/
52 /* Perform the chdir(name) system call.
53 * syscall might provide 'name' embedded in the message.
59 char fullpath
[PATH_MAX
];
60 struct lookup resolve
;
62 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
65 /* Try to open the directory */
66 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
67 resolve
.l_vmnt_lock
= VMNT_READ
;
68 resolve
.l_vnode_lock
= VNODE_READ
;
69 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
71 r
= change_into(&fp
->fp_wd
, vp
);
80 /*===========================================================================*
82 *===========================================================================*/
85 /* Perform the chroot(name) system call.
86 * syscall might provide 'name' embedded in the message.
91 char fullpath
[PATH_MAX
];
92 struct lookup resolve
;
94 if (!super_user
) return(EPERM
); /* only su may chroot() */
96 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
99 /* Try to open the directory */
100 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
101 resolve
.l_vmnt_lock
= VMNT_READ
;
102 resolve
.l_vnode_lock
= VNODE_READ
;
103 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
105 r
= change_into(&fp
->fp_rd
, vp
);
114 /*===========================================================================*
116 *===========================================================================*/
117 static int change_into(struct vnode
**result
, struct vnode
*vp
)
121 if (*result
== vp
) return(OK
); /* Nothing to do */
123 /* It must be a directory and also be searchable */
124 if (!S_ISDIR(vp
->v_mode
))
127 r
= forbidden(fp
, vp
, X_BIT
); /* Check if dir is searchable*/
128 if (r
!= OK
) return(r
);
130 /* Everything is OK. Make the change. */
131 put_vnode(*result
); /* release the old directory */
133 *result
= vp
; /* acquire the new one */
137 /*===========================================================================*
139 *===========================================================================*/
142 /* Perform the stat(name, buf) system call. */
146 char fullpath
[PATH_MAX
];
147 struct lookup resolve
;
148 vir_bytes vname1
, statbuf
;
149 size_t vname1_length
;
151 vname1
= job_m_in
.m_lc_vfs_stat
.name
;
152 vname1_length
= job_m_in
.m_lc_vfs_stat
.len
;
153 statbuf
= job_m_in
.m_lc_vfs_stat
.buf
;
155 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
156 resolve
.l_vmnt_lock
= VMNT_READ
;
157 resolve
.l_vnode_lock
= VNODE_READ
;
159 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
160 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
161 r
= req_stat(vp
->v_fs_e
, vp
->v_inode_nr
, who_e
, statbuf
);
170 /*===========================================================================*
172 *===========================================================================*/
175 /* Perform the fstat(fd, buf) system call. */
176 register struct filp
*rfilp
;
180 statbuf
= job_m_in
.m_lc_vfs_fstat
.buf
;
181 rfd
= job_m_in
.m_lc_vfs_fstat
.fd
;
183 /* Is the file descriptor valid? */
184 if ((rfilp
= get_filp(rfd
, VNODE_READ
)) == NULL
) return(err_code
);
186 r
= req_stat(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
,
194 /*===========================================================================*
196 *===========================================================================*/
197 int update_statvfs(struct vmnt
*vmp
, struct statvfs
*buf
)
199 /* Get statistics from a file system, and cache part of the results. */
202 if ((r
= req_statvfs(vmp
->m_fs_e
, buf
)) != OK
)
205 vmp
->m_stats
.f_flag
= buf
->f_flag
;
206 vmp
->m_stats
.f_bsize
= buf
->f_bsize
;
207 vmp
->m_stats
.f_frsize
= buf
->f_frsize
;
208 vmp
->m_stats
.f_iosize
= buf
->f_iosize
;
210 vmp
->m_stats
.f_blocks
= buf
->f_blocks
;
211 vmp
->m_stats
.f_bfree
= buf
->f_bfree
;
212 vmp
->m_stats
.f_bavail
= buf
->f_bavail
;
213 vmp
->m_stats
.f_bresvd
= buf
->f_bresvd
;
215 vmp
->m_stats
.f_files
= buf
->f_files
;
216 vmp
->m_stats
.f_ffree
= buf
->f_ffree
;
217 vmp
->m_stats
.f_favail
= buf
->f_favail
;
218 vmp
->m_stats
.f_fresvd
= buf
->f_fresvd
;
220 vmp
->m_stats
.f_syncreads
= buf
->f_syncreads
;
221 vmp
->m_stats
.f_syncwrites
= buf
->f_syncwrites
;
223 vmp
->m_stats
.f_asyncreads
= buf
->f_asyncreads
;
224 vmp
->m_stats
.f_asyncwrites
= buf
->f_asyncwrites
;
226 vmp
->m_stats
.f_namemax
= buf
->f_namemax
;
231 /*===========================================================================*
233 *===========================================================================*/
234 static int fill_statvfs(struct vmnt
*vmp
, endpoint_t endpt
, vir_bytes buf_addr
,
237 /* Fill a statvfs structure in a userspace process. First let the target file
238 * server fill in most fields, or use the cached copy if ST_NOWAIT is given.
239 * Then fill in some remaining fields with local information. Finally, copy
240 * the result to user space.
244 if (!(flags
& ST_NOWAIT
)) {
245 /* Get fresh statistics from the file system. */
246 if (update_statvfs(vmp
, &buf
) != OK
)
249 /* Use the cached statistics. */
250 memset(&buf
, 0, sizeof(buf
));
252 buf
.f_flag
= vmp
->m_stats
.f_flag
;
253 buf
.f_bsize
= vmp
->m_stats
.f_bsize
;
254 buf
.f_frsize
= vmp
->m_stats
.f_frsize
;
255 buf
.f_iosize
= vmp
->m_stats
.f_iosize
;
257 buf
.f_blocks
= vmp
->m_stats
.f_blocks
;
258 buf
.f_bfree
= vmp
->m_stats
.f_bfree
;
259 buf
.f_bavail
= vmp
->m_stats
.f_bavail
;
260 buf
.f_bresvd
= vmp
->m_stats
.f_bresvd
;
262 buf
.f_files
= vmp
->m_stats
.f_files
;
263 buf
.f_ffree
= vmp
->m_stats
.f_ffree
;
264 buf
.f_favail
= vmp
->m_stats
.f_favail
;
265 buf
.f_fresvd
= vmp
->m_stats
.f_fresvd
;
267 buf
.f_syncreads
= vmp
->m_stats
.f_syncreads
;
268 buf
.f_syncwrites
= vmp
->m_stats
.f_syncwrites
;
270 buf
.f_asyncreads
= vmp
->m_stats
.f_asyncreads
;
271 buf
.f_asyncwrites
= vmp
->m_stats
.f_asyncwrites
;
273 buf
.f_namemax
= vmp
->m_stats
.f_namemax
;
276 if (vmp
->m_flags
& VMNT_READONLY
)
277 buf
.f_flag
|= ST_RDONLY
;
279 buf
.f_fsid
= (unsigned long)vmp
->m_dev
;
280 buf
.f_fsidx
.__fsid_val
[0] = (long)vmp
->m_dev
; /* This is what is done on NetBSD */
281 buf
.f_fsidx
.__fsid_val
[1] = 0; /* Here they convert the FS type name into a number. */
283 strlcpy(buf
.f_fstypename
, vmp
->m_fstype
, sizeof(buf
.f_fstypename
));
284 strlcpy(buf
.f_mntonname
, vmp
->m_mount_path
, sizeof(buf
.f_mntonname
));
285 strlcpy(buf
.f_mntfromname
, vmp
->m_mount_dev
, sizeof(buf
.f_mntfromname
));
287 return sys_datacopy_wrapper(SELF
, (vir_bytes
) &buf
,
288 endpt
, buf_addr
, sizeof(buf
));
291 /*===========================================================================*
293 *===========================================================================*/
296 /* Perform the statvfs1(name, buf, flags) system call. */
300 char fullpath
[PATH_MAX
];
301 struct lookup resolve
;
302 vir_bytes vname1
, statbuf
;
303 size_t vname1_length
;
305 vname1
= job_m_in
.m_lc_vfs_statvfs1
.name
;
306 vname1_length
= job_m_in
.m_lc_vfs_statvfs1
.len
;
307 statbuf
= job_m_in
.m_lc_vfs_statvfs1
.buf
;
308 flags
= job_m_in
.m_lc_vfs_statvfs1
.flags
;
310 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
311 resolve
.l_vmnt_lock
= VMNT_READ
;
312 resolve
.l_vnode_lock
= VNODE_READ
;
314 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
315 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
316 r
= fill_statvfs(vp
->v_vmnt
, who_e
, statbuf
, flags
);
325 /*===========================================================================*
327 *===========================================================================*/
328 int do_fstatvfs(void)
330 /* Perform the fstatvfs1(fd, buf, flags) system call. */
331 register struct filp
*rfilp
;
335 rfd
= job_m_in
.m_lc_vfs_statvfs1
.fd
;
336 statbuf
= job_m_in
.m_lc_vfs_statvfs1
.buf
;
337 flags
= job_m_in
.m_lc_vfs_statvfs1
.flags
;
339 /* Is the file descriptor valid? */
340 if ((rfilp
= get_filp(rfd
, VNODE_READ
)) == NULL
) return(err_code
);
341 r
= fill_statvfs(rfilp
->filp_vno
->v_vmnt
, who_e
, statbuf
, flags
);
348 /*===========================================================================*
350 *===========================================================================*/
351 int do_getvfsstat(void)
353 /* Perform the getvfsstat(buf, bufsize, flags) system call. */
357 int r
, flags
, count
, do_lock
;
359 buf
= job_m_in
.m_lc_vfs_getvfsstat
.buf
;
360 bufsize
= job_m_in
.m_lc_vfs_getvfsstat
.len
;
361 flags
= job_m_in
.m_lc_vfs_getvfsstat
.flags
;
366 /* We only need to lock target file systems if we are going to query
367 * them. This will only happen if ST_NOWAIT is not given. If we do
368 * not lock, we rely on the VMNT_CANSTAT flag to protect us from
369 * concurrent (un)mount operations. Note that procfs relies on
370 * ST_NOWAIT calls being lock free, as it is a file system itself.
372 do_lock
= !(flags
& ST_NOWAIT
);
374 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
375 /* If there is no more space, return the count so far. */
376 if (bufsize
< sizeof(struct statvfs
))
379 /* Lock the file system before checking any fields. */
380 if (do_lock
&& (r
= lock_vmnt(vmp
, VMNT_READ
)) != OK
)
383 /* Obtain information for this file system, if it is in use and
384 * can be reported. File systems that are being (un)mounted
385 * are skipped, as is PFS. The fill call will block only if
386 * ST_NOWAIT was not given.
388 if (vmp
->m_dev
!= NO_DEV
&& (vmp
->m_flags
& VMNT_CANSTAT
)) {
389 if ((r
= fill_statvfs(vmp
, who_e
, buf
, flags
)) != OK
) {
397 buf
+= sizeof(struct statvfs
);
398 bufsize
-= sizeof(struct statvfs
);
405 /* Just report a file system count. No need to lock, as above. */
406 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
407 if (vmp
->m_dev
!= NO_DEV
&& (vmp
->m_flags
& VMNT_CANSTAT
))
415 /*===========================================================================*
417 *===========================================================================*/
420 /* Perform the lstat(name, buf) system call. */
424 char fullpath
[PATH_MAX
];
425 struct lookup resolve
;
426 vir_bytes vname1
, statbuf
;
427 size_t vname1_length
;
429 vname1
= job_m_in
.m_lc_vfs_stat
.name
;
430 vname1_length
= job_m_in
.m_lc_vfs_stat
.len
;
431 statbuf
= job_m_in
.m_lc_vfs_stat
.buf
;
433 lookup_init(&resolve
, fullpath
, PATH_RET_SYMLINK
, &vmp
, &vp
);
434 resolve
.l_vmnt_lock
= VMNT_READ
;
435 resolve
.l_vnode_lock
= VNODE_READ
;
437 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
438 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(err_code
);
439 r
= req_stat(vp
->v_fs_e
, vp
->v_inode_nr
, who_e
, statbuf
);