2 * (C) Copyright Transarc Corporation 1989
3 * Licensed Materials - Property of Transarc
7 /*------------------------------------------------------------------------
11 * Check the integrity of the configuration tree for package, the
12 * AFS workstation configuration tool.
15 * Transarc Corporation & Carnegie Mellon University
16 *------------------------------------------------------------------------*/
18 #include <afs/param.h>
20 #include <sys/types.h>
22 #include <sys/param.h>
29 CTREEPTR LocateChildNode();
31 static char path2[MAXPATHLEN+1]; /* $$get rid of this */
32 static char path3[MAXPATHLEN+1]; /* $$get rid of this */
34 /*------------------------------------------------------------------------
38 * Check the assertion that the given path is a Unix mountpoint.
41 * char *path : Path to check.
45 * Exit from package on failure.
48 * This routine is private to the module.
51 * May exit from package.
52 *------------------------------------------------------------------------*/
54 static CheckMount(path)
59 struct stat stb; /*Parent's stat block*/
60 struct stat stb2; /*Child's stat block*/
61 char dir[MAXPATHLEN]; /*Pathname of candidate mount point*/
62 char parent[MAXPATHLEN]; /*Parent's pathname*/
63 register char *ep, *dp, *sp; /*Sliding ptr to above strings*/
64 int ret; /*Return value*/
66 debug_message("%% CheckMount called on path %s", path);
70 * Copy out the candidate mountpoint's pathname into dir, throwing
71 * off any leaf component from the original path.
73 ep = strrchr(path, '/');
74 for (sp = path, dp = dir; sp < ep; *dp++ = *sp++);
80 * Copy out the parent's pathname into parent.
82 ep = strrchr(dir, '/');
83 for (sp = dir, dp = parent; sp < ep; *dp++ = *sp++);
89 * Only perform the following test if the candidate mountpoint is
90 * something other than `/', which we know is a mountpoint.
92 if (strcmp(dir, "/")) {
94 * Stat the given directory and its parent. If either is not a
95 * directory or if the device numbers are the same, then the
96 * candidate has failed and is not a Unix mountpoint.
98 if (stat(dir, &stb) < 0)
100 if (stat(parent, &stb2) < 0)
102 if ((stb.st_mode & S_IFMT) != S_IFDIR)
104 if ((stb2.st_mode & S_IFMT) != S_IFDIR)
106 if (stb2.st_dev == stb.st_dev)
112 * Our assertion that the given path is a mountpoint is false.
113 * Tell our caller, then croak off.
115 fatal("** %s is not a Unix mountpoint, as was expected!", dir);
119 * The candidate mountpoint has passed the test. If we're being
120 * verbose, tell everyone.
122 verbose_message("Found Unix mountpoint %s", dir);
126 /*------------------------------------------------------------------------
130 * Check the validity of the given node compared to the associated
134 * CTREEPTR np : Node pointer to check.
135 * char *path : Associated pathname.
139 * Exits the program otherwise.
142 * This is one of the routines applied to the entire configuration
146 * May exit from package.
147 *------------------------------------------------------------------------*/
150 register CTREEPTR np;
155 register CTREEPTR np2; /*Node ptr for np's child*/
156 register struct dirent *de; /*Ptr to directory entry*/
157 DIR *dp; /*Ptr to directory being read*/
158 struct stat stb; /*Stat block for path2*/
159 int retval; /*Return value*/
162 debug_message("[check] Checking pathname %s", path, np);
164 if ((np->flag & F_TYPE) && (np->updtspec & U_LOSTFOUND))
166 if (!(np->flag & F_PROTO)) {
167 if (!(np->flag & F_TYPE))
168 fatal("** Incomplete: %s", path);
170 if ((np->type == S_IFCHR) || (np->type == S_IFBLK))
171 /* $$Note: Actually, the parser takes care of this */
172 fatal("** No device numbers specified for device %s\n", path);
177 * No checks needed for character & block special devices (& sockets
180 if ((np->type == S_IFCHR)
181 || (np->type == S_IFBLK)
183 || (np->type == S_IFSOCK)
184 #endif /* AFS_AIX_ENV */
186 || (np->type == S_IFIFO)
192 * Construct the target path, either absolute or prefixed.
194 if (np->updtspec & U_ABSPATH)
198 sprintf(path2, "%s", np->proto.info.path);
203 sprintf(path2, "%s%s", np->proto.info.path, path);
205 debug_message("[check] Statting %s", path2);
208 * If this is a symlink, lstat the guy and warn people if it
211 if ((np->flag & F_TYPE) && (np->type == S_IFLNK)) {
212 if (lstat(path2, &stb) < 0)
213 verbose_message("* Warning: symlink %s not found", path2);
218 * Do a normal stat, failing if it does.
220 if (stat(path2, &stb) < 0)
221 fatal("** Stat failed for %s; %m", path2);
223 if (np->flag & F_TYPE) {
224 if (np->type == S_IFLNK)
226 if ((stb.st_mode & S_IFMT) != np->type)
227 fatal("** Type conflict for %s", path2);
230 np->type = stb.st_mode & S_IFMT;
234 if (!(np->flag & F_MODE)) {
235 /*Fill in the mode (protection) info from the stat block*/
236 np->mode |= stb.st_mode & ~S_IFMT;
240 if (!(np->flag & F_UID)) {
241 /*Fill in the user info from the stat block*/
242 np->uid = stb.st_uid;
246 if (!(np->flag & F_GID)) {
247 /*Fill in the group info from the stat block*/
249 np->gid = (stb.st_gid == 32767) ? 0 : stb.st_gid;
251 np->gid = stb.st_gid;
256 if (!(np->flag & F_MTIME)) {
257 /*Fill in the last modified time from the stat block*/
258 np->mtime = stb.st_mtime;
263 * If we've reached a non-directory, we're all done.
265 if (np->type != S_IFDIR) {
266 debug_message("[check] Reached leaf node, returning");
271 * Open up the directory and sweep through it, checking all its
274 verbose_message("Scanning directory %s", path2);
275 if ((dp = opendir(path2)) == 0)
276 fatal("** Opendir failed on %s; %m", path2);
278 while ((de = readdir(dp)) != 0) {
279 if (de->d_name[0] == '.') {
281 * Don't process dot, the current directory, or dotdot, the
284 if (de->d_name[1] == 0)
286 if (de->d_name[1] == '.' && de->d_name[2] == 0)
290 if ((np2 = LocateChildNode(np, de->d_name, C_LOCATE|C_CREATE)) == NULL)
291 fatal("** Bad path: %s/%s", path, de->d_name);
293 if (!(np2->flag & F_PROTO)) {
294 if (np->updtspec & U_ABSPATH) {
295 np2->updtspec |= U_ABSPATH;
296 sprintf(path3,"%s/%s",np->proto.info.path,de->d_name);
297 np2->proto.info.path = emalloc((unsigned)(strlen(path3)+1));
298 (void)strcpy(np2->proto.info.path, path3);
301 np2->proto.info.path = np->proto.info.path;
303 np2->flag |= F_PROTO;
306 if ((np2->updtspec & U_ABSPATH) != (np->updtspec & U_ABSPATH))
307 fatal("** Prototype conflict: %s/%s: Absolute & relative paths given",
309 if (np->updtspec & U_ABSPATH) {
310 sprintf(path3,"%s/%s", np->proto, de->d_name);
311 if (strcmp(path3, np2->proto.info.path))
312 fatal("** Prototype conflict: %s/%s: Previously %s",
313 path, de->d_name, np2->proto.info.path);
316 if (strcmp(np->proto.info.path, np2->proto.info.path))
317 fatal("** Prototype conflict: %s/%s: Mismatch for %s and %s",
320 np2->proto.info.path);
322 } /*For each directory entry*/
325 * Make sure to close the directory before we leave.