maint: fix factor's test file name pattern in .gitignore
[coreutils.git] / src / pwd.c
blob23b7c53a45384f949280e9364b4753b043ce6b53
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/>. */
17 #include <config.h>
18 #include <getopt.h>
19 #include <stdio.h>
20 #include <sys/types.h>
22 #include "system.h"
23 #include "error.h"
24 #include "quote.h"
25 #include "root-dev-ino.h"
26 #include "xgetcwd.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")
33 struct file_name
35 char *buf;
36 size_t n_alloc;
37 char *start;
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},
46 {NULL, 0, NULL, 0}
49 void
50 usage (int status)
52 if (status != EXIT_SUCCESS)
53 emit_try_help ();
54 else
56 printf (_("Usage: %s [OPTION]...\n"), program_name);
57 fputs (_("\
58 Print the full filename of the current working directory.\n\
59 \n\
60 "), stdout);
61 fputs (_("\
62 -L, --logical use PWD from environment, even if it contains symlinks\n\
63 -P, --physical avoid all symlinks\n\
64 "), stdout);
65 fputs (HELP_OPTION_DESCRIPTION, stdout);
66 fputs (VERSION_OPTION_DESCRIPTION, stdout);
67 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
68 emit_ancillary_info ();
70 exit (status);
73 static void
74 file_name_free (struct file_name *p)
76 free (p->buf);
77 free (p);
80 static struct file_name *
81 file_name_init (void)
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);
91 p->start[0] = '\0';
92 return p;
95 /* Prepend the name S of length S_LEN, to the growing file_name, P. */
96 static void
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);
111 free (p->buf);
112 p->buf = q;
113 p->n_alloc = 2 * half;
116 p->start -= 1 + s_len;
117 p->start[0] = '/';
118 memcpy (p->start + 1, s, s_len);
121 /* Return a string (malloc'd) consisting of N '/'-separated ".." components. */
122 static char *
123 nth_parent (size_t n)
125 char *buf = xnmalloc (3, n);
126 char *p = buf;
127 size_t i;
129 for (i = 0; i < n; i++)
131 memcpy (p, "../", 3);
132 p += 3;
134 p[-1] = '\0';
135 return buf;
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. */
149 static void
150 find_dir_entry (struct stat *dot_sb, struct file_name *file_name,
151 size_t parent_height)
153 DIR *dirp;
154 int fd;
155 struct stat parent_sb;
156 bool use_lstat;
157 bool found;
159 dirp = opendir ("..");
160 if (dirp == NULL)
161 error (EXIT_FAILURE, errno, _("cannot open directory %s"),
162 quote (nth_parent (parent_height)));
164 fd = dirfd (dirp);
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);
177 found = false;
178 while (1)
180 struct dirent const *dp;
181 struct stat ent_sb;
182 ino_t ino;
184 errno = 0;
185 if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
187 if (errno)
189 /* Save/restore errno across closedir call. */
190 int e = errno;
191 closedir (dirp);
192 errno = e;
194 /* Arrange to give a diagnostic after exiting this loop. */
195 dirp = NULL;
197 break;
200 ino = D_INO (dp);
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. */
207 continue;
209 ino = ent_sb.st_ino;
212 if (ino != dot_sb->st_ino)
213 continue;
215 /* If we're not crossing a device boundary, then a simple i-node
216 match is enough. */
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));
220 found = true;
221 break;
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)));
233 if ( ! found)
234 error (EXIT_FAILURE, 0,
235 _("couldn't find directory entry in %s with matching i-node"),
236 quote (nth_parent (parent_height)));
238 *dot_sb = parent_sb;
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
258 ENAMETOOLONG.
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. */
264 static void
265 robust_getcwd (struct file_name *file_name)
267 size_t height = 1;
268 struct dev_ino dev_ino_buf;
269 struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
270 struct stat dot_sb;
272 if (root_dev_ino == NULL)
273 error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
274 quote ("/"));
276 if (stat (".", &dot_sb) < 0)
277 error (EXIT_FAILURE, errno, _("failed to stat %s"), quote ("."));
279 while (1)
281 /* If we've reached the root, we're done. */
282 if (SAME_INODE (dot_sb, *root_dev_ino))
283 break;
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. */
296 static char *
297 logical_getcwd (void)
299 struct stat st1;
300 struct stat st2;
301 char *wd = getenv ("PWD");
302 char *p;
304 /* Textual validation first. */
305 if (!wd || wd[0] != '/')
306 return NULL;
307 p = wd;
308 while ((p = strstr (p, "/.")))
310 if (!p[2] || p[2] == '/'
311 || (p[2] == '.' && (!p[3] || p[3] == '/')))
312 return NULL;
313 p++;
316 /* System call validation. */
317 if (stat (wd, &st1) == 0 && stat (".", &st2) == 0 && SAME_INODE (st1, st2))
318 return wd;
319 return NULL;
324 main (int argc, char **argv)
326 char *wd;
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);
338 while (1)
340 int c = getopt_long (argc, argv, "LP", longopts, NULL);
341 if (c == -1)
342 break;
343 switch (c)
345 case 'L':
346 logical = true;
347 break;
348 case 'P':
349 logical = false;
350 break;
352 case_GETOPT_HELP_CHAR;
354 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
356 default:
357 usage (EXIT_FAILURE);
361 if (optind < argc)
362 error (0, 0, _("ignoring non-option arguments"));
364 if (logical)
366 wd = logical_getcwd ();
367 if (wd)
369 puts (wd);
370 exit (EXIT_SUCCESS);
374 wd = xgetcwd ();
375 if (wd != NULL)
377 puts (wd);
378 free (wd);
380 else
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);
388 exit (EXIT_SUCCESS);