Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/src/pwd.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* pwd - print current directory | - | ||||||||||||||||||||||||
2 | Copyright (C) 1994-2018 Free Software Foundation, Inc. | - | ||||||||||||||||||||||||
3 | - | |||||||||||||||||||||||||
4 | This program is free software: you can redistribute it and/or modify | - | ||||||||||||||||||||||||
5 | it under the terms of the GNU General Public License as published by | - | ||||||||||||||||||||||||
6 | the Free Software Foundation, either version 3 of the License, or | - | ||||||||||||||||||||||||
7 | (at your option) any later version. | - | ||||||||||||||||||||||||
8 | - | |||||||||||||||||||||||||
9 | This program is distributed in the hope that it will be useful, | - | ||||||||||||||||||||||||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | ||||||||||||||||||||||||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | ||||||||||||||||||||||||
12 | GNU General Public License for more details. | - | ||||||||||||||||||||||||
13 | - | |||||||||||||||||||||||||
14 | You should have received a copy of the GNU General Public License | - | ||||||||||||||||||||||||
15 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ | - | ||||||||||||||||||||||||
16 | - | |||||||||||||||||||||||||
17 | #include <config.h> | - | ||||||||||||||||||||||||
18 | #include <getopt.h> | - | ||||||||||||||||||||||||
19 | #include <stdio.h> | - | ||||||||||||||||||||||||
20 | #include <sys/types.h> | - | ||||||||||||||||||||||||
21 | - | |||||||||||||||||||||||||
22 | #include "system.h" | - | ||||||||||||||||||||||||
23 | #include "die.h" | - | ||||||||||||||||||||||||
24 | #include "error.h" | - | ||||||||||||||||||||||||
25 | #include "quote.h" | - | ||||||||||||||||||||||||
26 | #include "root-dev-ino.h" | - | ||||||||||||||||||||||||
27 | #include "xgetcwd.h" | - | ||||||||||||||||||||||||
28 | - | |||||||||||||||||||||||||
29 | /* The official name of this program (e.g., no 'g' prefix). */ | - | ||||||||||||||||||||||||
30 | #define PROGRAM_NAME "pwd" | - | ||||||||||||||||||||||||
31 | - | |||||||||||||||||||||||||
32 | #define AUTHORS proper_name ("Jim Meyering") | - | ||||||||||||||||||||||||
33 | - | |||||||||||||||||||||||||
34 | struct file_name | - | ||||||||||||||||||||||||
35 | { | - | ||||||||||||||||||||||||
36 | char *buf; | - | ||||||||||||||||||||||||
37 | size_t n_alloc; | - | ||||||||||||||||||||||||
38 | char *start; | - | ||||||||||||||||||||||||
39 | }; | - | ||||||||||||||||||||||||
40 | - | |||||||||||||||||||||||||
41 | static struct option const longopts[] = | - | ||||||||||||||||||||||||
42 | { | - | ||||||||||||||||||||||||
43 | {"logical", no_argument, NULL, 'L'}, | - | ||||||||||||||||||||||||
44 | {"physical", no_argument, NULL, 'P'}, | - | ||||||||||||||||||||||||
45 | {GETOPT_HELP_OPTION_DECL}, | - | ||||||||||||||||||||||||
46 | {GETOPT_VERSION_OPTION_DECL}, | - | ||||||||||||||||||||||||
47 | {NULL, 0, NULL, 0} | - | ||||||||||||||||||||||||
48 | }; | - | ||||||||||||||||||||||||
49 | - | |||||||||||||||||||||||||
50 | void | - | ||||||||||||||||||||||||
51 | usage (int status) | - | ||||||||||||||||||||||||
52 | { | - | ||||||||||||||||||||||||
53 | if (status != EXIT_SUCCESS)
| 1-2 | ||||||||||||||||||||||||
54 | emit_try_help (); executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||||||||
55 | else | - | ||||||||||||||||||||||||
56 | { | - | ||||||||||||||||||||||||
57 | printf (_("Usage: %s [OPTION]...\n"), program_name); | - | ||||||||||||||||||||||||
58 | fputs (_("\ | - | ||||||||||||||||||||||||
59 | Print the full filename of the current working directory.\n\ | - | ||||||||||||||||||||||||
60 | \n\ | - | ||||||||||||||||||||||||
61 | "), stdout); | - | ||||||||||||||||||||||||
62 | fputs (_("\ | - | ||||||||||||||||||||||||
63 | -L, --logical use PWD from environment, even if it contains symlinks\n\ | - | ||||||||||||||||||||||||
64 | -P, --physical avoid all symlinks\n\ | - | ||||||||||||||||||||||||
65 | "), stdout); | - | ||||||||||||||||||||||||
66 | fputs (HELP_OPTION_DESCRIPTION, stdout); | - | ||||||||||||||||||||||||
67 | fputs (VERSION_OPTION_DESCRIPTION, stdout); | - | ||||||||||||||||||||||||
68 | fputs (_("\n\ | - | ||||||||||||||||||||||||
69 | If no option is specified, -P is assumed.\n\ | - | ||||||||||||||||||||||||
70 | "), stdout); | - | ||||||||||||||||||||||||
71 | printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); | - | ||||||||||||||||||||||||
72 | emit_ancillary_info (PROGRAM_NAME); | - | ||||||||||||||||||||||||
73 | } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||||||||
74 | exit (status); executed 3 times by 1 test: exit (status); Executed by:
| 3 | ||||||||||||||||||||||||
75 | } | - | ||||||||||||||||||||||||
76 | - | |||||||||||||||||||||||||
77 | static void | - | ||||||||||||||||||||||||
78 | file_name_free (struct file_name *p) | - | ||||||||||||||||||||||||
79 | { | - | ||||||||||||||||||||||||
80 | free (p->buf); | - | ||||||||||||||||||||||||
81 | free (p); | - | ||||||||||||||||||||||||
82 | } never executed: end of block | 0 | ||||||||||||||||||||||||
83 | - | |||||||||||||||||||||||||
84 | static struct file_name * | - | ||||||||||||||||||||||||
85 | file_name_init (void) | - | ||||||||||||||||||||||||
86 | { | - | ||||||||||||||||||||||||
87 | struct file_name *p = xmalloc (sizeof *p); | - | ||||||||||||||||||||||||
88 | - | |||||||||||||||||||||||||
89 | /* Start with a buffer larger than PATH_MAX, but beware of systems | - | ||||||||||||||||||||||||
90 | on which PATH_MAX is very large -- e.g., INT_MAX. */ | - | ||||||||||||||||||||||||
91 | p->n_alloc = MIN (2 * PATH_MAX, 32 * 1024);
| 0 | ||||||||||||||||||||||||
92 | - | |||||||||||||||||||||||||
93 | p->buf = xmalloc (p->n_alloc); | - | ||||||||||||||||||||||||
94 | p->start = p->buf + (p->n_alloc - 1); | - | ||||||||||||||||||||||||
95 | p->start[0] = '\0'; | - | ||||||||||||||||||||||||
96 | return p; never executed: return p; | 0 | ||||||||||||||||||||||||
97 | } | - | ||||||||||||||||||||||||
98 | - | |||||||||||||||||||||||||
99 | /* Prepend the name S of length S_LEN, to the growing file_name, P. */ | - | ||||||||||||||||||||||||
100 | static void | - | ||||||||||||||||||||||||
101 | file_name_prepend (struct file_name *p, char const *s, size_t s_len) | - | ||||||||||||||||||||||||
102 | { | - | ||||||||||||||||||||||||
103 | size_t n_free = p->start - p->buf; | - | ||||||||||||||||||||||||
104 | if (n_free < 1 + s_len)
| 0 | ||||||||||||||||||||||||
105 | { | - | ||||||||||||||||||||||||
106 | size_t half = p->n_alloc + 1 + s_len; | - | ||||||||||||||||||||||||
107 | /* Use xnmalloc+free rather than xnrealloc, since with the latter | - | ||||||||||||||||||||||||
108 | we'd end up copying the data twice: once via realloc, then again | - | ||||||||||||||||||||||||
109 | to align it with the end of the new buffer. With xnmalloc, we | - | ||||||||||||||||||||||||
110 | copy it only once. */ | - | ||||||||||||||||||||||||
111 | char *q = xnmalloc (2, half); | - | ||||||||||||||||||||||||
112 | size_t n_used = p->n_alloc - n_free; | - | ||||||||||||||||||||||||
113 | p->start = q + 2 * half - n_used; | - | ||||||||||||||||||||||||
114 | memcpy (p->start, p->buf + n_free, n_used); | - | ||||||||||||||||||||||||
115 | free (p->buf); | - | ||||||||||||||||||||||||
116 | p->buf = q; | - | ||||||||||||||||||||||||
117 | p->n_alloc = 2 * half; | - | ||||||||||||||||||||||||
118 | } never executed: end of block | 0 | ||||||||||||||||||||||||
119 | - | |||||||||||||||||||||||||
120 | p->start -= 1 + s_len; | - | ||||||||||||||||||||||||
121 | p->start[0] = '/'; | - | ||||||||||||||||||||||||
122 | memcpy (p->start + 1, s, s_len); | - | ||||||||||||||||||||||||
123 | } never executed: end of block | 0 | ||||||||||||||||||||||||
124 | - | |||||||||||||||||||||||||
125 | /* Return a string (malloc'd) consisting of N '/'-separated ".." components. */ | - | ||||||||||||||||||||||||
126 | static char * | - | ||||||||||||||||||||||||
127 | nth_parent (size_t n) | - | ||||||||||||||||||||||||
128 | { | - | ||||||||||||||||||||||||
129 | char *buf = xnmalloc (3, n); | - | ||||||||||||||||||||||||
130 | char *p = buf; | - | ||||||||||||||||||||||||
131 | - | |||||||||||||||||||||||||
132 | for (size_t i = 0; i < n; i++)
| 0 | ||||||||||||||||||||||||
133 | { | - | ||||||||||||||||||||||||
134 | memcpy (p, "../", 3); | - | ||||||||||||||||||||||||
135 | p += 3; | - | ||||||||||||||||||||||||
136 | } never executed: end of block | 0 | ||||||||||||||||||||||||
137 | p[-1] = '\0'; | - | ||||||||||||||||||||||||
138 | return buf; never executed: return buf; | 0 | ||||||||||||||||||||||||
139 | } | - | ||||||||||||||||||||||||
140 | - | |||||||||||||||||||||||||
141 | /* Determine the basename of the current directory, where DOT_SB is the | - | ||||||||||||||||||||||||
142 | result of lstat'ing "." and prepend that to the file name in *FILE_NAME. | - | ||||||||||||||||||||||||
143 | Find the directory entry in '..' that matches the dev/i-node of DOT_SB. | - | ||||||||||||||||||||||||
144 | Upon success, update *DOT_SB with stat information of '..', chdir to '..', | - | ||||||||||||||||||||||||
145 | and prepend "/basename" to FILE_NAME. | - | ||||||||||||||||||||||||
146 | Otherwise, exit with a diagnostic. | - | ||||||||||||||||||||||||
147 | PARENT_HEIGHT is the number of levels '..' is above the starting directory. | - | ||||||||||||||||||||||||
148 | The first time this function is called (from the initial directory), | - | ||||||||||||||||||||||||
149 | PARENT_HEIGHT is 1. This is solely for diagnostics. | - | ||||||||||||||||||||||||
150 | Exit nonzero upon error. */ | - | ||||||||||||||||||||||||
151 | - | |||||||||||||||||||||||||
152 | static void | - | ||||||||||||||||||||||||
153 | find_dir_entry (struct stat *dot_sb, struct file_name *file_name, | - | ||||||||||||||||||||||||
154 | size_t parent_height) | - | ||||||||||||||||||||||||
155 | { | - | ||||||||||||||||||||||||
156 | DIR *dirp; | - | ||||||||||||||||||||||||
157 | int fd; | - | ||||||||||||||||||||||||
158 | struct stat parent_sb; | - | ||||||||||||||||||||||||
159 | bool use_lstat; | - | ||||||||||||||||||||||||
160 | bool found; | - | ||||||||||||||||||||||||
161 | - | |||||||||||||||||||||||||
162 | dirp = opendir (".."); | - | ||||||||||||||||||||||||
163 | if (dirp == NULL)
| 0 | ||||||||||||||||||||||||
164 | die (EXIT_FAILURE, errno, _("cannot open directory %s"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"cannot open directory %s\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 ,...t (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "cannot open directory %s" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
165 | quote (nth_parent (parent_height))); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"cannot open directory %s\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 ,...t (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "cannot open directory %s" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
166 | - | |||||||||||||||||||||||||
167 | fd = dirfd (dirp); | - | ||||||||||||||||||||||||
168 | if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
| 0 | ||||||||||||||||||||||||
169 | die (EXIT_FAILURE, errno, _("failed to chdir to %s"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to chdir to %s\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , (*...rent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to chdir to %s" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
170 | quote (nth_parent (parent_height))); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to chdir to %s\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , (*...rent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to chdir to %s" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
171 | - | |||||||||||||||||||||||||
172 | if ((0 <= fd ? fstat (fd, &parent_sb) : stat (".", &parent_sb)) < 0)
| 0 | ||||||||||||||||||||||||
173 | die (EXIT_FAILURE, errno, _("failed to stat %s"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to stat %s\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , (*__er...h_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to stat %s" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
174 | quote (nth_parent (parent_height))); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to stat %s\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , (*__er...h_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to stat %s" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
175 | - | |||||||||||||||||||||||||
176 | /* If parent and child directory are on different devices, then we | - | ||||||||||||||||||||||||
177 | can't rely on d_ino for useful i-node numbers; use lstat instead. */ | - | ||||||||||||||||||||||||
178 | use_lstat = (parent_sb.st_dev != dot_sb->st_dev); | - | ||||||||||||||||||||||||
179 | - | |||||||||||||||||||||||||
180 | found = false; | - | ||||||||||||||||||||||||
181 | while (1) | - | ||||||||||||||||||||||||
182 | { | - | ||||||||||||||||||||||||
183 | struct dirent const *dp; | - | ||||||||||||||||||||||||
184 | struct stat ent_sb; | - | ||||||||||||||||||||||||
185 | ino_t ino; | - | ||||||||||||||||||||||||
186 | - | |||||||||||||||||||||||||
187 | errno = 0; | - | ||||||||||||||||||||||||
188 | if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
| 0 | ||||||||||||||||||||||||
189 | { | - | ||||||||||||||||||||||||
190 | if (errno)
| 0 | ||||||||||||||||||||||||
191 | { | - | ||||||||||||||||||||||||
192 | /* Save/restore errno across closedir call. */ | - | ||||||||||||||||||||||||
193 | int e = errno; | - | ||||||||||||||||||||||||
194 | closedir (dirp); | - | ||||||||||||||||||||||||
195 | errno = e; | - | ||||||||||||||||||||||||
196 | - | |||||||||||||||||||||||||
197 | /* Arrange to give a diagnostic after exiting this loop. */ | - | ||||||||||||||||||||||||
198 | dirp = NULL; | - | ||||||||||||||||||||||||
199 | } never executed: end of block | 0 | ||||||||||||||||||||||||
200 | break; never executed: break; | 0 | ||||||||||||||||||||||||
201 | } | - | ||||||||||||||||||||||||
202 | - | |||||||||||||||||||||||||
203 | ino = D_INO (dp); | - | ||||||||||||||||||||||||
204 | - | |||||||||||||||||||||||||
205 | if (ino == NOT_AN_INODE_NUMBER || use_lstat)
| 0 | ||||||||||||||||||||||||
206 | { | - | ||||||||||||||||||||||||
207 | if (lstat (dp->d_name, &ent_sb) < 0)
| 0 | ||||||||||||||||||||||||
208 | { | - | ||||||||||||||||||||||||
209 | /* Skip any entry we can't stat. */ | - | ||||||||||||||||||||||||
210 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
211 | } | - | ||||||||||||||||||||||||
212 | ino = ent_sb.st_ino; | - | ||||||||||||||||||||||||
213 | } never executed: end of block | 0 | ||||||||||||||||||||||||
214 | - | |||||||||||||||||||||||||
215 | if (ino != dot_sb->st_ino)
| 0 | ||||||||||||||||||||||||
216 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
217 | - | |||||||||||||||||||||||||
218 | /* If we're not crossing a device boundary, then a simple i-node | - | ||||||||||||||||||||||||
219 | match is enough. */ | - | ||||||||||||||||||||||||
220 | if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
| 0 | ||||||||||||||||||||||||
221 | { | - | ||||||||||||||||||||||||
222 | file_name_prepend (file_name, dp->d_name, _D_EXACT_NAMLEN (dp)); | - | ||||||||||||||||||||||||
223 | found = true; | - | ||||||||||||||||||||||||
224 | break; never executed: break; | 0 | ||||||||||||||||||||||||
225 | } | - | ||||||||||||||||||||||||
226 | } never executed: end of block | 0 | ||||||||||||||||||||||||
227 | - | |||||||||||||||||||||||||
228 | if (dirp == NULL || closedir (dirp) != 0)
| 0 | ||||||||||||||||||||||||
229 | { | - | ||||||||||||||||||||||||
230 | /* Note that this diagnostic serves for both readdir | - | ||||||||||||||||||||||||
231 | and closedir failures. */ | - | ||||||||||||||||||||||||
232 | die (EXIT_FAILURE, errno, _("reading directory %s"), | - | ||||||||||||||||||||||||
233 | quote (nth_parent (parent_height))); | - | ||||||||||||||||||||||||
234 | } never executed: end of block | 0 | ||||||||||||||||||||||||
235 | - | |||||||||||||||||||||||||
236 | if ( ! found)
| 0 | ||||||||||||||||||||||||
237 | die (EXIT_FAILURE, 0, never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"couldn't find directory entry in %s with matching i-node\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((...height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "couldn't find directory entry in %s with matching i-node" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
238 | _("couldn't find directory entry in %s with matching i-node"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"couldn't find directory entry in %s with matching i-node\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((...height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "couldn't find directory entry in %s with matching i-node" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
239 | quote (nth_parent (parent_height))); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"couldn't find directory entry in %s with matching i-node\", 5), quote (nth_parent (parent_height))), assume (false))" ")"); int _gl_dummy; })) ? ((...height))), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "couldn't find directory entry in %s with matching i-node" , 5) , quote (nth_parent (parent_height))), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
240 | - | |||||||||||||||||||||||||
241 | *dot_sb = parent_sb; | - | ||||||||||||||||||||||||
242 | } never executed: end of block | 0 | ||||||||||||||||||||||||
243 | - | |||||||||||||||||||||||||
244 | /* Construct the full, absolute name of the current working | - | ||||||||||||||||||||||||
245 | directory and store it in *FILE_NAME. | - | ||||||||||||||||||||||||
246 | The getcwd function performs nearly the same task, but is typically | - | ||||||||||||||||||||||||
247 | unable to handle names longer than PATH_MAX. This function has | - | ||||||||||||||||||||||||
248 | no such limitation. However, this function *can* fail due to | - | ||||||||||||||||||||||||
249 | permission problems or a lack of memory, while GNU/Linux's getcwd | - | ||||||||||||||||||||||||
250 | function works regardless of restricted permissions on parent | - | ||||||||||||||||||||||||
251 | directories. Upon failure, give a diagnostic and exit nonzero. | - | ||||||||||||||||||||||||
252 | - | |||||||||||||||||||||||||
253 | Note: although this function is similar to getcwd, it has a fundamental | - | ||||||||||||||||||||||||
254 | difference in that it gives a diagnostic and exits upon failure. | - | ||||||||||||||||||||||||
255 | I would have liked a function that did not exit, and that could be | - | ||||||||||||||||||||||||
256 | used as a getcwd replacement. Unfortunately, considering all of | - | ||||||||||||||||||||||||
257 | the information the caller would require in order to produce good | - | ||||||||||||||||||||||||
258 | diagnostics, it doesn't seem worth the added complexity. | - | ||||||||||||||||||||||||
259 | In any case, any getcwd replacement must *not* exceed the PATH_MAX | - | ||||||||||||||||||||||||
260 | limitation. Otherwise, functions like 'chdir' would fail with | - | ||||||||||||||||||||||||
261 | ENAMETOOLONG. | - | ||||||||||||||||||||||||
262 | - | |||||||||||||||||||||||||
263 | FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd, | - | ||||||||||||||||||||||||
264 | in case the unreadable directory is close enough to the root that | - | ||||||||||||||||||||||||
265 | getcwd works from there. */ | - | ||||||||||||||||||||||||
266 | - | |||||||||||||||||||||||||
267 | static void | - | ||||||||||||||||||||||||
268 | robust_getcwd (struct file_name *file_name) | - | ||||||||||||||||||||||||
269 | { | - | ||||||||||||||||||||||||
270 | size_t height = 1; | - | ||||||||||||||||||||||||
271 | struct dev_ino dev_ino_buf; | - | ||||||||||||||||||||||||
272 | struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf); | - | ||||||||||||||||||||||||
273 | struct stat dot_sb; | - | ||||||||||||||||||||||||
274 | - | |||||||||||||||||||||||||
275 | if (root_dev_ino == NULL)
| 0 | ||||||||||||||||||||||||
276 | die (EXIT_FAILURE, errno, _("failed to get attributes of %s"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to get attributes of %s\", 5), quotearg_style (shell_escape_always_quoting_style, \"/\")), assume (false))" ")"); int _... ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to get attributes of %s" , 5) , quotearg_style (shell_escape_always_quoting_style, "/")), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
277 | quoteaf ("/")); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to get attributes of %s\", 5), quotearg_style (shell_escape_always_quoting_style, \"/\")), assume (false))" ")"); int _... ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to get attributes of %s" , 5) , quotearg_style (shell_escape_always_quoting_style, "/")), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||||||||
278 | - | |||||||||||||||||||||||||
279 | if (stat (".", &dot_sb) < 0)
| 0 | ||||||||||||||||||||||||
280 | die (EXIT_FAILURE, errno, _("failed to stat %s"), quoteaf (".")); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to stat %s\", 5), quotearg_style (shell_escape_always_quoting_style, \".\")), assume (false))" ")"); int _gl_dummy; }))... ".")), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to stat %s" , 5) , quotearg_style (shell_escape_always_quoting_style, ".")), (( 0 ) ? (void) 0 : __builtin_unreachable ())))); | 0 | ||||||||||||||||||||||||
281 | - | |||||||||||||||||||||||||
282 | while (1) | - | ||||||||||||||||||||||||
283 | { | - | ||||||||||||||||||||||||
284 | /* If we've reached the root, we're done. */ | - | ||||||||||||||||||||||||
285 | if (SAME_INODE (dot_sb, *root_dev_ino))
| 0 | ||||||||||||||||||||||||
286 | break; never executed: break; | 0 | ||||||||||||||||||||||||
287 | - | |||||||||||||||||||||||||
288 | find_dir_entry (&dot_sb, file_name, height++); | - | ||||||||||||||||||||||||
289 | } never executed: end of block | 0 | ||||||||||||||||||||||||
290 | - | |||||||||||||||||||||||||
291 | /* See if a leading slash is needed; file_name_prepend adds one. */ | - | ||||||||||||||||||||||||
292 | if (file_name->start[0] == '\0')
| 0 | ||||||||||||||||||||||||
293 | file_name_prepend (file_name, "", 0); never executed: file_name_prepend (file_name, "", 0); | 0 | ||||||||||||||||||||||||
294 | } never executed: end of block | 0 | ||||||||||||||||||||||||
295 | - | |||||||||||||||||||||||||
296 | - | |||||||||||||||||||||||||
297 | /* Return PWD from the environment if it is acceptable for 'pwd -L' | - | ||||||||||||||||||||||||
298 | output, otherwise NULL. */ | - | ||||||||||||||||||||||||
299 | static char * | - | ||||||||||||||||||||||||
300 | logical_getcwd (void) | - | ||||||||||||||||||||||||
301 | { | - | ||||||||||||||||||||||||
302 | struct stat st1; | - | ||||||||||||||||||||||||
303 | struct stat st2; | - | ||||||||||||||||||||||||
304 | char *wd = getenv ("PWD"); | - | ||||||||||||||||||||||||
305 | char *p; | - | ||||||||||||||||||||||||
306 | - | |||||||||||||||||||||||||
307 | /* Textual validation first. */ | - | ||||||||||||||||||||||||
308 | if (!wd || wd[0] != '/')
| 0-5 | ||||||||||||||||||||||||
309 | return NULL; executed 1 time by 1 test: return ((void *)0) ; Executed by:
| 1 | ||||||||||||||||||||||||
310 | p = wd; | - | ||||||||||||||||||||||||
311 | while ((p = strstr (p, "/.")))
| 2 | ||||||||||||||||||||||||
312 | { | - | ||||||||||||||||||||||||
313 | if (!p[2] || p[2] == '/'
| 0-1 | ||||||||||||||||||||||||
314 | || (p[2] == '.' && (!p[3] || p[3] == '/')))
| 0-1 | ||||||||||||||||||||||||
315 | return NULL; executed 2 times by 1 test: return ((void *)0) ; Executed by:
| 2 | ||||||||||||||||||||||||
316 | p++; | - | ||||||||||||||||||||||||
317 | } never executed: end of block | 0 | ||||||||||||||||||||||||
318 | - | |||||||||||||||||||||||||
319 | /* System call validation. */ | - | ||||||||||||||||||||||||
320 | if (stat (wd, &st1) == 0 && stat (".", &st2) == 0 && SAME_INODE (st1, st2))
| 0-2 | ||||||||||||||||||||||||
321 | return wd; executed 2 times by 1 test: return wd; Executed by:
| 2 | ||||||||||||||||||||||||
322 | return NULL; never executed: return ((void *)0) ; | 0 | ||||||||||||||||||||||||
323 | } | - | ||||||||||||||||||||||||
324 | - | |||||||||||||||||||||||||
325 | - | |||||||||||||||||||||||||
326 | int | - | ||||||||||||||||||||||||
327 | main (int argc, char **argv) | - | ||||||||||||||||||||||||
328 | { | - | ||||||||||||||||||||||||
329 | char *wd; | - | ||||||||||||||||||||||||
330 | /* POSIX requires a default of -L, but most scripts expect -P. | - | ||||||||||||||||||||||||
331 | Currently shells default to -L, while stand-alone | - | ||||||||||||||||||||||||
332 | pwd implementations default to -P. */ | - | ||||||||||||||||||||||||
333 | bool logical = (getenv ("POSIXLY_CORRECT") != NULL); | - | ||||||||||||||||||||||||
334 | - | |||||||||||||||||||||||||
335 | initialize_main (&argc, &argv); | - | ||||||||||||||||||||||||
336 | set_program_name (argv[0]); | - | ||||||||||||||||||||||||
337 | setlocale (LC_ALL, ""); | - | ||||||||||||||||||||||||
338 | bindtextdomain (PACKAGE, LOCALEDIR); | - | ||||||||||||||||||||||||
339 | textdomain (PACKAGE); | - | ||||||||||||||||||||||||
340 | - | |||||||||||||||||||||||||
341 | atexit (close_stdout); | - | ||||||||||||||||||||||||
342 | - | |||||||||||||||||||||||||
343 | while (1) | - | ||||||||||||||||||||||||
344 | { | - | ||||||||||||||||||||||||
345 | int c = getopt_long (argc, argv, "LP", longopts, NULL); | - | ||||||||||||||||||||||||
346 | if (c == -1)
| 17-26 | ||||||||||||||||||||||||
347 | break; executed 17 times by 1 test: break; Executed by:
| 17 | ||||||||||||||||||||||||
348 | switch (c) | - | ||||||||||||||||||||||||
349 | { | - | ||||||||||||||||||||||||
350 | case 'L': executed 5 times by 1 test: case 'L': Executed by:
| 5 | ||||||||||||||||||||||||
351 | logical = true; | - | ||||||||||||||||||||||||
352 | break; executed 5 times by 1 test: break; Executed by:
| 5 | ||||||||||||||||||||||||
353 | case 'P': executed 7 times by 1 test: case 'P': Executed by:
| 7 | ||||||||||||||||||||||||
354 | logical = false; | - | ||||||||||||||||||||||||
355 | break; executed 7 times by 1 test: break; Executed by:
| 7 | ||||||||||||||||||||||||
356 | - | |||||||||||||||||||||||||
357 | case_GETOPT_HELP_CHAR; never executed: break; executed 2 times by 1 test: case GETOPT_HELP_CHAR: Executed by:
| 0-2 | ||||||||||||||||||||||||
358 | - | |||||||||||||||||||||||||
359 | case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); executed 11 times by 1 test: exit ( 0 ); Executed by:
never executed: break; executed 11 times by 1 test: case GETOPT_VERSION_CHAR: Executed by:
| 0-11 | ||||||||||||||||||||||||
360 | - | |||||||||||||||||||||||||
361 | default: executed 1 time by 1 test: default: Executed by:
| 1 | ||||||||||||||||||||||||
362 | usage (EXIT_FAILURE); | - | ||||||||||||||||||||||||
363 | } never executed: end of block | 0 | ||||||||||||||||||||||||
364 | } | - | ||||||||||||||||||||||||
365 | - | |||||||||||||||||||||||||
366 | if (optind < argc)
| 0-17 | ||||||||||||||||||||||||
367 | error (0, 0, _("ignoring non-option arguments")); never executed: error (0, 0, dcgettext (((void *)0), "ignoring non-option arguments" , 5) ); | 0 | ||||||||||||||||||||||||
368 | - | |||||||||||||||||||||||||
369 | if (logical)
| 5-12 | ||||||||||||||||||||||||
370 | { | - | ||||||||||||||||||||||||
371 | wd = logical_getcwd (); | - | ||||||||||||||||||||||||
372 | if (wd)
| 2-3 | ||||||||||||||||||||||||
373 | { | - | ||||||||||||||||||||||||
374 | puts (wd); | - | ||||||||||||||||||||||||
375 | return EXIT_SUCCESS; executed 2 times by 1 test: return 0 ; Executed by:
| 2 | ||||||||||||||||||||||||
376 | } | - | ||||||||||||||||||||||||
377 | } executed 3 times by 1 test: end of block Executed by:
| 3 | ||||||||||||||||||||||||
378 | - | |||||||||||||||||||||||||
379 | wd = xgetcwd (); | - | ||||||||||||||||||||||||
380 | if (wd != NULL)
| 0-15 | ||||||||||||||||||||||||
381 | { | - | ||||||||||||||||||||||||
382 | puts (wd); | - | ||||||||||||||||||||||||
383 | free (wd); | - | ||||||||||||||||||||||||
384 | } executed 15 times by 1 test: end of block Executed by:
| 15 | ||||||||||||||||||||||||
385 | else | - | ||||||||||||||||||||||||
386 | { | - | ||||||||||||||||||||||||
387 | struct file_name *file_name = file_name_init (); | - | ||||||||||||||||||||||||
388 | robust_getcwd (file_name); | - | ||||||||||||||||||||||||
389 | puts (file_name->start); | - | ||||||||||||||||||||||||
390 | file_name_free (file_name); | - | ||||||||||||||||||||||||
391 | } never executed: end of block | 0 | ||||||||||||||||||||||||
392 | - | |||||||||||||||||||||||||
393 | return EXIT_SUCCESS; executed 15 times by 1 test: return 0 ; Executed by:
| 15 | ||||||||||||||||||||||||
394 | } | - | ||||||||||||||||||||||||
Source code | Switch to Preprocessed file |