xref: /titanic_44/usr/src/lib/libast/common/path/pathcd.c (revision f80ce222af313ec87dc070b2219b29c81c5e5d8c)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * K. P. Vo
25  * G. S. Fowler
26  * AT&T Research
27  */
28 
29 #include <ast.h>
30 #include <error.h>
31 #include <stk.h>
32 
33 #if DEBUG
34 
35 #undef	PATH_MAX
36 
37 #define PATH_MAX	16
38 
39 static int
40 vchdir(const char* path)
41 {
42 	int	n;
43 
44 	if (strlen(path) >= PATH_MAX)
45 	{
46 		errno = ENAMETOOLONG;
47 		n = -1;
48 	}
49 	else n = chdir(path);
50 	return n;
51 }
52 
53 #define chdir(p)	vchdir(p)
54 
55 #endif
56 
57 /*
58  * set the current directory to path
59  * if path is long and home!=0 then pathcd(home,0)
60  * is called on intermediate chdir errors
61  */
62 
63 int
64 pathcd(const char* path, const char* home)
65 {
66 	register char*	p = (char*)path;
67 	register char*	s;
68 	register int	n;
69 	int		i;
70 	int		r;
71 
72 	r = 0;
73 	for (;;)
74 	{
75 		/*
76 		 * this should work 99% of the time
77 		 */
78 
79 		if (!chdir(p))
80 			return r;
81 
82 		/*
83 		 * chdir failed
84 		 */
85 
86 		if ((n = strlen(p)) < PATH_MAX)
87 			return -1;
88 #ifdef ENAMETOOLONG
89 		if (errno != ENAMETOOLONG)
90 			return -1;
91 #endif
92 
93 		/*
94 		 * path is too long -- copy so it can be modified in place
95 		 */
96 
97 		i = stktell(stkstd);
98 		sfputr(stkstd, p, 0);
99 		stkseek(stkstd, i);
100 		p = stkptr(stkstd, i);
101 		for (;;)
102 		{
103 			/*
104 			 * get a short prefix component
105 			 */
106 
107 			s = p + PATH_MAX;
108 			while (--s >= p && *s != '/');
109 			if (s <= p)
110 				break;
111 
112 			/*
113 			 * chdir to the prefix
114 			 */
115 
116 			*s++ = 0;
117 			if (chdir(p))
118 				break;
119 
120 			/*
121 			 * do the remainder
122 			 */
123 
124 			if ((n -= s - p) < PATH_MAX)
125 			{
126 				if (chdir(s))
127 					break;
128 				return r;
129 			}
130 			p = s;
131 		}
132 
133 		/*
134 		 * try to recover back to home
135 		 */
136 
137 		if (!(p = (char*)home))
138 			return -1;
139 		home = 0;
140 		r = -1;
141 	}
142 }
143