360 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			360 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* pathchk - check pathnames for validity and portability */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Usage: pathchk [-p] path ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   For each PATH, print a message if any of these conditions are false:
							 | 
						||
| 
								 | 
							
								   * all existing leading directories in PATH have search (execute) permission
							 | 
						||
| 
								 | 
							
								   * strlen (PATH) <= PATH_MAX
							 | 
						||
| 
								 | 
							
								   * strlen (each_directory_in_PATH) <= NAME_MAX
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Exit status:
							 | 
						||
| 
								 | 
							
								   0			All PATH names passed all of the tests.
							 | 
						||
| 
								 | 
							
								   1			An error occurred.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Options:
							 | 
						||
| 
								 | 
							
								   -p			Instead of performing length checks on the
							 | 
						||
| 
								 | 
							
											underlying filesystem, test the length of the
							 | 
						||
| 
								 | 
							
											pathname and its components against the POSIX.1
							 | 
						||
| 
								 | 
							
											minimum limits for portability, _POSIX_NAME_MAX
							 | 
						||
| 
								 | 
							
											and _POSIX_PATH_MAX in 2.9.2.  Also check that
							 | 
						||
| 
								 | 
							
											the pathname contains no character not in the
							 | 
						||
| 
								 | 
							
											portable filename character set. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* See Makefile for compilation details. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <config.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <sys/types.h>
							 | 
						||
| 
								 | 
							
								#include "posixstat.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined (HAVE_UNISTD_H)
							 | 
						||
| 
								 | 
							
								#  include <unistd.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined (HAVE_LIMITS_H)
							 | 
						||
| 
								 | 
							
								#  include <limits.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "bashansi.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "builtins.h"
							 | 
						||
| 
								 | 
							
								#include "shell.h"
							 | 
						||
| 
								 | 
							
								#include "stdc.h"
							 | 
						||
| 
								 | 
							
								#include "bashgetopt.h"
							 | 
						||
| 
								 | 
							
								#include "maxpath.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if !defined (errno)
							 | 
						||
| 
								 | 
							
								extern int errno;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if !defined (_POSIX_PATH_MAX)
							 | 
						||
| 
								 | 
							
								#  define _POSIX_PATH_MAX 255
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#if !defined (_POSIX_NAME_MAX)
							 | 
						||
| 
								 | 
							
								#  define _POSIX_NAME_MAX 14
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* How do we get PATH_MAX? */
							 | 
						||
| 
								 | 
							
								#if defined (_POSIX_VERSION) && !defined (PATH_MAX)
							 | 
						||
| 
								 | 
							
								#  define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* How do we get NAME_MAX? */
							 | 
						||
| 
								 | 
							
								#if defined (_POSIX_VERSION) && !defined (NAME_MAX)
							 | 
						||
| 
								 | 
							
								#  define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if !defined (PATH_MAX_FOR)
							 | 
						||
| 
								 | 
							
								#  define PATH_MAX_FOR(p)	PATH_MAX
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if !defined (NAME_MAX_FOR)
							 | 
						||
| 
								 | 
							
								#  define NAME_MAX_FOR(p)	NAME_MAX
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern char *strerror ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int validate_path ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								pathchk_builtin (list)
							 | 
						||
| 
								 | 
							
								     WORD_LIST *list;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int retval, pflag, opt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  reset_internal_getopt ();
							 | 
						||
