1 /* pwd - print current directory
2 Copyright (C) 1994-2012 Free Software Foundation, Inc.
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include <sys/types.h>
25 #include "root-dev-ino.h"
28 /* The official name of this program (e.g., no 'g' prefix). */
29 #define PROGRAM_NAME "pwd"
31 #define AUTHORS proper_name ("Jim Meyering")
40 static struct option
const longopts
[] =
42 {"logical", no_argument
, NULL
, 'L'},
43 {"physical", no_argument
, NULL
, 'P'},
44 {GETOPT_HELP_OPTION_DECL
},
45 {GETOPT_VERSION_OPTION_DECL
},
52 if (status
!= EXIT_SUCCESS
)
56 printf (_("Usage: %s [OPTION]...\n"), program_name
);
58 Print the full filename of the current working directory.\n\
62 -L, --logical use PWD from environment, even if it contains symlinks\n\
63 -P, --physical avoid all symlinks\n\
65 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
66 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
67 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
68 emit_ancillary_info ();
74 file_name_free (struct file_name
*p
)
80 static struct file_name
*
83 struct file_name
*p
= xmalloc (sizeof *p
);
85 /* Start with a buffer larger than PATH_MAX, but beware of systems
86 on which PATH_MAX is very large -- e.g., INT_MAX. */
87 p
->n_alloc
= MIN (2 * PATH_MAX
, 32 * 1024);
89 p
->buf
= xmalloc (p
->n_alloc
);
90 p
->start
= p
->buf
+ (p
->n_alloc
- 1);
95 /* Prepend the name S of length S_LEN, to the growing file_name, P. */
97 file_name_prepend (struct file_name
*p
, char const *s
, size_t s_len
)
99 size_t n_free
= p
->start
- p
->buf
;
100 if (n_free
< 1 + s_len
)
102 size_t half
= p
->n_alloc
+ 1 + s_len
;
103 /* Use xnmalloc+free rather than xnrealloc, since with the latter
104 we'd end up copying the data twice: once via realloc, then again
105 to align it with the end of the new buffer. With xnmalloc, we
106 copy it only once. */
107 char *q
= xnmalloc (2, half
);
108 size_t n_used
= p
->n_alloc
- n_free
;
109 p
->start
= q
+ 2 * half
- n_used
;
110 memcpy (p
->start
, p
->buf
+ n_free
, n_used
);
113 p
->n_alloc
= 2 * half
;
116 p
->start
-= 1 + s_len
;
118 memcpy (p
->start
+ 1, s
, s_len
);
121 /* Return a string (malloc'd) consisting of N '/'-separated ".." components. */
123 nth_parent (size_t n
)
125 char *buf
= xnmalloc (3, n
);
129 for (i
= 0; i
< n
; i
++)
131 memcpy (p
, "../", 3);
138 /* Determine the basename of the current directory, where DOT_SB is the
139 result of lstat'ing "." and prepend that to the file name in *FILE_NAME.
140 Find the directory entry in '..' that matches the dev/i-node of DOT_SB.
141 Upon success, update *DOT_SB with stat information of '..', chdir to '..',
142 and prepend "/basename" to FILE_NAME.
143 Otherwise, exit with a diagnostic.
144 PARENT_HEIGHT is the number of levels '..' is above the starting directory.
145 The first time this function is called (from the initial directory),
146 PARENT_HEIGHT is 1. This is solely for diagnostics.
147 Exit nonzero upon error. */
150 find_dir_entry (struct stat
*dot_sb
, struct file_name
*file_name
,
151 size_t parent_height
)
155 struct stat parent_sb
;
159 dirp
= opendir ("..");
161 error (EXIT_FAILURE
, errno
, _("cannot open directory %s"),
162 quote (nth_parent (parent_height
)));
165 if ((0 <= fd
? fchdir (fd
) : chdir ("..")) < 0)
166 error (EXIT_FAILURE
, errno
, _("failed to chdir to %s"),
167 quote (nth_parent (parent_height
)));
169 if ((0 <= fd
? fstat (fd
, &parent_sb
) : stat (".", &parent_sb
)) < 0)
170 error (EXIT_FAILURE
, errno
, _("failed to stat %s"),
171 quote (nth_parent (parent_height
)));
173 /* If parent and child directory are on different devices, then we
174 can't rely on d_ino for useful i-node numbers; use lstat instead. */
175 use_lstat
= (parent_sb
.st_dev
!= dot_sb
->st_dev
);
180 struct dirent
const *dp
;
185 if ((dp
= readdir_ignoring_dot_and_dotdot (dirp
)) == NULL
)
189 /* Save/restore errno across closedir call. */
194 /* Arrange to give a diagnostic after exiting this loop. */
202 if (ino
== NOT_AN_INODE_NUMBER
|| use_lstat
)
204 if (lstat (dp
->d_name
, &ent_sb
) < 0)
206 /* Skip any entry we can't stat. */
212 if (ino
!= dot_sb
->st_ino
)
215 /* If we're not crossing a device boundary, then a simple i-node
217 if ( ! use_lstat
|| ent_sb
.st_dev
== dot_sb
->st_dev
)
219 file_name_prepend (file_name
, dp
->d_name
, _D_EXACT_NAMLEN (dp
));
225 if (dirp
== NULL
|| closedir (dirp
) != 0)
227 /* Note that this diagnostic serves for both readdir
228 and closedir failures. */
229 error (EXIT_FAILURE
, errno
, _("reading directory %s"),
230 quote (nth_parent (parent_height
)));
234 error (EXIT_FAILURE
, 0,
235 _("couldn't find directory entry in %s with matching i-node"),
236 quote (nth_parent (parent_height
)));
241 /* Construct the full, absolute name of the current working
242 directory and store it in *FILE_NAME.
243 The getcwd function performs nearly the same task, but is typically
244 unable to handle names longer than PATH_MAX. This function has
245 no such limitation. However, this function *can* fail due to
246 permission problems or a lack of memory, while GNU/Linux's getcwd
247 function works regardless of restricted permissions on parent
248 directories. Upon failure, give a diagnostic and exit nonzero.
250 Note: although this function is similar to getcwd, it has a fundamental
251 difference in that it gives a diagnostic and exits upon failure.
252 I would have liked a function that did not exit, and that could be
253 used as a getcwd replacement. Unfortunately, considering all of
254 the information the caller would require in order to produce good
255 diagnostics, it doesn't seem worth the added complexity.
256 In any case, any getcwd replacement must *not* exceed the PATH_MAX
257 limitation. Otherwise, functions like 'chdir' would fail with
260 FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd,
261 in case the unreadable directory is close enough to the root that
262 getcwd works from there. */
265 robust_getcwd (struct file_name
*file_name
)
268 struct dev_ino dev_ino_buf
;
269 struct dev_ino
*root_dev_ino
= get_root_dev_ino (&dev_ino_buf
);
272 if (root_dev_ino
== NULL
)
273 error (EXIT_FAILURE
, errno
, _("failed to get attributes of %s"),
276 if (stat (".", &dot_sb
) < 0)
277 error (EXIT_FAILURE
, errno
, _("failed to stat %s"), quote ("."));
281 /* If we've reached the root, we're done. */
282 if (SAME_INODE (dot_sb
, *root_dev_ino
))
285 find_dir_entry (&dot_sb
, file_name
, height
++);
288 /* See if a leading slash is needed; file_name_prepend adds one. */
289 if (file_name
->start
[0] == '\0')
290 file_name_prepend (file_name
, "", 0);
294 /* Return PWD from the environment if it is acceptable for 'pwd -L'
295 output, otherwise NULL. */
297 logical_getcwd (void)
301 char *wd
= getenv ("PWD");
304 /* Textual validation first. */
305 if (!wd
|| wd
[0] != '/')
308 while ((p
= strstr (p
, "/.")))
310 if (!p
[2] || p
[2] == '/'
311 || (p
[2] == '.' && (!p
[3] || p
[3] == '/')))
316 /* System call validation. */
317 if (stat (wd
, &st1
) == 0 && stat (".", &st2
) == 0 && SAME_INODE (st1
, st2
))
324 main (int argc
, char **argv
)
327 /* POSIX requires a default of -L, but most scripts expect -P. */
328 bool logical
= (getenv ("POSIXLY_CORRECT") != NULL
);
330 initialize_main (&argc
, &argv
);
331 set_program_name (argv
[0]);
332 setlocale (LC_ALL
, "");
333 bindtextdomain (PACKAGE
, LOCALEDIR
);
334 textdomain (PACKAGE
);
336 atexit (close_stdout
);
340 int c
= getopt_long (argc
, argv
, "LP", longopts
, NULL
);
352 case_GETOPT_HELP_CHAR
;
354 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
357 usage (EXIT_FAILURE
);
362 error (0, 0, _("ignoring non-option arguments"));
366 wd
= logical_getcwd ();
382 struct file_name
*file_name
= file_name_init ();
383 robust_getcwd (file_name
);
384 puts (file_name
->start
);
385 file_name_free (file_name
);