]> git.cworth.org Git - fips/blob - execute.c
Start wrapping OpenGL, and print periodic FPS value to stdout.
[fips] / execute.c
1 /* Copyright © 2013, Intel Corporation
2  *
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:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
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
19  * THE SOFTWARE.
20  */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include <string.h>
28 #include <errno.h>
29
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34
35 #include <talloc.h>
36
37 #include <linux/limits.h>
38
39 #include "execute.h"
40
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).
44  *
45  * Notes: A path containing no '/' character will not be modified.
46  *        A path consisting only of "/" will not be modified.
47  */
48 static void
49 chop_trailing_path_component (char *path)
50 {
51         char *slash;
52
53         slash = strrchr (path, '/');
54
55         if (slash == NULL)
56                 return;
57
58         if (slash == path)
59                 return;
60
61         *slash = '\0';
62 }
63
64 /* Find the absolute path of the currently executing binary.
65  *
66  * Returns: a string talloc'ed to 'ctx'
67  */
68 static char *
69 get_bin_name (void *ctx)
70 {
71         const char *link = "/proc/self/exe";
72         char *name;
73
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;
80
81         name = talloc_size (ctx, name_len - 1);
82         if (name == NULL) {
83                 fprintf (stderr, "Out of memory.\n");
84                 exit (1);
85         }
86
87         name_len = readlink (link, name, name_len);
88         if (name_len < 0) {
89                 fprintf (stderr, "Failed to readlink %s: %s\n", link,
90                          strerror (errno));
91                 exit (1);
92         }
93
94         name[name_len + 1] = '\0';
95
96         return name;
97 }
98
99 /* Does path exist? */
100 static int
101 exists (const char *path)
102 {
103         struct stat st;
104         int err;
105
106         err = stat (path, &st);
107
108         /* Failed to stat. It either doesn't exist, or might as well not. */
109         if (err == -1)
110                 return 0;
111
112         return 1;
113 }
114
115 /* Given "library" filename resolve it to an absolute path to an
116  * existing file as follows:
117  *
118  *   1. Look in same directory as current executable image
119  *
120  *      This is to support running from the source directory, without
121  *      having installed anything.
122  *
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).
126  *
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
132  *      correct.
133  *
134  * Returns: a string talloc'ed to 'ctx'
135  */
136 static char *
137 resolve_path (void *ctx, const char *library)
138 {
139         char *bin_path, *lib_path;
140
141         bin_path = get_bin_name (ctx);
142
143         chop_trailing_path_component (bin_path);
144
145         lib_path = talloc_asprintf(ctx, "%s/%s", bin_path, library);
146
147         if (exists (lib_path))
148                 return lib_path;
149
150         talloc_free (lib_path);
151
152         lib_path = talloc_asprintf(ctx, "%s/" BINDIR_TO_LIBFIPSDIR "/%s",
153                                    bin_path, library);
154
155         if (exists (lib_path))
156                 return lib_path;
157
158         fprintf (stderr, "Error: Failed to find library %s.\n", library);
159         fprintf (stderr, "Looked in both:\n"
160                  "\t%s\n"
161                  "and\n"
162                  "\t%s/" BINDIR_TO_LIBFIPSDIR "\n", bin_path, bin_path);
163         exit (1);
164 }
165
166 /* After forking, set LD_PRELOAD to preload "library" within child
167  * environment, then exec given arguments.
168  *
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. */
172 static int
173 fork_exec_with_preload_and_wait (char * const argv[], const char *library)
174 {
175         pid_t pid;
176         int i, status;
177
178         pid = fork ();
179
180         /* Child */
181         if (pid == 0) {
182                 void *ctx = talloc_new (NULL);
183                 char *lib_path;
184
185                 lib_path = resolve_path (ctx, library);
186
187                 setenv ("LD_PRELOAD", lib_path, 1);
188
189                 talloc_free (ctx);
190                 
191                 execvp (argv[0], argv);
192                 fprintf (stderr, "Failed to execute:");
193                 for (i = 0; argv[i]; i++) {
194                         fprintf (stderr, " %s", argv[i]);
195                 }
196                 fprintf (stderr, "\n");
197                 exit (1);
198         }
199
200         /* Parent */
201         waitpid (pid, &status, 0);
202         if (WIFEXITED (status)) {
203                 return (WEXITSTATUS (status));
204         }
205         if (WIFSIGNALED (status)) {
206                 fprintf (stderr, "Child terminated by signal %d\n",
207                          WTERMSIG (status));
208         }
209         return 1;
210 }
211
212 int
213 execute_with_preload (int argc, char * const argv[], const char *library)
214 {
215         char **execvp_args;
216         int i;
217
218         execvp_args = malloc((argc + 1) * sizeof(char *));
219         if (execvp_args == NULL) {
220                 fprintf (stderr, "Out of memory,\n");
221                 return 1;
222         }
223
224         for (i = 0; i < argc; i++) {
225                 execvp_args[i] = argv[i];
226         }
227
228         /* execvp needs final NULL */
229         execvp_args[i] = NULL;
230
231         return fork_exec_with_preload_and_wait (execvp_args, library);
232 }