source: trunk/src/sh_files.c@ 26

Last change on this file since 26 was 22, checked in by rainer, 19 years ago

Minor code revisions.

File size: 51.4 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <limits.h>
26
27#include <errno.h>
28
29/* Must be before <utime.h> on FreeBSD
30 */
31#include <sys/types.h>
32#include <unistd.h>
33
34#include <utime.h>
35
36
37#ifdef HAVE_DIRENT_H
38#include <dirent.h>
39#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
40#else
41#define dirent direct
42#define NAMLEN(dirent) (dirent)->d_namlen
43#ifdef HAVE_SYS_NDIR_H
44#include <sys/ndir.h>
45#endif
46#ifdef HAVE_SYS_DIR_H
47#include <sys/dir.h>
48#endif
49#ifdef HAVE_NDIR_H
50#include <ndir.h>
51#endif
52#endif
53
54#ifdef HAVE_GLOB_H
55#include <glob.h>
56#endif
57
58#include "samhain.h"
59
60#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
61
62#include "sh_error.h"
63#include "sh_utils.h"
64#include "sh_unix.h"
65#include "sh_files.h"
66#include "sh_tiger.h"
67#include "sh_hash.h"
68#include "sh_ignore.h"
69#include "zAVLTree.h"
70
71#undef FIL__
72#define FIL__ _("sh_files.c")
73
74extern int flag_err_debug;
75extern int flag_err_info;
76
77int sh_files_reportonce(const char * c)
78{
79 int i;
80 SL_ENTER(_("sh_files_reportonce"));
81 i = sh_util_flagval(c, &(sh.flag.reportonce));
82
83 SL_RETURN(i, _("sh_files_reportonce"));
84}
85
86int sh_files_fulldetail(const char * c)
87{
88 int i;
89 SL_ENTER(_("sh_files_fulldetail"));
90 i = sh_util_flagval(c, &(sh.flag.fulldetail));
91
92 SL_RETURN((i), _("sh_files_fulldetail"));
93}
94
95
96typedef struct dir_struct {
97 long NumRegular;
98 long NumDirs;
99 long NumSymlinks;
100 long NumFifos;
101 long NumSockets;
102 long NumCDev;
103 long NumBDev;
104 long NumAll;
105 long TotalBytes;
106 char DirPath[PATH_MAX];
107} dir_type;
108
109typedef struct dirstack_entry {
110 char * name;
111 int class;
112 unsigned long check_mask;
113 int rdepth;
114 short checked;
115 short childs_checked;
116 short reported;
117 /* struct dirstack_entry * next; */
118} dirstack_t;
119
120
121/* the destructor
122 */
123void free_dirstack (void * inptr)
124{
125 dirstack_t * here;
126
127 SL_ENTER(_("free_dirstack"));
128 if (inptr == NULL)
129 SL_RET0(_("free_dirstack"));
130 else
131 here = (dirstack_t *) inptr;
132
133 if (here->name != NULL)
134 SH_FREE(here->name);
135 SH_FREE(here);
136 SL_RET0(_("free_dirstack"));
137}
138
139/* Function to return the key for indexing
140 * the argument
141 */
142zAVLKey zdirstack_key (void const * arg)
143{
144 const dirstack_t * sa = (const dirstack_t *) arg;
145 return (zAVLKey) sa->name;
146}
147
148
149static zAVLTree * zdirListOne = NULL;
150static zAVLTree * zdirListTwo = NULL;
151static zAVLTree * zfileList = NULL;
152
153
154static int sh_files_fullpath (char * testdir, char * d_name,
155 char * statpath);
156static int sh_files_pushdir (int class, const char * str_s);
157static int sh_files_pushfile (int class, const char * str_s);
158static int sh_files_checkdir (int class, int rdepth, char * dirName,
159 char * relativeName);
160static ShFileType sh_files_filecheck (int class, char * dirName,
161 char * fileName, int * reported,
162 int rsrcflag);
163
164static long MaxRecursionLevel = 0;
165
166/* set default recursion level
167 */
168int sh_files_setrecursion (const char * flag_s)
169{
170 long flag = 0;
171 static int reject = 0;
172
173 SL_ENTER( _("sh_files_setrecursion"));
174
175 if (reject == 1)
176 SL_RETURN((-1), _("sh_files_setrecursion"));
177
178 if (sh.flag.opts == 1)
179 reject = 1;
180
181 if (flag_s != NULL)
182 flag = (int)(atof(flag_s));
183
184 if (flag >= 0 && flag <= 99)
185 MaxRecursionLevel = flag;
186 else
187 SL_RETURN((-1), _("sh_files_setrecursion"));
188
189 SL_RETURN((0), _("sh_files_setrecursion"));
190}
191
192
193unsigned long sh_files_chk ()
194{
195 zAVLCursor cursor;
196 ShFileType status;
197 unsigned long fcount = 0;
198
199 char * tmp = NULL;
200
201 dirstack_t * ptr;
202 char * base;
203 char * file;
204
205 SL_ENTER(_("sh_files_chk"));
206
207 for (ptr = (dirstack_t *) zAVLFirst(&cursor, zfileList); ptr;
208 ptr = (dirstack_t *) zAVLNext(&cursor))
209 {
210
211 if (sig_urgent > 0) {
212 SL_RETURN(fcount, _("sh_files_chk"));
213 }
214
215 if (ptr->checked == S_FALSE)
216 {
217 base = sh_util_basename (ptr->name);
218 file = sh_util_filename (ptr->name);
219#if defined(WITH_TPT)
220 tmp = sh_util_safe_name (ptr->name);
221#endif
222
223
224 if (flag_err_info == SL_TRUE)
225 {
226#if !defined(WITH_TPT)
227 tmp = sh_util_safe_name (ptr->name);
228#endif
229 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CHK, tmp);
230 }
231
232 BREAKEXIT(sh_files_filecheck);
233 status = sh_files_filecheck (ptr->class, base, file,
234 (int *) &(ptr->reported), 0);
235
236 TPT(( 0, FIL__, __LINE__,
237 _("msg=<filecheck complete: %s> status=<%d> reported=<%d>\n"),
238 tmp, status, ptr->reported));
239
240 if (status == SH_FILE_UNKNOWN && ptr->reported == S_FALSE)
241 {
242 TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"),
243 tmp, status));
244
245 if ( sh.flag.checkSum == SH_CHECK_INIT ||
246 sh_hash_have_it (ptr->name) >= 0)
247 {
248 if (S_FALSE == sh_ignore_chk_del(ptr->name))
249 {
250 if (0 != hashreport_missing(ptr->name,
251 (ptr->class == SH_LEVEL_ALLIGNORE) ?
252 ShDFLevel[ptr->class] :
253 ShDFLevel[SH_ERR_T_FILE])) {
254 if (tmp == NULL)
255 tmp = sh_util_safe_name (ptr->name);
256 sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
257 ShDFLevel[ptr->class] :
258 ShDFLevel[SH_ERR_T_FILE],
259 FIL__, __LINE__, 0, MSG_FI_MISS,
260 tmp);
261 }
262 }
263 }
264 else /* not there at init, and still missing */
265 {
266 if (tmp == NULL)
267 tmp = sh_util_safe_name (ptr->name);
268 sh_error_handle (SH_ERR_NOTICE,
269 FIL__, __LINE__, 0,
270 MSG_FI_FAIL,
271 tmp);
272 }
273#ifndef REPLACE_OLD
274 /* this will tell that we have seen the file, and thus prevent
275 * deletion from the database, resulting in an incomplete
276 * message when the file reappears
277 */
278 if (sh.flag.checkSum != SH_CHECK_INIT)
279 sh_hash_set_visited_true(ptr->name);
280#else
281 if (sh.flag.checkSum != SH_CHECK_INIT)
282 sh_hash_set_missing(ptr->name);
283#endif
284 if (sh.flag.reportonce == S_TRUE)
285 ptr->reported = S_TRUE;
286 }
287 else
288 {
289 /* exists (status >= 0), but was missing (reported == TRUE)
290 */
291 if (status != SH_FILE_UNKNOWN && ptr->reported == S_TRUE)
292 {
293 ptr->reported = S_FALSE;
294 }
295 /* Catchall
296 */
297 else if (status == SH_FILE_UNKNOWN)
298 {
299 /* Thu Mar 7 15:09:40 CET 2002 Make sure missing file
300 * is reported if ptr->reported == S_TRUE because the
301 * file has been added.
302 */
303 if (sh_hash_have_it (ptr->name) >= 0)
304 {
305 if (S_FALSE == sh_ignore_chk_del(ptr->name))
306 {
307 if (0 != hashreport_missing(ptr->name,
308 (ptr->class == SH_LEVEL_ALLIGNORE) ?
309 ShDFLevel[ptr->class] :
310 ShDFLevel[SH_ERR_T_FILE])) {
311 if (tmp == NULL)
312 tmp = sh_util_safe_name (ptr->name);
313 sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE)?
314 ShDFLevel[ptr->class] :
315 ShDFLevel[SH_ERR_T_FILE],
316 FIL__, __LINE__, 0, MSG_FI_MISS,
317 tmp);
318 }
319 }
320#ifndef REPLACE_OLD
321 if (sh.flag.checkSum != SH_CHECK_INIT)
322 sh_hash_set_visited_true(ptr->name);
323#else
324 /* delete from database
325 */
326 if (sh.flag.checkSum != SH_CHECK_INIT)
327 sh_hash_set_missing(ptr->name);
328#endif
329 }
330 else
331 {
332 if (tmp == NULL)
333 tmp = sh_util_safe_name (ptr->name);
334 sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
335 MSG_FI_FAIL,
336 tmp);
337 if (sh.flag.checkSum != SH_CHECK_INIT)
338 sh_hash_set_visited_true(ptr->name);
339 }
340 }
341 ++fcount;
342 }
343
344 if (tmp != NULL)
345 {
346 SH_FREE(tmp);
347 tmp = NULL;
348 }
349 SH_FREE(file);
350 SH_FREE(base);
351
352 ptr->checked = S_TRUE;
353 }
354 }
355
356 SL_RETURN(fcount, _("sh_files_chk"));
357}
358
359int sh_files_delfilestack ()
360{
361 SL_ENTER(_("sh_files_delfilestack"));
362
363 zAVLFreeTree (zfileList, free_dirstack);
364 zfileList = NULL;
365
366 SL_RETURN(0, _("sh_files_delfilestack"));
367}
368
369int sh_files_setrec_int (zAVLTree * tree)
370{
371 dirstack_t * ptr;
372 zAVLCursor avlcursor;
373
374 SL_ENTER(_("sh_files_setrec"));
375 if (tree != NULL) {
376 for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
377 ptr = (dirstack_t *) zAVLNext(&avlcursor))
378 {
379 if (ptr->rdepth < (-1) || ptr->rdepth > 99)
380 {
381 ptr->rdepth = MaxRecursionLevel;
382 }
383 if (ptr->rdepth == (-1) && sh.flag.checkSum != SH_CHECK_INIT)
384 hash_remove_tree (ptr->name);
385 }
386 }
387 SL_RETURN(0, _("sh_files_setrec"));
388}
389
390int sh_files_setrec ()
391{
392 sh_files_setrec_int(zdirListOne);
393 return sh_files_setrec_int(zdirListTwo);
394}
395
396zAVLTree * sh_files_deldirstack_int (zAVLTree * ptr)
397{
398 SL_ENTER(_("sh_files_deldirstack"));
399
400 zAVLFreeTree (ptr, free_dirstack);
401
402 SL_RETURN(NULL, _("sh_files_deldirstack"));
403}
404
405int sh_files_deldirstack ()
406{
407 zdirListOne = sh_files_deldirstack_int(zdirListOne);
408 zdirListTwo = sh_files_deldirstack_int(zdirListTwo);
409 return 0;
410}
411
412void sh_files_reset()
413{
414 dirstack_t * ptr;
415 zAVLCursor avlcursor;
416
417 SL_ENTER(_("sh_files_reset"));
418
419 for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, zfileList); ptr;
420 ptr = (dirstack_t *) zAVLNext(&avlcursor))
421 ptr->checked = 0;
422
423 SL_RET0(_("sh_files_reset"));
424}
425
426void sh_dirs_reset()
427{
428 dirstack_t * ptr;
429 zAVLCursor avlcursor1;
430 zAVLCursor avlcursor2;
431
432 SL_ENTER(_("sh_dirs_reset"));
433
434 for (ptr = (dirstack_t *) zAVLFirst(&avlcursor1, zdirListOne); ptr;
435 ptr = (dirstack_t *) zAVLNext(&avlcursor1))
436 ptr->checked = 0;
437
438 for (ptr = (dirstack_t *) zAVLFirst(&avlcursor2, zdirListTwo); ptr;
439 ptr = (dirstack_t *) zAVLNext(&avlcursor2))
440 ptr->checked = 0;
441
442 SL_RET0(_("sh_dirs_reset"));
443}
444
445
446int sh_files_pushfile_prelink (const char * str_s)
447{
448 return (sh_files_pushfile (SH_LEVEL_PRELINK, str_s));
449}
450
451int sh_files_pushfile_user0 (const char * str_s)
452{
453 return (sh_files_pushfile (SH_LEVEL_USER0, str_s));
454}
455
456
457int sh_files_pushfile_user1 (const char * str_s)
458{
459 return (sh_files_pushfile (SH_LEVEL_USER1, str_s));
460}
461
462
463int sh_files_pushfile_ro (const char * str_s)
464{
465 return (sh_files_pushfile (SH_LEVEL_READONLY, str_s));
466}
467
468int sh_files_pushfile_attr (const char * str_s)
469{
470 return (sh_files_pushfile (SH_LEVEL_ATTRIBUTES, str_s));
471}
472
473int sh_files_pushfile_log (const char * str_s)
474{
475 return (sh_files_pushfile (SH_LEVEL_LOGFILES, str_s));
476}
477
478int sh_files_pushfile_glog (const char * str_s)
479{
480 return (sh_files_pushfile (SH_LEVEL_LOGGROW, str_s));
481}
482
483int sh_files_pushfile_noig (const char * str_s)
484{
485 return (sh_files_pushfile (SH_LEVEL_NOIGNORE, str_s));
486}
487
488int sh_files_pushfile_allig (const char * str_s)
489{
490 return (sh_files_pushfile (SH_LEVEL_ALLIGNORE, str_s));
491}
492
493
494static void sh_files_set_mask (unsigned long * mask,
495 unsigned long val, int act)
496{
497 SL_ENTER(_("sh_files_set_mask"));
498
499 if (act == 0)
500 (*mask) = val;
501 else if (act > 0)
502 (*mask) |= val;
503 else
504 (*mask) &= ~val;
505
506 SL_RET0(_("sh_files_set_mask"));
507}
508
509/* set mask(class)
510 */
511static int sh_files_parse_mask (unsigned long * mask, const char * str)
512{
513 int l, i = 0, act = 0, k = 0;
514 char myword[64];
515
516 SL_ENTER(_("sh_files_parse_mask"));
517
518 if (str == NULL)
519 {
520 SL_RETURN ( (-1), _("sh_files_parse_mask"));
521 }
522 else
523 l = sl_strlen(str);
524
525 while (i < l) {
526 if (str[i] == '\0')
527 break;
528 if (str[i] == ' ' || str[i] == '\t' || str[i] == ',')
529 {
530 ++i;
531 continue;
532 }
533
534 if (str[i] == '+')
535 {
536 act = +1; ++i;
537 continue;
538 }
539 else if (str[i] == '-')
540 {
541 act = -1; ++i;
542 continue;
543 }
544 else /* a word */
545 {
546 k = 0;
547 while (k < 63 && str[i] != ' ' && str[i] != '\t' && str[i] != ','
548 && str[i] != '+' && str[i] != '-' && str[i] != '\0') {
549 myword[k] = str[i];
550 ++i; ++k;
551 }
552 myword[k] = '\0';
553
554/* checksum */
555 if (0 == strncmp(myword, _("CHK"), 3))
556 sh_files_set_mask (mask, MODI_CHK, act);
557/* link */
558 if (0 == strncmp(myword, _("LNK"), 3))
559 sh_files_set_mask (mask, MODI_LNK, act);
560/* inode */
561 if (0 == strncmp(myword, _("RDEV"), 3))
562 sh_files_set_mask (mask, MODI_RDEV, act);
563/* inode */
564 if (0 == strncmp(myword, _("INO"), 3))
565 sh_files_set_mask (mask, MODI_INO, act);
566/* user */
567 if (0 == strncmp(myword, _("USR"), 3))
568 sh_files_set_mask (mask, MODI_USR, act);
569/* group */
570 if (0 == strncmp(myword, _("GRP"), 3))
571 sh_files_set_mask (mask, MODI_GRP, act);
572/* mtime */
573 if (0 == strncmp(myword, _("MTM"), 3))
574 sh_files_set_mask (mask, MODI_MTM, act);
575/* ctime */
576 if (0 == strncmp(myword, _("CTM"), 3))
577 sh_files_set_mask (mask, MODI_CTM, act);
578/* atime */
579 if (0 == strncmp(myword, _("ATM"), 3))
580 sh_files_set_mask (mask, MODI_ATM, act);
581/* size */
582 if (0 == strncmp(myword, _("SIZ"), 3))
583 sh_files_set_mask (mask, MODI_SIZ, act);
584/* file mode */
585 if (0 == strncmp(myword, _("MOD"), 3))
586 sh_files_set_mask (mask, MODI_MOD, act);
587/* hardlinks */
588 if (0 == strncmp(myword, _("HLN"), 3))
589 sh_files_set_mask (mask, MODI_HLN, act);
590/* size may grow */
591 if (0 == strncmp(myword, _("GROW"), 3))
592 sh_files_set_mask (mask, MODI_SGROW, act);
593/* use prelink */
594 if (0 == strncmp(myword, _("PRE"), 3))
595 sh_files_set_mask (mask, MODI_PREL, act);
596
597 }
598 }
599 SL_RETURN ( (0), _("sh_files_parse_mask"));
600}
601
602int sh_files_redef_prelink(const char * str)
603{
604 return (sh_files_parse_mask(&mask_PRELINK, str));
605}
606int sh_files_redef_user0(const char * str)
607{
608 return (sh_files_parse_mask(&mask_USER0, str));
609}
610int sh_files_redef_user1(const char * str)
611{
612 return (sh_files_parse_mask(&mask_USER1, str));
613}
614int sh_files_redef_readonly(const char * str)
615{
616 return (sh_files_parse_mask(&mask_READONLY, str));
617}
618int sh_files_redef_loggrow(const char * str)
619{
620 return (sh_files_parse_mask(&mask_LOGGROW, str));
621}
622int sh_files_redef_logfiles(const char * str)
623{
624 return (sh_files_parse_mask(&mask_LOGFILES, str));
625}
626int sh_files_redef_attributes(const char * str)
627{
628 return (sh_files_parse_mask(&mask_ATTRIBUTES, str));
629}
630int sh_files_redef_noignore(const char * str)
631{
632 return (sh_files_parse_mask(&mask_NOIGNORE, str));
633}
634int sh_files_redef_allignore(const char * str)
635{
636 return (sh_files_parse_mask(&mask_ALLIGNORE, str));
637}
638
639unsigned long sh_files_maskof (int class)
640{
641 switch (class)
642 {
643 case SH_LEVEL_READONLY:
644 return (unsigned long) mask_READONLY;
645 case SH_LEVEL_ATTRIBUTES:
646 return (unsigned long) mask_ATTRIBUTES;
647 case SH_LEVEL_LOGFILES:
648 return (unsigned long) mask_LOGFILES;
649 case SH_LEVEL_LOGGROW:
650 return (unsigned long) mask_LOGGROW;
651 case SH_LEVEL_ALLIGNORE:
652 return (unsigned long) mask_ALLIGNORE;
653 case SH_LEVEL_NOIGNORE:
654 return (unsigned long) mask_NOIGNORE;
655 case SH_LEVEL_USER0:
656 return (unsigned long) mask_USER0;
657 case SH_LEVEL_USER1:
658 return (unsigned long) mask_USER1;
659 case SH_LEVEL_PRELINK:
660 return (unsigned long) mask_PRELINK;
661 default:
662 return (unsigned long) 0;
663 }
664}
665
666#ifdef HAVE_GLOB_H
667int sh_files_has_metachar (const char * str)
668{
669 SL_ENTER(_("sh_files_has_metachar"));
670 if (NULL != strchr(str, '*'))
671 SL_RETURN(1, _("sh_files_has_metachar"));
672 else if (NULL != strchr(str, '?'))
673 SL_RETURN(1, _("sh_files_has_metachar"));
674 else if (NULL != (strchr(str, '[')))
675 SL_RETURN(1, _("sh_files_has_metachar"));
676 else
677 SL_RETURN(0, _("sh_files_has_metachar"));
678}
679
680
681int sh_files_globerr (const char * epath, int errnum)
682{
683 char * p;
684
685 SL_ENTER(_("sh_files_globerr"));
686
687 p = sh_util_safe_name (epath);
688 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_FI_GLOB,
689 sh_error_message (errnum), p);
690 SH_FREE(p);
691
692 SL_RETURN(0, _("sh_files_globerr"));
693}
694
695/* #ifdef HAVE_GLOB_H
696 */
697#endif
698
699int sh_files_push_file_int (int class, const char * str_s, int len)
700{
701 dirstack_t * new_item_ptr;
702 char * fileName;
703 int ret;
704
705 SL_ENTER(_("sh_files_push_file_int"));
706
707 fileName = SH_ALLOC(len+1);
708 sl_strlcpy(fileName, str_s, len+1);
709
710 new_item_ptr = (dirstack_t *) SH_ALLOC (sizeof(dirstack_t));
711
712 new_item_ptr->name = fileName;
713 new_item_ptr->class = class;
714 new_item_ptr->check_mask = sh_files_maskof(class);
715 new_item_ptr->rdepth = 0;
716 new_item_ptr->checked = S_FALSE;
717 new_item_ptr->reported = S_FALSE;
718 new_item_ptr->childs_checked = S_FALSE;
719
720 if (zfileList == NULL)
721 {
722 zfileList = zAVLAllocTree (zdirstack_key);
723 if (zfileList == NULL)
724 {
725 (void) safe_logger (0, 0, NULL);
726 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
727 }
728 }
729
730 ret = zAVLInsert (zfileList, new_item_ptr);
731
732 if (-1 == ret)
733 {
734 (void) safe_logger (0, 0, NULL);
735 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
736 }
737 if (3 == ret)
738 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
739 fileName);
740
741 SL_RETURN(0, _("sh_files_push_file_int"));
742}
743
744
745static int sh_files_pushfile (int class, const char * str_s)
746{
747 int len;
748 char * tmp;
749 char * p;
750#ifdef HAVE_GLOB_H
751 int globstatus = -1;
752 unsigned int gloop;
753 glob_t pglob;
754#endif
755
756 static int reject = 0;
757
758 SL_ENTER(_("sh_files_pushfile"));
759
760 if (reject == 1)
761 SL_RETURN((-1),_("sh_files_pushfile"));
762
763 /* if we push a filename from the command line, make sure it
764 * is the only one -- and will stay the only one
765 */
766 if (sh.flag.opts == 1)
767 {
768 sh_files_delfilestack ();
769 sh_files_deldirstack ();
770 reject = 1;
771 }
772
773 if (str_s == NULL)
774 SL_RETURN((-1),_("sh_files_pushfile"));
775
776 len = sl_strlen(str_s);
777
778 if (len >= PATH_MAX)
779 {
780 /* Name too long
781 */
782 tmp = sh_util_safe_name (str_s);
783 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
784 tmp);
785 SH_FREE(tmp);
786 SL_RETURN((-1),_("sh_files_pushfile"));
787 }
788 else if (len < 1)
789 {
790 /* Should not happen (str_s == NULL caught further above)
791 */
792 SL_RETURN((-1),_("sh_files_pushfile"));
793 }
794 else if (str_s[0] != '/')
795 {
796 /* Not an absolute path
797 */
798 tmp = sh_util_safe_name (str_s);
799 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
800 tmp);
801 SH_FREE(tmp);
802 SL_RETURN((-1),_("sh_files_pushfile"));
803 }
804 else
805 {
806 /* remove a terminating '/', take care of the
807 * special case of the root directory.
808 */
809 p = sh_util_strdup (str_s);
810 if (p[len-1] == '/' && len > 1)
811 {
812 p[len-1] = '\0';
813 --len;
814 }
815
816 }
817
818#ifdef HAVE_GLOB_H
819 if (0 == sh_files_has_metachar(p))
820 {
821 sh_files_push_file_int (class, p, len);
822 }
823 else
824 {
825 pglob.gl_offs = 0;
826 globstatus = glob (p, 0, sh_files_globerr, &pglob);
827
828 if (globstatus == 0 && pglob.gl_pathc > 0)
829 {
830 for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
831 sh_files_push_file_int (class, pglob.gl_pathv[gloop],
832 sl_strlen(pglob.gl_pathv[gloop]));
833 }
834 else
835 {
836 tmp = sh_util_safe_name (p);
837
838 if (pglob.gl_pathc == 0
839#ifdef GLOB_NOMATCH
840 || globstatus == GLOB_NOMATCH
841#endif
842 )
843 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
844 globstatus, MSG_FI_GLOB,
845 _("No matches found"), tmp);
846#ifdef GLOB_NOSPACE
847 else if (globstatus == GLOB_NOSPACE)
848 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
849 globstatus, MSG_FI_GLOB,
850 _("Out of memory"), tmp);
851#endif
852#ifdef GLOB_ABORTED
853 else if (globstatus == GLOB_ABORTED)
854 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
855 globstatus, MSG_FI_GLOB,
856 _("Read error"), tmp);
857#endif
858 else
859 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
860 globstatus, MSG_FI_GLOB,
861 _("Unknown error"), tmp);
862
863 SH_FREE(tmp);
864
865 }
866
867 globfree(&pglob);
868 }
869
870#else
871 sh_files_push_file_int (class, p, len);
872#endif
873
874 SH_FREE(p);
875 SL_RETURN((0),_("sh_files_pushfile"));
876}
877
878
879/* ------ directories ----- */
880
881int sh_files_is_allignore_int (char * str, zAVLTree * tree)
882{
883 dirstack_t * ptr;
884
885 SL_ENTER(_("sh_files_is_allignore"));
886
887 if (tree)
888 {
889 ptr = zAVLSearch(tree, str);
890 if (ptr)
891 {
892 if (ptr->class == SH_LEVEL_ALLIGNORE)
893 SL_RETURN( 1, _("sh_files_is_allignore"));
894 else
895 SL_RETURN( 0, _("sh_files_is_allignore"));
896 }
897 }
898 SL_RETURN( 0, _("sh_files_is_allignore"));
899}
900
901int sh_files_is_allignore (char * str)
902{
903 if (1 == sh_files_is_allignore_int(str, zdirListOne))
904 return 1;
905 if (NULL == zdirListTwo)
906 return 0;
907 return sh_files_is_allignore_int(str, zdirListTwo);
908}
909
910unsigned long sh_dirs_chk (int which)
911{
912 zAVLTree * tree;
913 zAVLCursor cursor;
914 dirstack_t * ptr;
915 dirstack_t * dst_ptr;
916 int status;
917 unsigned long dcount = 0;
918 char * tmp;
919
920 SL_ENTER(_("sh_dirs_chk"));
921
922 if (which == 1)
923 tree = zdirListOne;
924 else
925 tree = zdirListTwo;
926
927 for (ptr = (dirstack_t *) zAVLFirst(&cursor, tree); ptr;
928 ptr = (dirstack_t *) zAVLNext(&cursor))
929 {
930 if (sig_urgent > 0) {
931 SL_RETURN(dcount, _("sh_dirs_chk"));
932 }
933
934 if (ptr->checked == S_FALSE)
935 {
936 /* 28 Aug 2001 check the top level directory
937 */
938 status = S_FALSE;
939 dst_ptr = zAVLSearch(zfileList, ptr->name);
940 if (dst_ptr)
941 {
942 if (dst_ptr->checked == S_FALSE)
943 {
944 BREAKEXIT(sh_files_filecheck);
945 sh_files_filecheck (dst_ptr->class, ptr->name,
946 NULL, &status, 0);
947 dst_ptr->checked = S_TRUE;
948 status = S_TRUE;
949 }
950 else
951 {
952 status = S_TRUE;
953 }
954 }
955
956 if (status == S_FALSE)
957 sh_files_filecheck (ptr->class, ptr->name, NULL, &status, 0);
958
959 BREAKEXIT(sh_files_checkdir);
960 status = sh_files_checkdir (ptr->class, ptr->rdepth, ptr->name,
961 ptr->name);
962
963 if (status < 0 && ptr->reported == S_FALSE)
964 {
965 /* directory is missing
966 */
967 if (S_FALSE == sh_ignore_chk_del(ptr->name))
968 {
969 if (0 != hashreport_missing(ptr->name,
970 (ptr->class == SH_LEVEL_ALLIGNORE) ?
971 ShDFLevel[ptr->class] :
972 ShDFLevel[SH_ERR_T_DIR])) {
973 tmp = sh_util_safe_name (ptr->name);
974 sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
975 ShDFLevel[ptr->class] :
976 ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__,
977 0, MSG_FI_MISS, tmp);
978 SH_FREE(tmp);
979 }
980 }
981 if (sh.flag.reportonce == S_TRUE)
982 ptr->reported = S_TRUE;
983 }
984 else
985 {
986 /* exists (status >= 0), but was missing (reported == TRUE)
987 */
988 if (status >= 0 && ptr->reported == S_TRUE)
989 {
990 ptr->reported = S_FALSE;
991#if 0
992 /* obsoleted (really?) by the mandatory sh_files_filecheck()
993 * above, which will catch missing directories anyway
994 */
995 tmp = sh_util_safe_name (ptr->name);
996 sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
997 ShDFLevel[ptr->class] :
998 ShDFLevel[SH_ERR_T_DIR],
999 FIL__, __LINE__, 0, MSG_FI_ADD,
1000 tmp);
1001 SH_FREE(tmp);
1002#endif
1003 }
1004 else if (status == SH_FILE_UNKNOWN)
1005 {
1006 /* catchall
1007 */
1008 tmp = sh_util_safe_name (ptr->name);
1009 sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
1010 MSG_FI_FAIL,
1011 tmp);
1012 SH_FREE(tmp);
1013 if (sh.flag.checkSum != SH_CHECK_INIT)
1014 sh_hash_set_visited_true(ptr->name);
1015 }
1016
1017 ++dcount;
1018 }
1019 ptr->checked = S_TRUE;
1020 ptr->childs_checked = S_TRUE;
1021 }
1022
1023 if (sig_urgent > 0) {
1024 SL_RETURN(dcount, _("sh_dirs_chk"));
1025 }
1026
1027 }
1028 SL_RETURN(dcount, _("sh_dirs_chk"));
1029}
1030
1031int sh_files_pushdir_prelink (const char * str_s)
1032{
1033 return (sh_files_pushdir (SH_LEVEL_PRELINK, str_s));
1034}
1035
1036int sh_files_pushdir_user0 (const char * str_s)
1037{
1038 return (sh_files_pushdir (SH_LEVEL_USER0, str_s));
1039}
1040
1041int sh_files_pushdir_user1 (const char * str_s)
1042{
1043 return (sh_files_pushdir (SH_LEVEL_USER1, str_s));
1044}
1045
1046int sh_files_pushdir_attr (const char * str_s)
1047{
1048 return (sh_files_pushdir (SH_LEVEL_ATTRIBUTES, str_s));
1049}
1050
1051int sh_files_pushdir_ro (const char * str_s)
1052{
1053 return (sh_files_pushdir (SH_LEVEL_READONLY, str_s));
1054}
1055
1056int sh_files_pushdir_log (const char * str_s)
1057{
1058 return (sh_files_pushdir (SH_LEVEL_LOGFILES, str_s));
1059}
1060
1061int sh_files_pushdir_glog (const char * str_s)
1062{
1063 return (sh_files_pushdir (SH_LEVEL_LOGGROW, str_s));
1064}
1065
1066int sh_files_pushdir_noig (const char * str_s)
1067{
1068 return (sh_files_pushdir (SH_LEVEL_NOIGNORE, str_s));
1069}
1070
1071int sh_files_pushdir_allig (const char * str_s)
1072{
1073 return (sh_files_pushdir (SH_LEVEL_ALLIGNORE, str_s));
1074}
1075
1076static int which_dirList = 1;
1077
1078int set_dirList (int which)
1079{
1080 if (which == 2)
1081 which_dirList = 2;
1082 else
1083 which_dirList = 1;
1084 return 0;
1085}
1086
1087int sh_files_push_dir_int (int class, char * tail, int len, int rdepth)
1088{
1089 zAVLTree * tree;
1090 dirstack_t * new_item_ptr;
1091 char * dirName;
1092 int ret;
1093
1094 SL_ENTER(_("sh_files_push_dir_int"));
1095
1096 dirName = SH_ALLOC(len+1);
1097 sl_strlcpy(dirName, tail, len+1);
1098
1099 new_item_ptr = (dirstack_t * ) SH_ALLOC (sizeof(dirstack_t));
1100
1101 new_item_ptr->name = dirName;
1102 new_item_ptr->class = class;
1103 new_item_ptr->check_mask = sh_files_maskof(class);
1104 new_item_ptr->rdepth = rdepth;
1105 new_item_ptr->checked = S_FALSE;
1106 new_item_ptr->reported = S_FALSE;
1107 new_item_ptr->childs_checked = S_FALSE;
1108
1109 if (which_dirList == 1)
1110 {
1111 tree = zdirListOne;
1112 }
1113 else
1114 {
1115 tree = zdirListTwo;
1116 }
1117
1118 if (tree == NULL)
1119 {
1120 tree = zAVLAllocTree (zdirstack_key);
1121 if (tree == NULL)
1122 {
1123 (void) safe_logger (0, 0, NULL);
1124 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1125 }
1126 if (which_dirList == 1)
1127 zdirListOne = tree;
1128 else
1129 zdirListTwo = tree;
1130 }
1131
1132 ret = zAVLInsert (tree, new_item_ptr);
1133
1134 if (-1 == ret)
1135 {
1136 (void) safe_logger (0, 0, NULL);
1137 aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1138 }
1139 if (3 == ret)
1140 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
1141 dirName);
1142
1143 SL_RETURN(0, _("sh_files_push_dir_int"));
1144}
1145
1146static int sh_files_pushdir (int class, const char * str_s)
1147{
1148 char * tmp;
1149 int len;
1150 int rdepth = 0;
1151 char * tail = NULL;
1152 char * p;
1153
1154#ifdef HAVE_GLOB_H
1155 glob_t pglob;
1156 int globstatus = -1;
1157 unsigned int gloop;
1158#endif
1159
1160 SL_ENTER(_("sh_files_pushdir"));
1161
1162 if (sh.flag.opts == 1) {
1163 sh_files_delfilestack ();
1164 sh_files_deldirstack ();
1165 }
1166
1167 if (str_s == NULL)
1168 SL_RETURN((-1), _("sh_files_pushdir"));
1169
1170 p = sh_util_strdup (str_s);
1171
1172 if (p[0] != '/')
1173 {
1174 rdepth = strtol(p, &tail, 10);
1175 if (tail == p)
1176 {
1177 SH_FREE(p);
1178 SL_RETURN((-1), _("sh_files_pushdir"));
1179 }
1180 }
1181 else
1182 tail = p;
1183
1184
1185 if (rdepth < (-1) || tail == p || rdepth > 99)
1186 rdepth = (-2);
1187
1188 len = sl_strlen(tail);
1189
1190 if (len >= PATH_MAX)
1191 {
1192 tmp = sh_util_safe_name (tail);
1193 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
1194 tmp);
1195 SH_FREE(tmp);
1196 SH_FREE(p);
1197 SL_RETURN((-1), _("sh_files_pushdir"));
1198 }
1199 else if (len < 1)
1200 {
1201 SH_FREE(p);
1202 SL_RETURN((-1), _("sh_files_pushdir"));
1203 }
1204 else if (tail[0] != '/')
1205 {
1206 tmp = sh_util_safe_name (tail);
1207 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
1208 tmp);
1209 SH_FREE(tmp);
1210 SH_FREE(p);
1211 SL_RETURN((-1), _("sh_files_pushdir"));
1212 }
1213 else
1214 {
1215
1216 if (tail[len-1] == '/' && len > 1)
1217 {
1218 tail[len-1] = '\0';
1219 --len;
1220 }
1221
1222 }
1223
1224#ifdef HAVE_GLOB_H
1225 if (0 == sh_files_has_metachar(tail))
1226 {
1227 sh_files_push_dir_int (class, tail, len, rdepth);
1228 }
1229 else
1230 {
1231 pglob.gl_offs = 0;
1232 globstatus = glob (tail, 0, sh_files_globerr, &pglob);
1233
1234 if (globstatus == 0 && pglob.gl_pathc > 0)
1235 {
1236 for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
1237 sh_files_push_dir_int (class,
1238 pglob.gl_pathv[gloop],
1239 sl_strlen(pglob.gl_pathv[gloop]),
1240 rdepth);
1241 }
1242 else
1243 {
1244 tmp = sh_util_safe_name (tail);
1245
1246 if (pglob.gl_pathc == 0
1247#ifdef GLOB_NOMATCH
1248 || globstatus == GLOB_NOMATCH
1249#endif
1250 )
1251 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1252 globstatus, MSG_FI_GLOB,
1253 _("No matches found"), tmp);
1254#ifdef GLOB_NOSPACE
1255 else if (globstatus == GLOB_NOSPACE)
1256 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1257 globstatus, MSG_FI_GLOB,
1258 _("Out of memory"), tmp);
1259#endif
1260#ifdef GLOB_ABORTED
1261 else if (globstatus == GLOB_ABORTED)
1262 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1263 globstatus, MSG_FI_GLOB,
1264 _("Read error"), tmp);
1265#endif
1266 else
1267 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1268 globstatus, MSG_FI_GLOB,
1269 _("Unknown error"), tmp);
1270 SH_FREE(tmp);
1271 }
1272
1273 globfree(&pglob);
1274 }
1275#else
1276 sh_files_push_dir_int (class, tail, len, rdepth);
1277#endif
1278
1279 SH_FREE(p);
1280 SL_RETURN((0), _("sh_files_pushdir"));
1281}
1282
1283struct sh_dirent {
1284 /* char sh_d_name[NAME_MAX + 2]; */
1285 char * sh_d_name;
1286 struct sh_dirent * next;
1287};
1288
1289static void kill_sh_dirlist (struct sh_dirent * dirlist)
1290{
1291 struct sh_dirent * this;
1292
1293 while (dirlist)
1294 {
1295 this = dirlist->next;
1296 SH_FREE(dirlist->sh_d_name);
1297 SH_FREE(dirlist);
1298 dirlist = this;
1299 }
1300 return;
1301}
1302
1303/* -- add an entry to a directory listing
1304 */
1305static struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry,
1306 struct sh_dirent * dirlist)
1307{
1308 struct sh_dirent * this;
1309 int i;
1310
1311 if (thisEntry == NULL)
1312 return dirlist;
1313
1314 i = sl_strlen(thisEntry->d_name);
1315 if (i == 0)
1316 return dirlist;
1317 ++i;
1318
1319 this = SH_ALLOC(sizeof(struct sh_dirent));
1320 if (!this)
1321 return dirlist;
1322
1323 this->sh_d_name = SH_ALLOC(i);
1324 sl_strlcpy(this->sh_d_name, thisEntry->d_name, i);
1325
1326 this->next = dirlist;
1327 return this;
1328}
1329
1330static int sh_check_hardlinks = S_TRUE;
1331
1332/* Simply sets our boolean as to whether this check is active
1333 */
1334int sh_files_check_hardlinks (const char * opt)
1335{
1336 int i;
1337 SL_ENTER(_("sh_files_check_hardlinks"));
1338 i = sh_util_flagval(opt, &sh_check_hardlinks);
1339 SL_RETURN(i, _("sh_files_check_hardlinks"));
1340}
1341
1342struct sh_hle_struct {
1343 long offset;
1344 char * path;
1345 struct sh_hle_struct * next;
1346};
1347
1348static struct sh_hle_struct * sh_hl_exc = NULL;
1349
1350int sh_files_hle_reg (const char * str)
1351{
1352 long offset;
1353 size_t len;
1354 char * path;
1355
1356 struct sh_hle_struct * tmp = sh_hl_exc;
1357
1358 SL_ENTER(_("sh_files_hle_reg"));
1359
1360 /* Free the linked list if called with NULL argument
1361 */
1362 if (str == NULL)
1363 {
1364 while (tmp)
1365 {
1366 sh_hl_exc = tmp->next;
1367 SH_FREE(tmp->path);
1368 SH_FREE(tmp);
1369 tmp = sh_hl_exc;
1370 }
1371 sh_hl_exc = NULL;
1372 SL_RETURN(0, _("sh_files_hle_reg"));
1373 }
1374
1375 /* We expect 'offset:/path'
1376 */
1377 offset = strtol(str, &path, 0);
1378 if ((path == NULL) || (*path == '\0') || (*path != ':') || (path[1] != '/'))
1379 {
1380 SL_RETURN(-1, _("sh_files_hle_reg"));
1381 }
1382 ++path;
1383 len = 1 + sl_strlen(path);
1384
1385 tmp = SH_ALLOC(sizeof(struct sh_hle_struct));
1386 tmp->path = SH_ALLOC(len);
1387 sl_strlcpy (tmp->path, path, len);
1388 tmp->offset = offset;
1389 tmp->next = sh_hl_exc;
1390 sh_hl_exc = tmp;
1391
1392 SL_RETURN(0, _("sh_files_hle_reg"));
1393}
1394
1395#if !defined(HOST_IS_DARWIN)
1396static int sh_files_hle_test (int offset, char * path)
1397{
1398 struct sh_hle_struct * tmp = sh_hl_exc;
1399
1400 SL_ENTER(_("sh_files_hle_reg"));
1401
1402 while(tmp)
1403 {
1404 if ((offset == tmp->offset) && (0 == strcmp(path, tmp->path)))
1405 {
1406 SL_RETURN(0, _("sh_files_hle_test"));
1407 }
1408 tmp = tmp->next;
1409 }
1410 SL_RETURN(-1, _("sh_files_hle_test"));
1411}
1412#endif
1413
1414/* -- check a single directory and its content
1415 */
1416static int sh_files_checkdir (int iclass, int idepth, char * iname,
1417 char * relativeName)
1418{
1419 struct sh_dirent * dirlist = NULL;
1420 struct sh_dirent * dirlist_orig = NULL;
1421
1422 DIR * thisDir = NULL;
1423 struct dirent * thisEntry;
1424 int status;
1425 int dummy = S_FALSE;
1426 dir_type theDir;
1427 ShFileType checkit;
1428
1429
1430 file_type theFile;
1431 char * tmpname;
1432 char * tmpcat;
1433
1434 int rdepth = 0;
1435 int class = 0;
1436 int rdepth_next;
1437 int class_next;
1438 int file_class_next;
1439
1440 int checked_flag = S_FALSE;
1441 int cchecked_flag = S_FALSE;
1442
1443 dirstack_t * dst_ptr;
1444 dirstack_t * tmp_ptr;
1445
1446 int hardlink_num = 0;
1447
1448
1449 SL_ENTER(_("sh_files_checkdir"));
1450
1451 if (sig_urgent > 0) {
1452 SL_RETURN((0), _("sh_files_checkdir"));
1453 }
1454
1455 if (iname == NULL || idepth < (-1))
1456 SL_RETURN((-1), _("sh_files_checkdir"));
1457
1458 if (idepth < 0)
1459 {
1460 /* hash_remove_tree (iname); */
1461 SL_RETURN((0), _("sh_files_checkdir"));
1462 }
1463
1464 rdepth = idepth;
1465 class = iclass;
1466
1467 tmpname = sh_util_safe_name (iname);
1468
1469 /* ---- check for obscure name ----
1470 */
1471 if (iclass != SH_LEVEL_ALLIGNORE)
1472 {
1473 sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], iname, S_TRUE);
1474 }
1475
1476 if (flag_err_info == SL_TRUE)
1477 {
1478 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CHK, tmpname);
1479 }
1480
1481 /* ---- check input ----
1482 */
1483 if ( sl_strlen(iname) >= PATH_MAX)
1484 {
1485 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
1486 MSG_FI_2LONG,
1487 tmpname);
1488 SH_FREE(tmpname);
1489 SL_RETURN((-1), _("sh_files_checkdir"));
1490 }
1491
1492 /* ---- check for absolute path ---- */
1493 if ( iname[0] != '/')
1494 {
1495 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
1496 MSG_FI_NOPATH,
1497 tmpname);
1498 SH_FREE(tmpname);
1499 SL_RETURN((-1), _("sh_files_checkdir"));
1500 }
1501
1502
1503 /* ---- stat the directory ----
1504 */
1505 sl_strlcpy (theFile.fullpath, iname, PATH_MAX);
1506
1507 (void) relativeName;
1508 status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_DIR],
1509 iname,
1510 &theFile, NULL, iclass);
1511
1512 if ((sig_termfast == 1) || (sig_terminate == 1))
1513 {
1514 SL_RETURN((0), _("sh_files_checkdir"));
1515 }
1516
1517 if (status == -1)
1518 {
1519 SH_FREE(tmpname);
1520 SL_RETURN((-1), _("sh_files_checkdir"));
1521 }
1522
1523 if (theFile.c_mode[0] != 'd')
1524 {
1525 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
1526 MSG_FI_NODIR,
1527 tmpname);
1528 SH_FREE(tmpname);
1529 SL_RETURN((-1), _("sh_files_checkdir"));
1530 }
1531
1532 hardlink_num = theFile.hardlinks;
1533
1534
1535 /* ---- open directory for reading ----
1536 *
1537 * opendir() will fail with ENOTDIR if the path has been changed
1538 * to a non-directory in between lstat() and opendir().
1539 */
1540 thisDir = opendir (iname);
1541
1542 if (thisDir == NULL)
1543 {
1544 status = errno;
1545 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
1546 MSG_E_OPENDIR,
1547 sh_error_message (status), tmpname);
1548 SH_FREE(tmpname);
1549
1550 SL_RETURN((-1), _("sh_files_checkdir"));
1551 }
1552
1553 theDir.NumRegular = 0;
1554 theDir.NumDirs = 0;
1555 theDir.NumSymlinks = 0;
1556 theDir.NumFifos = 0;
1557 theDir.NumSockets = 0;
1558 theDir.NumCDev = 0;
1559 theDir.NumBDev = 0;
1560 theDir.NumAll = 0;
1561 theDir.TotalBytes = 0;
1562 sl_strlcpy (theDir.DirPath, iname, PATH_MAX);
1563
1564
1565 /* ---- read ----
1566 */
1567 do {
1568 thisEntry = readdir (thisDir);
1569 if (thisEntry != NULL)
1570 {
1571 ++theDir.NumAll;
1572 if (sl_strcmp (thisEntry->d_name, ".") == 0)
1573 {
1574 ++theDir.NumDirs;
1575 continue;
1576 }
1577 if (sl_strcmp (thisEntry->d_name, "..") == 0)
1578 {
1579 ++theDir.NumDirs;
1580 continue;
1581 }
1582 dirlist = addto_sh_dirlist (thisEntry, dirlist);
1583 }
1584 } while (thisEntry != NULL);
1585
1586 closedir (thisDir);
1587
1588 ++sh.statistics.dirs_checked;
1589
1590 dirlist_orig = dirlist;
1591
1592 do {
1593
1594 /* If the directory is empty, dirlist = NULL
1595 */
1596 if (!dirlist)
1597 break;
1598
1599 if (sig_termfast == 1)
1600 {
1601 SL_RETURN((0), _("sh_files_checkdir"));
1602 }
1603
1604 BREAKEXIT(sh_derr);
1605 if (0 == (rand() % 5))
1606 (void) sh_derr();
1607
1608 /* ---- Check the file. ----
1609 */
1610 tmpcat = SH_ALLOC(PATH_MAX);
1611 sl_strlcpy(tmpcat, iname, PATH_MAX);
1612 if (sl_strlen(tmpcat) > 1 || tmpcat[0] != '/')
1613 sl_strlcat(tmpcat, "/", PATH_MAX);
1614 sl_strlcat(tmpcat, dirlist->sh_d_name, PATH_MAX);
1615
1616 rdepth_next = rdepth - 1;
1617 class_next = class;
1618 file_class_next = class;
1619 checked_flag = -1;
1620 cchecked_flag = -1;
1621
1622 /* Wed Aug 24 2005 compare against dirListOne, dirListTwo
1623 * this fixes the problem that the directory special file
1624 * is checked with the policy of the parent directory
1625 */
1626 dst_ptr = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
1627
1628 if (dst_ptr)
1629 {
1630 /* Tue Aug 6 22:13:27 CEST 2002 introduce file_class_next
1631 * this fixes the problem that a policy for the directory
1632 * inode erroneously becomes a policy for the directory itself.
1633 */
1634 file_class_next = dst_ptr->class;
1635 checked_flag = dst_ptr->checked;
1636 cchecked_flag = dst_ptr->childs_checked;
1637 }
1638
1639 if (checked_flag == -1)
1640 {
1641 dst_ptr = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
1642
1643 if (dst_ptr)
1644 {
1645 /* Tue Aug 6 22:13:27 CEST 2002 introduce file_class_next
1646 * this fixes the problem that a policy for the directory
1647 * inode erroneously becomes a policy for the directory itself.
1648 */
1649 file_class_next = dst_ptr->class;
1650 checked_flag = dst_ptr->checked;
1651 cchecked_flag = dst_ptr->childs_checked;
1652 }
1653 }
1654
1655 dst_ptr = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
1656
1657 if (dst_ptr)
1658 {
1659 /* Tue Aug 6 22:13:27 CEST 2002 introduce file_class_next
1660 * this fixes the problem that a policy for the directory
1661 * inode erroneously becomes a policy for the directory itself.
1662 */
1663 file_class_next = dst_ptr->class;
1664 checked_flag = dst_ptr->checked;
1665 /* not set, hence always FALSE */
1666 /* cchecked_flag = dst_ptr->childs_checked; */
1667 }
1668
1669 /* ---- Has been checked already. ----
1670 */
1671 if (checked_flag == S_TRUE && cchecked_flag == S_TRUE)
1672 {
1673 /* Mar 11 2004 get ftype for complete directory count
1674 */
1675 checkit = sh_unix_get_ftype(tmpcat);
1676 if (checkit == SH_FILE_DIRECTORY)
1677 {
1678 ++theDir.NumDirs;
1679 }
1680 SH_FREE(tmpcat);
1681 dirlist = dirlist->next;
1682 continue;
1683 }
1684
1685 /* --- May be true, false, or not found. ---
1686 */
1687 if (checked_flag == S_TRUE)
1688 {
1689 /* -- need only the file type --
1690 */
1691 checkit = sh_unix_get_ftype(tmpcat);
1692 }
1693 else
1694 {
1695 /* -- need to check the file itself --
1696 */
1697 if (dst_ptr && sh.flag.reportonce == S_TRUE)
1698 dummy = dst_ptr->reported;
1699
1700 checkit = sh_files_filecheck (file_class_next,
1701 iname,
1702 dirlist->sh_d_name,
1703 &dummy, 0);
1704
1705 if (dst_ptr && checked_flag == S_FALSE)
1706 dst_ptr->checked = S_TRUE;
1707 /* Thu Mar 7 15:09:40 CET 2002 Propagate the 'reported' flag
1708 */
1709 if (dst_ptr && sh.flag.reportonce == S_TRUE)
1710 dst_ptr->reported = dummy;
1711 }
1712
1713 if (checkit == SH_FILE_REGULAR)
1714 ++theDir.NumRegular;
1715
1716 else if (checkit == SH_FILE_DIRECTORY)
1717 {
1718 ++theDir.NumDirs;
1719 if (rdepth_next >= 0 && cchecked_flag != S_TRUE)
1720 {
1721 rdepth_next = rdepth - 1;
1722
1723 /* check whether the new directory is in the
1724 * list with a recursion depth already defined
1725 */
1726 checked_flag = -1;
1727 cchecked_flag = -1;
1728
1729 tmp_ptr = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
1730
1731 if (tmp_ptr)
1732 {
1733 TPT((0, FIL__, __LINE__,
1734 _("msg=<%s -> recursion depth %d\n>"),
1735 tmp_ptr->name, tmp_ptr->rdepth));
1736 rdepth_next = tmp_ptr->rdepth;
1737 class_next = tmp_ptr->class;
1738 /* 28. Aug 2001 reversed
1739 */
1740 cchecked_flag = tmp_ptr->childs_checked;
1741 checked_flag = tmp_ptr->checked;
1742 }
1743
1744 if (checked_flag == -1)
1745 {
1746 tmp_ptr = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
1747
1748 if (tmp_ptr)
1749 {
1750 TPT((0, FIL__, __LINE__,
1751 _("msg=<%s -> recursion depth %d\n>"),
1752 tmp_ptr->name, tmp_ptr->rdepth));
1753 rdepth_next = tmp_ptr->rdepth;
1754 class_next = tmp_ptr->class;
1755 /* 28. Aug 2001 reversed
1756 */
1757 cchecked_flag = tmp_ptr->childs_checked;
1758 checked_flag = tmp_ptr->checked;
1759 }
1760 }
1761
1762 if (cchecked_flag == S_FALSE)
1763 {
1764 sh_files_checkdir (class_next, rdepth_next, tmpcat,
1765 dirlist->sh_d_name);
1766 tmp_ptr->childs_checked = S_TRUE;
1767 /*
1768 * 04. Feb 2006 avoid double checking
1769 */
1770 tmp_ptr->checked = S_TRUE;
1771 }
1772 else if (checked_flag == -1)
1773 sh_files_checkdir (class_next, rdepth_next, tmpcat,
1774 dirlist->sh_d_name);
1775
1776 }
1777 }
1778
1779 else if (checkit == SH_FILE_SYMLINK) ++theDir.NumSymlinks;
1780 else if (checkit == SH_FILE_FIFO) ++theDir.NumFifos;
1781 else if (checkit == SH_FILE_SOCKET) ++theDir.NumSockets;
1782 else if (checkit == SH_FILE_CDEV) ++theDir.NumCDev;
1783 else if (checkit == SH_FILE_BDEV) ++theDir.NumBDev;
1784
1785 SH_FREE(tmpcat);
1786
1787 if ((sig_termfast == 1) || (sig_terminate == 1))
1788 {
1789 SL_RETURN((0), _("sh_files_checkdir"));
1790 }
1791
1792 dirlist = dirlist->next;
1793
1794 if (dst_ptr)
1795 dst_ptr->childs_checked = S_TRUE;
1796
1797 } while (dirlist != NULL);
1798
1799 if (flag_err_info == SL_TRUE)
1800 {
1801 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DSUM,
1802 theDir.NumDirs,
1803 theDir.NumRegular,
1804 theDir.NumSymlinks,
1805 theDir.NumFifos,
1806 theDir.NumSockets,
1807 theDir.NumCDev,
1808 theDir.NumBDev);
1809 }
1810
1811 kill_sh_dirlist (dirlist_orig);
1812
1813#if !defined(HOST_IS_DARWIN)
1814 /*
1815 * Hardlink check; not done on MacOS X because of resource forks
1816 */
1817 if ((sh_check_hardlinks == S_TRUE) && (hardlink_num != theDir.NumDirs))
1818 {
1819 if (0 != sh_files_hle_test(hardlink_num-theDir.NumDirs, iname))
1820 {
1821 tmpcat = SH_ALLOC(strlen(tmpname) + 256);
1822 sl_snprintf(tmpcat, strlen(tmpname) + 256,
1823 _("%s: subdirectory count (%d) != hardlinks (%d)"),
1824 tmpname, theDir.NumDirs, hardlink_num);
1825 sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
1826 MSG_E_SUBGEN, tmpcat, _("sh_files_checkdir"));
1827 SH_FREE(tmpcat);
1828 }
1829 }
1830#endif
1831
1832 SH_FREE(tmpname);
1833
1834 SL_RETURN((0), _("sh_files_checkdir"));
1835}
1836
1837int get_the_fd (SL_TICKET ticket);
1838
1839
1840static ShFileType sh_files_filecheck (int class, char * dirName,
1841 char * fileName,
1842 int * reported,
1843 int rsrcflag)
1844{
1845 /* 28 Aug 2001 allow NULL fileName
1846 */
1847 char fullpath[PATH_MAX];
1848 char fileHash[2*(KEY_LEN + 1)];
1849 int status;
1850 file_type theFile;
1851 char * tmpdir;
1852 char * tmpname;
1853 struct utimbuf utime_buf;
1854
1855 SL_ENTER(_("sh_files_filecheck"));
1856
1857 BREAKEXIT(sh_derr);
1858 if (0 == (rand() % 2))
1859 (void) sh_derr();
1860
1861 /* fileName may be NULL if this is a directory
1862 */
1863 if (dirName == NULL /* || fileName == NULL */)
1864 {
1865 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NULL);
1866 SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
1867 }
1868
1869 if ((fileName != NULL) && (class != SH_LEVEL_ALLIGNORE) &&
1870 (0 != sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME],
1871 fileName, S_FALSE)))
1872 {
1873 if ((dirName != NULL) && (dirName[0] == '/') && (dirName[1] == '\0'))
1874 {
1875 tmpname = sh_util_safe_name (fileName);
1876 sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
1877 MSG_FI_OBSC2,
1878 "", tmpname);
1879 SH_FREE(tmpname);
1880 }
1881 else
1882 {
1883 tmpdir = sh_util_safe_name (dirName);
1884 tmpname = sh_util_safe_name (fileName);
1885 sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
1886 MSG_FI_OBSC2,
1887 tmpdir, tmpname);
1888 SH_FREE(tmpname);
1889 SH_FREE(tmpdir);
1890 }
1891 }
1892
1893 /* sh_files_fullpath accepts NULL fileName
1894 */
1895 if (0 != sh_files_fullpath (dirName, fileName, fullpath))
1896 {
1897 tmpdir = sh_util_safe_name (dirName);
1898 tmpname = sh_util_safe_name (fileName);
1899 sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, 0,
1900 MSG_FI_2LONG2,
1901 tmpdir, tmpname);
1902 SH_FREE(tmpname);
1903 SH_FREE(tmpdir);
1904 SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
1905 }
1906
1907
1908 /* stat the file and determine checksum (if a regular file)
1909 */
1910 sl_strlcpy (theFile.fullpath, fullpath, PATH_MAX);
1911 theFile.check_mask = sh_files_maskof(class);
1912 theFile.reported = (*reported);
1913
1914 TPT(( 0, FIL__, __LINE__, _("msg=<checking file: %s>\n"), fullpath));
1915
1916 status = sh_unix_getinfo ( (class == SH_LEVEL_ALLIGNORE) ?
1917 ShDFLevel[class] : ShDFLevel[SH_ERR_T_FILE],
1918 fileName,
1919 &theFile, fileHash, class);
1920
1921 if (status != 0)
1922 {
1923 TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"),
1924 fullpath, status));
1925 if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT)
1926 sh_hash_set_visited_true (fullpath);
1927 SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
1928 }
1929
1930 if (sig_termfast == 1) {
1931 goto ret_point;
1932 }
1933
1934 /* report
1935 */
1936 if ((flag_err_debug == SL_TRUE) && (theFile.c_mode[0] == '-'))
1937 {
1938 tmpname = sh_util_safe_name (fullpath); /* fixed in 1.5.4 */
1939 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CSUM,
1940 fileHash, tmpname);
1941 SH_FREE(tmpname);
1942 }
1943 ++sh.statistics.files_checked;
1944
1945 if ( sh.flag.checkSum == SH_CHECK_INIT && sh.flag.update == S_FALSE )
1946 {
1947 sh_hash_pushdata (&theFile, fileHash);
1948 }
1949 else if (sh.flag.checkSum == SH_CHECK_INIT && sh.flag.update == S_TRUE )
1950 {
1951 if (0 == sh_hash_compdata (class, &theFile, fileHash, NULL, -1))
1952 {
1953 sh_hash_pushdata (&theFile, fileHash);
1954 }
1955 }
1956 else if (sh.flag.checkSum == SH_CHECK_CHECK
1957 /* && theFile.c_mode[0] == '-' */
1958 /* && class != SH_LEVEL_ALLIGNORE */
1959 )
1960 {
1961 sh_hash_compdata (class, &theFile, fileHash, NULL, -1);
1962 }
1963
1964 (*reported) = theFile.reported;
1965
1966 /* reset the access time
1967 */
1968 if (class == SH_LEVEL_NOIGNORE && (theFile.check_mask & MODI_ATM) != 0)
1969 {
1970 utime_buf.actime = (time_t) theFile.atime;
1971 utime_buf.modtime = (time_t) theFile.mtime;
1972#if !defined(O_NOATIME)
1973 retry_aud_utime (FIL__, __LINE__, fullpath, &utime_buf);
1974#endif
1975 }
1976
1977#ifdef HOST_IS_DARWIN
1978 /*
1979 * Check for resource fork
1980 */
1981 if ( (theFile.c_mode[0] != 'd') && (rsrcflag == 0) )
1982 {
1983 int dummy;
1984 static int rsrc_init = 0;
1985 static char rsrc[17];
1986 char testpath[PATH_MAX];
1987
1988 if (rsrc_init == 0) {
1989 sl_strlcpy(rsrc, _("..namedfork/rsrc"), 17);
1990 rsrc_init = 1;
1991 }
1992 sl_strlcpy (testpath, fullpath, PATH_MAX);
1993 sl_strlcat (testpath, "/", PATH_MAX);
1994 sl_strlcat (testpath, rsrc, PATH_MAX);
1995
1996 if (sl_strlen(testpath) == (17 + sl_strlen(fullpath)))
1997 {
1998 if (0 == sh_unix_file_stat (testpath))
1999 {
2000 sh_files_filecheck (class, fullpath, rsrc, &dummy, 1);
2001 }
2002 }
2003 }
2004#else
2005 (void) rsrcflag; /* avoid compiler warning */
2006#endif
2007
2008 ret_point:
2009
2010 switch (theFile.c_mode[0])
2011 {
2012 case '-': SL_RETURN(SH_FILE_REGULAR, _("sh_files_filecheck"));
2013 case 'l': SL_RETURN(SH_FILE_SYMLINK, _("sh_files_filecheck"));
2014 case 'd': SL_RETURN(SH_FILE_DIRECTORY, _("sh_files_filecheck"));
2015 case 'c': SL_RETURN(SH_FILE_CDEV, _("sh_files_filecheck"));
2016 case 'b': SL_RETURN(SH_FILE_BDEV, _("sh_files_filecheck"));
2017 case '|': SL_RETURN(SH_FILE_FIFO, _("sh_files_filecheck"));
2018 case 's': SL_RETURN(SH_FILE_SOCKET, _("sh_files_filecheck"));
2019 default: SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2020 }
2021
2022 /* notreached */
2023}
2024
2025/* concatenate statpath = testdir"/"d_name
2026 */
2027static int sh_files_fullpath (char * testdir, char * d_name, char * statpath)
2028{
2029 int llen = 0;
2030
2031 SL_ENTER(_("sh_files_fullpath"));
2032
2033 if (testdir != NULL)
2034 {
2035 if ( (llen = sl_strlen(testdir)) > (PATH_MAX-2) )
2036 SL_RETURN((-1),_("sh_files_fullpath"));
2037 sl_strlcpy(statpath, testdir, PATH_MAX - 1);
2038 }
2039 if (d_name != NULL)
2040 {
2041 if (llen > 1 || statpath[0] != '/')
2042 sl_strlcat(statpath, "/", PATH_MAX);
2043 if ((sl_strlen(d_name) + sl_strlen(statpath)) >= PATH_MAX)
2044 SL_RETURN((-1),_("sh_files_fullpath"));
2045 sl_strlcat(statpath, d_name, PATH_MAX);
2046 }
2047 if (statpath == NULL)
2048 SL_RETURN((-1),_("sh_files_fullpath"));
2049 SL_RETURN((0),_("sh_files_fullpath"));
2050}
2051
2052
2053/* -----------------------------------
2054 *
2055 * The following two routines serve to
2056 * verify that the user has selected
2057 * a proper setup for file policies.
2058 *
2059 * -----------------------------------
2060 */
2061static int check_file(char * name)
2062{
2063 dirstack_t * pfilL;
2064 zAVLCursor cursor;
2065
2066 SL_ENTER(_("check_file"));
2067
2068 if (SH_FILE_DIRECTORY == sh_unix_get_ftype(name))
2069 SL_RETURN(0, _("check_file"));
2070
2071 for (pfilL = (dirstack_t *) zAVLFirst (&cursor, zfileList); pfilL;
2072 pfilL = (dirstack_t *) zAVLNext (&cursor))
2073 {
2074 if (0 == strcmp(name, pfilL->name) &&
2075 (pfilL->check_mask & MODI_ATM) == 0 &&
2076 (pfilL->check_mask & MODI_CTM) == 0 &&
2077 (pfilL->check_mask & MODI_MTM) == 0)
2078 SL_RETURN(0, _("check_file"));
2079 }
2080 SL_RETURN((-1), _("check_file"));
2081}
2082
2083int sh_files_test_setup_int (zAVLTree * tree)
2084{
2085 int dlen, flen;
2086 zAVLCursor cursor1;
2087 zAVLCursor cursor2;
2088
2089 dirstack_t * pdirL;
2090 dirstack_t * pfilL;
2091
2092 SL_ENTER(_("sh_files_test_setup"));
2093
2094 for (pdirL = (dirstack_t *) zAVLFirst (&cursor1, tree); pdirL;
2095 pdirL = (dirstack_t *) zAVLNext (&cursor1))
2096 {
2097 dlen = strlen(pdirL->name);
2098
2099 for (pfilL = (dirstack_t *) zAVLFirst (&cursor2, zfileList); pfilL;
2100 pfilL = (dirstack_t *) zAVLNext (&cursor2))
2101 {
2102 flen = strlen(pfilL->name);
2103
2104 /* check whether file is in tree of dir
2105 */
2106 if ((pfilL->class == SH_LEVEL_READONLY) ||
2107 (pfilL->class == SH_LEVEL_NOIGNORE))
2108 {
2109 ; /* do nothing */
2110 }
2111 else
2112 {
2113 if ((flen > (dlen+1)) &&
2114 (pfilL->name[dlen] == '/') &&
2115 (NULL == strchr(&(pfilL->name[dlen+1]), '/')) && /*30-5-01*/
2116 (0 == strncmp(pfilL->name, pdirL->name, dlen)))
2117 {
2118 if ((pdirL->check_mask & MODI_ATM) != 0 ||
2119 (pdirL->check_mask & MODI_MTM) != 0 ||
2120 (pdirL->check_mask & MODI_CTM) != 0)
2121 {
2122 if (check_file (pdirL->name) != 0)
2123 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_COLL,
2124 pdirL->name, pfilL->name);
2125 }
2126 }
2127 }
2128 }
2129 }
2130
2131 SL_RETURN((0), _("sh_files_test_setup"));
2132}
2133
2134int sh_files_test_double (zAVLTree * firstList, zAVLTree * secondList)
2135{
2136 int count;
2137 int retval = 0;
2138
2139 zAVLCursor cursor;
2140
2141 dirstack_t * first;
2142
2143 for (first = (dirstack_t *) zAVLFirst (&cursor, firstList); first;
2144 first = (dirstack_t *) zAVLNext (&cursor))
2145 {
2146
2147 if (NULL != zAVLSearch(secondList, first->name))
2148 {
2149 ++count;
2150 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
2151 first->name);
2152 retval = 1;
2153 }
2154 }
2155 return retval;
2156}
2157
2158extern void aud_exit (char * file, int line, int fd);
2159
2160int sh_files_test_setup ()
2161{
2162 int retval = 0;
2163
2164 /* Test for modifications allowed in ReadOnly directory
2165 */
2166 sh_files_test_setup_int (zdirListOne);
2167 sh_files_test_setup_int (zdirListTwo);
2168
2169 /* Test for files/dirz defined twice
2170 */
2171 retval = sh_files_test_double (zdirListOne, zdirListTwo);
2172 if (retval != 0)
2173 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2174
2175 retval = sh_files_test_double (zdirListTwo, zdirListOne);
2176 if (retval != 0)
2177 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2178
2179
2180 /*
2181 retval = sh_files_test_double (zfileList, NULL);
2182 if (retval != 0)
2183 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2184 */
2185 return 0;
2186}
2187
2188#endif
Note: See TracBrowser for help on using the repository browser.