1 /* pwd - print current directory
2 Copyright (C) 1994-1997, 1999-2005 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., 51 Franklin Street, Fifth Floor, 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 (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
74 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
80 path_free (struct Path *p)
89 struct Path *p = xmalloc (sizeof *p);
91 /* Start with a buffer larger than PATH_MAX, but beware of systems
92 on which PATH_MAX is very large -- e.g., INT_MAX. */
93 p->n_alloc = MIN (2 * PATH_MAX, 32 * 1024);
95 p->buf = xmalloc (p->n_alloc);
96 p->start = p->buf + (p->n_alloc - 1);
101 /* Prepend the name S of length S_LEN, to the growing path, P. */
103 path_prepend (struct Path *p, char const *s, size_t s_len)
105 size_t n_free = p->start - p->buf;
106 if (n_free < 1 + s_len)
108 size_t half = p->n_alloc + 1 + s_len;
109 /* Use xnmalloc+free rather than xnrealloc, since with the latter
110 we'd end up copying the data twice: once via realloc, then again
111 to align it with the end of the new buffer. With xnmalloc, we
112 copy it only once. */
113 char *q = xnmalloc (2, half);
114 size_t n_used = p->n_alloc - n_free;
115 p->start = q + 2 * half - n_used;
116 memcpy (p->start, p->buf + n_free, n_used);
119 p->n_alloc = 2 * half;
122 p->start -= 1 + s_len;
124 memcpy (p->start + 1, s, s_len);
127 /* Return a string (malloc'd) consisting of N `/'-separated ".." components. */
129 nth_parent (size_t n)
131 char *buf = xnmalloc (3, n);
135 for (i = 0; i < n; i++)
137 memcpy (p, "../", 3);
144 /* Determine the basename of the current directory, where DOT_SB is the
145 result of lstat'ing "." and prepend that to the file name in *PATH.
146 Find the directory entry in `..' that matches the dev/i-node of DOT_SB.
147 Upon success, update *DOT_SB with stat information of `..', chdir to `..',
148 and prepend "/basename" to PATH.
149 Otherwise, exit with a diagnostic.
150 PARENT_HEIGHT is the number of levels `..' is above the starting directory.
151 The first time this function is called (from the initial directory),
152 PARENT_HEIGHT is 1. This is solely for diagnostics.
153 Exit nonzero upon error. */
156 find_dir_entry (struct stat *dot_sb, struct Path *path, size_t parent_height)
160 struct stat parent_sb;
164 dirp = opendir ("..");
166 error (EXIT_FAILURE, errno, _("cannot open directory %s"),
167 quote (nth_parent (parent_height)));
170 if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
171 error (EXIT_FAILURE, errno, _("failed to chdir to %s"),
172 quote (nth_parent (parent_height)));
174 if ((0 <= fd ? fstat (fd, &parent_sb) : stat (".", &parent_sb)) < 0)
175 error (EXIT_FAILURE, errno, _("failed to stat %s"),
176 quote (nth_parent (parent_height)));
178 /* If parent and child directory are on different devices, then we
179 can't rely on d_ino for useful i-node numbers; use lstat instead. */
180 use_lstat = (parent_sb.st_dev != dot_sb->st_dev);
185 struct dirent const *dp;
191 if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
195 /* Save/restore errno across closedir call. */
200 /* Arrange to give a diagnostic after exiting this loop. */
208 ent_sb_valid = false;
209 if (ino == NOT_AN_INODE_NUMBER || use_lstat)
211 if (lstat (dp->d_name, &ent_sb) < 0)
213 /* Skip any entry we can't stat. */
220 if (ino != dot_sb->st_ino)
223 /* If we're not crossing a device boundary, then a simple i-node
225 if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
227 path_prepend (path, dp->d_name, NLENGTH (dp));
233 if (dirp == NULL || CLOSEDIR (dirp) != 0)
235 /* Note that this diagnostic serves for both readdir
236 and closedir failures. */
237 error (EXIT_FAILURE, errno, _("reading directory %s"),
238 quote (nth_parent (parent_height)));
242 error (EXIT_FAILURE, 0,
243 _("couldn't find directory entry in %s with matching i-node"),
244 quote (nth_parent (parent_height)));
249 /* Construct the full, absolute name of the current working
250 directory and store it in *PATH.
251 The getcwd function performs nearly the same task, but is typically
252 unable to handle names longer than PATH_MAX. This function has
253 no such limitation. However, this function *can* fail due to
254 permission problems or a lack of memory, while Linux's getcwd
255 function works regardless of restricted permissions on parent
256 directories. Upon failure, give a diagnostic and exit nonzero.
258 Note: although this function is similar to getcwd, it has a fundamental
259 difference in that it gives a diagnostic and exits upon failure.
260 I would have liked a function that did not exit, and that could be
261 used as a getcwd replacement. Unfortunately, considering all of
262 the information the caller would require in order to produce good
263 diagnostics, it doesn't seem worth the added complexity.
264 In any case, any getcwd replacement must *not* exceed the PATH_MAX
265 limitation. Otherwise, functions like `chdir' would fail with
268 FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd,
269 in case the unreadable directory is close enough to the root that
270 getcwd works from there. */
273 robust_getcwd (struct Path *path)
276 struct dev_ino dev_ino_buf;
277 struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
280 if (root_dev_ino == NULL)
281 error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
284 if (stat (".", &dot_sb) < 0)
285 error (EXIT_FAILURE, errno, _("failed to stat %s"), quote ("."));
289 /* If we've reached the root, we're done. */
290 if (SAME_INODE (dot_sb, *root_dev_ino))
293 find_dir_entry (&dot_sb, path, height++);
296 if (path->start[0] == '\0')
297 path_prepend (path, "/", 1);
301 main (int argc, char **argv)
305 initialize_main (&argc, &argv);
306 program_name = argv[0];
307 setlocale (LC_ALL, "");
308 bindtextdomain (PACKAGE, LOCALEDIR);
309 textdomain (PACKAGE);
311 atexit (close_stdout);
313 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
314 usage, AUTHORS, (char const *) NULL);
315 if (getopt_long (argc, argv, "", NULL, NULL) != -1)
316 usage (EXIT_FAILURE);
319 error (0, 0, _("ignoring non-option arguments"));
329 struct Path *path = path_init ();
330 robust_getcwd (path);