3 # This shell-script genereates the fl_wrapper.c source file.
6 /* ROCK Linux Wrapper for getting a list of created files
8 * --- T2-COPYRIGHT-NOTE-BEGIN ---
9 * This copyright note is auto-generated by scripts/Create-CopyPatch.
11 * T2 SDE: misc/tools-source/fl_wrapper.c.sh
12 * Copyright (C) 2006 - 2020 René Rebe <rene@exactcode.de>
13 * Copyright (C) 2004 - 2021 The T2 SDE Project
14 * Copyright (C) 1998 - 2003 ROCK Linux Project
16 * More information can be found in the files COPYING and README.
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; version 2 of the License. A copy of the
21 * GNU General Public License can be found in the file COPYING.
22 * --- T2-COPYRIGHT-NOTE-END ---
24 * gcc -Wall -O2 -ldl -shared -o fl_wrapper.so fl_wrapper.c
26 * !!! THIS FILE IS AUTO-GENERATED BY $0 !!!
28 * ELF Dynamic Loading Documentation:
29 * - http://www.linuxdoc.org/HOWTO/GCC-HOWTO-7.html
30 * - http://www.educ.umu.se/~bjorn/mhonarc-files/linux-gcc/msg00576.html
31 * - /usr/include/dlfcn.h
35 /* Headers and prototypes */
39 #ifndef FLWRAPPER_LIBC
40 # define FLWRAPPER_LIBC "libc.so.6"
47 #define open64 xxx_open64
48 #define openat xxx_openat
49 #define openat64 xxx_openat64
50 #define mkfifo xxx_mkfifo
51 #define mknod xxx_mknod
52 #define __xmknod xxx___xmknod
54 #define _LARGEFILE_SOURCE
55 #define _LARGEFILE64_SOURCE
65 #include <sys/types.h>
70 /* somehow it can happen that PATH_MAX does not get defined...? -- jsaw */
72 #include <linux/limits.h>
75 #warning "PATH_MAX was not defined - BUG in your system headers?"
80 #undef _LARGEFILE64_SOURCE
81 #undef _LARGEFILE_SOURCE
93 static void * get_dl_symbol(char *);
102 static int initialized = 0;
104 #ifdef FLWRAPPER_BASEDIR
105 static void check_write_access(const char * , const char * );
107 static void handle_file_access_before(const char *, const char *, struct status_t *);
108 static void handle_file_access_after(const char *, const char *, struct status_t *);
110 char *cmdname = "unkown";
111 char wlog[PATH_MAX], rlog[PATH_MAX], filterdir[PATH_MAX], atpath[PATH_MAX];
113 const char* getatpath(int dirfd, const char* pathname) {
117 ret = snprintf(selffd, sizeof(selffd), "/proc/self/fd/%d", dirfd);
118 /* TODO: short buffer handling */
119 ret = readlink(selffd, atpath, sizeof(atpath) - 1);
121 fprintf(stderr, "Failed to get atpath: %d, %s\n", dirfd, pathname);
126 strncat(atpath, "/", sizeof(atpath) - 1);
127 strncat(atpath, pathname, sizeof(atpath) - 1);
128 /* TODO: short buffer handling */
133 /* Wrapper Functions */
136 # This has been made with cpp-macros before until they turned to be absolutely
141 line
="$( echo "$
*" | sed 's/ *, */,/g' )"
142 old_ifs
="$IFS" ; IFS
="," ; set $line ; IFS
="$old_ifs"
144 ret_type
=$1 ; shift ; function=$1 ; shift
145 p1
="" ; p2
="" ; for x
; do p1
="$p1$x, " ; done
146 for x
; do x
="${x%%\[*\]}" ; p2
="$p2${x##* }, " ; done
147 p1
="${p1%, }" ; p2
="${p2%, }"
149 # sanity check all new-style *at dirfd
153 if [[ "$x" = *atfd
]]; then
154 atcheck
="${atcheck}if (${x##* } != AT_FDCWD) {f2 = getatpath(${x##* }, f);}"
160 # remove varg from $p2
163 extern $ret_type $function($p1);
164 $ret_type (*orig_$function)($p1) = 0;
166 $ret_type $function($p1)
168 struct status_t status;
178 #ifdef FLWRAPPER_BASEDIR
179 if (a & (O_WRONLY|O_CREAT|O_APPEND))
180 check_write_access("$function", f2);
183 handle_file_access_before("$function", f2, &status);
184 if (!orig_$function) orig_$function = get_dl_symbol("$function");
188 fprintf(stderr, "fl_wrapper.so debug [%d]: going to run original $function() at %p (wrapper at %p).\n",
189 getpid(), orig_$function, $function);
196 b = va_arg(ap, mode_t);
199 rc = orig_$function($p2, b);
202 rc = orig_$function($p2);
205 handle_file_access_after("$function", f2, &status);
214 extern $ret_type $function($p1);
215 $ret_type (*orig_$function)($p1) = 0;
217 $ret_type $function($p1)
221 handle_file_access_after("$function", f, 0);
222 if (!orig_$function) orig_$function = get_dl_symbol("$function");
225 return orig_$function($p2);
231 extern $ret_type $function($p1);
232 $ret_type (*orig_$function)($p1) = 0;
234 $ret_type $function($p1)
236 struct status_t status;
245 handle_file_access_before("$function", f2, &status);
246 if (!orig_$function) orig_$function = get_dl_symbol("$function");
250 fprintf(stderr, "fl_wrapper.so debug [%d]: going to run original $function() at %p (wrapper at %p).\n",
251 getpid(), orig_$function, $function);
254 rc = orig_$function($p2);
257 handle_file_access_after("$function", f2, &status);
267 add_wrapper
'int, open, const char* f, int a, ...'
268 add_wrapper
'int, open64, const char* f, int a, ...'
269 add_wrapper
'int, openat, int atfd, const char* f, int a, ...'
270 add_wrapper
'int, openat64,int atfd, const char* f, int a, ...'
272 add_wrapper
'FILE*, fopen, const char* f, const char* g'
273 add_wrapper
'FILE*, fopen64, const char* f, const char* g'
275 add_wrapper
'int, creat, const char* f, mode_t m'
276 add_wrapper
'int, creat64, const char* f, mode_t m'
278 add_wrapper
'int, mkdir, const char* f, mode_t m'
279 add_wrapper
'int, mkfifo, const char* f, mode_t m'
280 add_wrapper
'int, mknod, const char* f, mode_t m, dev_t d'
281 add_wrapper
'int, __xmknod, int ver, const char* f, mode_t m, dev_t* d'
283 add_wrapper
'int, link, const char* s, const char* f'
284 add_wrapper
'int, linkat, int atfd, const char* s, int atfd2, const char* f, int flags'
286 add_wrapper
'int, symlink, const char* s, const char* f'
287 add_wrapper
'int, symlinkat, const char* s, int atfd, const char* f'
288 add_wrapper
'int, rename, const char* s, const char* f'
289 add_wrapper
'int, renameat, int atfds, const char* s, int atfd, const char* f'
290 add_wrapper
'int, renameat2, int atfds, const char* s, int atfd, const char* f, unsigned int flags'
292 add_wrapper
'int, utime, const char* f, const struct utimbuf* t'
293 add_wrapper
'int, utimes, const char* f, struct timeval* t'
294 add_wrapper
'int, utimensat, int atfd, const char* f, const struct timespec t[2], int flags'
296 add_wrapper
'int, execv, const char* f, char* const a[]'
297 add_wrapper
'int, execve, const char* f, char* const a[], char* const e[]'
300 cat misc
/tools-source
/fl_wrapper_execl.c
303 /* Internal Functions
*/
305 static void
* get_dl_symbol
(char
* symname
)
309 static void
* libc_handle
= 0;
311 if (!libc_handle
) libc_handle
=dlopen
(FLWRAPPER_LIBC
, RTLD_LAZY
);
313 fprintf
(stderr
, "fl_wrapper.so: Can't dlopen libc: %s\n", dlerror
()); fflush
(stderr
);
317 rc
= dlsym
(libc_handle
, symname
);
319 fprintf
(stderr
, "fl_wrapper.so debug [%d]: Symbol '%s' in libc (%p) has been resolved to %p.\n",
320 getpid
(), symname
, libc_handle
, rc
);
323 rc
= dlsym
(RTLD_NEXT
, symname
);
325 fprintf
(stderr
, "fl_wrapper.so debug [%d]: Symbol '%s' (RTLD_NEXT) has been resolved to %p.\n",
326 getpid
(), symname
, rc
);
330 fprintf
(stderr
, "fl_wrapper.so: Can't resolve %s: %s\n",
331 symname
, dlerror
()); fflush
(stderr
);
338 static pid_t pid2ppid
(pid_t pid
)
344 snprintf
(buffer
, sizeof
(buffer
), "/proc/%d/stat", pid
);
345 if ( (fd
= open
(buffer
, O_RDONLY
, 0)) < 0 ) return 0;
346 if ( (rc
= read(fd
, buffer
, sizeof
(buffer
))) > 0) {
348 /* format
: 27910 (bash
) S
27315 ...
*/
349 sscanf
(buffer
, "%*[^ ] %*[^ ] %*[^ ] %d", &ppid
);
356 /* this is only called from fl_wrapper_init
(). so it doesn
't need to be
358 static char *getpname(int pid)
365 snprintf(buffer, sizeof(buffer), "/proc/%d/cmdline", pid);
366 if ( (fd = open(buffer, O_RDONLY, 0)) < 0 ) return "unkown";
367 if ( (rc = read(fd, buffer, sizeof(buffer))) > 0) {
370 if (!buffer[i]) { arg = buffer+i+1; break; }
374 b = basename(buffer);
375 snprintf(p, 512, "%s", b);
377 if ( !strcmp(b, "bash") || !strcmp(b, "sh") || !strcmp(b, "perl") )
378 if (arg && *arg && *arg != '-')
379 snprintf(p, 512, "%s(%s)", b, basename(arg));
384 /* invert the order by recursion. there will be only one recursion tree
385 * so we can use a static var for managing the last ent */
386 static void addptree(int *txtpos, char *cmdtxt, int pid, int basepid)
388 static char l[512] = "";
391 if (!pid || pid == basepid) return;
393 addptree(txtpos, cmdtxt, pid2ppid(pid), basepid);
398 *txtpos += snprintf(cmdtxt+*txtpos, 4096-*txtpos, "%s%s",
399 *txtpos ? "." : "", getpname(pid));
401 *txtpos += snprintf(cmdtxt+*txtpos, 4096-*txtpos, "*");
406 void copy_getenv (char* var, const char* name)
408 char *c = getenv(name);
409 if (c) strcpy (var, c);
413 void __attribute__ ((constructor)) fl_wrapper_init()
415 char cmdtxt[4096] = "";
416 char *basepid_txt = getenv("FLWRAPPER_BASEPID");
417 int basepid = 0, txtpos=0;
420 basepid = atoi(basepid_txt);
422 addptree(&txtpos, cmdtxt, getpid(), basepid);
423 cmdname = strdup(cmdtxt);
425 /* we copy the vars, so evil code can not unset them ... e.g.
426 the perl/spamassassin build ... -ReneR */
427 copy_getenv(filterdir, "FLWRAPPER_FILTERDIR");
428 copy_getenv(wlog, "FLWRAPPER_WLOG");
429 copy_getenv(rlog, "FLWRAPPER_RLOG");
434 #ifdef FLWRAPPER_BASEDIR
435 static void check_write_access(const char * func, const char * file)
437 if (*file == '/') { /* do only check rooted paths */
438 while (file[1] == '/') file++;
440 if (!strcmp(file, "/dev/null") || !strncmp(file, "/tmp", 4)) {
442 else if (strncmp(file, FLWRAPPER_BASEDIR, sizeof(FLWRAPPER_BASEDIR)-1)) {
443 fprintf(stderr, "fl_wrapper.so: write outside basedir (%s): %s\n", FLWRAPPER_BASEDIR, file);
451 static void handle_file_access_before(const char * func, const char * file,
452 struct status_t * status)
456 if (!initialized) return;
458 fprintf(stderr, "fl_wrapper.so debug [%d]: begin of handle_file_access_before(\"%s\", \"%s\", ...)\n",
459 getpid(), func, file);
461 if ( lstat(file,&st) ) {
462 status->inode=0; status->size=0;
463 status->mtime=0; status->ctime=0;
465 status->inode=st.st_ino; status->size=st.st_size;
466 status->mtime=st.st_mtime; status->ctime=st.st_ctime;
469 fprintf(stderr, "fl_wrapper.so debug [%d]: end of handle_file_access_before(\"%s\", \"%s\", ...)\n",
470 getpid(), func, file);
474 /* sort of, private realpath, mostly not readlink() */
475 static void sort_of_realpath (const char *file, char absfile[PATH_MAX])
477 /* make sure the filename is absolute */
478 if (file[0] != '/') {
480 getcwd(cwd, PATH_MAX);
481 snprintf(absfile, PATH_MAX, "%s/%s", cwd, file);
485 const char* src = file; char* dst = absfile;
486 /* till the end, remove ./ and ../ parts */
487 while (dst < absfile + PATH_MAX && *src) {
488 if (*src == '/' && src[1] == '/')
489 while (src[1] == '/') src++;
490 else if (*src == '.
') {
491 if (src[1] == '.
' && (src[2] == '/' || src[2] == 0)) {
492 if (dst > absfile+1) --dst; /* jump to last '/' */
493 while (dst > absfile+1 && dst[-1] != '/')
495 src += 2; if (*src) src++;
496 while (*src == '/') src++;
499 else if (src[1] == '/' || src[1] == 0) {
500 src += 1; if (*src) src++;
501 while (*src == '/') src++;
508 /* remove trailing slashes */
509 while (--dst, dst > absfile+1 && *dst == '/')
513 static void handle_file_access_after(const char * func, const char * file,
514 struct status_t * status)
516 char buf[PATH_MAX], *logfile, filterdir2 [PATH_MAX], *tfilterdir;
517 char absfile [PATH_MAX];
518 int fd; struct stat st;
520 if (!initialized) return;
522 fprintf(stderr, "fl_wrapper.so debug [%d]: begin of handle_file_access_after(\"%s\", \"%s\", ...)\n",
523 getpid(), func, file);
525 if ( !strcmp(file, wlog) ) return;
526 if ( !strcmp(file, rlog) ) return;
527 if ( lstat(file, &st) ) return;
529 if ( (status != 0) && (status->inode != st.st_ino ||
530 status->size != st.st_size || status->mtime != st.st_mtime ||
531 status->ctime != st.st_ctime) ) { logfile = wlog; }
532 else { logfile = rlog; }
533 if ( logfile == 0 ) return;
535 /* make sure the filename is "canonical" */
536 sort_of_realpath (file, absfile);
538 /* We ignore access inside the collon seperated directory list
539 $FLWRAPPER_BASE, to keep the log smaller and reduce post
540 processing time. -ReneR */
541 strcpy (filterdir2, filterdir); /* due to strtok - sigh */
542 tfilterdir = strtok(filterdir2, ":");
543 for ( ; tfilterdir ; tfilterdir = strtok(NULL, ":") )
545 if ( !strncmp(absfile, tfilterdir, strlen(tfilterdir)) ) {
548 "fl_wrapper.so debug [%d]: \"%s\" dropped due to filterdir \"%s\"\n",
549 getpid(), absfile, tfilterdir);
555 #ifdef __USE_LARGEFILE
556 fd=open64(logfile,O_APPEND|O_WRONLY|O_LARGEFILE,0);
558 #warning "The wrapper library may not work properly for large logs!"
559 fd=open(logfile,O_APPEND|O_WRONLY,0);
561 if (fd == -1) return;
563 snprintf(buf,sizeof(buf), "%s.%s:\t%s\n", cmdname, func, absfile);
564 write(fd,buf,strlen(buf));
568 fprintf(stderr, "fl_wrapper.so debug [%d]: end of handle_file_access_after(\"%s\", \"%s\", ...)\n",
569 getpid(), func, file);