Require that this test be run as non-root.
[coreutils.git] / src / pwd.c
blobf89c8d1e5e41b25bea3714b5df78e841c8554da2
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)
7 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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 #include <config.h>
19 #include <getopt.h>
20 #include <stdio.h>
21 #include <sys/types.h>
23 #include "system.h"
24 #include "dirfd.h"
25 #include "error.h"
26 #include "long-options.h"
27 #include "quote.h"
28 #include "root-dev-ino.h"
29 #include "xgetcwd.h"
31 /* The official name of this program (e.g., no `g' prefix). */
32 #define PROGRAM_NAME "pwd"
34 #define AUTHORS "Jim Meyering"
36 struct file_name
38 char *buf;
39 size_t n_alloc;
40 char *start;
43 enum
45 NOT_AN_INODE_NUMBER = 0
48 #ifdef D_INO_IN_DIRENT
49 # define D_INO(dp) ((dp)->d_ino)
50 #else
51 /* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */
52 # define D_INO(dp) NOT_AN_INODE_NUMBER
53 #endif
55 /* The name this program was run with. */
56 char *program_name;
58 void
59 usage (int status)
61 if (status != EXIT_SUCCESS)
62 fprintf (stderr, _("Try `%s --help' for more information.\n"),
63 program_name);
64 else
66 printf (_("Usage: %s [OPTION]\n"), program_name);
67 fputs (_("\
68 Print the full filename of the current working directory.\n\
69 \n\
70 "), stdout);
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);
76 exit (status);
79 static void
80 file_name_free (struct file_name *p)
82 free (p->buf);
83 free (p);
86 static struct file_name *
87 file_name_init (void)
89 struct file_name *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);
97 p->start[0] = '\0';
98 return p;
101 /* Prepend the name S of length S_LEN, to the growing file_name, P. */
102 static void
103 file_name_prepend (struct file_name *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);
117 free (p->buf);
118 p->buf = q;
119 p->n_alloc = 2 * half;
122 p->start -= 1 + s_len;
123 p->start[0] = '/';
124 memcpy (p->start + 1, s, s_len);
127 /* Return a string (malloc'd) consisting of N `/'-separated ".." components. */
128 static char *
129 nth_parent (size_t n)
131 char *buf = xnmalloc (3, n);
132 char *p = buf;
133 size_t i;
135 for (i = 0; i < n; i++)
137 memcpy (p, "../", 3);
138 p += 3;
140 p[-1] = '\0';
141 return buf;
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 *FILE_NAME.
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 FILE_NAME.
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. */
155 static void
156 find_dir_entry (struct stat *dot_sb, struct file_name *file_name,
157 size_t parent_height)
159 DIR *dirp;
160 int fd;
161 struct stat parent_sb;
162 bool use_lstat;
163 bool found;
165 dirp = opendir ("..");
166 if (dirp == NULL)
167 error (EXIT_FAILURE, errno, _("cannot open directory %s"),
168 quote (nth_parent (parent_height)));
170 fd = dirfd (dirp);
171 if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
172 error (EXIT_FAILURE, errno, _("failed to chdir to %s"),
173 quote (nth_parent (parent_height)));
175 if ((0 <= fd ? fstat (fd, &parent_sb) : stat (".", &parent_sb)) < 0)
176 error (EXIT_FAILURE, errno, _("failed to stat %s"),
177 quote (nth_parent (parent_height)));
179 /* If parent and child directory are on different devices, then we
180 can't rely on d_ino for useful i-node numbers; use lstat instead. */
181 use_lstat = (parent_sb.st_dev != dot_sb->st_dev);
183 found = false;
184 while (1)
186 struct dirent const *dp;
187 struct stat ent_sb;
188 ino_t ino;
189 bool ent_sb_valid;
191 errno = 0;
192 if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
194 if (errno)
196 /* Save/restore errno across closedir call. */
197 int e = errno;
198 closedir (dirp);
199 errno = e;
201 /* Arrange to give a diagnostic after exiting this loop. */
202 dirp = NULL;
204 break;
207 ino = D_INO (dp);
209 ent_sb_valid = false;
210 if (ino == NOT_AN_INODE_NUMBER || use_lstat)
212 if (lstat (dp->d_name, &ent_sb) < 0)
214 /* Skip any entry we can't stat. */
215 continue;
217 ino = ent_sb.st_ino;
218 ent_sb_valid = true;
221 if (ino != dot_sb->st_ino)
222 continue;
224 /* If we're not crossing a device boundary, then a simple i-node
225 match is enough. */
226 if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
228 file_name_prepend (file_name, dp->d_name, NLENGTH (dp));
229 found = true;
230 break;
234 if (dirp == NULL || CLOSEDIR (dirp) != 0)
236 /* Note that this diagnostic serves for both readdir
237 and closedir failures. */
238 error (EXIT_FAILURE, errno, _("reading directory %s"),
239 quote (nth_parent (parent_height)));
242 if ( ! found)
243 error (EXIT_FAILURE, 0,
244 _("couldn't find directory entry in %s with matching i-node"),
245 quote (nth_parent (parent_height)));
247 *dot_sb = parent_sb;
250 /* Construct the full, absolute name of the current working
251 directory and store it in *FILE_NAME.
252 The getcwd function performs nearly the same task, but is typically
253 unable to handle names longer than PATH_MAX. This function has
254 no such limitation. However, this function *can* fail due to
255 permission problems or a lack of memory, while Linux's getcwd
256 function works regardless of restricted permissions on parent
257 directories. Upon failure, give a diagnostic and exit nonzero.
259 Note: although this function is similar to getcwd, it has a fundamental
260 difference in that it gives a diagnostic and exits upon failure.
261 I would have liked a function that did not exit, and that could be
262 used as a getcwd replacement. Unfortunately, considering all of
263 the information the caller would require in order to produce good
264 diagnostics, it doesn't seem worth the added complexity.
265 In any case, any getcwd replacement must *not* exceed the PATH_MAX
266 limitation. Otherwise, functions like `chdir' would fail with
267 ENAMETOOLONG.
269 FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd,
270 in case the unreadable directory is close enough to the root that
271 getcwd works from there. */
273 static void
274 robust_getcwd (struct file_name *file_name)
276 size_t height = 1;
277 struct dev_ino dev_ino_buf;
278 struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
279 struct stat dot_sb;
281 if (root_dev_ino == NULL)
282 error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
283 quote ("/"));
285 if (stat (".", &dot_sb) < 0)
286 error (EXIT_FAILURE, errno, _("failed to stat %s"), quote ("."));
288 while (1)
290 /* If we've reached the root, we're done. */
291 if (SAME_INODE (dot_sb, *root_dev_ino))
292 break;
294 find_dir_entry (&dot_sb, file_name, height++);
297 if (file_name->start[0] == '\0')
298 file_name_prepend (file_name, "/", 1);
302 main (int argc, char **argv)
304 char *wd;
306 initialize_main (&argc, &argv);
307 program_name = argv[0];
308 setlocale (LC_ALL, "");
309 bindtextdomain (PACKAGE, LOCALEDIR);
310 textdomain (PACKAGE);
312 atexit (close_stdout);
314 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
315 usage, AUTHORS, (char const *) NULL);
316 if (getopt_long (argc, argv, "", NULL, NULL) != -1)
317 usage (EXIT_FAILURE);
319 if (optind < argc)
320 error (0, 0, _("ignoring non-option arguments"));
322 wd = xgetcwd ();
323 if (wd != NULL)
325 puts (wd);
326 free (wd);
328 else
330 struct file_name *file_name = file_name_init ();
331 robust_getcwd (file_name);
332 puts (file_name->start);
333 file_name_free (file_name);
336 exit (EXIT_SUCCESS);