reindent-20030715
[openafs.git] / src / package / update.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*------------------------------------------------------------------------
11  * update.c
12  *
13  * Description:
14  *      Routines that actually do the disk updates.
15  *
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 <time.h>
25 #include <sys/time.h>
26 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
27 #include <sys/mkdev.h>
28 #endif
29 #ifdef AFS_LINUX20_ENV
30 #include <sys/sysmacros.h>
31 #endif
32 #include "globals.h"
33 #include "package.h"
34
35 char *emalloc();
36 char *strcpy();
37 CTREEPTR LocateChildNode();
38
39 static struct stat stb;
40
41 static UpdateSock();
42 static UpdateDev();
43 static UpdatePipe();
44 static UpdateLnk();
45 static UpdateDir();
46 static UpdateReg();
47 static dochtyp();
48 static dochmod();
49 static dochown();
50 static dochtim();
51 static int FixLostFoundDir();
52 static int FixDir();
53 static FixReg();
54
55 /* $$important: these will have to be fixed with an error recovery mechanism */
56
57 int
58 update(np, path)
59      CTREEPTR np;
60      char *path;
61
62 {                               /*update */
63
64     switch (np->type) {
65 #ifndef AFS_AIX_ENV
66     case S_IFSOCK:
67         UpdateSock(np, path);
68         break;
69 #endif /* AFS_AIX_ENV */
70
71 #ifdef S_IFIFO
72     case S_IFIFO:
73         UpdatePipe(np, path);
74         break;
75 #endif /* S_IFIFO */
76
77     case S_IFCHR:
78     case S_IFBLK:
79         UpdateDev(np, path);
80         break;
81
82     case S_IFLNK:
83         UpdateLnk(np, path);
84         break;
85
86     case S_IFDIR:
87         UpdateDir(np, path);
88         break;
89
90     case S_IFREG:
91         UpdateReg(np, path);
92         break;
93     }
94
95 }                               /*update */
96
97 static
98 UpdateSock(np, path)
99      CTREEPTR np;
100      char *path;
101
102 {                               /*UpdateSock */
103
104     (void)dochtyp(np, path);
105
106 }                               /*UpdateSock */
107
108
109 static
110 UpdateDev(np, path)
111      CTREEPTR np;
112      char *path;
113
114 {                               /*UpdateDev */
115
116     register int ret;
117
118     ret = dochtyp(np, path);
119
120 #ifdef  KFLAG
121     if (ret == 1)
122         return;
123 #endif /* KFLAG */
124     if ((np->flag & F_PROTO) != 0) {
125         if (ret >= 0) {
126             if (np->proto.info.rdev != stb.st_rdev) {
127                 rm(path);
128                 ret = -1;
129             }
130         }
131         if (ret < 0) {
132             char *type;
133
134             switch (np->type) {
135             case S_IFBLK:
136                 type = "b";
137                 break;
138
139             case S_IFCHR:
140                 type = "c";
141                 break;
142
143             default:
144                 message("Unknown device type: %d\n", np->type);
145                 break;
146             }
147
148             loudonly_message("mknod %s %d %d %s", type,
149                              major(np->proto.info.rdev),
150                              minor(np->proto.info.rdev), path);
151             if (!opt_lazy) {
152                 if (mknod
153                     (path, (int)np->mode | (int)np->type,
154                      (int)np->proto.info.rdev) < 0)
155                     message("mknod %s %d %d %s; %m", type,
156                             major(np->proto.info.rdev),
157                             minor(np->proto.info.rdev), path);
158                 if ((ret = lstat(path, &stb)) < 0)
159                     message("lstat %s; %m", path);
160             }
161         }
162     }
163     if (ret >= 0) {
164         dochmod(np, path);
165         dochown(np, path);
166     }
167
168 }                               /*UpdateDev */
169
170 static
171 UpdatePipe(np, path)
172      CTREEPTR np;
173      char *path;
174
175 {                               /*UpdatePipe */
176
177     register int ret;
178
179     /*
180      * Don't have to call dochtyp() here; just set ret to the value
181      * saying everything is fine.
182      */
183     ret = -1;
184
185 #ifdef  KFLAG
186     if (ret == 1)
187         return;
188 #endif /* KFLAG */
189     if ((np->flag & F_PROTO) != 0) {
190         if (ret >= 0) {
191             if (np->proto.info.rdev != stb.st_rdev) {
192                 rm(path);
193                 ret = -1;
194             }
195         }
196         if (ret < 0) {
197             loudonly_message("mknod p %s", path);
198
199             if (!opt_lazy) {
200                 if (mknod
201                     (path, (int)(np->mode) | (int)(np->type),
202                      (int)(np->proto.info.rdev)) < 0)
203                     message("mknod p %s; %m", path);
204                 if ((ret = lstat(path, &stb)) < 0)
205                     message("lstat %s; %m", path);
206             }
207         }
208     }
209
210     if (ret >= 0) {
211         dochmod(np, path);
212         dochown(np, path);
213     }
214
215 }                               /*UpdatePipe */
216
217 static
218 UpdateLnk(np, path)
219      CTREEPTR np;
220      char *path;
221
222 {                               /*UpdateLnk */
223
224     register int ret;
225     char temp[MAXPATHLEN], temp2[MAXPATHLEN];
226     int cc;
227
228     ret = dochtyp(np, path);
229 #ifdef  KFLAG
230     if (ret == 1)
231         return;
232 #endif /* KFLAG */
233     if ((np->flag & F_PROTO) == 0)
234         return;
235     if (np->updtspec & U_ABSPATH)
236         sprintf(temp, "%s", np->proto.info.path);
237     else
238         sprintf(temp, "%s%s", np->proto.info.path, path);
239     if (ret >= 0) {
240         if ((cc = readlink(path, temp2, sizeof(temp2) - 1)) < 0) {
241             message("readlink %s; %m", path);
242             return;
243         }
244         temp2[cc] = 0;
245         if (strcmp(temp2, temp)) {
246             if ((np->updtspec & U_NOOVERWRITE) == 0) {
247                 rm(path);
248                 ret = -1;
249             } else {
250                 loudonly_message("INHIBIT %s updating", path);
251             }
252         }
253     }
254     if (ret < 0) {
255         loudonly_message("ln %s %s", path, temp);
256         if (!opt_lazy && symlink(temp, path) < 0)
257             message("symlink %s %s; %m", temp, path);
258     }
259
260 }                               /*UpdateLnk */
261
262
263 static
264 UpdateDir(np, path)
265      CTREEPTR np;
266      char *path;
267
268 {                               /*UpdateDir */
269
270     register int ret;
271
272     ret = dochtyp(np, path);
273 #ifdef  KFLAG
274     if (ret == 1)
275         return;
276 #endif /* KFLAG */
277     if (ret < 0) {
278         loudonly_message("mkdir %s", path);
279         if (!opt_lazy) {
280             if (mkdir(path, (int)np->mode & ~S_IFMT) < 0)
281                 message("mkdir %s; %m", path);
282             if ((ret = lstat(path, &stb)) < 0)
283                 message("lstat %s; %m", path);
284         }
285     }
286     if (np->updtspec & U_LOSTFOUND)
287         (void)FixLostFoundDir(path);
288     if (np->updtspec & U_RMEXTRA)
289         (void)FixDir(np, path);
290     if (ret >= 0) {
291         dochmod(np, path);
292         dochown(np, path);
293     }
294
295 }                               /*UpdateDir */
296
297
298 static
299 UpdateReg(np, path)
300      CTREEPTR np;
301      char *path;
302
303 {                               /*UpdateReg */
304
305     register int ret;
306
307     ret = dochtyp(np, path);
308 #ifdef  KFLAG
309     if (ret == 1)
310         return;
311 #endif /* KFLAG */
312     if ((np->flag & F_PROTO) != 0) {
313         if (ret < 0)
314             np->updtspec &= ~U_RENAMEOLD;
315         if (ret >= 0) {
316             if ((np->updtspec & U_NOOVERWRITE) == 0)
317                 if (np->mtime != stb.st_mtime)
318                     ret = -1;
319         }
320         if (ret < 0) {
321             if ((ret = FixReg(np, path)) >= 0)
322                 ret = lstat(path, &stb);
323             if (ret >= 0)
324                 dochtim(np, path);
325         }
326     }
327     if (ret >= 0) {
328         dochmod(np, path);
329         dochown(np, path);
330     }
331
332 }                               /*UpdateReg */
333
334
335 /*
336  * dochtyp
337  *
338  * This function makes sure the path on local disk has the same file type
339  * as that in the given prototype.  If it doesn't (and the -rebootfile
340  * flag hasn't been used with a file marked as requiring a reboot), then
341  * we delete the local disk copy and return -1.  If inhibiting the overwrite
342  * is in order, we return 1.  If the types already match (or the above
343  * reboot scenario is true), we return 0.
344  */
345
346 static
347 dochtyp(np, path)
348      CTREEPTR np;
349      char *path;
350
351 {                               /*dochtyp */
352
353     if (lstat(path, &stb) < 0)
354         return -1;
355 #ifdef  KFLAG
356     if (opt_kflag && (stb.st_mode & 0222) == 0) {
357         loudonly_message("INHIBIT %s updating", path);
358         return 1;
359     }
360 #endif /* KFLAG */
361     if ((stb.st_mode & S_IFMT) == np->type)
362         return 0;
363     if (!opt_reboot && (np->flag & F_UPDT) && (np->updtspec & U_REBOOT)) {
364         message("%s is out of date; please REBOOT!", path);
365         return 0;
366     } else {
367         rm(path);
368         return -1;
369     }
370
371 }                               /*dochtyp */
372
373 static
374 dochmod(np, path)
375      CTREEPTR np;
376      char *path;
377
378 {                               /*dochmod */
379
380     if ((np->flag & F_MODE) == 0)
381         return;
382     if ((np->mode & ~S_IFMT) == (stb.st_mode & ~S_IFMT))
383         return;
384     loudonly_message("chmod %s %o", path, np->mode & ~S_IFMT);
385     if (!opt_lazy && chmod(path, (int)np->mode & ~S_IFMT) < 0)
386         message("chmod %s; %m", path);
387
388 }                               /*dochmod */
389
390 static
391 dochown(np, path)
392      CTREEPTR np;
393      char *path;
394
395 {                               /*dochown */
396
397     if ((np->flag & F_UID) == 0)
398         np->uid = stb.st_uid;
399     if ((np->flag & F_GID) == 0)
400         np->gid = stb.st_gid;
401     if (np->uid == stb.st_uid && np->gid == stb.st_gid)
402         return;
403     loudonly_message("chown %s %d %d", path, np->uid, np->gid);
404     if (!opt_lazy && chown(path, np->uid, np->gid) < 0)
405         message("chown %s; %m", path);
406
407 }                               /*dochown */
408
409 static
410 dochtim(np, path)
411      CTREEPTR np;
412      char *path;
413
414 {                               /*dochtim */
415
416     struct timeval tm[2];
417
418     if (np->mtime == stb.st_mtime
419         || (!opt_reboot && (np->updtspec & U_REBOOT)))
420         return;
421     tm[0].tv_sec = tm[1].tv_sec = np->mtime;
422     tm[0].tv_usec = tm[1].tv_usec = 0;
423     if (!opt_silent) {
424         char *date;
425
426         date = ctime((time_t *) & np->mtime);
427         date[24] = 0;
428         loudonly_message("utimes %s [%s]", path, date);
429     }
430     if (!opt_lazy && utimes(path, tm) < 0)
431         message("utimes %s; %m", path);
432
433 }                               /*dochtim */
434
435 static int
436 FixLostFoundDir(path)
437      char *path;
438
439 {                               /*FixLostFoundDir */
440
441     if (stb.st_size >= 3584)
442         return 0;
443     return mklostfound(path);
444
445 }                               /*FixLostFoundDir */
446
447 static int
448 FixDir(np, path)
449      CTREEPTR np;
450      char *path;
451
452 {                               /*FixDir */
453
454     register DIR *dp;
455     register struct dirent *de;
456     register char *endp;
457
458     verbose_message("cleandir %s", path);
459     if ((dp = opendir(path)) == 0) {
460         message("opendir %s; %m", path);
461         return -1;
462     }
463     endp = path + strlen(path);
464     *endp++ = '/';
465     while ((de = readdir(dp)) != 0) {
466         if (de->d_name[0] == '.') {
467             if (de->d_name[1] == 0)
468                 continue;
469             if (de->d_name[1] == '.' && de->d_name[2] == 0)
470                 continue;
471         }
472         if (LocateChildNode(np, de->d_name, C_LOCATE) != 0)
473             continue;
474         (void)strcpy(endp, de->d_name);
475         rm(path);
476     }
477     *--endp = 0;
478     (void)closedir(dp);
479     return 0;
480
481 }                               /*FixDir */
482
483 static
484 FixReg(np, path)
485      CTREEPTR np;
486      char *path;
487
488 {                               /*FixReg */
489
490     char new[MAXPATHLEN], old[MAXPATHLEN], temp[MAXPATHLEN];
491
492     if (!opt_reboot && (np->updtspec & U_REBOOT)) {
493         verbose_message
494             ("%s is a 'Q' file and -rebootfiles is set; not updated!", path);
495         return 0;
496     }
497     (void)sprintf(new, "%s.new", path);
498     if (np->updtspec & U_ABSPATH)
499         (void)sprintf(temp, "%s", np->proto.info.path);
500     else
501         (void)sprintf(temp, "%s%s", np->proto.info.path, path);
502     if (cp(temp, new))
503         return -1;
504     if (np->updtspec & U_RENAMEOLD) {
505         (void)sprintf(old, "%s.old", path);
506         (void)rm(old);
507         (void)ln(path, old);
508     }
509     if (mv(new, path))
510         return -1;
511     if (np->updtspec & U_REBOOT)
512         status = status_reboot;
513     return 0;
514
515 }                               /*FixReg */