1 /* Automatic generation of BuildRequires dependencies for rpmbuild.
2 * Copyright (C) 2008 Red Hat Inc.
3 * Written by Richard W.M. Jones <rjones@redhat.com>
4 * Patches from Rajeesh K Nambiar <rajeeshknambiar@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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.
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.
21 /* This is an LD_PRELOAD extension which logs accesses to any files by
22 * trapping access to any system calls which open files. Details of
23 * opened files are written to the file named in
24 * the AUTO_BUILDREQUIRES_LOGFILE environment variable.
33 #include <sys/types.h>
39 #include <gnu/lib-names.h>
41 #define ALIAS(ret,syscall,params,brfunc) \
42 extern ret syscall params __attribute__((alias (brfunc)))
44 static char *br_path (const char *path);
45 static void br_init (void) __attribute__((constructor));
46 static void br_log (const char *fs, ...) __attribute__((format (printf,1,2)));
48 /* These are the real glibc symbols, initialized in br_init. */
49 static int (*glibc_open) (const char *pathname, int flags, mode_t mode);
50 static int (*glibc_execve) (const char *filename, char *const argv[],
53 /* Canonicalize a relative or absolute path. If that isn't possible,
54 * return an absolute path.
56 * The caller must free the result.
59 br_path (const char *path)
64 if (path == NULL) return NULL;
67 rp = realpath (path, NULL);
68 if (!rp) rp = strdup (path);
72 dir = get_current_dir_name ();
73 if (dir == NULL) return NULL;
75 len = strlen (dir) + 1 + strlen (path) + 1;
86 rp = realpath (cat, NULL);
88 if (!rp) rp = cat; else free (cat);
93 abr_open (const char *pathname, int flags, mode_t mode)
98 /* Constructors in other libraries can call this function before
99 * br_init has been called. Detect this and call br_init to avoid a
102 if (glibc_open == NULL)
105 rp = br_path (pathname);
107 br_log ("open %s\n", rp);
112 fd = glibc_open (pathname, flags, mode);
116 ALIAS (int, open, (const char *, int, ...), "abr_open");
119 abr_execve (const char *filename, char *const argv[], char *const envp[])
124 /* Constructors in other libraries can call this function before
125 * br_init has been called. Detect this and call br_init to avoid a
128 if (glibc_open == NULL)
131 rp = br_path (filename);
133 br_log ("execve %s\n", rp);
138 r = glibc_execve (filename, argv, envp);
142 ALIAS (int, execve, (const char *filename, char *const argv[],
143 char *const envp[]), "abr_execve");
145 /* Other syscalls to consider:
153 * 'connect' params can contain a path in some rare circumstances.
156 /* This is the logging function. We have to be very cautious in this
157 * function and not disturb any part of the process (so far as that is
158 * possible). eg. When we open a file descriptor we must close it
161 * Any errors should either call abort() if they are serious, or
162 * return without harm if not.
164 * Also remember to call glibc_* for any syscalls that we are
165 * intercepting, otherwise you'll get an infinite loop.
168 br_log (const char *fs, ...)
170 const char *filename;
175 /* Got the logging environment variable? Should we cleanse this
176 * variable for security reasons, or is it not a problem because RPM
177 * specfiles can do arbitrary Bad Stuff already? (XXX)
179 filename = getenv ("AUTO_BUILDREQUIRES_LOGFILE");
180 if (filename == NULL) return;
182 fd = glibc_open (filename, O_WRONLY | O_APPEND, 0);
183 if (fd == -1) { perror ("open logfile"); abort (); }
185 /* Create the log string. */
187 len = vasprintf (&msg, fs, args);
189 perror ("vasprintf");
194 /* Write it in a single operation. Should be atomic, right?? (XXX) */
195 if (write (fd, msg, len) != len) {
207 _Atomic static void *dl;
209 if (dl != NULL) return;
211 dl = dlopen ("/lib64/" LIBC_SO, RTLD_LAZY|RTLD_LOCAL);
212 if (dl == NULL) // Try '/lib/' also
213 dl = dlopen("/lib/" LIBC_SO, RTLD_LAZY|RTLD_LOCAL);
215 fprintf (stderr, "%s\n", dlerror ());
218 glibc_open = dlsym (dl, "open");
219 glibc_execve = dlsym (dl, "execve");