Update all copyright notices to use the newer form.
[platform/upstream/coreutils.git] / src / pwd.c
1 /* pwd - print current directory
2    Copyright (C) 1994-1997, 1999-2006 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>.  */
16
17 #include <config.h>
18 #include <getopt.h>
19 #include <stdio.h>
20 #include <sys/types.h>
21
22 #include "system.h"
23 #include "dirfd.h"
24 #include "error.h"
25 #include "long-options.h"
26 #include "quote.h"
27 #include "root-dev-ino.h"
28 #include "xgetcwd.h"
29
30 /* The official name of this program (e.g., no `g' prefix).  */
31 #define PROGRAM_NAME "pwd"
32
33 #define AUTHORS "Jim Meyering"
34
35 struct file_name
36 {
37   char *buf;
38   size_t n_alloc;
39   char *start;
40 };
41
42 /* The name this program was run with. */
43 char *program_name;
44
45 void
46 usage (int status)
47 {
48   if (status != EXIT_SUCCESS)
49     fprintf (stderr, _("Try `%s --help' for more information.\n"),
50              program_name);
51   else
52     {
53       printf (_("Usage: %s [OPTION]\n"), program_name);
54       fputs (_("\
55 Print the full filename of the current working directory.\n\
56 \n\
57 "), stdout);
58       fputs (HELP_OPTION_DESCRIPTION, stdout);
59       fputs (VERSION_OPTION_DESCRIPTION, stdout);
60       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
61       emit_bug_reporting_address ();
62     }
63   exit (status);
64 }
65
66 static void
67 file_name_free (struct file_name *p)
68 {
69   free (p->buf);
70   free (p);
71 }
72
73 static struct file_name *
74 file_name_init (void)
75 {
76   struct file_name *p = xmalloc (sizeof *p);
77
78   /* Start with a buffer larger than PATH_MAX, but beware of systems
79      on which PATH_MAX is very large -- e.g., INT_MAX.  */
80   p->n_alloc = MIN (2 * PATH_MAX, 32 * 1024);
81
82   p->buf = xmalloc (p->n_alloc);
83   p->start = p->buf + (p->n_alloc - 1);
84   p->start[0] = '\0';
85   return p;
86 }
87
88 /* Prepend the name S of length S_LEN, to the growing file_name, P.  */
89 static void
90 file_name_prepend (struct file_name *p, char const *s, size_t s_len)
91 {
92   size_t n_free = p->start - p->buf;
93   if (n_free < 1 + s_len)
94     {
95       size_t half = p->n_alloc + 1 + s_len;
96       /* Use xnmalloc+free rather than xnrealloc, since with the latter
97          we'd end up copying the data twice: once via realloc, then again
98          to align it with the end of the new buffer.  With xnmalloc, we
99          copy it only once.  */
100       char *q = xnmalloc (2, half);
101       size_t n_used = p->n_alloc - n_free;
102       p->start = q + 2 * half - n_used;
103       memcpy (p->start, p->buf + n_free, n_used);
104       free (p->buf);
105       p->buf = q;
106       p->n_alloc = 2 * half;
107     }
108
109   p->start -= 1 + s_len;
110   p->start[0] = '/';
111   memcpy (p->start + 1, s, s_len);
112 }
113
114 /* Return a string (malloc'd) consisting of N `/'-separated ".." components.  */
115 static char *
116 nth_parent (size_t n)
117 {
118   char *buf = xnmalloc (3, n);
119   char *p = buf;
120   size_t i;
121
122   for (i = 0; i < n; i++)
123     {
124       memcpy (p, "../", 3);
125       p += 3;
126     }
127   p[-1] = '\0';
128   return buf;
129 }
130
131 /* Determine the basename of the current directory, where DOT_SB is the
132    result of lstat'ing "." and prepend that to the file name in *FILE_NAME.
133    Find the directory entry in `..' that matches the dev/i-node of DOT_SB.
134    Upon success, update *DOT_SB with stat information of `..', chdir to `..',
135    and prepend "/basename" to FILE_NAME.
136    Otherwise, exit with a diagnostic.
137    PARENT_HEIGHT is the number of levels `..' is above the starting directory.
138    The first time this function is called (from the initial directory),
139    PARENT_HEIGHT is 1.  This is solely for diagnostics.
140    Exit nonzero upon error.  */
141
142 static void
143 find_dir_entry (struct stat *dot_sb, struct file_name *file_name,
144                 size_t parent_height)
145 {
146   DIR *dirp;
147   int fd;
148   struct stat parent_sb;
149   bool use_lstat;
150   bool found;
151
152   dirp = opendir ("..");
153   if (dirp == NULL)
154     error (EXIT_FAILURE, errno, _("cannot open directory %s"),
155            quote (nth_parent (parent_height)));
156
157   fd = dirfd (dirp);
158   if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
159     error (EXIT_FAILURE, errno, _("failed to chdir to %s"),
160            quote (nth_parent (parent_height)));
161
162   if ((0 <= fd ? fstat (fd, &parent_sb) : stat (".", &parent_sb)) < 0)
163     error (EXIT_FAILURE, errno, _("failed to stat %s"),
164            quote (nth_parent (parent_height)));
165
166   /* If parent and child directory are on different devices, then we
167      can't rely on d_ino for useful i-node numbers; use lstat instead.  */
168   use_lstat = (parent_sb.st_dev != dot_sb->st_dev);
169
170   found = false;
171   while (1)
172     {
173       struct dirent const *dp;
174       struct stat ent_sb;
175       ino_t ino;
176
177       errno = 0;
178       if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
179         {
180           if (errno)
181             {
182               /* Save/restore errno across closedir call.  */
183               int e = errno;
184               closedir (dirp);
185               errno = e;
186
187               /* Arrange to give a diagnostic after exiting this loop.  */
188               dirp = NULL;
189             }
190           break;
191         }
192
193       ino = D_INO (dp);
194
195       if (ino == NOT_AN_INODE_NUMBER || use_lstat)
196         {
197           if (lstat (dp->d_name, &ent_sb) < 0)
198             {
199               /* Skip any entry we can't stat.  */
200               continue;
201             }
202           ino = ent_sb.st_ino;
203         }
204
205       if (ino != dot_sb->st_ino)
206         continue;
207
208       /* If we're not crossing a device boundary, then a simple i-node
209          match is enough.  */
210       if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
211         {
212           file_name_prepend (file_name, dp->d_name, _D_EXACT_NAMLEN (dp));
213           found = true;
214           break;
215         }
216     }
217
218   if (dirp == NULL || closedir (dirp) != 0)
219     {
220       /* Note that this diagnostic serves for both readdir
221          and closedir failures.  */
222       error (EXIT_FAILURE, errno, _("reading directory %s"),
223              quote (nth_parent (parent_height)));
224     }
225
226   if ( ! found)
227     error (EXIT_FAILURE, 0,
228            _("couldn't find directory entry in %s with matching i-node"),
229              quote (nth_parent (parent_height)));
230
231   *dot_sb = parent_sb;
232 }
233
234 /* Construct the full, absolute name of the current working
235    directory and store it in *FILE_NAME.
236    The getcwd function performs nearly the same task, but is typically
237    unable to handle names longer than PATH_MAX.  This function has
238    no such limitation.  However, this function *can* fail due to
239    permission problems or a lack of memory, while Linux's getcwd
240    function works regardless of restricted permissions on parent
241    directories.  Upon failure, give a diagnostic and exit nonzero.
242
243    Note: although this function is similar to getcwd, it has a fundamental
244    difference in that it gives a diagnostic and exits upon failure.
245    I would have liked a function that did not exit, and that could be
246    used as a getcwd replacement.  Unfortunately, considering all of
247    the information the caller would require in order to produce good
248    diagnostics, it doesn't seem worth the added complexity.
249    In any case, any getcwd replacement must *not* exceed the PATH_MAX
250    limitation.  Otherwise, functions like `chdir' would fail with
251    ENAMETOOLONG.
252
253    FIXME-maybe: if find_dir_entry fails due to permissions, try getcwd,
254    in case the unreadable directory is close enough to the root that
255    getcwd works from there.  */
256
257 static void
258 robust_getcwd (struct file_name *file_name)
259 {
260   size_t height = 1;
261   struct dev_ino dev_ino_buf;
262   struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
263   struct stat dot_sb;
264
265   if (root_dev_ino == NULL)
266     error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
267            quote ("/"));
268
269   if (stat (".", &dot_sb) < 0)
270     error (EXIT_FAILURE, errno, _("failed to stat %s"), quote ("."));
271
272   while (1)
273     {
274       /* If we've reached the root, we're done.  */
275       if (SAME_INODE (dot_sb, *root_dev_ino))
276         break;
277
278       find_dir_entry (&dot_sb, file_name, height++);
279     }
280
281   /* See if a leading slash is needed; file_name_prepend adds one.  */
282   if (file_name->start[0] == '\0')
283     file_name_prepend (file_name, "", 0);
284 }
285
286 int
287 main (int argc, char **argv)
288 {
289   char *wd;
290
291   initialize_main (&argc, &argv);
292   program_name = argv[0];
293   setlocale (LC_ALL, "");
294   bindtextdomain (PACKAGE, LOCALEDIR);
295   textdomain (PACKAGE);
296
297   atexit (close_stdout);
298
299   parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
300                       usage, AUTHORS, (char const *) NULL);
301   if (getopt_long (argc, argv, "", NULL, NULL) != -1)
302     usage (EXIT_FAILURE);
303
304   if (optind < argc)
305     error (0, 0, _("ignoring non-option arguments"));
306
307   wd = xgetcwd ();
308   if (wd != NULL)
309     {
310       puts (wd);
311       free (wd);
312     }
313   else
314     {
315       struct file_name *file_name = file_name_init ();
316       robust_getcwd (file_name);
317       puts (file_name->start);
318       file_name_free (file_name);
319     }
320
321   exit (EXIT_SUCCESS);
322 }