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 does 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.
264 FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd,
265 in case the unreadable directory is close enough to the root that
266 getcwd works from there. */
269 robust_getcwd (struct Path *path)
272 struct dev_ino dev_ino_buf;
273 struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
276 if (root_dev_ino == NULL)
277 error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
280 if (stat (".", &dot_sb) < 0)
281 error (EXIT_FAILURE, errno, _("failed to stat %s"), quote ("."));
285 /* If we've reached the root, we're done. */
286 if (SAME_INODE (dot_sb, *root_dev_ino))
289 find_dir_entry (&dot_sb, path, height++);
292 if (path->start[0] == '\0')
293 path_prepend (path, "/", 1);
297 main (int argc, char **argv)
301 initialize_main (&argc, &argv);
302 program_name = argv[0];
303 setlocale (LC_ALL, "");
304 bindtextdomain (PACKAGE, LOCALEDIR);
305 textdomain (PACKAGE);
307 atexit (close_stdout);
309 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
310 usage, AUTHORS, (char const *) NULL);
311 if (getopt_long (argc, argv, "", NULL, NULL) != -1)
312 usage (EXIT_FAILURE);
315 error (0, 0, _("ignoring non-option arguments"));
325 struct Path *path = path_init ();
326 robust_getcwd (path);