1 /* pwd - print current directory
2 Copyright (C) 1994-1997, 1999-2004 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 2, or (at your option)
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, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 #include <sys/types.h>
26 #include "long-options.h"
28 #include "root-dev-ino.h"
31 /* The official name of this program (e.g., no `g' prefix). */
32 #define PROGRAM_NAME "pwd"
34 #define AUTHORS "Jim Meyering"
45 NOT_AN_INODE_NUMBER = 0
48 #ifdef D_INO_IN_DIRENT
49 # define D_INO(dp) ((dp)->d_ino)
51 /* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */
52 # define D_INO(dp) NOT_AN_INODE_NUMBER
55 /* The name this program was run with. */
61 if (status != EXIT_SUCCESS)
62 fprintf (stderr, _("Try `%s --help' for more information.\n"),
66 printf (_("Usage: %s [OPTION]\n"), program_name);
68 Print the full filename of the current working directory.\n\
71 fputs (HELP_OPTION_DESCRIPTION, stdout);
72 fputs (VERSION_OPTION_DESCRIPTION, stdout);
73 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
79 path_free (struct Path *p)
88 struct Path *p = xmalloc (sizeof *p);
90 /* Start with a buffer larger than PATH_MAX, but beware of systems
91 on which PATH_MAX is very large -- e.g., INT_MAX. */
92 p->n_alloc = MIN (2 * PATH_MAX, 32 * 1024);
94 p->buf = xmalloc (p->n_alloc);
95 p->start = p->buf + (p->n_alloc - 1);
100 /* Prepend the name S of length S_LEN, to the growing path, P. */
102 path_prepend (struct Path *p, char const *s, size_t s_len)
104 size_t n_free = p->start - p->buf;
105 if (n_free < 1 + s_len)
107 size_t half = p->n_alloc + 1 + s_len;
108 /* Use xnmalloc+free rather than xnrealloc, since with the latter
109 we'd end up copying the data twice: once via realloc, then again
110 to align it with the end of the new buffer. With xnmalloc, we
111 copy it only once. */
112 char *q = xnmalloc (2, half);
113 size_t n_used = p->n_alloc - n_free;
114 p->start = q + 2 * half - n_used;
115 memcpy (p->start, p->buf + n_free, n_used);
118 p->n_alloc = 2 * half;
121 p->start -= 1 + s_len;
123 memcpy (p->start + 1, s, s_len);
126 /* Return a string (malloc'd) consisting of N `/'-separated ".." components. */
128 nth_parent (size_t n)
130 char *buf = xnmalloc (3, n);
134 for (i = 0; i < n; i++)
136 memcpy (p, "../", 3);
143 /* Determine the basename of the current directory, where DOT_SB is the
144 result of lstat'ing "." and prepend that to the file name in *PATH.
145 Find the directory entry in `..' that matches the dev/i-node of DOT_SB.
146 Upon success, update *DOT_SB with stat information of `..', chdir to `..',
147 and prepend "/basename" to PATH.
148 Otherwise, exit with a diagnostic.
149 PARENT_HEIGHT is the number of levels `..' is above the starting directory.
150 The first time this function is called (from the initial directory),
151 PARENT_HEIGHT is 1. This is solely for diagnostics.
152 Exit nonzero upon error. */
155 find_dir_entry (struct stat *dot_sb, struct Path *path, size_t parent_height)
159 struct stat parent_sb;
163 dirp = opendir ("..");
165 error (EXIT_FAILURE, errno, _("cannot open directory %s"),
166 quote (nth_parent (parent_height)));
169 if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
170 error (EXIT_FAILURE, errno, _("failed to chdir to %s"),
171 quote (nth_parent (parent_height)));
173 if ((0 <= fd ? fstat (fd, &parent_sb) : stat (".", &parent_sb)) < 0)
174 error (EXIT_FAILURE, errno, _("failed to stat %s"),
175 quote (nth_parent (parent_height)));
177 /* If parent and child directory are on different devices, then we
178 can't rely on d_ino for useful i-node numbers; use lstat instead. */
179 use_lstat = (parent_sb.st_dev != dot_sb->st_dev);
184 struct dirent const *dp;
190 if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
194 /* Save/restore errno across closedir call. */
199 /* Arrange to give a diagnostic after exiting this loop. */
207 ent_sb_valid = false;
208 if (ino == NOT_AN_INODE_NUMBER || use_lstat)
210 if (lstat (dp->d_name, &ent_sb) < 0)
212 /* Skip any entry we can't stat. */
219 if (ino != dot_sb->st_ino)
222 /* If we're not crossing a device boundary, then a simple i-node
224 if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
226 path_prepend (path, dp->d_name, NLENGTH (dp));
232 if (dirp == NULL || CLOSEDIR (dirp) != 0)
234 /* Note that this diagnostic serves for both readdir
235 and closedir failures. */
236 error (EXIT_FAILURE, errno, _("reading directory %s"),
237 quote (nth_parent (parent_height)));
241 error (EXIT_FAILURE, 0,
242 _("couldn't find directory entry in %s with matching i-node"),
243 quote (nth_parent (parent_height)));
248 /* Construct the full, absolute name of the current working
249 directory and store it in *PATH.
250 The getcwd function performs nearly the same task, but is typically
251 unable to handle names longer than PATH_MAX. This function has
252 no such limitation. However, this function *can* fail due to
253 permission problems or a lack of memory, while Linux's getcwd
254 function works regardless of restricted permissions on parent
255 directories. Upon failure, give a diagnostic and exit nonzero.
257 Note: although this function is similar to getcwd, it has a fundamental
258 difference in that it gives a diagnostic and exits upon failure.
259 I would have liked a function that did not exit, and that could be
260 used as a getcwd replacement. Unfortunately, considering all of
261 the information the caller would require in order to produce good
262 diagnostics, it doesn't seem worth the added complexity.
263 In any case, any getcwd replacement must *not* exceed the PATH_MAX
264 limitation. Otherwise, functions like `chdir' would fail with
267 FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd,
268 in case the unreadable directory is close enough to the root that
269 getcwd works from there. */
272 robust_getcwd (struct Path *path)
275 struct dev_ino dev_ino_buf;
276 struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
279 if (root_dev_ino == NULL)
280 error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
283 if (stat (".", &dot_sb) < 0)
284 error (EXIT_FAILURE, errno, _("failed to stat %s"), quote ("."));
288 /* If we've reached the root, we're done. */
289 if (SAME_INODE (dot_sb, *root_dev_ino))
292 find_dir_entry (&dot_sb, path, height++);
295 if (path->start[0] == '\0')
296 path_prepend (path, "/", 1);
300 main (int argc, char **argv)
304 initialize_main (&argc, &argv);
305 program_name = argv[0];
306 setlocale (LC_ALL, "");
307 bindtextdomain (PACKAGE, LOCALEDIR);
308 textdomain (PACKAGE);
310 atexit (close_stdout);
312 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
313 usage, AUTHORS, (char const *) NULL);
314 if (getopt_long (argc, argv, "", NULL, NULL) != -1)
315 usage (EXIT_FAILURE);
318 error (0, 0, _("ignoring non-option arguments"));
328 struct Path *path = path_init ();
329 robust_getcwd (path);