1 /* Copyright © 2013, Intel Corporation
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 #include <sys/types.h>
37 #include <linux/limits.h>
41 /* Terminate a string representing a filename at the final '/' to
42 * eliminate the final filename component, (leaving only the directory
43 * portions of the original path).
45 * Notes: A path containing no '/' character will not be modified.
46 * A path consisting only of "/" will not be modified.
49 chop_trailing_path_component (char *path)
53 slash = strrchr (path, '/');
64 /* Find the absolute path of the currently executing binary.
66 * Returns: a string talloc'ed to 'ctx'
69 get_bin_name (void *ctx)
71 const char *link = "/proc/self/exe";
74 /* Yes, PATH_MAX is cheesy. I would have preferred to have
75 * used lstat and read the resulting st_size, but everytime I
76 * did that with /proc/self/exe I got a value of 0, (whereas
77 * with a "real" symbolic link I make myself I get the length
78 * of the filename being linked to). Go figure. */
79 int name_len = PATH_MAX + 1;
81 name = talloc_size (ctx, name_len - 1);
83 fprintf (stderr, "Out of memory.\n");
87 name_len = readlink (link, name, name_len);
89 fprintf (stderr, "Failed to readlink %s: %s\n", link,
94 name[name_len + 1] = '\0';
99 /* Does path exist? */
101 exists (const char *path)
106 err = stat (path, &st);
108 /* Failed to stat. It either doesn't exist, or might as well not. */
115 /* Given "library" filename resolve it to an absolute path to an
116 * existing file as follows:
118 * 1. Look in same directory as current executable image
120 * This is to support running from the source directory, without
121 * having installed anything.
123 * 2. Look in relative path from $(foo)/$(bindir) to
124 * $(foo)/$(libdir)/fips based on $(foo) from current executable
125 * image and configured $(bindir) and $(libdir).
127 * We do this rather than looking directly at the configured
128 * $(libdir) to support cases where the application may have been
129 * moved after being installed, (in particular, we want to be
130 * particularly careful not to mix one program with a different
131 * wrapper---so this "nearest search" should most often be
134 * Returns: a string talloc'ed to 'ctx'
137 resolve_path (void *ctx, const char *library)
139 char *bin_path, *lib_path;
141 bin_path = get_bin_name (ctx);
143 chop_trailing_path_component (bin_path);
145 lib_path = talloc_asprintf(ctx, "%s/%s", bin_path, library);
147 if (exists (lib_path))
150 talloc_free (lib_path);
152 lib_path = talloc_asprintf(ctx, "%s/" BINDIR_TO_LIBFIPSDIR "/%s",
155 if (exists (lib_path))
158 fprintf (stderr, "Error: Failed to find library %s.\n", library);
159 fprintf (stderr, "Looked in both:\n"
162 "\t%s/" BINDIR_TO_LIBFIPSDIR "\n", bin_path, bin_path);
166 /* After forking, set LD_PRELOAD to preload "library" within child
167 * environment, then exec given arguments.
169 * The "library" argument is the filename (without path) of a shared
170 * library to load. The complete path will be resolved with
171 * resolve_library_path above. */
173 fork_exec_with_preload_and_wait (char * const argv[], const char *library)
182 void *ctx = talloc_new (NULL);
185 lib_path = resolve_path (ctx, library);
187 setenv ("LD_PRELOAD", lib_path, 1);
191 execvp (argv[0], argv);
192 fprintf (stderr, "Failed to execute:");
193 for (i = 0; argv[i]; i++) {
194 fprintf (stderr, " %s", argv[i]);
196 fprintf (stderr, "\n");
201 waitpid (pid, &status, 0);
202 if (WIFEXITED (status)) {
203 return (WEXITSTATUS (status));
205 if (WIFSIGNALED (status)) {
206 fprintf (stderr, "Child terminated by signal %d\n",
213 execute_with_preload (int argc, char * const argv[], const char *library)
218 execvp_args = malloc((argc + 1) * sizeof(char *));
219 if (execvp_args == NULL) {
220 fprintf (stderr, "Out of memory,\n");
224 for (i = 0; i < argc; i++) {
225 execvp_args[i] = argv[i];
228 /* execvp needs final NULL */
229 execvp_args[i] = NULL;
231 return fork_exec_with_preload_and_wait (execvp_args, library);