1 /* pathchk -- check whether file names are valid or portable
2 Copyright (C) 1991-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>
28 #include "euidaccess.h"
32 #if ! (HAVE_MBRLEN && HAVE_MBSTATE_T)
33 # define mbrlen(s, n, ps) 1
34 # define mbstate_t int
37 /* The official name of this program (e.g., no `g' prefix). */
38 #define PROGRAM_NAME "pathchk"
40 #define AUTHORS "Paul Eggert", "David MacKenzie", "Jim Meyering"
42 #ifndef _POSIX_PATH_MAX
43 # define _POSIX_PATH_MAX 255
45 #ifndef _POSIX_NAME_MAX
46 # define _POSIX_NAME_MAX 14
49 #ifdef _XOPEN_NAME_MAX
50 # define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
52 # define NAME_MAX_MINIMUM _POSIX_NAME_MAX
54 #ifdef _XOPEN_PATH_MAX
55 # define PATH_MAX_MINIMUM _XOPEN_PATH_MAX
57 # define PATH_MAX_MINIMUM _POSIX_PATH_MAX
60 #if ! (HAVE_PATHCONF && defined _PC_NAME_MAX && defined _PC_PATH_MAX)
62 # define _PC_NAME_MAX 0
63 # define _PC_PATH_MAX 1
66 # define pathconf(file, flag) \
67 (flag == _PC_NAME_MAX ? NAME_MAX_MINIMUM : PATH_MAX_MINIMUM)
71 static bool validate_file_name (char *file, bool portability);
73 /* The name this program was run with. */
76 static struct option const longopts[] =
78 {"portability", no_argument, NULL, 'p'},
79 {GETOPT_HELP_OPTION_DECL},
80 {GETOPT_VERSION_OPTION_DECL},
87 if (status != EXIT_SUCCESS)
88 fprintf (stderr, _("Try `%s --help' for more information.\n"),
92 printf (_("Usage: %s [OPTION]... NAME...\n"), program_name);
94 Diagnose unportable constructs in NAME.\n\
96 -p, --portability check for all POSIX systems, not only this one\n\
98 fputs (HELP_OPTION_DESCRIPTION, stdout);
99 fputs (VERSION_OPTION_DESCRIPTION, stdout);
100 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
106 main (int argc, char **argv)
109 bool check_portability = false;
112 initialize_main (&argc, &argv);
113 program_name = argv[0];
114 setlocale (LC_ALL, "");
115 bindtextdomain (PACKAGE, LOCALEDIR);
116 textdomain (PACKAGE);
118 atexit (close_stdout);
120 while ((optc = getopt_long (argc, argv, "+p", longopts, NULL)) != -1)
125 check_portability = true;
128 case_GETOPT_HELP_CHAR;
130 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
133 usage (EXIT_FAILURE);
139 error (0, 0, _("missing operand"));
140 usage (EXIT_FAILURE);
143 for (; optind < argc; ++optind)
144 ok &= validate_file_name (argv[optind], check_portability);
146 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
149 /* If FILE (of length FILELEN) contains only portable characters,
150 return true, else report an error and return false. */
153 portable_chars_only (char const *file, size_t filelen)
155 size_t validlen = strspn (file,
157 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
158 "abcdefghijklmnopqrstuvwxyz"
160 char const *invalid = file + validlen;
164 mbstate_t mbstate = {0};
165 size_t charlen = mbrlen (invalid, filelen - validlen, &mbstate);
167 _("nonportable character %s in file name %s"),
168 quotearg_n_style_mem (1, locale_quoting_style, invalid,
169 (charlen <= MB_LEN_MAX ? charlen : 1)),
177 /* Return the address of the start of the next file name component in F. */
180 component_start (char *f)
187 /* Return the size of the file name component F. F must be nonempty. */
190 component_len (char const *f)
193 for (len = 1; f[len] != '/' && f[len]; len++)
199 strlen (FILE) <= PATH_MAX
200 && strlen (each-existing-directory-in-FILE) <= NAME_MAX
202 If PORTABILITY is true, compare against _POSIX_PATH_MAX and
203 _POSIX_NAME_MAX instead, and make sure that FILE contains no
204 characters not in the POSIX portable filename character set, which
205 consists of A-Z, a-z, 0-9, ., _, - (plus / for separators).
207 If PORTABILITY is false, make sure that all leading directories
208 along FILE that exist are searchable.
210 Return true if all of these tests are successful, false if any fail. */
213 validate_file_name (char *file, bool portability)
215 size_t filelen = strlen (file);
217 /* Start of file name component being checked. */
220 /* True if component lengths need to be checked. */
221 bool check_component_lengths;
223 if (portability && ! portable_chars_only (file, filelen))
229 if (portability || PATH_MAX_MINIMUM <= filelen)
234 maxsize = _POSIX_PATH_MAX;
238 char const *dir = (*file == '/' ? "/" : ".");
240 size = pathconf (dir, _PC_PATH_MAX);
241 if (size < 0 && errno != 0)
244 _("%s: unable to determine maximum file name length"),
248 maxsize = MIN (size, SIZE_MAX);
251 if (maxsize <= filelen)
253 unsigned long int len = filelen;
254 unsigned long int maxlen = maxsize - 1;
255 error (0, 0, _("limit %lu exceeded by length %lu of file name %s"),
256 maxlen, len, quote (file));
263 /* Check whether a file name component is in a directory that
264 is not searchable, or has some other serious problem. */
267 if (lstat (file, &st) != 0 && errno != ENOENT)
269 error (0, errno, "%s", file);
274 /* Check whether pathconf (..., _PC_NAME_MAX) can be avoided, i.e.,
275 whether all file name components are so short that they are valid
276 in any file system on this platform. If PORTABILITY, though,
277 it's more convenient to check component lengths below. */
279 check_component_lengths = portability;
280 if (! check_component_lengths)
282 for (start = file; *(start = component_start (start)); )
284 size_t length = component_len (start);
286 if (NAME_MAX_MINIMUM < length)
288 check_component_lengths = true;
296 if (check_component_lengths)
298 /* The limit on file name components for the current component.
299 This defaults to NAME_MAX_MINIMUM, for the sake of non-POSIX
300 systems (NFS, say?) where pathconf fails on "." or "/" with
302 size_t name_max = NAME_MAX_MINIMUM;
304 /* If nonzero, the known limit on file name components. */
305 size_t known_name_max = (portability ? _POSIX_NAME_MAX : 0);
307 for (start = file; *(start = component_start (start)); )
312 name_max = known_name_max;
316 char const *dir = (start == file ? "." : file);
320 len = pathconf (dir, _PC_NAME_MAX);
323 name_max = MIN (len, SIZE_MAX);
328 /* There is no limit. */
333 /* DIR does not exist; use its parent's maximum. */
334 known_name_max = name_max;
339 error (0, errno, "%s", dir);
345 length = component_len (start);
347 if (name_max < length)
349 unsigned long int len = length;
350 unsigned long int maxlen = name_max;
354 _("limit %lu exceeded by length %lu "
355 "of file name component %s"),
356 maxlen, len, quote (start));