| 
								 | 
							
								  while ((opt = internal_getopt (list, "p")) != -1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      switch (opt)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									case 'p':
							 | 
						||
| 
								 | 
							
									  pflag = 1;
							 | 
						||
| 
								 | 
							
									  break;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
									  builtin_usage ();
							 | 
						||
| 
								 | 
							
									  return (EX_USAGE);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  list = loptend;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (list == 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      builtin_usage ();
							 | 
						||
| 
								 | 
							
								      return (EX_USAGE);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (retval = 0; list; list = list->next)
							 | 
						||
| 
								 | 
							
								    retval |= validate_path (list->word->word, pflag);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								char *pathchk_doc[] = {
							 | 
						||
| 
								 | 
							
									"Check each pathname argument for validity (i.e., it may be used to",
							 | 
						||
| 
								 | 
							
									"create or access a file without casuing syntax errors) and portability",
							 | 
						||
| 
								 | 
							
									"(i.e., no filename truncation will result).  If the `-p' option is",
							 | 
						||
| 
								 | 
							
									"supplied, more extensive portability checks are performed.",
							 | 
						||
| 
								 | 
							
									(char *)NULL
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* The standard structure describing a builtin command.  bash keeps an array
							 | 
						||
| 
								 | 
							
								   of these structures. */
							 | 
						||
| 
								 | 
							
								struct builtin pathchk_struct = {
							 | 
						||
| 
								 | 
							
									"pathchk",		/* builtin name */
							 | 
						||
| 
								 | 
							
									pathchk_builtin,	/* function implementing the builtin */
							 | 
						||
| 
								 | 
							
									BUILTIN_ENABLED,	/* initial flags for builtin */
							 | 
						||
| 
								 | 
							
									pathchk_doc,		/* array of long documentation strings. */
							 | 
						||
| 
								 | 
							
									"pathchk [-p] pathname ...",	/* usage synopsis */
							 | 
						||
| 
								 | 
							
									0			/* reserved for internal use */
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* The remainder of this file is stolen shamelessly from `pathchk.c' in
							 | 
						||
| 
								 | 
							
								   the sh-utils-1.12 distribution, by 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   David MacKenzie <djm@gnu.ai.mit.edu>
							 | 
						||
| 
								 | 
							
								   and Jim Meyering <meyering@cs.utexas.edu> */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Each element is nonzero if the corresponding ASCII character is
							 | 
						||
| 
								 | 
							
								   in the POSIX portable character set, and zero if it is not.
							 | 
						||
| 
								 | 
							
								   In addition, the entry for `/' is nonzero to simplify checking. */
							 | 
						||
| 
								 | 
							
								static char const portable_chars[256] =
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
							 | 
						||
| 
								 | 
							
								  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
							 | 
						||
| 
								 | 
							
								  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
							 | 
						||
| 
								 | 
							
								  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
							 | 
						||
| 
								 | 
							
								  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
							 | 
						||
| 
								 | 
							
								  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
							 | 
						||
| 
								 | 
							
								  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* If PATH contains only portable characters, return 1, else 0.  */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								portable_chars_only (path)
							 | 
						||
| 
								 | 
							
								     const char *path;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  const char *p;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (p = path; *p; ++p)
							 | 
						||
| 
								 | 
							
								    if (portable_chars[(const unsigned char) *p] == 0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
									error (0, 0, "path `%s' contains nonportable character `%c'",
							 | 
						||
| 
								 | 
							
									       path, *p);
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								  return 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* On some systems, stat can return EINTR.  */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef EINTR
							 | 
						||
| 
								 | 
							
								# define SAFE_STAT(name, buf) stat (name, buf)
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								# define SAFE_STAT(name, buf) safe_stat (name, buf)
							 | 
						||
| 
								 | 
							
								static inline int
							 | 
						||
| 
								 | 
							
								safe_stat (name, buf)
							 | 
						||
| 
								 | 
							
								     const char *name;
							 | 
						||
| 
								 | 
							
								     struct stat *buf;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int ret;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  do
							 | 
						||
| 
								 | 
							
								    ret = stat (name, buf);
							 | 
						||
| 
								 | 
							
								  while (ret < 0 && errno == EINTR);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ret;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Return 1 if PATH is a usable leading directory, 0 if not,
							 | 
						||
| 
								 | 
							
								   2 if it doesn't exist.  */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								dir_ok (path)
							 | 
						||
| 
								 | 
							
								     const char *path;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  struct stat stats;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (SAFE_STAT (path, &stats))
							 | 
						||
| 
								 | 
							
								    return 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!S_ISDIR (stats.st_mode))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      error (0, 0, "`%s' is not a directory", path);
							 | 
						||
| 
								 | 
							
								      return 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Use access to test for search permission because
							 | 
						||
| 
								 | 
							
								     testing permission bits of st_mode can lose with new
							 | 
						||
| 
								 | 
							
								     access control mechanisms.  Of course, access loses if you're
							 | 
						||
| 
								 | 
							
								     running setuid. */
							 | 
						||
| 
								 | 
							
								  if (access (path, X_OK) != 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      if (errno == EACCES)
							 | 
						||
| 
								 | 
							
									builtin_error ("directory `%s' is not searchable", path);
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
									builtin_error ("%s: %s", path, strerror (errno));
							 | 
						||
| 
								 | 
							
								      return 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static char *
							 | 
						||
| 
								 | 
							
								xstrdup (s)
							 | 
						||
| 
								 | 
							
								     char *s;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  return (savestring (s));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Make sure that
							 | 
						||
| 
								 | 
							
								   strlen (PATH) <= PATH_MAX
							 | 
						||
| 
								 | 
							
								   && strlen (each-existing-directory-in-PATH) <= NAME_MAX
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
							 | 
						||
| 
								 | 
							
								   _POSIX_NAME_MAX instead, and make sure that PATH contains no
							 | 
						||
| 
								 | 
							
								   characters not in the POSIX portable filename character set, which
							 | 
						||
| 
								 | 
							
								   consists of A-Z, a-z, 0-9, ., _, -.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Make sure that all leading directories along PATH that exist have
							 | 
						||
| 
								 | 
							
								   `x' permission.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Return 0 if all of these tests are successful, 1 if any fail. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int
							 | 
						||
| 
								 | 
							
								validate_path (path, portability)
							 | 
						||
| 
								 | 
							
								     char *path;
							 | 
						||
| 
								 | 
							
								     int portability;
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  int path_max;
							 | 
						||
| 
								 | 
							
								  int last_elem;		/* Nonzero if checking last element of path. */
							 | 
						||
| 
								 | 
							
								  int exists;			/* 2 if the path element exists.  */
							 | 
						||
| 
								 | 
							
								  char *slash;
							 | 
						||
| 
								 | 
							
								  char *parent;			/* Last existing leading directory so far.  */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (portability && !portable_chars_only (path))
							 | 
						||
| 
								 | 
							
								    return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (*path == '\0')
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef lint
							 | 
						||
| 
								 | 
							
								  /* Suppress `used before initialized' warning.  */
							 | 
						||
| 
								 | 
							
								  exists = 0;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Figure out the parent of the first element in PATH.  */
							 | 
						||
| 
								 | 
							
								  parent = xstrdup (*path == '/' ? "/" : ".");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  slash = path;
							 | 
						||
| 
								 | 
							
								  last_elem = 0;
							 | 
						||
| 
								 | 
							
								  while (1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      int name_max;
							 | 
						||
| 
								 | 
							
								      int length;		/* Length of partial path being checked. */
							 | 
						||
| 
								 | 
							
								      char *start;		/* Start of path element being checked. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      /* Find the end of this element of the path.
							 | 
						||
| 
								 | 
							
									 Then chop off the rest of the path after this element. */
							 | 
						||
| 
								 | 
							
								      while (*slash == '/')
							 | 
						||
| 
								 | 
							
									slash++;
							 | 
						||
| 
								 | 
							
								      start = slash;
							 | 
						||
| 
								 | 
							
								      slash = strchr (slash, '/');
							 | 
						||
| 
								 | 
							
								      if (slash != NULL)
							 | 
						||
| 
								 | 
							
									*slash = '\0';
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									  last_elem = 1;
							 | 
						||
| 
								 | 
							
									  slash = strchr (start, '\0');
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (!last_elem)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									  exists = dir_ok (path);
							 | 
						||
| 
								 | 
							
									  if (dir_ok == 0)
							 | 
						||
| 
								 | 
							
									    {
							 | 
						||
| 
								 | 
							
									      free (parent);
							 | 
						||
| 
								 | 
							
									      return 1;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      length = slash - start;
							 | 
						||
| 
								 | 
							
								      /* Since we know that `parent' is a directory, it's ok to call
							 | 
						||
| 
								 | 
							
									 pathconf with it as the argument.  (If `parent' isn't a directory
							 | 
						||
| 
								 | 
							
									 or doesn't exist, the behavior of pathconf is undefined.)
							 | 
						||
| 
								 | 
							
									 But if `parent' is a directory and is on a remote file system,
							 | 
						||
| 
								 | 
							
									 it's likely that pathconf can't give us a reasonable value
							 | 
						||
| 
								 | 
							
									 and will return -1.  (NFS and tempfs are not POSIX . . .)
							 | 
						||
| 
								 | 
							
									 In that case, we have no choice but to assume the pessimal
							 | 
						||
| 
								 | 
							
									 POSIX minimums.  */
							 | 
						||
| 
								 | 
							
								      name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
							 | 
						||
| 
								 | 
							
								      if (name_max < 0)
							 | 
						||
| 
								 | 
							
									name_max = _POSIX_NAME_MAX;
							 | 
						||
| 
								 | 
							
								      if (length > name_max)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									  error (0, 0, "name `%s' has length %d; exceeds limit of %d",
							 | 
						||
| 
								 | 
							
										 start, length, name_max);
							 | 
						||
| 
								 | 
							
									  free (parent);
							 | 
						||
| 
								 | 
							
									  return 1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (last_elem)
							 | 
						||
| 
								 | 
							
									break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (exists == 1)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									  free (parent);
							 | 
						||
| 
								 | 
							
									  parent = xstrdup (path);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      *slash++ = '/';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* `parent' is now the last existing leading directory in the whole path,
							 | 
						||
| 
								 | 
							
								     so it's ok to call pathconf with it as the argument.  */
							 | 
						||
| 
								 | 
							
								  path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
							 | 
						||
| 
								 | 
							
								  if (path_max < 0)
							 | 
						||
| 
								 | 
							
								    path_max = _POSIX_PATH_MAX;
							 | 
						||
| 
								 | 
							
								  free (parent);
							 | 
						||
| 
								 | 
							
								  if (strlen (path) > path_max)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      error (0, 0, "path `%s' has length %d; exceeds limit of %d",
							 | 
						||
| 
								 | 
							
									     path, strlen (path), path_max);
							 | 
						||
| 
								 | 
							
								      return 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								}
							 |