Imported Upstream version 2.4.5p1
[debian/amanda] / client-src / selfcheck.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /* 
28  * $Id: selfcheck.c,v 1.40.2.3.4.4.2.22.2.3 2005/09/20 21:31:52 jrjackson Exp $
29  *
30  * do self-check and send back any error messages
31  */
32
33 #include "amanda.h"
34 #include "clock.h"
35 #include "statfs.h"
36 #include "version.h"
37 #include "getfsent.h"
38 #include "amandates.h"
39 #include "util.h"
40 #include "pipespawn.h"
41 #include "amfeatures.h"
42 #include "client_util.h"
43
44 #ifdef SAMBA_CLIENT
45 #include "findpass.h"
46 #endif
47
48 int need_samba=0;
49 int need_rundump=0;
50 int need_dump=0;
51 int need_restore=0;
52 int need_vdump=0;
53 int need_vrestore=0;
54 int need_xfsdump=0;
55 int need_xfsrestore=0;
56 int need_vxdump=0;
57 int need_vxrestore=0;
58 int need_runtar=0;
59 int need_gnutar=0;
60 int need_compress_path=0;
61 int need_calcsize=0;
62
63 static am_feature_t *our_features = NULL;
64 static char *our_feature_string = NULL;
65 static g_option_t *g_options = NULL;
66
67 /* local functions */
68 int main P((int argc, char **argv));
69
70 static void check_options P((char *program, char *calcprog, char *disk, char *device, option_t *options));
71 static void check_disk P((char *program, char *calcprog, char *disk, char *amdevice, int level));
72 static void check_overall P((void));
73 static void check_access P((char *filename, int mode));
74 static void check_file P((char *filename, int mode));
75 static void check_dir P((char *dirname, int mode));
76 static void check_suid P((char *filename));
77 static void check_space P((char *dir, long kbytes));
78
79 int main(argc, argv)
80 int argc;
81 char **argv;
82 {
83     int level;
84     char *line = NULL;
85     char *program = NULL;
86     char *calcprog = NULL;
87     char *disk = NULL;
88     char *device = NULL;
89     char *optstr = NULL;
90     char *err_extra = NULL;
91     char *s, *fp;
92     int ch;
93     unsigned long malloc_hist_1, malloc_size_1;
94     unsigned long malloc_hist_2, malloc_size_2;
95     option_t *options;
96
97     /* initialize */
98
99     safe_fd(-1, 0);
100     safe_cd();
101
102     set_pname("selfcheck");
103
104     malloc_size_1 = malloc_inuse(&malloc_hist_1);
105
106     erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
107     dbopen();
108     startclock();
109     dbprintf(("%s: version %s\n", argv[0], version()));
110
111     our_features = am_init_feature_set();
112     our_feature_string = am_feature_to_string(our_features);
113
114     /* handle all service requests */
115
116     for(; (line = agets(stdin)) != NULL; free(line)) {
117 #define sc "OPTIONS "
118         if(strncmp(line, sc, sizeof(sc)-1) == 0) {
119 #undef sc
120             g_options = parse_g_options(line+8, 1);
121             if(!g_options->hostname) {
122                 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
123                 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
124                 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
125             }
126
127             printf("OPTIONS ");
128             if(am_has_feature(g_options->features, fe_rep_options_features)) {
129                 printf("features=%s;", our_feature_string);
130             }
131             if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
132                 printf("hostname=%s;", g_options->hostname);
133             }
134             printf("\n");
135             fflush(stdout);
136             continue;
137         }
138
139         s = line;
140         ch = *s++;
141
142         skip_whitespace(s, ch);                 /* find program name */
143         if (ch == '\0') {
144             goto err;                           /* no program */
145         }
146         program = s - 1;
147         skip_non_whitespace(s, ch);
148         s[-1] = '\0';                           /* terminate the program name */
149
150         if(strncmp(program, "CALCSIZE", 8) == 0) {
151             skip_whitespace(s, ch);             /* find program name */
152             if (ch == '\0') {
153                 goto err;                       /* no program */
154             }
155             calcprog = s - 1;
156             skip_non_whitespace(s, ch);
157             s[-1] = '\0';
158         }
159         else {
160             calcprog = NULL;
161         }
162
163         skip_whitespace(s, ch);                 /* find disk name */
164         if (ch == '\0') {
165             goto err;                           /* no disk */
166         }
167         disk = s - 1;
168         skip_non_whitespace(s, ch);
169         s[-1] = '\0';                           /* terminate the disk name */
170
171         skip_whitespace(s, ch);                 /* find the device or level */
172         if (ch == '\0') {
173             goto err;                           /* no device or level */
174         }
175         if(!isdigit((int)s[-1])) {
176             fp = s - 1;
177             skip_non_whitespace(s, ch);
178             s[-1] = '\0';                       /* terminate the device */
179             device = stralloc(fp);
180             skip_whitespace(s, ch);             /* find level number */
181         }
182         else {
183             device = stralloc(disk);
184         }
185
186                                                 /* find level number */
187         if (ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
188             goto err;                           /* bad level */
189         }
190         skip_integer(s, ch);
191
192         skip_whitespace(s, ch);
193 #define sc "OPTIONS "
194         if (ch && strncmp (s - 1, sc, sizeof(sc)-1) == 0) {
195             s += sizeof(sc)-1;
196             ch = s[-1];
197 #undef sc
198             skip_whitespace(s, ch);             /* find the option string */
199             if(ch == '\0') {
200                 goto err;                       /* bad options string */
201             }
202             optstr = s - 1;
203             skip_non_whitespace(s, ch);
204             s[-1] = '\0';                       /* terminate the options */
205             options = parse_options(optstr, disk, device, g_options->features, 1);
206             check_options(program, calcprog, disk, device, options);
207             check_disk(program, calcprog, disk, device, level);
208             free_sl(options->exclude_file);
209             free_sl(options->exclude_list);
210             free_sl(options->include_file);
211             free_sl(options->include_list);
212             amfree(options->str);
213             amfree(options);
214         } else if (ch == '\0') {
215             /* check all since no option */
216             need_samba=1;
217             need_rundump=1;
218             need_dump=1;
219             need_restore=1;
220             need_vdump=1;
221             need_vrestore=1;
222             need_xfsdump=1;
223             need_xfsrestore=1;
224             need_vxdump=1;
225             need_vxrestore=1;
226             need_runtar=1;
227             need_gnutar=1;
228             need_compress_path=1;
229             need_calcsize=1;
230             check_disk(program, calcprog, disk, device, level);
231         } else {
232             goto err;                           /* bad syntax */
233         }
234         amfree(device);
235     }
236
237     check_overall();
238
239     amfree(line);
240     amfree(our_feature_string);
241     am_release_feature_set(our_features);
242     our_features = NULL;
243     am_release_feature_set(g_options->features);
244     g_options->features = NULL;
245     amfree(g_options->str);
246     amfree(g_options->hostname);
247     amfree(g_options);
248
249     malloc_size_2 = malloc_inuse(&malloc_hist_2);
250
251     if(malloc_size_1 != malloc_size_2) {
252 #if defined(USE_DBMALLOC)
253         extern int dbfd;
254
255         malloc_list(dbfd(), malloc_hist_1, malloc_hist_2);
256 #endif
257     }
258
259     dbclose();
260     return 0;
261
262  err:
263     printf("ERROR [BOGUS REQUEST PACKET]\n");
264     dbprintf(("%s: REQ packet is bogus%s%s\n",
265               debug_prefix_time(NULL),
266               err_extra ? ": " : "",
267               err_extra ? err_extra : ""));
268     dbclose();
269     return 1;
270 }
271
272
273 static void
274 check_options(program, calcprog, disk, device, options)
275     char *program, *calcprog, *disk, *device;
276     option_t *options;
277 {
278     char *myprogram = program;
279
280     if(strcmp(myprogram,"CALCSIZE") == 0) {
281         int nb_exclude = 0;
282         int nb_include = 0;
283         char *file_exclude = NULL;
284         char *file_include = NULL;
285
286         if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
287         if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
288         if(options->include_file) nb_include += options->include_file->nb_element;
289         if(options->include_list) nb_include += options->include_list->nb_element;
290
291         if(nb_exclude > 0) file_exclude = build_exclude(disk, device, options, 1);
292         if(nb_include > 0) file_include = build_include(disk, device, options, 1);
293
294         amfree(file_exclude);
295         amfree(file_include);
296
297         need_calcsize=1;
298         myprogram = calcprog;
299     }
300
301     if(strcmp(myprogram,"GNUTAR") == 0) {
302         need_gnutar=1;
303         if(disk[0] == '/' && disk[1] == '/') {
304             if(options->exclude_file && options->exclude_file->nb_element > 1) {
305                 printf("ERROR [samba support only one exclude file]\n");
306             }
307             if(options->exclude_list && options->exclude_list->nb_element > 0 &&
308                options->exclude_optional==0) {
309                 printf("ERROR [samba does not support exclude list]\n");
310             }
311             if(options->include_file && options->include_file->nb_element > 0) {
312                 printf("ERROR [samba does not support include file]\n");
313             }
314             if(options->include_list && options->include_list->nb_element > 0 &&
315                options->include_optional==0) {
316                 printf("ERROR [samba does not support include list]\n");
317             }
318             need_samba=1;
319         }
320         else {
321             int nb_exclude = 0;
322             int nb_include = 0;
323             char *file_exclude = NULL;
324             char *file_include = NULL;
325
326             if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
327             if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
328             if(options->include_file) nb_include += options->include_file->nb_element;
329             if(options->include_list) nb_include += options->include_list->nb_element;
330
331             if(nb_exclude > 0) file_exclude = build_exclude(disk, device, options, 1);
332             if(nb_include > 0) file_include = build_include(disk, device, options, 1);
333
334             amfree(file_exclude);
335             amfree(file_include);
336
337             need_runtar=1;
338         }
339     }
340
341     if(strcmp(myprogram,"DUMP") == 0) {
342         if(options->exclude_file && options->exclude_file->nb_element > 0) {
343             printf("ERROR [DUMP does not support exclude file]\n");
344         }
345         if(options->exclude_list && options->exclude_list->nb_element > 0) {
346             printf("ERROR [DUMP does not support exclude list]\n");
347         }
348         if(options->include_file && options->include_file->nb_element > 0) {
349             printf("ERROR [DUMP does not support include file]\n");
350         }
351         if(options->include_list && options->include_list->nb_element > 0) {
352             printf("ERROR [DUMP does not support include list]\n");
353         }
354 #ifdef USE_RUNDUMP
355         need_rundump=1;
356 #endif
357 #ifndef AIX_BACKUP
358 #ifdef VDUMP
359 #ifdef DUMP
360         if (strcmp(amname_to_fstype(disk), "advfs") == 0)
361 #else
362         if (1)
363 #endif
364         {
365             need_vdump=1;
366             need_rundump=1;
367             if (options->createindex)
368                 need_vrestore=1;
369         }
370         else
371 #endif /* VDUMP */
372 #ifdef XFSDUMP
373 #ifdef DUMP
374         if (strcmp(amname_to_fstype(disk), "xfs") == 0)
375 #else
376         if (1)
377 #endif
378         {
379             need_xfsdump=1;
380             need_rundump=1;
381             if (options->createindex)
382                 need_xfsrestore=1;
383         }
384         else
385 #endif /* XFSDUMP */
386 #ifdef VXDUMP
387 #ifdef DUMP
388         if (strcmp(amname_to_fstype(disk), "vxfs") == 0)
389 #else
390         if (1)
391 #endif
392         {
393             need_vxdump=1;
394             if (options->createindex)
395                 need_vxrestore=1;
396         }
397         else
398 #endif /* VXDUMP */
399         {
400             need_dump=1;
401             if (options->createindex)
402                 need_restore=1;
403         }
404 #else
405         /* AIX backup program */
406         need_dump=1;
407         if (options->createindex)
408             need_restore=1;
409 #endif
410     }
411     if(options->compress == COMPR_BEST || options->compress == COMPR_FAST) 
412         need_compress_path=1;
413 }
414
415 static void check_disk(program, calcprog, disk, amdevice, level)
416 char *program, *calcprog, *disk, *amdevice;
417 int level;
418 {
419     char *device = NULL;
420     char *err = NULL;
421     char *user_and_password = NULL, *domain = NULL;
422     char *share = NULL, *subdir = NULL;
423     int lpass = 0;
424     int amode;
425     int access_result;
426     char *access_type;
427     char *extra_info = NULL;
428     char *myprogram = program;
429
430     if(strcmp(myprogram,"CALCSIZE") == 0) {
431         if(amdevice[0] == '/' && amdevice[1] == '/') {
432             err = vstralloc("Can't use CALCSIZE for samba estimate,",
433                             " use CLIENT: ",
434                             amdevice,
435                             NULL);
436             goto common_exit;
437         }
438         myprogram = calcprog;
439     }
440
441     dbprintf(("%s: checking disk %s\n", debug_prefix_time(NULL), disk));
442
443     if (strcmp(myprogram, "GNUTAR") == 0) {
444         if(amdevice[0] == '/' && amdevice[1] == '/') {
445 #ifdef SAMBA_CLIENT
446             int nullfd, checkerr;
447             int passwdfd;
448             char *pwtext;
449             int pwtext_len;
450             int checkpid;
451             amwait_t retstat;
452             char number[NUM_STR_SIZE];
453             int wpid;
454             int ret, sig, rc;
455             char *line;
456             char *sep;
457             FILE *ferr;
458             char *pw_fd_env;
459             int errdos;
460
461             parsesharename(amdevice, &share, &subdir);
462             if (!share) {
463                 err = stralloc2("cannot parse for share/subdir disk entry ", amdevice);
464                 goto common_exit;
465             }
466             if ((subdir) && (SAMBA_VERSION < 2)) {
467                 err = vstralloc("subdirectory specified for share '",
468                                 amdevice,
469                                 "' but samba not v2 or better",
470                                 NULL);
471                 goto common_exit;
472             }
473             if ((user_and_password = findpass(share, &domain)) == NULL) {
474                 err = stralloc2("cannot find password for ", amdevice);
475                 goto common_exit;
476             }
477             lpass = strlen(user_and_password);
478             if ((pwtext = strchr(user_and_password, '%')) == NULL) {
479                 err = stralloc2("password field not \'user%pass\' for ", amdevice);
480                 goto common_exit;
481             }
482             *pwtext++ = '\0';
483             pwtext_len = strlen(pwtext);
484             if ((device = makesharename(share, 0)) == NULL) {
485                 err = stralloc2("cannot make share name of ", share);
486                 goto common_exit;
487             }
488
489             nullfd = open("/dev/null", O_RDWR);
490             if (pwtext_len > 0) {
491                 pw_fd_env = "PASSWD_FD";
492             } else {
493                 pw_fd_env = "dummy_PASSWD_FD";
494             }
495             checkpid = pipespawn(SAMBA_CLIENT, STDERR_PIPE|PASSWD_PIPE,
496                                  &nullfd, &nullfd, &checkerr,
497                                  pw_fd_env, &passwdfd,
498                                  "smbclient",
499                                  device,
500                                  *user_and_password ? "-U" : skip_argument,
501                                  *user_and_password ? user_and_password : skip_argument,
502                                  "-E",
503                                  domain ? "-W" : skip_argument,
504                                  domain ? domain : skip_argument,
505 #if SAMBA_VERSION >= 2
506                                  subdir ? "-D" : skip_argument,
507                                  subdir ? subdir : skip_argument,
508 #endif
509                                  "-c", "quit",
510                                  NULL);
511             if (domain) {
512                 memset(domain, '\0', strlen(domain));
513                 amfree(domain);
514             }
515             aclose(nullfd);
516             if (pwtext_len > 0 && fullwrite(passwdfd, pwtext, pwtext_len) < 0) {
517                 err = vstralloc("password write failed: ",
518                                 amdevice,
519                                 ": ",
520                                 strerror(errno),
521                                 NULL);
522                 aclose(passwdfd);
523                 goto common_exit;
524             }
525             memset(user_and_password, '\0', lpass);
526             amfree(user_and_password);
527             aclose(passwdfd);
528             ferr = fdopen(checkerr, "r");
529             sep = "";
530             errdos = 0;
531             for(sep = ""; (line = agets(ferr)) != NULL; free(line)) {
532                 strappend(extra_info, sep);
533                 strappend(extra_info, line);
534                 sep = ": ";
535                 if(strstr(line, "ERRDOS") != NULL) {
536                     errdos = 1;
537                 }
538             }
539             afclose(ferr);
540             checkerr = -1;
541             rc = 0;
542             while ((wpid = wait(&retstat)) != -1) {
543                 if (WIFSIGNALED(retstat)) {
544                     ret = 0;
545                     rc = sig = WTERMSIG(retstat);
546                 } else {
547                     sig = 0;
548                     rc = ret = WEXITSTATUS(retstat);
549                 }
550                 if (rc != 0) {
551                     strappend(err, sep);
552                     if (ret == 0) {
553                         strappend(err, "got signal ");
554                         ret = sig;
555                     } else {
556                         strappend(err, "returned ");
557                     }
558                     ap_snprintf(number, sizeof(number), "%d", ret);
559                     strappend(err, number);
560                 }
561             }
562             if (errdos != 0 || rc != 0) {
563                 err = newvstralloc(err,
564                                    "samba access error: ",
565                                    amdevice,
566                                    ": ",
567                                    extra_info ? extra_info : "",
568                                    err,
569                                    NULL);
570                 amfree(extra_info);
571             }
572 #else
573             err = stralloc2("This client is not configured for samba: ", amdevice);
574 #endif
575             goto common_exit;
576         }
577         amode = F_OK;
578         device = amname_to_dirname(amdevice);
579     } else {
580         if(amdevice[0] == '/' && amdevice[1] == '/') {
581             err = vstralloc("The DUMP program cannot handle samba shares,",
582                             " use GNUTAR: ",
583                             amdevice,
584                             NULL);
585             goto common_exit;
586         }
587 #ifdef VDUMP                                                            /* { */
588 #ifdef DUMP                                                             /* { */
589         if (strcmp(amname_to_fstype(amdevice), "advfs") == 0)
590 #else                                                                   /* }{ */
591         if (1)
592 #endif                                                                  /* } */
593         {
594             device = amname_to_dirname(amdevice);
595             amode = F_OK;
596         } else
597 #endif                                                                  /* } */
598         {
599             device = amname_to_devname(amdevice);
600 #ifdef USE_RUNDUMP
601             amode = F_OK;
602 #else
603             amode = R_OK;
604 #endif
605         }
606     }
607
608     dbprintf(("%s: device %s\n", debug_prefix_time(NULL), device));
609
610     /* skip accessability test if this is an AFS entry */
611     if(strncmp(device, "afs:", 4) != 0) {
612 #ifdef CHECK_FOR_ACCESS_WITH_OPEN
613         access_result = open(device, O_RDONLY);
614         access_type = "open";
615 #else
616         access_result = access(device, amode);
617         access_type = "access";
618 #endif
619         if(access_result == -1) {
620             err = vstralloc("could not ", access_type, " ", device,
621                         " (", disk, "): ", strerror(errno), NULL);
622         }
623 #ifdef CHECK_FOR_ACCESS_WITH_OPEN
624         aclose(access_result);
625 #endif
626     }
627
628 common_exit:
629
630     amfree(share);
631     amfree(subdir);
632     if(user_and_password) {
633         memset(user_and_password, '\0', lpass);
634         amfree(user_and_password);
635     }
636     if(domain) {
637         memset(domain, '\0', strlen(domain));
638         amfree(domain);
639     }
640
641     if(err) {
642         printf("ERROR [%s]\n", err);
643         dbprintf(("%s: %s\n", debug_prefix_time(NULL), err));
644         amfree(err);
645     } else {
646         printf("OK %s\n", disk);
647         dbprintf(("%s: disk \"%s\" OK\n", debug_prefix_time(NULL), disk));
648         printf("OK %s\n", amdevice);
649         dbprintf(("%s: amdevice \"%s\" OK\n",
650                   debug_prefix_time(NULL), amdevice));
651         printf("OK %s\n", device);
652         dbprintf(("%s: device \"%s\" OK\n", debug_prefix_time(NULL), device));
653     }
654     if(extra_info) {
655         dbprintf(("%s: extra info: %s\n", debug_prefix_time(NULL), extra_info));
656         amfree(extra_info);
657     }
658     amfree(device);
659
660     /* XXX perhaps do something with level: read dumpdates and sanity check */
661 }
662
663 static void check_overall()
664 {
665     char *cmd;
666     struct stat buf;
667     int testfd;
668
669     if( need_runtar )
670     {
671         cmd = vstralloc(libexecdir, "/", "runtar", versionsuffix(), NULL);
672         check_file(cmd,X_OK);
673         check_suid(cmd);
674         amfree(cmd);
675     }
676
677     if( need_rundump )
678     {
679         cmd = vstralloc(libexecdir, "/", "rundump", versionsuffix(), NULL);
680         check_file(cmd,X_OK);
681         check_suid(cmd);
682         amfree(cmd);
683     }
684
685     if( need_dump ) {
686 #ifdef DUMP
687         check_file(DUMP, X_OK);
688 #else
689         printf("ERROR [DUMP program not available]\n");
690 #endif
691     }
692
693     if( need_restore ) {
694 #ifdef RESTORE
695         check_file(RESTORE, X_OK);
696 #else
697         printf("ERROR [RESTORE program not available]\n");
698 #endif
699     }
700
701     if ( need_vdump ) {
702 #ifdef VDUMP
703         check_file(VDUMP, X_OK);
704 #else
705         printf("ERROR [VDUMP program not available]\n");
706 #endif
707     }
708
709     if ( need_vrestore ) {
710 #ifdef VRESTORE
711         check_file(VRESTORE, X_OK);
712 #else
713         printf("ERROR [VRESTORE program not available]\n");
714 #endif
715     }
716
717     if( need_xfsdump ) {
718 #ifdef XFSDUMP
719         check_file(XFSDUMP, F_OK);
720 #else
721         printf("ERROR [XFSDUMP program not available]\n");
722 #endif
723     }
724
725     if( need_xfsrestore ) {
726 #ifdef XFSRESTORE
727         check_file(XFSRESTORE, X_OK);
728 #else
729         printf("ERROR [XFSRESTORE program not available]\n");
730 #endif
731     }
732
733     if( need_vxdump ) {
734 #ifdef VXDUMP
735         check_file(VXDUMP, X_OK);
736 #else
737         printf("ERROR [VXDUMP program not available]\n");
738 #endif
739     }
740
741     if( need_vxrestore ) {
742 #ifdef VXRESTORE
743         check_file(VXRESTORE, X_OK);
744 #else
745         printf("ERROR [VXRESTORE program not available]\n");
746 #endif
747     }
748
749     if( need_gnutar ) {
750 #ifdef GNUTAR
751         check_file(GNUTAR, X_OK);
752 #else
753         printf("ERROR [GNUTAR program not available]\n");
754 #endif
755 #ifdef AMANDATES_FILE
756         check_file(AMANDATES_FILE, R_OK|W_OK);
757 #endif
758 #ifdef GNUTAR_LISTED_INCREMENTAL_DIR
759         check_dir(GNUTAR_LISTED_INCREMENTAL_DIR,R_OK|W_OK);
760 #endif
761     }
762
763     if( need_calcsize ) {
764         char *cmd;
765
766         cmd = vstralloc(libexecdir, "/", "calcsize", versionsuffix(), NULL);
767
768         check_file(cmd, X_OK);
769
770         amfree(cmd);
771     }
772
773     if( need_samba ) {
774 #ifdef SAMBA_CLIENT
775         check_file(SAMBA_CLIENT, X_OK);
776 #else
777         printf("ERROR [SMBCLIENT program not available]\n");
778 #endif
779         testfd = open("/etc/amandapass", R_OK);
780         if (testfd >= 0) {
781             if(fstat(testfd, &buf) == 0) {
782                 if ((buf.st_mode & 0x7) != 0) {
783                     printf("ERROR [/etc/amandapass is world readable!]\n");
784                 } else {
785                     printf("OK [/etc/amandapass is readable, but not by all]\n");
786                 }
787             } else {
788                 printf("OK [unable to stat /etc/amandapass: %s]\n",
789                        strerror(errno));
790             }
791             aclose(testfd);
792         } else {
793             printf("ERROR [unable to open /etc/amandapass: %s]\n",
794                    strerror(errno));
795         }
796     }
797
798     if( need_compress_path ) {
799         check_file(COMPRESS_PATH, X_OK);
800     }
801
802     if( need_dump || need_xfsdump )
803         check_file("/etc/dumpdates",
804 #ifdef USE_RUNDUMP
805                    F_OK
806 #else
807                    R_OK|W_OK
808 #endif
809                    );
810
811     if (need_vdump) {
812         check_file("/etc/vdumpdates", F_OK);
813     }
814
815     check_access("/dev/null", R_OK|W_OK);
816     check_space(AMANDA_TMPDIR, 64);     /* for amandad i/o */
817
818 #ifdef AMANDA_DBGDIR
819     check_space(AMANDA_DBGDIR, 64);     /* for amandad i/o */
820 #endif
821
822     check_space("/etc", 64);            /* for /etc/dumpdates writing */
823 }
824
825 static void check_space(dir, kbytes)
826 char *dir;
827 long kbytes;
828 {
829     generic_fs_stats_t statp;
830
831     if(get_fs_stats(dir, &statp) == -1)
832         printf("ERROR [cannot statfs %s: %s]\n", dir, strerror(errno));
833     else if(statp.avail < kbytes)
834         printf("ERROR [dir %s needs %ldKB, only has %ldKB available.]\n",
835                dir, kbytes, statp.avail);
836     else
837         printf("OK %s has more than %ld KB available.\n", dir, kbytes);
838 }
839
840 static void check_access(filename, mode)
841 char *filename;
842 int mode;
843 {
844     char *noun, *adjective;
845
846     if(mode == F_OK)
847         noun = "find", adjective = "exists";
848     else if((mode & X_OK) == X_OK)
849         noun = "execute", adjective = "executable";
850     else if((mode & (W_OK|R_OK)) == (W_OK|R_OK))
851         noun = "read/write", adjective = "read/writable";
852     else 
853         noun = "access", adjective = "accessible";
854
855     if(access(filename, mode) == -1)
856         printf("ERROR [can not %s %s: %s]\n", noun, filename, strerror(errno));
857     else
858         printf("OK %s %s\n", filename, adjective);
859 }
860
861 static void check_file(filename, mode)
862 char *filename;
863 int mode;
864 {
865     struct stat stat_buf;
866     if(!stat(filename, &stat_buf)) {
867         if(!S_ISREG(stat_buf.st_mode)) {
868             printf("ERROR [%s is not a file]\n", filename);
869         }
870     }
871     check_access(filename, mode);
872 }
873
874 static void check_dir(dirname, mode)
875 char *dirname;
876 int mode;
877 {
878     struct stat stat_buf;
879     char *dir;
880
881     if(!stat(dirname, &stat_buf)) {
882         if(!S_ISDIR(stat_buf.st_mode)) {
883             printf("ERROR [%s is not a directory]\n", dirname);
884         }
885     }
886     dir = stralloc2(dirname, "/.");
887     check_access(dir, mode);
888     amfree(dir);
889 }
890
891 static void check_suid(filename)
892 char *filename;
893 {
894 /* The following is only valid for real Unixs */
895 #ifndef IGNORE_UID_CHECK
896     struct stat stat_buf;
897     if(!stat(filename, &stat_buf)) {
898         if(stat_buf.st_uid != 0 ) {
899             printf("ERROR [%s is not owned by root]\n",filename);
900         }
901         if((stat_buf.st_mode & S_ISUID) != S_ISUID) {
902             printf("ERROR [%s is not SUID root]\n",filename);
903         }
904     }
905     else {
906         printf("ERROR [can not stat %s]\n",filename);
907     }
908 #endif
909 }