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>
60 #include <sys/fs_subr.h>
63 * Change current working directory (".").
65 static int chdirec(vnode_t
*, int ischroot
, int do_traverse
);
75 if (error
= lookupname(fname
, UIO_USERSPACE
, FOLLOW
, NULLVPP
, &vp
)) {
76 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
78 return (set_errno(error
));
81 error
= chdirec(vp
, 0, 1);
83 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
85 return (set_errno(error
));
91 * File-descriptor based version of 'chdir'.
100 if ((fp
= getf(fd
)) == NULL
)
101 return (set_errno(EBADF
));
105 error
= chdirec(vp
, 0, 0);
107 return (set_errno(error
));
112 * Change notion of root ("/") directory.
119 int estale_retry
= 0;
122 if (error
= lookupname(fname
, UIO_USERSPACE
, FOLLOW
, NULLVPP
, &vp
)) {
123 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
125 return (set_errno(error
));
128 error
= chdirec(vp
, 1, 1);
130 if ((error
== ESTALE
) && fs_need_estale_retry(estale_retry
++))
132 return (set_errno(error
));
138 * ++++++++++++++++++++++++
139 * ++ SunOS4.1 Buyback ++
140 * ++++++++++++++++++++++++
141 * Change root directory with a user given fd
150 if ((fp
= getf(fd
)) == NULL
)
151 return (set_errno(EBADF
));
155 error
= chdirec(vp
, 1, 0);
157 return (set_errno(error
));
162 chdirec(vnode_t
*vp
, int ischroot
, int do_traverse
)
166 proc_t
*pp
= curproc
;
171 if (vp
->v_type
!= VDIR
) {
175 if (error
= fop_access(vp
, VEXEC
, 0, CRED(), NULL
))
179 * The fop_access() may have covered 'vp' with a new filesystem,
180 * if 'vp' is an autoFS vnode. Traverse the mountpoint so
181 * that we don't end up with a covered current directory.
183 if (vn_mountedvfs(vp
) != NULL
&& do_traverse
) {
184 if (error
= traverse(&vp
))
189 * Special chroot semantics: chroot is allowed if privileged
190 * or if the target is really a loopback mount of the root (or
191 * root of the zone) as determined by comparing dev and inode
197 vnode_t
*zonevp
= curproc
->p_zone
->zone_rootvp
;
199 tattr
.va_mask
= AT_FSID
|AT_NODEID
;
200 if (error
= fop_getattr(vp
, &tattr
, 0, CRED(), NULL
))
203 rattr
.va_mask
= AT_FSID
|AT_NODEID
;
204 if (error
= fop_getattr(zonevp
, &rattr
, 0, CRED(), NULL
))
207 if ((tattr
.va_fsid
!= rattr
.va_fsid
||
208 tattr
.va_nodeid
!= rattr
.va_nodeid
) &&
209 (error
= secpolicy_chroot(CRED())) != 0)
212 vpp
= &PTOU(pp
)->u_rdir
;
214 vpp
= &PTOU(pp
)->u_cdir
;
217 /* update abs cwd/root path see c2/audit.c */
219 audit_chdirec(vp
, vpp
);
221 mutex_enter(&pp
->p_lock
);
223 * This bit of logic prevents us from overwriting u_cwd if we are
224 * changing to the same directory. We set the cwd to NULL so that we
225 * don't try to do the lookup on the next call to getcwd().
227 if (!ischroot
&& *vpp
!= NULL
&& vp
!= NULL
&& VN_CMP(*vpp
, vp
))
232 if ((cwd
= PTOU(pp
)->u_cwd
) != NULL
&& newcwd
)
233 PTOU(pp
)->u_cwd
= NULL
;
234 mutex_exit(&pp
->p_lock
);