4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
34 #include <sys/param.h>
35 #include <sys/isa_defs.h>
36 #include <sys/types.h>
37 #include <sys/sysmacros.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/fcntl.h>
43 #include <sys/pathname.h>
46 #include <sys/vnode.h>
53 #include <sys/filio.h>
54 #include <sys/cmn_err.h>
55 #include <sys/policy.h>
58 #include <sys/debug.h>
59 #include <sys/fs_subr.h>
62 * Change current working directory (".").
64 static int chdirec(vnode_t
*, int ischroot
, int do_traverse
);
74 if (error
= lookupname(fname
, UIO_USERSPACE
, FOLLOW
, NULLVPP
, &vp
)) {
75 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
77 return (set_errno(error
));
80 error
= chdirec(vp
, 0, 1);
82 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
84 return (set_errno(error
));
90 * File-descriptor based version of 'chdir'.
99 if ((fp
= getf(fd
)) == NULL
)
100 return (set_errno(EBADF
));
104 error
= chdirec(vp
, 0, 0);
106 return (set_errno(error
));
111 * Change notion of root ("/") directory.
118 int estale_retry
= 0;
121 if (error
= lookupname(fname
, UIO_USERSPACE
, FOLLOW
, NULLVPP
, &vp
)) {
122 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
124 return (set_errno(error
));
127 error
= chdirec(vp
, 1, 1);
129 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
131 return (set_errno(error
));
137 * ++++++++++++++++++++++++
138 * ++ SunOS4.1 Buyback ++
139 * ++++++++++++++++++++++++
140 * Change root directory with a user given fd
149 if ((fp
= getf(fd
)) == NULL
)
150 return (set_errno(EBADF
));
154 error
= chdirec(vp
, 1, 0);
156 return (set_errno(error
));
161 chdirec(vnode_t
*vp
, int ischroot
, int do_traverse
)
165 proc_t
*pp
= curproc
;
170 if (vp
->v_type
!= VDIR
) {
174 if (error
= fop_access(vp
, VEXEC
, 0, CRED(), NULL
))
178 * The fop_access() may have covered 'vp' with a new filesystem,
179 * if 'vp' is an autoFS vnode. Traverse the mountpoint so
180 * that we don't end up with a covered current directory.
182 if (vn_mountedvfs(vp
) != NULL
&& do_traverse
) {
183 if (error
= traverse(&vp
))
188 * Special chroot semantics: chroot is allowed if privileged
189 * or if the target is really a loopback mount of the root (or
190 * root of the zone) as determined by comparing dev and inode
196 vnode_t
*zonevp
= curproc
->p_zone
->zone_rootvp
;
198 tattr
.va_mask
= VATTR_FSID
|VATTR_NODEID
;
199 if (error
= fop_getattr(vp
, &tattr
, 0, CRED(), NULL
))
202 rattr
.va_mask
= VATTR_FSID
|VATTR_NODEID
;
203 if (error
= fop_getattr(zonevp
, &rattr
, 0, CRED(), NULL
))
206 if ((tattr
.va_fsid
!= rattr
.va_fsid
||
207 tattr
.va_nodeid
!= rattr
.va_nodeid
) &&
208 (error
= secpolicy_chroot(CRED())) != 0)
211 vpp
= &PTOU(pp
)->u_rdir
;
213 vpp
= &PTOU(pp
)->u_cdir
;
216 mutex_enter(&pp
->p_lock
);
218 * This bit of logic prevents us from overwriting u_cwd if we are
219 * changing to the same directory. We set the cwd to NULL so that we
220 * don't try to do the lookup on the next call to getcwd().
222 if (!ischroot
&& *vpp
!= NULL
&& vp
!= NULL
&& VN_CMP(*vpp
, vp
))
227 if ((cwd
= PTOU(pp
)->u_cwd
) != NULL
&& newcwd
)
228 PTOU(pp
)->u_cwd
= NULL
;
229 mutex_exit(&pp
->p_lock
);