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_stat: perform the STAT system call
8 * do_fstat: perform the FSTAT system call
9 * do_fstatfs: perform the FSTATFS system call
10 * do_lstat: perform the LSTAT system call
11 * do_rdlink: perform the RDLNK system call
16 #include <sys/statfs.h>
17 #include <minix/com.h>
26 FORWARD
_PROTOTYPE( int change
, (struct inode
**iip
, char *name_ptr
, int len
));
27 FORWARD
_PROTOTYPE( int change_into
, (struct inode
**iip
, struct inode
*ip
));
28 FORWARD
_PROTOTYPE( int stat_inode
, (struct inode
*rip
, struct filp
*fil_ptr
,
31 /*===========================================================================*
33 *===========================================================================*/
34 PUBLIC
int do_fchdir()
36 /* Change directory on already-opened fd. */
39 /* Is the file descriptor valid? */
40 if ( (rfilp
= get_filp(m_in
.fd
)) == NIL_FILP
) return(err_code
);
41 dup_inode(rfilp
->filp_ino
);
42 return change_into(&fp
->fp_workdir
, rfilp
->filp_ino
);
45 /*===========================================================================*
47 *===========================================================================*/
50 /* Change directory. This function is also called by MM to simulate a chdir
51 * in order to do EXEC, etc. It also changes the root directory, the uids and
52 * gids, and the umask.
56 register struct fproc
*rfp
;
58 if (who_e
== PM_PROC_NR
) {
60 if(isokendpt(m_in
.endpt1
, &slot
) != OK
)
63 put_inode(fp
->fp_rootdir
);
64 dup_inode(fp
->fp_rootdir
= rfp
->fp_rootdir
);
65 put_inode(fp
->fp_workdir
);
66 dup_inode(fp
->fp_workdir
= rfp
->fp_workdir
);
68 /* MM uses access() to check permissions. To make this work, pretend
69 * that the user's real ids are the same as the user's effective ids.
70 * FS calls other than access() do not use the real ids, so are not
74 fp
->fp_effuid
= rfp
->fp_effuid
;
76 fp
->fp_effgid
= rfp
->fp_effgid
;
77 fp
->fp_umask
= rfp
->fp_umask
;
81 /* Perform the chdir(name) system call. */
82 r
= change(&fp
->fp_workdir
, m_in
.name
, m_in
.name_length
);
86 /*===========================================================================*
88 *===========================================================================*/
89 PUBLIC
int do_chroot()
91 /* Perform the chroot(name) system call. */
95 if (!super_user
) return(EPERM
); /* only su may chroot() */
96 r
= change(&fp
->fp_rootdir
, m_in
.name
, m_in
.name_length
);
100 /*===========================================================================*
102 *===========================================================================*/
103 PRIVATE
int change(iip
, name_ptr
, len
)
104 struct inode
**iip
; /* pointer to the inode pointer for the dir */
105 char *name_ptr
; /* pointer to the directory name to change to */
106 int len
; /* length of the directory name string */
108 /* Do the actual work for chdir() and chroot(). */
111 /* Try to open the new directory. */
112 if (fetch_name(name_ptr
, len
, M3
) != OK
) return(err_code
);
113 if ( (rip
= eat_path(user_path
)) == NIL_INODE
) return(err_code
);
114 return change_into(iip
, rip
);
117 /*===========================================================================*
119 *===========================================================================*/
120 PRIVATE
int change_into(iip
, rip
)
121 struct inode
**iip
; /* pointer to the inode pointer for the dir */
122 struct inode
*rip
; /* this is what the inode has to become */
126 /* It must be a directory and also be searchable. */
127 if ( (rip
->i_mode
& I_TYPE
) != I_DIRECTORY
)
130 r
= forbidden(rip
, X_BIT
); /* check if dir is searchable */
132 /* If error, return inode. */
138 /* Everything is OK. Make the change. */
139 put_inode(*iip
); /* release the old directory */
140 *iip
= rip
; /* acquire the new one */
144 /*===========================================================================*
146 *===========================================================================*/
149 /* Perform the stat(name, buf) system call. */
151 register struct inode
*rip
;
154 /* Both stat() and fstat() use the same routine to do the real work. That
155 * routine expects an inode, so acquire it temporarily.
157 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
158 if ( (rip
= eat_path(user_path
)) == NIL_INODE
) return(err_code
);
159 r
= stat_inode(rip
, NIL_FILP
, m_in
.name2
); /* actually do the work.*/
160 put_inode(rip
); /* release the inode */
164 /*===========================================================================*
166 *===========================================================================*/
167 PUBLIC
int do_fstat()
169 /* Perform the fstat(fd, buf) system call. */
171 register struct filp
*rfilp
;
173 /* Is the file descriptor valid? */
174 if ( (rfilp
= get_filp(m_in
.fd
)) == NIL_FILP
) return(err_code
);
176 return(stat_inode(rfilp
->filp_ino
, rfilp
, m_in
.buffer
));
179 /*===========================================================================*
181 *===========================================================================*/
182 PRIVATE
int stat_inode(rip
, fil_ptr
, user_addr
)
183 register struct inode
*rip
; /* pointer to inode to stat */
184 struct filp
*fil_ptr
; /* filp pointer, supplied by 'fstat' */
185 char *user_addr
; /* user space address where stat buf goes */
187 /* Common code for stat and fstat system calls. */
193 /* Update the atime, ctime, and mtime fields in the inode, if need be. */
194 if (rip
->i_update
) update_times(rip
);
196 /* Fill in the statbuf struct. */
197 mo
= rip
->i_mode
& I_TYPE
;
199 /* true iff special */
200 s
= (mo
== I_CHAR_SPECIAL
|| mo
== I_BLOCK_SPECIAL
);
202 statbuf
.st_dev
= rip
->i_dev
;
203 statbuf
.st_ino
= rip
->i_num
;
204 statbuf
.st_mode
= rip
->i_mode
;
205 statbuf
.st_nlink
= rip
->i_nlinks
;
206 statbuf
.st_uid
= rip
->i_uid
;
207 statbuf
.st_gid
= rip
->i_gid
;
208 statbuf
.st_rdev
= (dev_t
) (s
? rip
->i_zone
[0] : NO_DEV
);
209 statbuf
.st_size
= rip
->i_size
;
211 if (rip
->i_pipe
== I_PIPE
) {
212 statbuf
.st_mode
&= ~I_REGULAR
; /* wipe out I_REGULAR bit for pipes */
213 if (fil_ptr
!= NIL_FILP
&& fil_ptr
->filp_mode
& R_BIT
)
214 statbuf
.st_size
-= fil_ptr
->filp_pos
;
217 statbuf
.st_atime
= rip
->i_atime
;
218 statbuf
.st_mtime
= rip
->i_mtime
;
219 statbuf
.st_ctime
= rip
->i_ctime
;
221 /* Copy the struct to user space. */
222 r
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) &statbuf
,
223 who_e
, (vir_bytes
) user_addr
, (phys_bytes
) sizeof(statbuf
));
227 /*===========================================================================*
229 *===========================================================================*/
230 PUBLIC
int do_fstatfs()
232 /* Perform the fstatfs(fd, buf) system call. */
234 register struct filp
*rfilp
;
237 /* Is the file descriptor valid? */
238 if ( (rfilp
= get_filp(m_in
.fd
)) == NIL_FILP
) return(err_code
);
240 st
.f_bsize
= rfilp
->filp_ino
->i_sp
->s_block_size
;
242 r
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) &st
,
243 who_e
, (vir_bytes
) m_in
.buffer
, (phys_bytes
) sizeof(st
));
248 /*===========================================================================*
250 *===========================================================================*/
251 PUBLIC
int do_lstat()
253 /* Perform the lstat(name, buf) system call. */
255 register int r
; /* return value */
256 register struct inode
*rip
; /* target inode */
258 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
259 if ((rip
= parse_path(user_path
, (char *) 0, EAT_PATH_OPAQUE
)) == NIL_INODE
)
261 r
= stat_inode(rip
, NIL_FILP
, m_in
.name2
);
266 /*===========================================================================*
268 *===========================================================================*/
269 PUBLIC
int do_rdlink()
271 /* Perform the readlink(name, buf) system call. */
273 register int r
; /* return value */
274 block_t b
; /* block containing link text */
275 struct buf
*bp
; /* buffer containing link text */
276 register struct inode
*rip
; /* target inode */
278 copylen
= m_in
.m1_i2
;
279 if(copylen
< 0) return EINVAL
;
281 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
282 if ((rip
= parse_path(user_path
, (char *) 0, EAT_PATH_OPAQUE
)) == NIL_INODE
)
286 if (S_ISLNK(rip
->i_mode
) && (b
= read_map(rip
, (off_t
) 0)) != NO_BLOCK
) {
287 if (m_in
.name2_length
<= 0) r
= EINVAL
;
288 else if (m_in
.name2_length
< rip
->i_size
) r
= ERANGE
;
290 if(rip
->i_size
< copylen
) copylen
= rip
->i_size
;
291 bp
= get_block(rip
->i_dev
, b
, NORMAL
);
292 r
= sys_vircopy(SELF
, D
, (vir_bytes
) bp
->b_data
,
293 who_e
, D
, (vir_bytes
) m_in
.name2
, (vir_bytes
) copylen
);
295 if (r
== OK
) r
= copylen
;
296 put_block(bp
, DIRECTORY_BLOCK
);