cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

files_select.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <files_select.h>
26 
27 #include <eval_context.h>
28 #include <files_names.h>
29 #include <files_interfaces.h>
30 #include <promises.h>
31 #include <match_scope.h>
32 #include <string_lib.h>
33 #include <files_lib.h>
34 #include <pipes.h>
35 #include <promises.h>
36 #include <exec_tools.h>
37 #include <chflags.h>
38 
39 static bool SelectTypeMatch(const struct stat *lstatptr, Rlist *crit);
40 static bool SelectOwnerMatch(EvalContext *ctx, char *path, const struct stat *lstatptr, Rlist *crit);
41 static bool SelectModeMatch(const struct stat *lstatptr, Rlist *ls);
42 static bool SelectTimeMatch(time_t stattime, time_t fromtime, time_t totime);
43 static bool SelectNameRegexMatch(EvalContext *ctx, const char *filename, char *crit);
44 static bool SelectPathRegexMatch(EvalContext *ctx, char *filename, char *crit);
45 static bool SelectExecRegexMatch(EvalContext *ctx, char *filename, char *crit, char *prog);
46 static bool SelectIsSymLinkTo(EvalContext *ctx, char *filename, Rlist *crit);
47 static bool SelectExecProgram(char *filename, char *command);
48 static bool SelectSizeMatch(size_t size, size_t min, size_t max);
49 
50 #if !defined(__MINGW32__)
51 static bool SelectGroupMatch(EvalContext *ctx, const struct stat *lstatptr, Rlist *crit);
52 #endif
53 
54 #if defined HAVE_CHFLAGS
55 static bool SelectBSDMatch(const struct stat *lstatptr, Rlist *bsdflags);
56 #endif
57 
58 bool SelectLeaf(EvalContext *ctx, char *path, const struct stat *sb, const FileSelect *fs)
59 {
60  Rlist *rp;
61 
62  StringSet *leaf_attr = StringSetNew();
63 
64 #ifdef __MINGW32__
65  if (fs->issymlinkto != NULL)
66  {
68  "files_select.issymlinkto is ignored on Windows (symbolic links are not supported by Windows)");
69  }
70 
71  if (fs->groups != NULL)
72  {
74  "files_select.search_groups is ignored on Windows (file groups are not supported by Windows)");
75  }
76 
77  if (fs->bsdflags != NULL)
78  {
79  Log(LOG_LEVEL_VERBOSE, "files_select.search_bsdflags is ignored on Windows");
80  }
81 #endif /* __MINGW32__ */
82 
83  if (fs->name == NULL)
84  {
85  StringSetAdd(leaf_attr, xstrdup("leaf_name"));
86  }
87 
88  for (rp = fs->name; rp != NULL; rp = rp->next)
89  {
90  if (SelectNameRegexMatch(ctx, path, RlistScalarValue(rp)))
91  {
92  StringSetAdd(leaf_attr, xstrdup("leaf_name"));
93  break;
94  }
95  }
96 
97  if (fs->path == NULL)
98  {
99  StringSetAdd(leaf_attr, xstrdup("leaf_path"));
100  }
101 
102  for (rp = fs->path; rp != NULL; rp = rp->next)
103  {
104  if (SelectPathRegexMatch(ctx, path, RlistScalarValue(rp)))
105  {
106  StringSetAdd(leaf_attr, xstrdup("path_name"));
107  break;
108  }
109  }
110 
111  if (SelectTypeMatch(sb, fs->filetypes))
112  {
113  StringSetAdd(leaf_attr, xstrdup("file_types"));
114  }
115 
116  if ((fs->owners) && (SelectOwnerMatch(ctx, path, sb, fs->owners)))
117  {
118  StringSetAdd(leaf_attr, xstrdup("owner"));
119  }
120 
121  if (fs->owners == NULL)
122  {
123  StringSetAdd(leaf_attr, xstrdup("owner"));
124  }
125 
126 #ifdef __MINGW32__
127  StringSetAdd(leaf_attr, xstrdup("group"));
128 
129 #else /* !__MINGW32__ */
130  if ((fs->groups) && (SelectGroupMatch(ctx, sb, fs->groups)))
131  {
132  StringSetAdd(leaf_attr, xstrdup("group"));
133  }
134 
135  if (fs->groups == NULL)
136  {
137  StringSetAdd(leaf_attr, xstrdup("group"));
138  }
139 #endif /* !__MINGW32__ */
140 
141  if (SelectModeMatch(sb, fs->perms))
142  {
143  StringSetAdd(leaf_attr, xstrdup("mode"));
144  }
145 
146 #if defined HAVE_CHFLAGS
147  if (SelectBSDMatch(sb, fs->bsdflags))
148  {
149  StringSetAdd(leaf_attr, xstrdup("bsdflags"));
150  }
151 #endif
152 
153  if (SelectTimeMatch(sb->st_atime, fs->min_atime, fs->max_atime))
154  {
155  StringSetAdd(leaf_attr, xstrdup("atime"));
156  }
157 
158  if (SelectTimeMatch(sb->st_ctime, fs->min_ctime, fs->max_ctime))
159  {
160  StringSetAdd(leaf_attr, xstrdup("ctime"));
161  }
162 
163  if (SelectSizeMatch(sb->st_size, fs->min_size, fs->max_size))
164  {
165  StringSetAdd(leaf_attr, xstrdup("size"));
166  }
167 
168  if (SelectTimeMatch(sb->st_mtime, fs->min_mtime, fs->max_mtime))
169  {
170  StringSetAdd(leaf_attr, xstrdup("mtime"));
171  }
172 
173  if ((fs->issymlinkto) && (SelectIsSymLinkTo(ctx, path, fs->issymlinkto)))
174  {
175  StringSetAdd(leaf_attr, xstrdup("issymlinkto"));
176  }
177 
178  if ((fs->exec_regex) && (SelectExecRegexMatch(ctx, path, fs->exec_regex, fs->exec_program)))
179  {
180  StringSetAdd(leaf_attr, xstrdup("exec_regex"));
181  }
182 
183  if ((fs->exec_program) && (SelectExecProgram(path, fs->exec_program)))
184  {
185  StringSetAdd(leaf_attr, xstrdup("exec_program"));
186  }
187 
188  bool result = EvalFileResult(fs->result, leaf_attr);
189 
190  Log(LOG_LEVEL_VERBOSE, "file_select result '%s' on '%s' was '%s'",
191  fs->result, path,
192  result ? "true" : "false");
193 
194  StringSetDestroy(leaf_attr);
195 
196  return result;
197 }
198 
199 /*******************************************************************/
200 /* Level */
201 /*******************************************************************/
202 
203 static bool SelectSizeMatch(size_t size, size_t min, size_t max)
204 {
205  if ((size <= max) && (size >= min))
206  {
207  return true;
208  }
209 
210  return false;
211 }
212 
213 /*******************************************************************/
214 
215 static bool SelectTypeMatch(const struct stat *lstatptr, Rlist *crit)
216 {
217  Rlist *rp;
218 
219  StringSet *leafattrib = StringSetNew();
220 
221  if (S_ISREG(lstatptr->st_mode))
222  {
223  StringSetAdd(leafattrib, xstrdup("reg"));
224  StringSetAdd(leafattrib, xstrdup("plain"));
225  }
226 
227  if (S_ISDIR(lstatptr->st_mode))
228  {
229  StringSetAdd(leafattrib, xstrdup("dir"));
230  }
231 
232 #ifndef __MINGW32__
233  if (S_ISLNK(lstatptr->st_mode))
234  {
235  StringSetAdd(leafattrib, xstrdup("symlink"));
236  }
237 
238  if (S_ISFIFO(lstatptr->st_mode))
239  {
240  StringSetAdd(leafattrib, xstrdup("fifo"));
241  }
242 
243  if (S_ISSOCK(lstatptr->st_mode))
244  {
245  StringSetAdd(leafattrib, xstrdup("socket"));
246  }
247 
248  if (S_ISCHR(lstatptr->st_mode))
249  {
250  StringSetAdd(leafattrib, xstrdup("char"));
251  }
252 
253  if (S_ISBLK(lstatptr->st_mode))
254  {
255  StringSetAdd(leafattrib, xstrdup("block"));
256  }
257 #endif /* !__MINGW32__ */
258 
259 #ifdef HAVE_DOOR_CREATE
260  if (S_ISDOOR(lstatptr->st_mode))
261  {
262  StringSetAdd(leafattrib, xstrdup("door"));
263  }
264 #endif
265 
266  for (rp = crit; rp != NULL; rp = rp->next)
267  {
268  if (EvalFileResult(RlistScalarValue(rp), leafattrib))
269  {
270  StringSetDestroy(leafattrib);
271  return true;
272  }
273  }
274 
275  StringSetDestroy(leafattrib);
276  return false;
277 }
278 
279 static bool SelectOwnerMatch(EvalContext *ctx, char *path, const struct stat *lstatptr, Rlist *crit)
280 {
281  Rlist *rp;
282  char ownerName[CF_BUFSIZE];
283 
284  StringSet *leafattrib = StringSetNew();
285 
286 #ifndef __MINGW32__ // no uids on Windows
287  char buffer[CF_SMALLBUF];
288  snprintf(buffer, CF_SMALLBUF, "%ju", (uintmax_t) lstatptr->st_uid);
289  StringSetAdd(leafattrib, xstrdup(buffer));
290 #endif /* __MINGW32__ */
291 
292  bool gotOwner = GetOwnerName(path, lstatptr, ownerName, sizeof(ownerName));
293 
294  if (gotOwner)
295  {
296  StringSetAdd(leafattrib, xstrdup(ownerName));
297  }
298  else
299  {
300  StringSetAdd(leafattrib, xstrdup("none"));
301  }
302 
303  for (rp = crit; rp != NULL; rp = rp->next)
304  {
305  if (EvalFileResult(RlistScalarValue(rp), leafattrib))
306  {
307  Log(LOG_LEVEL_DEBUG, "Select owner match");
308  StringSetDestroy(leafattrib);
309  return true;
310  }
311 
312  if (gotOwner && (FullTextMatch(ctx, RlistScalarValue(rp), ownerName)))
313  {
314  Log(LOG_LEVEL_DEBUG, "Select owner match");
315  StringSetDestroy(leafattrib);
316  return true;
317  }
318 
319 #ifndef __MINGW32__
320  if (FullTextMatch(ctx, RlistScalarValue(rp), buffer))
321  {
322  Log(LOG_LEVEL_DEBUG, "Select owner match");
323  StringSetDestroy(leafattrib);
324  return true;
325  }
326 #endif /* !__MINGW32__ */
327  }
328 
329  StringSetDestroy(leafattrib);
330  return false;
331 }
332 
333 /*******************************************************************/
334 
335 static bool SelectModeMatch(const struct stat *lstatptr, Rlist *list)
336 {
337  mode_t newperm, plus, minus;
338  Rlist *rp;
339 
340  for (rp = list; rp != NULL; rp = rp->next)
341  {
342  plus = 0;
343  minus = 0;
344 
345  if (!ParseModeString(RlistScalarValue(rp), &plus, &minus))
346  {
347  Log(LOG_LEVEL_ERR, "Problem validating a mode string '%s' in search filter", RlistScalarValue(rp));
348  continue;
349  }
350 
351  newperm = (lstatptr->st_mode & 07777);
352  newperm |= plus;
353  newperm &= ~~minus;
354 
355  if ((newperm & 07777) == (lstatptr->st_mode & 07777))
356  {
357  return true;
358  }
359  }
360 
361  return false;
362 }
363 
364 /*******************************************************************/
365 
366 #if defined HAVE_CHFLAGS
367 static bool SelectBSDMatch(const struct stat *lstatptr, Rlist *bsdflags)
368 {
369  u_long newflags, plus, minus;
370 
371  if (!ParseFlagString(bsdflags, &plus, &minus))
372  {
373  Log(LOG_LEVEL_ERR, "Problem validating a BSD flag string");
374  }
375 
376  newflags = (lstatptr->st_flags & CHFLAGS_MASK);
377  newflags |= plus;
378  newflags &= ~~minus;
379 
380  if ((newflags & CHFLAGS_MASK) == (lstatptr->st_flags & CHFLAGS_MASK)) /* file okay */
381  {
382  return true;
383  }
384 
385  return false;
386 }
387 #endif
388 /*******************************************************************/
389 
390 static bool SelectTimeMatch(time_t stattime, time_t fromtime, time_t totime)
391 {
392  return ((fromtime < stattime) && (stattime < totime));
393 }
394 
395 /*******************************************************************/
396 
397 static bool SelectNameRegexMatch(EvalContext *ctx, const char *filename, char *crit)
398 {
399  if (FullTextMatch(ctx, crit, ReadLastNode(filename)))
400  {
401  return true;
402  }
403 
404  return false;
405 }
406 
407 /*******************************************************************/
408 
409 static bool SelectPathRegexMatch(EvalContext *ctx, char *filename, char *crit)
410 {
411  if (FullTextMatch(ctx, crit, filename))
412  {
413  return true;
414  }
415 
416  return false;
417 }
418 
419 /*******************************************************************/
420 
421 static bool SelectExecRegexMatch(EvalContext *ctx, char *filename, char *crit, char *prog)
422 {
423  // insert real value of $(this.promiser) in command
424 
425  char *buf_tmp = SearchAndReplace(prog, "$(this.promiser)", filename);
426  char *buf = SearchAndReplace(buf_tmp, "${this.promiser}", filename);
427  free(buf_tmp);
428 
429  FILE *pp = cf_popen(buf, "r", true);
430  if (pp == NULL)
431  {
432  Log(LOG_LEVEL_ERR, "Couldn't open pipe to command '%s'. (cf_popen: %s)", buf, GetErrorStr());
433  free(buf);
434  return false;
435  }
436 
437  size_t line_size = CF_BUFSIZE;
438  char *line = xmalloc(line_size);
439 
440  for (;;)
441  {
442  ssize_t res = CfReadLine(&line, &line_size, pp);
443  if (res == -1)
444  {
445  if (!feof(pp))
446  {
447  Log(LOG_LEVEL_ERR, "Error reading output from command '%s'. (fgets: %s)", buf, GetErrorStr());
448  }
449  cf_pclose(pp);
450  free(line);
451  free(buf);
452  return false;
453  }
454 
455  if (FullTextMatch(ctx, crit, line))
456  {
457  cf_pclose(pp);
458  free(line);
459  free(buf);
460  return true;
461  }
462  }
463 
464  cf_pclose(pp);
465  free(line);
466  free(buf);
467  return false;
468 }
469 
470 /*******************************************************************/
471 
472 static bool SelectIsSymLinkTo(EvalContext *ctx, char *filename, Rlist *crit)
473 {
474 #ifndef __MINGW32__
475  char buffer[CF_BUFSIZE];
476  Rlist *rp;
477 
478  for (rp = crit; rp != NULL; rp = rp->next)
479  {
480  memset(buffer, 0, CF_BUFSIZE);
481 
482  struct stat statbuf;
483 
484  // Don't worry if this gives an error, that's handled above us.
485 
486  // We're calling lstat() here to avoid dereferencing the
487  // symlink... and we only care if the inode is a directory.
488  if (lstat(filename, &statbuf) == -1)
489  {
490  // Do nothing.
491  }
492  else if (!S_ISLNK(statbuf.st_mode))
493  {
494  Log(LOG_LEVEL_DEBUG, "Skipping readlink() on non-symlink %s", filename);
495  return false;
496  }
497 
498  if (readlink(filename, buffer, CF_BUFSIZE - 1) == -1)
499  {
500  Log(LOG_LEVEL_ERR, "Unable to read link '%s' in filter. (readlink: %s)",
501  filename, GetErrorStr());
502  return false;
503  }
504 
505  if (FullTextMatch(ctx, RlistScalarValue(rp), buffer))
506  {
507  return true;
508  }
509  }
510 #endif /* !__MINGW32__ */
511  return false;
512 }
513 
514 /*******************************************************************/
515 
516 static bool SelectExecProgram(char *filename, char *command)
517  /* command can include $(this.promiser) for the name of the file */
518 {
519 // insert real value of $(this.promiser) in command
520 
521  char *buf_tmp = SearchAndReplace(command, "$(this.promiser)", filename);
522  char *buf = SearchAndReplace(buf_tmp, "${this.promiser}", filename);
523  free(buf_tmp);
524 
525  bool returns_zero = ShellCommandReturnsZero(buf, SHELL_TYPE_NONE);
526 
527  if (returns_zero)
528  {
529  Log(LOG_LEVEL_DEBUG, "Select ExecProgram match for '%s'", buf);
530  free(buf);
531  return true;
532  }
533  else
534  {
535  free(buf);
536  return false;
537  }
538 }
539 
540 #ifndef __MINGW32__
541 
542 /*******************************************************************/
543 /* Unix implementations */
544 /*******************************************************************/
545 
546 bool GetOwnerName(ARG_UNUSED char *path, const struct stat *lstatptr, char *owner, int ownerSz)
547 {
548  struct passwd *pw;
549 
550  memset(owner, 0, ownerSz);
551  pw = getpwuid(lstatptr->st_uid);
552 
553  if (pw == NULL)
554  {
555  Log(LOG_LEVEL_ERR, "Could not get owner name of user with 'uid=%ju'. (getpwuid: %s)",
556  (uintmax_t)lstatptr->st_uid, GetErrorStr());
557  return false;
558  }
559 
560  strncpy(owner, pw->pw_name, ownerSz - 1);
561 
562  return true;
563 }
564 
565 /*******************************************************************/
566 
567 static bool SelectGroupMatch(EvalContext *ctx, const struct stat *lstatptr, Rlist *crit)
568 {
569  char buffer[CF_SMALLBUF];
570  struct group *gr;
571  Rlist *rp;
572 
573  StringSet *leafattrib = StringSetNew();
574 
575  snprintf(buffer, CF_SMALLBUF, "%ju", (uintmax_t) lstatptr->st_gid);
576  StringSetAdd(leafattrib, xstrdup(buffer));
577 
578  if ((gr = getgrgid(lstatptr->st_gid)) != NULL)
579  {
580  StringSetAdd(leafattrib, xstrdup(gr->gr_name));
581  }
582  else
583  {
584  StringSetAdd(leafattrib, xstrdup("none"));
585  }
586 
587  for (rp = crit; rp != NULL; rp = rp->next)
588  {
589  if (EvalFileResult(RlistScalarValue(rp), leafattrib))
590  {
591  Log(LOG_LEVEL_DEBUG, "Select group match");
592  StringSetDestroy(leafattrib);
593  return true;
594  }
595 
596  if (gr && (FullTextMatch(ctx, RlistScalarValue(rp), gr->gr_name)))
597  {
598  Log(LOG_LEVEL_DEBUG, "Select group match");
599  StringSetDestroy(leafattrib);
600  return true;
601  }
602 
603  if (FullTextMatch(ctx, RlistScalarValue(rp), buffer))
604  {
605  Log(LOG_LEVEL_DEBUG, "Select group match");
606  StringSetDestroy(leafattrib);
607  return true;
608  }
609  }
610 
611  StringSetDestroy(leafattrib);
612  return false;
613 }
614 
615 #endif /* !__MINGW32__ */
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
#define ARG_UNUSED
Definition: cf-net.c:47
@ SHELL_TYPE_NONE
Definition: cf3.defs.h:1106
void free(void *)
bool ParseFlagString(Rlist *bitlist, u_long *plusmask, u_long *minusmask)
Definition: chflags.c:64
#define CF_BUFSIZE
Definition: definitions.h:50
#define CF_SMALLBUF
Definition: definitions.h:49
bool EvalFileResult(const char *file_result, StringSet *leaf_attr)
Definition: eval_context.c:635
bool ShellCommandReturnsZero(const char *command, ShellType shell)
Definition: unix.c:190
ssize_t CfReadLine(char **buff, size_t *size, FILE *fp)
Works exactly like posix 'getline', EXCEPT it does not include carriage return at the end.
Definition: file_lib.c:1476
const char * ReadLastNode(const char *str)
Definition: files_names.c:539
static bool SelectTimeMatch(time_t stattime, time_t fromtime, time_t totime)
Definition: files_select.c:390
static bool SelectIsSymLinkTo(EvalContext *ctx, char *filename, Rlist *crit)
Definition: files_select.c:472
static bool SelectTypeMatch(const struct stat *lstatptr, Rlist *crit)
Definition: files_select.c:215
bool SelectLeaf(EvalContext *ctx, char *path, const struct stat *sb, const FileSelect *fs)
Definition: files_select.c:58
static bool SelectSizeMatch(size_t size, size_t min, size_t max)
Definition: files_select.c:203
static bool SelectGroupMatch(EvalContext *ctx, const struct stat *lstatptr, Rlist *crit)
Definition: files_select.c:567
static bool SelectOwnerMatch(EvalContext *ctx, char *path, const struct stat *lstatptr, Rlist *crit)
Definition: files_select.c:279
static bool SelectModeMatch(const struct stat *lstatptr, Rlist *ls)
Definition: files_select.c:335
static bool SelectExecProgram(char *filename, char *command)
Definition: files_select.c:516
static bool SelectNameRegexMatch(EvalContext *ctx, const char *filename, char *crit)
Definition: files_select.c:397
bool GetOwnerName(char *path, const struct stat *lstatptr, char *owner, int ownerSz)
Definition: files_select.c:546
static bool SelectExecRegexMatch(EvalContext *ctx, char *filename, char *crit, char *prog)
Definition: files_select.c:421
static bool SelectPathRegexMatch(EvalContext *ctx, char *filename, char *crit)
Definition: files_select.c:409
#define NULL
Definition: getopt1.c:56
const char * GetErrorStr(void)
Definition: logging.c:275
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
bool FullTextMatch(EvalContext *ctx, const char *regexp, const char *teststring)
Definition: match_scope.c:87
bool ParseModeString(const char *modestring, mode_t *plusmask, mode_t *minusmask)
Definition: modes.c:51
int cf_pclose(FILE *pp)
Definition: pipes_unix.c:812
FILE * cf_popen(const char *command, const char *type, bool capture_stderr)
Definition: pipes_unix.c:332
#define CHFLAGS_MASK
Definition: platform.h:996
int lstat(const char *file_name, struct stat *buf)
#define S_ISDIR(m)
Definition: platform.h:916
#define S_ISBLK(m)
Definition: platform.h:928
#define S_ISSOCK(m)
Definition: platform.h:931
#define S_ISCHR(m)
Definition: platform.h:925
#define S_ISFIFO(m)
Definition: platform.h:922
#define S_ISLNK(m)
Definition: platform.h:919
#define S_ISREG(m)
Definition: platform.h:913
char * RlistScalarValue(const Rlist *rlist)
Definition: rlist.c:83
StringSet * StringSetNew(void)
Definition: set.c:34
void StringSetDestroy(StringSet *set)
Definition: set.c:34
void StringSetAdd(const StringSet *set, char *element)
Definition: set.c:34
char * SearchAndReplace(const char *source, const char *search, const char *replace)
Definition: string_lib.c:313
char * exec_program
Definition: cf3.defs.h:1050
time_t min_atime
Definition: cf3.defs.h:1048
Rlist * owners
Definition: cf3.defs.h:1039
time_t min_ctime
Definition: cf3.defs.h:1044
Rlist * perms
Definition: cf3.defs.h:1037
Rlist * bsdflags
Definition: cf3.defs.h:1038
Rlist * groups
Definition: cf3.defs.h:1040
time_t max_mtime
Definition: cf3.defs.h:1045
Rlist * name
Definition: cf3.defs.h:1035
Rlist * path
Definition: cf3.defs.h:1036
Rlist * issymlinkto
Definition: cf3.defs.h:1052
Rlist * filetypes
Definition: cf3.defs.h:1051
time_t min_mtime
Definition: cf3.defs.h:1046
char * result
Definition: cf3.defs.h:1053
char * exec_regex
Definition: cf3.defs.h:1049
time_t max_atime
Definition: cf3.defs.h:1047
long min_size
Definition: cf3.defs.h:1042
long max_size
Definition: cf3.defs.h:1041
time_t max_ctime
Definition: cf3.defs.h:1043
Definition: rlist.h:35
Rlist * next
Definition: rlist.h:37
Definition: set.h:138