1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// This file is part of yash, an extended POSIX shell.
// Copyright (C) 2023 WATANABE Yuki
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Cd built-in
//!
//! The **`cd`** built-in changes the working directory.
//!
//! # Synopsis
//!
//! ```sh
//! cd [-L|-P] [directory]
//! ```
//!
//! # Description
//!
//! The built-in changes the working directory to the specified directory. The
//! new working directory is determined from the option and operand as follows:
//!
//! 1. If the operand is omitted, the value of `$HOME` is used for the operand.
//! If the operand is a single hyphen (`-`), the value of `$OLDPWD` is used
//! for the operand. If the variable is not set or empty, it is an error.
//! Otherwise, the operand is used as is.
//! 2. If the operand does not start with a slash (`/`) and the first pathname
//! component in the operand is neither dot (`.`) nor dot-dot (`..`), the
//! built-in searches the directories specified by the `$CDPATH` variable for
//! a first directory that contains the operand as a subdirectory.
//! If such a directory is found, the operand is replaced with the path to
//! the subdirectory, that is, the concatenation of the directory contained
//! in `$CDPATH` and the previous operand.
//! If no such directory is found, the operand is used as is.
//! (See below for security implications of `$CDPATH`.)
//! 3. If the `-L` option is effective, the operand is canonicalized as follows:
//! 1. If the operand does not start with a slash (`/`), the value of `$PWD`
//! is prepended to the operand.
//! 2. The dot (`.`) components in the operand are removed.
//! 3. The dot-dot (`..`) components in the operand are removed along with
//! the preceding component. However, if such a preceding component
//! refers to a non-existent directory, it is an error.
//! 4. Redundant slashes in the operand are removed.
//!
//! The working directory is changed to the operand after the above processing.
//! If the change is successful, the value of `$PWD` is updated to the new
//! working directory:
//!
//! - If the `-L` option is effective, the final operand value becomes the new
//! value of `$PWD`.
//! - If the `-P` option is effective, the new `$PWD` value is recomputed in the
//! same way as `pwd -P` does, so it does not include symbolic links.
//!
//! The previous `$PWD` value is assigned to `$OLDPWD`.
//!
//! If the new working directory is taken from `$CDPATH` or the operand is a
//! single hyphen (`-`), the built-in prints the new value of `$PWD` followed by
//! a newline to the standard output. (TODO: This printing can be enforced or
//! suppressed with the **`--print`** option.)
//!
//! # Options
//!
//! With the **`-L`** (**`--logical`**) option, the operand is resolved
//! logically, that is, the canonicalization is performed as above. With the
//! **`-P`** (**`--physical`**) option, the operand is resolved physically; the
//! canonicalization is skipped.
//! These two options are mutually exclusive. The last specified one applies if
//! given both. The default is `-L`.
//!
//! TODO: The **`--default-directory=directory`** option is not implemented.
//!
//! TODO: The **`--print={always,auto,never}`** option is not implemented.
//!
//! # Operands
//!
//! The built-in takes a single operand that specifies the directory to change
//! to. If omitted, the value of `$HOME` is used. If the operand is a single
//! hyphen (`-`), the value of `$OLDPWD` is used.
//!
//! # Errors
//!
//! This built-in may fail with a non-zero exit status when:
//!
//! - The operand does not resolve to an existing accessible directory.
//! - The operand is omitted and `$HOME` is not set or empty.
//! - The operand is a single hyphen (`-`) and `$OLDPWD` is not set or empty.
//! - The resolved pathname of the new working directory is too long.
//!
//! The built-in may also fail in the following cases, but the working directory
//! will remain changed and the exit status will be zero:
//!
//! - The new working directory cannot be written to the standard output.
//! - `$PWD` or `$OLDPWD` is read-only.
//!
//! # Exit Status
//!
//! Zero if the working directory was successfully changed; non-zero otherwise.
//!
//! # Security considerations
//!
//! Although `$CDPATH` can be helpful if used correctly, it can catch unwary
//! users off guard, leading to unintended changes in the behavior of shell
//! scripts. If a shell script is executed with the `$CDPATH` environment
//! variable set to a directory crafted by an attacker, the script may change
//! the working directory to an unexpected one. To ensure that the cd built-in
//! behaves as intended, shell script writers should unset the variable at the
//! beginning of the script. Users can configure `$CDPATH` in their shell
//! sessions, but must avoid exporting the variable to the environment.
//!
//! # Portability
//!
//! The `-L` and `-P` options are defined in POSIX. The other options are
//! non-standard.
//!
//! The shell sets `$PWD` on the startup and modifies it in the cd built-in.
//! If `$PWD` is modified or unset otherwise, the behavior of the cd and
//! [pwd](crate::pwd) built-ins is unspecified.
//!
//! The error handling behavior and the exit status do not agree between
//! existing implementations when the built-in fails because of a write error or
//! a read-only variable error.
//!
//! POSIX requires the shell to convert the pathname passed to the underlying
//! `chdir` system call to a shorter relative pathname when the `-L` option is
//! in effect. This conversion is mandatory if:
//!
//! - the original operand was not longer than PATH_MAX bytes (including the
//! terminating nul byte),
//! - the final operand is longer than PATH_MAX bytes (including the terminating
//! nul byte), and
//! - the final operand starts with `$PWD` and hence can be considered to be a
//! subdirectory of the current working directory.
//!
//! POSIX does not specify whether the shell should perform the conversion if
//! the above conditions are not met. The current implementation does it if and
//! only if the final operand starts with `$PWD`.
use cratereport_error;
use cratereport_failure;
use crateResult;
use Path;
use Field;
use PWD;
use Env;
/// Treatments of symbolic links in the pathname
/// Parsed command line arguments
/// Entry point for executing the `cd` built-in
///
/// This function uses functions in the submodules to execute the built-in.
pub async