convert-from-bsd-to-posix-string-and-memory-functions-20010807
[openafs.git] / src / package / check.c
1 /*
2  * (C) Copyright Transarc Corporation 1989
3  * Licensed Materials - Property of Transarc
4  * All Rights Reserved.
5  */
6
7 /*------------------------------------------------------------------------
8  * check.c
9  *
10  * Description:
11  *      Check the integrity of the configuration tree for package, the
12  *      AFS workstation configuration tool.
13  *
14  * Author:
15  *      Transarc Corporation & Carnegie Mellon University
16  *------------------------------------------------------------------------*/
17
18 #include <afs/param.h>
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/param.h>
23 #include <dirent.h>
24 #include "globals.h"
25 #include "package.h"
26
27 char *emalloc();
28 char *strcpy();
29 CTREEPTR LocateChildNode();
30
31 static char path2[MAXPATHLEN+1];    /* $$get rid of this */
32 static char path3[MAXPATHLEN+1];    /* $$get rid of this */
33
34 /*------------------------------------------------------------------------
35  * [static] CheckMount
36  *
37  * Description:
38  *      Check the assertion that the given path is a Unix mountpoint.
39  *
40  * Arguments:
41  *      char *path : Path to check.
42  *
43  * Returns:
44  *      0 on success,
45  *      Exit from package on failure.
46  *
47  * Environment:
48  *      This routine is private to the module.
49  *
50  * Side Effects:
51  *      May exit from package.
52  *------------------------------------------------------------------------*/
53
54 static CheckMount(path)
55      char *path;
56
57 { /*CheckMount*/
58
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*/
65
66     debug_message("%% CheckMount called on path %s", path);
67     ret = 0;
68
69     /*
70       * Copy out the candidate mountpoint's pathname into dir, throwing
71       * off any leaf component from the original path.
72       */
73     ep = strrchr(path, '/');
74     for (sp = path, dp = dir; sp < ep; *dp++ = *sp++);
75     if (dp == dir)
76         *dp++ = '/';
77     *dp = '\0';
78
79     /*
80       * Copy out the parent's pathname into parent.
81       */
82     ep = strrchr(dir, '/');
83     for (sp = dir, dp = parent; sp < ep; *dp++ = *sp++);
84     if (dp == parent)
85         *dp++ = '/';
86     *dp = '\0';
87
88     /*
89       * Only perform the following test if the candidate mountpoint is
90       * something other than `/', which we know is a mountpoint.
91       */
92     if (strcmp(dir, "/")) {
93       /*
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.
97         */
98       if (stat(dir, &stb) < 0)
99         ret = -1;
100       if (stat(parent, &stb2) < 0)
101         ret = -1;
102       if ((stb.st_mode & S_IFMT) != S_IFDIR)
103         ret = -1;
104       if ((stb2.st_mode & S_IFMT) != S_IFDIR)
105         ret = -1;
106       if (stb2.st_dev == stb.st_dev)
107         ret = -1;
108     }
109
110     if (ret < 0) {
111       /*
112         * Our assertion that the given path is a mountpoint is false.
113         * Tell our caller, then croak off.
114         */
115       fatal("** %s is not a Unix mountpoint, as was expected!", dir);
116     }
117
118     /*
119       * The candidate mountpoint has passed the test.  If we're being
120       * verbose, tell everyone.
121       */
122     verbose_message("Found Unix mountpoint %s", dir);
123
124 } /*CheckMount*/
125
126 /*------------------------------------------------------------------------
127  * check
128  *
129  * Description:
130  *      Check the validity of the given node compared to the associated
131  *      pathname.
132  *
133  * Arguments:
134  *      CTREEPTR np : Node pointer to check.
135  *      char *path  : Associated pathname.
136  *
137  * Returns:
138  *      0 upon success,
139  *      Exits the program otherwise.
140  *
141  * Environment:
142  *      This is one of the routines applied to the entire configuration
143  *      tree.
144  *
145  * Side Effects:
146  *      May exit from package.
147  *------------------------------------------------------------------------*/
148
149 int check(np, path)
150     register CTREEPTR np;
151     char *path;
152
153 { /*check*/
154
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*/
160
161     retval = 0;
162     debug_message("[check] Checking pathname %s", path, np);
163
164     if ((np->flag & F_TYPE) && (np->updtspec & U_LOSTFOUND))
165         CheckMount(path);
166     if (!(np->flag & F_PROTO)) {
167         if (!(np->flag & F_TYPE))
168             fatal("** Incomplete: %s", path);
169         else
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);
173         return(retval);
174     }
175
176     /*
177      * No checks needed for character & block special devices (& sockets
178      * & named pipes).
179      */
180     if ((np->type == S_IFCHR)
181         || (np->type == S_IFBLK)
182 #ifndef AFS_AIX_ENV
183         || (np->type == S_IFSOCK)
184 #endif /* AFS_AIX_ENV */
185 #ifdef S_IFIFO
186         || (np->type == S_IFIFO)
187 #endif /* S_IFIFO */
188         )
189       return(retval);
190
191     /*
192       * Construct the target path, either absolute or prefixed.
193       */
194     if (np->updtspec & U_ABSPATH)
195       /*
196         * Absolute path.
197         */
198       sprintf(path2, "%s", np->proto.info.path);
199     else
200       /*
201         * Prefixed path.
202         */
203       sprintf(path2, "%s%s", np->proto.info.path, path);
204
205     debug_message("[check] Statting %s", path2);
206
207     /*
208       * If this is a symlink, lstat the guy and warn people if it
209       * isn't found.
210       */
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);
214       return(retval);
215     }
216
217     /*
218       * Do a normal stat, failing if it does.
219       */
220     if (stat(path2, &stb) < 0)
221         fatal("** Stat failed for %s; %m", path2);
222
223     if (np->flag & F_TYPE) {
224       if (np->type == S_IFLNK)
225         return(retval);
226       if ((stb.st_mode & S_IFMT) != np->type)
227         fatal("** Type conflict for %s", path2);
228     }
229     else {
230       np->type = stb.st_mode & S_IFMT;
231       np->flag |= F_TYPE;
232     }
233
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;
237       np->flag |= F_MODE;
238     }
239
240     if (!(np->flag & F_UID)) {
241       /*Fill in the user info from the stat block*/
242       np->uid = stb.st_uid;
243       np->flag |= F_UID;
244     }
245
246     if (!(np->flag & F_GID)) {
247       /*Fill in the group info from the stat block*/
248 #ifdef  VICE
249       np->gid = (stb.st_gid == 32767) ? 0 : stb.st_gid;
250 #else /* VICE */
251       np->gid = stb.st_gid;
252 #endif /* VICE */
253       np->flag |= F_GID;
254     }
255
256     if (!(np->flag & F_MTIME)) {
257       /*Fill in the last modified time from the stat block*/
258       np->mtime = stb.st_mtime;
259       np->flag |= F_MTIME;
260     }
261
262     /*
263       * If we've reached a non-directory, we're all done.
264       */
265     if (np->type != S_IFDIR) {
266       debug_message("[check] Reached leaf node, returning");
267       return(retval);
268     }
269
270     /*
271       * Open up the directory and sweep through it, checking all its
272       * entries.
273       */
274     verbose_message("Scanning directory %s", path2);
275     if ((dp = opendir(path2)) == 0)
276         fatal("** Opendir failed on %s; %m", path2);
277
278     while ((de = readdir(dp)) != 0) {
279       if (de->d_name[0] == '.') {
280         /*
281           * Don't process dot, the current directory, or dotdot, the
282           * parent.
283           */
284         if (de->d_name[1] == 0)
285           continue;
286         if (de->d_name[1] == '.' && de->d_name[2] == 0)
287           continue;
288       }
289
290       if ((np2 = LocateChildNode(np, de->d_name, C_LOCATE|C_CREATE)) == NULL)
291         fatal("** Bad path: %s/%s", path, de->d_name);
292
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);
299         }
300         else {
301           np2->proto.info.path = np->proto.info.path;
302         }
303         np2->flag |= F_PROTO;
304         continue;
305       }
306       if ((np2->updtspec & U_ABSPATH) != (np->updtspec & U_ABSPATH))
307         fatal("** Prototype conflict: %s/%s: Absolute & relative paths given",
308               path, de->d_name);
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);
314       }
315       else {
316         if (strcmp(np->proto.info.path, np2->proto.info.path))
317           fatal("** Prototype conflict: %s/%s: Mismatch for %s and %s",
318                 path, de->d_name,
319                 np->proto.info.path,
320                 np2->proto.info.path);
321       }
322     } /*For each directory entry*/
323
324     /*
325       * Make sure to close the directory before we leave.
326       */
327     (void) closedir(dp);
328     return(retval);
329
330 } /*check*/
331