3 # This shell-script genereates the fl_wrapper.c source file.
6 /* Wrapper for getting a list of created files.
8 * --- T2-COPYRIGHT-NOTE-BEGIN ---
9 * T2 SDE: misc/tools-source/fl_wrapper.c.sh
10 * Copyright (C) 2006 - 2023 René Rebe <rene@exactcode.de>
11 * Copyright (C) 2004 - 2024 The T2 SDE Project
12 * Copyright (C) 1998 - 2003 ROCK Linux Project
14 * This Copyright note is generated by scripts/Create-CopyPatch,
15 * more information can be found in the files COPYING and README.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License version 2.
19 * --- T2-COPYRIGHT-NOTE-END ---
21 * gcc -Wall -O2 -ldl -shared -o fl_wrapper.so fl_wrapper.c
23 * !!! THIS FILE IS AUTO-GENERATED BY $0 !!!
25 * ELF Dynamic Loading Documentation:
26 * - http://www.linuxdoc.org/HOWTO/GCC-HOWTO-7.html
27 * - http://www.educ.umu.se/~bjorn/mhonarc-files/linux-gcc/msg00576.html
28 * - /usr/include/dlfcn.h
32 /* Headers and prototypes */
36 #ifndef FLWRAPPER_LIBC
37 # define FLWRAPPER_LIBC "libc.so.6"
44 #define open64 xxx_open64
45 #define openat xxx_openat
46 #define openat64 xxx_openat64
47 #define mkfifo xxx_mkfifo
48 #define mknod xxx_mknod
49 #define __xmknod xxx___xmknod
51 #define _LARGEFILE_SOURCE
52 #define _LARGEFILE64_SOURCE
62 #include <sys/types.h>
67 /* somehow it can happen that PATH_MAX does not get defined...? -- jsaw */
69 #include <linux/limits.h>
72 #warning "PATH_MAX was not defined - BUG in your system headers?"
77 #undef _LARGEFILE64_SOURCE
78 #undef _LARGEFILE_SOURCE
90 static void * get_dl_symbol(char *);
99 static int initialized = 0;
101 #ifdef FLWRAPPER_BASEDIR
102 static void check_write_access(const char * , const char * );
104 static void handle_file_access_before(const char *, const char *, struct status_t *);
105 static void handle_file_access_after(const char *, const char *, struct status_t *);
107 char *cmdname = "unkown";
108 char wlog[PATH_MAX], rlog[PATH_MAX], filterdir[PATH_MAX], atpath[PATH_MAX];
110 const char* getatpath(int dirfd, const char* pathname) {
114 ret = snprintf(selffd, sizeof(selffd), "/proc/self/fd/%d", dirfd);
115 /* TODO: short buffer handling */
116 ret = readlink(selffd, atpath, sizeof(atpath) - 1);
118 fprintf(stderr, "Failed to get atpath: %d, %s\n", dirfd, pathname);
123 strncat(atpath, "/", sizeof(atpath) - 1);
124 strncat(atpath, pathname, sizeof(atpath) - 1);
125 /* TODO: short buffer handling */
130 /* Wrapper Functions */
133 # This has been made with cpp-macros before until they turned to be absolutely
138 line
="$( echo "$
*" | sed 's/ *, */,/g' )"
139 old_ifs
="$IFS" ; IFS
="," ; set $line ; IFS
="$old_ifs"
141 ret_type
=$1 ; shift ; function=$1 ; shift
142 p1
="" ; p2
="" ; for x
; do p1
="$p1$x, " ; done
143 for x
; do x
="${x%%\[*\]}" ; p2
="$p2${x##* }, " ; done
144 p1
="${p1%, }" ; p2
="${p2%, }"
146 # sanity check all new-style *at dirfd
150 if [[ "$x" = *atfd
]]; then
151 atcheck
="${atcheck}if (${x##* } != AT_FDCWD) {f2 = getatpath(${x##* }, f);}"
157 # remove varg from $p2
160 extern $ret_type $function($p1);
161 $ret_type (*orig_$function)($p1) = 0;
163 $ret_type $function($p1)
165 struct status_t status;
175 #ifdef FLWRAPPER_BASEDIR
176 if (a & (O_WRONLY|O_CREAT|O_APPEND))
177 check_write_access("$function", f2);
180 handle_file_access_before("$function", f2, &status);
181 if (!orig_$function) orig_$function = get_dl_symbol("$function");
185 fprintf(stderr, "fl_wrapper.so debug [%d]: going to run original $function() at %p (wrapper at %p).\n",
186 getpid(), orig_$function, $function);
193 b = va_arg(ap, mode_t);
196 rc = orig_$function($p2, b);
199 rc = orig_$function($p2);
202 handle_file_access_after("$function", f2, &status);
211 extern $ret_type $function($p1);
212 $ret_type (*orig_$function)($p1) = 0;
214 $ret_type $function($p1)
218 handle_file_access_after("$function", f, 0);
219 if (!orig_$function) orig_$function = get_dl_symbol("$function");
222 return orig_$function($p2);
228 extern $ret_type $function($p1);
229 $ret_type (*orig_$function)($p1) = 0;
231 $ret_type $function($p1)
233 struct status_t status;
242 handle_file_access_before("$function", f2, &status);
243 if (!orig_$function) orig_$function = get_dl_symbol("$function");
247 fprintf(stderr, "fl_wrapper.so debug [%d]: going to run original $function() at %p (wrapper at %p).\n",
248 getpid(), orig_$function, $function);
251 rc = orig_$function($p2);
254 handle_file_access_after("$function", f2, &status);
264 add_wrapper
'int, open, const char* f, int a, ...'
265 add_wrapper
'int, open64, const char* f, int a, ...'
266 add_wrapper
'int, openat, int atfd, const char* f, int a, ...'
267 add_wrapper
'int, openat64,int atfd, const char* f, int a, ...'
269 add_wrapper
'FILE*, fopen, const char* f, const char* g'
270 add_wrapper
'FILE*, fopen64, const char* f, const char* g'
272 add_wrapper
'int, creat, const char* f, mode_t m'
273 add_wrapper
'int, creat64, const char* f, mode_t m'
275 add_wrapper
'int, mkdir, const char* f, mode_t m'
276 add_wrapper
'int, mkfifo, const char* f, mode_t m'
277 add_wrapper
'int, mknod, const char* f, mode_t m, dev_t d'
278 add_wrapper
'int, __xmknod, int ver, const char* f, mode_t m, dev_t* d'
280 add_wrapper
'int, link, const char* s, const char* f'
281 add_wrapper
'int, linkat, int atfd, const char* s, int atfd2, const char* f, int flags'
283 add_wrapper
'int, symlink, const char* s, const char* f'
284 add_wrapper
'int, symlinkat, const char* s, int atfd, const char* f'
285 add_wrapper
'int, rename, const char* s, const char* f'
286 add_wrapper
'int, renameat, int atfds, const char* s, int atfd, const char* f'
287 add_wrapper
'int, renameat2, int atfds, const char* s, int atfd, const char* f, unsigned int flags'
289 add_wrapper
'int, utime, const char* f, const struct utimbuf* t'
290 add_wrapper
'int, utimes, const char* f, struct timeval* t'
291 add_wrapper
'int, utimensat, int atfd, const char* f, const struct timespec t[2], int flags'
293 add_wrapper
'int, execv, const char* f, char* const a[]'
294 add_wrapper
'int, execve, const char* f, char* const a[], char* const e[]'
297 cat misc
/tools-source
/fl_wrapper_execl.c
300 /* Internal Functions
*/
302 static void
* get_dl_symbol
(char
* symname
)
306 static void
* libc_handle
= 0;
308 if (!libc_handle
) libc_handle
=dlopen
(FLWRAPPER_LIBC
, RTLD_LAZY
);
310 fprintf
(stderr
, "fl_wrapper.so: Can't dlopen libc: %s\n", dlerror
()); fflush
(stderr
);
314 rc
= dlsym
(libc_handle
, symname
);
316 fprintf
(stderr
, "fl_wrapper.so debug [%d]: Symbol '%s' in libc (%p) has been resolved to %p.\n",
317 getpid
(), symname
, libc_handle
, rc
);
320 rc
= dlsym
(RTLD_NEXT
, symname
);
322 fprintf
(stderr
, "fl_wrapper.so debug [%d]: Symbol '%s' (RTLD_NEXT) has been resolved to %p.\n",
323 getpid
(), symname
, rc
);
327 fprintf
(stderr
, "fl_wrapper.so: Can't resolve %s: %s\n",
328 symname
, dlerror
()); fflush
(stderr
);
335 static pid_t pid2ppid
(pid_t pid
)
341 snprintf
(buffer
, sizeof
(buffer
), "/proc/%d/stat", pid
);
342 if ( (fd
= open
(buffer
, O_RDONLY
, 0)) < 0 ) return 0;
343 if ( (rc
= read(fd
, buffer
, sizeof
(buffer
))) > 0) {
345 /* format
: 27910 (bash
) S
27315 ...
*/
346 sscanf
(buffer
, "%*[^ ] %*[^ ] %*[^ ] %d", &ppid
);
353 /* this is only called from fl_wrapper_init
(). so it doesn
't need to be
355 static char *getpname(int pid)
362 snprintf(buffer, sizeof(buffer), "/proc/%d/cmdline", pid);
363 if ( (fd = open(buffer, O_RDONLY, 0)) < 0 ) return "unkown";
364 if ( (rc = read(fd, buffer, sizeof(buffer))) > 0) {
367 if (!buffer[i]) { arg = buffer+i+1; break; }
371 b = basename(buffer);
372 snprintf(p, sizeof(p), "%s", b);
374 if ( !strcmp(b, "bash") || !strcmp(b, "sh") || !strcmp(b, "perl") )
375 if (arg && *arg && *arg != '-')
376 snprintf(p, sizeof(p), "%s(%s)", b, basename(arg));
381 /* invert the order by recursion. there will be only one recursion tree
382 * so we can use a static var for managing the last ent */
383 static void addptree(int *txtpos, char *cmdtxt, int pid, int basepid)
385 static char l[512] = "";
388 if (!pid || pid == basepid) return;
390 addptree(txtpos, cmdtxt, pid2ppid(pid), basepid);
395 *txtpos += snprintf(cmdtxt+*txtpos, 4096-*txtpos, "%s%s",
396 *txtpos ? "." : "", getpname(pid));
398 *txtpos += snprintf(cmdtxt+*txtpos, 4096-*txtpos, "*");
403 void copy_getenv (char* s, const char* name, int maxlen, int term)
405 char* v = getenv(name);
408 char* send = s + maxlen;
410 s = stpncpy(s, v, maxlen);
412 fprintf(stderr, "fl_wrapper.so: env string too large: %s\n", v); fflush(stderr);
422 void __attribute__ ((constructor)) fl_wrapper_init()
424 char cmdtxt[4096] = "";
425 char *basepid_txt = getenv("FLWRAPPER_BASEPID");
427 int basepid = 0, txtpos=0;
430 basepid = atoi(basepid_txt);
432 addptree(&txtpos, cmdtxt, getpid(), basepid);
433 cmdname = strdup(cmdtxt);
435 /* we copy the vars, so evil code can not unset them ... e.g.
436 the perl/spamassassin build ... -ReneR */
437 copy_getenv(wlog, "FLWRAPPER_WLOG", sizeof(wlog), 0);
438 copy_getenv(rlog, "FLWRAPPER_RLOG", sizeof(rlog), 0);
439 copy_getenv(filterdir, "FLWRAPPER_FILTERDIR", sizeof(filterdir), 1);
441 /* split filterdir strings once at startup to 0 terminated list */
442 for (tfilterdir = strtok(filterdir, ":"); tfilterdir; tfilterdir = strtok(NULL, ":") ) {
448 #ifdef FLWRAPPER_BASEDIR
449 static void check_write_access(const char * func, const char * file)
451 if (*file == '/') { /* do only check rooted paths */
452 while (file[1] == '/') file++;
454 if (!strcmp(file, "/dev/null") ||
455 !strncmp(file, "/dev/fd/", 8) ||
456 !strncmp(file, "/tmp", 4)) {
458 else if (strncmp(file, FLWRAPPER_BASEDIR, sizeof(FLWRAPPER_BASEDIR)-1)) {
459 fprintf(stderr, "fl_wrapper.so: write outside basedir (%s): %s\n", FLWRAPPER_BASEDIR, file);
467 static void handle_file_access_before(const char * func, const char * file,
468 struct status_t * status)
472 if (!initialized) return;
474 fprintf(stderr, "fl_wrapper.so debug [%d]: begin of handle_file_access_before(\"%s\", \"%s\", ...)\n",
475 getpid(), func, file);
477 if ( lstat(file,&st) ) {
478 status->inode=0; status->size=0;
479 status->mtime=0; status->ctime=0;
481 status->inode=st.st_ino; status->size=st.st_size;
482 status->mtime=st.st_mtime; status->ctime=st.st_ctime;
485 fprintf(stderr, "fl_wrapper.so debug [%d]: end of handle_file_access_before(\"%s\", \"%s\", ...)\n",
486 getpid(), func, file);
490 /* sort of, private realpath, mostly not readlink() */
491 static void sort_of_realpath (const char *file, char absfile[PATH_MAX])
493 /* make sure the filename is absolute */
494 if (file[0] != '/') {
496 getcwd(cwd, PATH_MAX);
497 snprintf(absfile, PATH_MAX, "%s/%s", cwd, file);
501 const char* src = file; char* dst = absfile;
502 /* till the end, remove ./ and ../ parts */
503 while (dst < absfile + PATH_MAX && *src) {
504 if (*src == '/' && src[1] == '/')
505 while (src[1] == '/') src++;
506 else if (*src == '.
') {
507 if (src[1] == '.
' && (src[2] == '/' || src[2] == 0)) {
508 if (dst > absfile+1) --dst; /* jump to last '/' */
509 while (dst > absfile+1 && dst[-1] != '/')
511 src += 2; if (*src) src++;
512 while (*src == '/') src++;
515 else if (src[1] == '/' || src[1] == 0) {
516 src += 1; if (*src) src++;
517 while (*src == '/') src++;
524 /* remove trailing slashes */
525 while (--dst, dst > absfile+1 && *dst == '/')
529 static void handle_file_access_after(const char * func, const char * file,
530 struct status_t * status)
532 char buf[PATH_MAX], *logfile;
533 char absfile [PATH_MAX];
535 int fd, len; struct stat st;
537 if (!initialized) return;
539 fprintf(stderr, "fl_wrapper.so debug [%d]: begin of handle_file_access_after(\"%s\", \"%s\", ...)\n",
540 getpid(), func, file);
542 if ( !strcmp(file, wlog) ) return;
543 if ( !strcmp(file, rlog) ) return;
544 if ( lstat(file, &st) ) return;
546 if ( (status != 0) && (status->inode != st.st_ino ||
547 status->size != st.st_size || status->mtime != st.st_mtime ||
548 status->ctime != st.st_ctime) ) { logfile = wlog; }
549 else { logfile = rlog; }
550 if ( logfile == 0 ) return;
552 /* make sure the filename is "canonical" */
553 sort_of_realpath (file, absfile);
555 /* We ignore access inside the collon seperated directory list
556 $FLWRAPPER_BASE, to keep the log smaller and reduce post
557 processing time. -ReneR */
558 for (tfilterdir = filterdir; (len = strlen(tfilterdir)) > 0; tfilterdir += len + 1) {
559 if (!strncmp(absfile, tfilterdir, len)) {
562 "fl_wrapper.so debug [%d]: \"%s\" dropped due to filterdir \"%s\"\n",
563 getpid(), absfile, tfilterdir);
569 #ifdef __USE_LARGEFILE
570 fd=open64(logfile,O_APPEND|O_WRONLY|O_LARGEFILE,0);
572 #warning "The wrapper library may not work properly for large logs!"
573 fd=open(logfile,O_APPEND|O_WRONLY,0);
575 if (fd == -1) return;
577 snprintf(buf,sizeof(buf), "%s.%s:\t%s\n", cmdname, func, absfile);
578 write(fd,buf,strlen(buf));
582 fprintf(stderr, "fl_wrapper.so debug [%d]: end of handle_file_access_after(\"%s\", \"%s\", ...)\n",
583 getpid(), func, file);