-rw-r--r-- | quickexec/johns/README | 21 | ||||
-rw-r--r-- | quickexec/johns/library.lst | 2 | ||||
-rw-r--r-- | quickexec/johns/qinit_srv.c | 242 | ||||
-rw-r--r-- | quickexec/johns/so_stub.c | 23 |
4 files changed, 288 insertions, 0 deletions
diff --git a/quickexec/johns/README b/quickexec/johns/README new file mode 100644 index 0000000..1af84dc --- a/dev/null +++ b/quickexec/johns/README | |||
@@ -0,0 +1,21 @@ | |||
1 | |||
2 | Compile qinit_srv.c to qinit_srv as usual | ||
3 | Compile your applications at shared libraries instead of as executables: | ||
4 | eg: gcc test.c -o test.so -shared | ||
5 | Make a symbolic link from qinit_srv to the name of the application: | ||
6 | eg: ln -s qinit_srv test | ||
7 | Now make sure 'test' (The symlink) and 'test.so' (the shared library version of the app) are together. | ||
8 | When you run ./test it will load test.so and run it just like you were running the application for real. | ||
9 | There will be a qinit_srv process created the first time you run a program this way. | ||
10 | |||
11 | How it works: | ||
12 | |||
13 | qinit_srv checks to see if there is already a server, if not it starts as a server which runs in the background as a deamon. | ||
14 | If it's a server it loads all the libraries listed in the library.lst file. | ||
15 | It then waits for signals to be sent to it which tell it to fork itself and load shared libraries and run them. | ||
16 | If it decides it's not the server, it sends a signal to the server to run the given command. | ||
17 | The server then executes a shared object file of whatever name the original process is invoked as (argv[0], the symlink trick) | ||
18 | The other process waits until the forked server finishes and signals the original process that it as finished and to return | ||
19 | |||
20 | |||
21 | |||
diff --git a/quickexec/johns/library.lst b/quickexec/johns/library.lst new file mode 100644 index 0000000..42f310b --- a/dev/null +++ b/quickexec/johns/library.lst | |||
@@ -0,0 +1,2 @@ | |||
1 | libqte.so | ||
2 | libqpe.so | ||
diff --git a/quickexec/johns/qinit_srv.c b/quickexec/johns/qinit_srv.c new file mode 100644 index 0000000..03c6cd3 --- a/dev/null +++ b/quickexec/johns/qinit_srv.c | |||
@@ -0,0 +1,242 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <stdio.h> | ||
3 | #include <signal.h> | ||
4 | #include <unistd.h> | ||
5 | #include <dlfcn.h> | ||
6 | |||
7 | |||
8 | #define PID_FILE "/tmp/qinit1.pid" | ||
9 | #define CMD_FILE "/tmp/qinit1.cmd" | ||
10 | #define RET_FILE "/tmp/qinit1.ret" | ||
11 | |||
12 | |||
13 | static int librariesFinishedLoading = 0; | ||
14 | static void **handles = NULL; | ||
15 | static int handleCount = 0; | ||
16 | |||
17 | |||
18 | static void savePid( void ); | ||
19 | static int loadPid( void ); | ||
20 | void saveRetVal( int retVal ); | ||
21 | int loadRetVal( void ); | ||
22 | static void saveCmd( int callingPid, int argc, char *argv[] ); | ||
23 | static int execCmd( void ); | ||
24 | static void loadLibraries( char *listFile ); | ||
25 | static void signalHandler( int signal ); | ||
26 | static void finishedHandler( int signal ); | ||
27 | static void cleanUpHandler( int signal ); | ||
28 | static void cleanUp( void ); | ||
29 | |||
30 | |||
31 | int main( int argc, char *argv[] ) { | ||
32 | FILE *fh; | ||
33 | |||
34 | // See if there is already a server running | ||
35 | if ( ( fh = fopen( PID_FILE, "r" ) ) != NULL ) { | ||
36 | // There appears to already be a server running | ||
37 | fclose( fh ); | ||
38 | // Install handler that tells us when the process created by the server has finished | ||
39 | signal( SIGUSR2, finishedHandler ); | ||
40 | // Send our command to the server (saved to a file) | ||
41 | saveCmd( getpid(), argc, argv ); | ||
42 | // Send a signal to the server to run our command | ||
43 | kill( loadPid(), SIGUSR1 ); | ||
44 | // Wait for the process created by the server to terminate | ||
45 | for (;;) | ||
46 | sleep( 1 ); // Will eventually terminate when the SIGUSER2 signal is sent to us by the server | ||
47 | } | ||
48 | |||
49 | // Send the server to the background | ||
50 | daemon( 1, 1 ); | ||
51 | |||
52 | // Save the process number of this process somewhere (in a file) | ||
53 | savePid(); | ||
54 | |||
55 | // Wait for signal used to let us know when to fork to run commands | ||
56 | signal( SIGUSR1, signalHandler ); | ||
57 | signal( SIGTERM, cleanUpHandler ); | ||
58 | signal( SIGINT, cleanUpHandler ); | ||
59 | signal( SIGABRT, cleanUpHandler ); | ||
60 | signal( SIGQUIT, cleanUpHandler ); | ||
61 | |||
62 | // Iterate library list file and dynamically load at runtime | ||
63 | // the library files from the list | ||
64 | if ( argc > 1 ) | ||
65 | loadLibraries( argv[1] ); // Use a library list file specified from command line | ||
66 | else | ||
67 | loadLibraries( "library.lst" ); // Use the default library list file | ||
68 | |||
69 | // Run the given command | ||
70 | signalHandler( SIGUSR1 ); | ||
71 | |||
72 | // Keep waiting for signals infinitely that tell us to fork | ||
73 | for (;;) | ||
74 | wait( NULL ); // Wait for child processes to die or signals to be sent to us | ||
75 | |||
76 | cleanUp(); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | |||
82 | void cleanUp( void ) { | ||
83 | int i; | ||
84 | |||
85 | // Close the shared libraries we opened | ||
86 | for ( i = 0; i < handleCount; i++ ) | ||
87 | dlclose( handles[ i ] ); | ||
88 | free( handles ); | ||
89 | |||
90 | // Unlink the PID_FILE file | ||
91 | remove( PID_FILE ); | ||
92 | } | ||
93 | |||
94 | |||
95 | void savePid( void ) { | ||
96 | int pid = getpid(); | ||
97 | FILE *fh = fopen( PID_FILE, "w"); | ||
98 | if ( !fh ) | ||
99 | fputs("error writing pid to file " PID_FILE, stderr), exit(1); | ||
100 | fprintf( fh, "%i", pid ); | ||
101 | fclose( fh ); | ||
102 | } | ||
103 | |||
104 | |||
105 | int loadPid( void ) { | ||
106 | int pid; | ||
107 | FILE *fh = fopen( PID_FILE, "r" ); | ||
108 | if ( !fh ) | ||
109 | fputs("error loading pid from file " PID_FILE, stderr), exit(1); | ||
110 | fscanf( fh, "%i", &pid ); | ||
111 | fclose( fh ); | ||
112 | return pid; | ||
113 | } | ||
114 | |||
115 | |||
116 | void saveRetVal( int retVal ) { | ||
117 | FILE *fh = fopen( RET_FILE, "w"); | ||
118 | if ( !fh ) | ||
119 | fputs("error writing retVal to file " RET_FILE, stderr), exit(1); | ||
120 | fprintf( fh, "%i", retVal ); | ||
121 | fclose( fh ); | ||
122 | } | ||
123 | |||
124 | |||
125 | int loadRetVal( void ) { | ||
126 | int retVal; | ||
127 | FILE *fh = fopen( RET_FILE, "r" ); | ||
128 | if ( !fh ) | ||
129 | fputs("error loading retVal from file " RET_FILE, stderr), exit(1); | ||
130 | fscanf( fh, "%i", &retVal ); | ||
131 | fclose( fh ); | ||
132 | return retVal; | ||
133 | } | ||
134 | |||
135 | |||
136 | void saveCmd( int callingPid, int argc, char *argv[] ) { | ||
137 | int i; | ||
138 | FILE *fh = fopen( CMD_FILE, "w" ); | ||
139 | if ( !fh ) | ||
140 | fputs("error saving arg list to file " CMD_FILE, stderr), exit(1); | ||
141 | fprintf( fh, "%i\n", callingPid ); | ||
142 | fprintf( fh, "%s.so", argv[0] ); | ||
143 | for ( i = 0; i < argc; i++ ) | ||
144 | fprintf( fh, "\n%s", argv[i] ); | ||
145 | fclose( fh ); | ||
146 | } | ||
147 | |||
148 | |||
149 | int execCmd( void ) { | ||
150 | int callingPid; | ||
151 | char sharedObject[128]; | ||
152 | int argc; | ||
153 | char argv[128][128]; | ||
154 | int (*childMain)( int argc, char *argv[] ); | ||
155 | char *error; | ||
156 | void *handle; | ||
157 | int retVal = 0; | ||
158 | |||
159 | // Get the name of the file to dlopen and the arguments to pass (from a file) | ||
160 | FILE *fh = fopen( CMD_FILE, "r" ); | ||
161 | fscanf( fh, "%i\n", &callingPid ); | ||
162 | fgets( sharedObject, 128, fh ); | ||
163 | sharedObject[strlen( sharedObject ) - 1] = '\0'; | ||
164 | for ( argc = 0; fgets( argv[argc], 128, fh ); argc++) | ||
165 | argv[argc][strlen( argv[argc] ) - 1] = '\0'; | ||
166 | fclose( fh ); | ||
167 | |||
168 | // Open the shared object of what we want to execute | ||
169 | handle = dlopen( sharedObject, RTLD_LAZY ); | ||
170 | if ( !handle ) | ||
171 | fputs( dlerror(), stderr ), kill( callingPid, SIGUSR2 ), exit( 1 ); | ||
172 | |||
173 | // Find main symbol and jump to it | ||
174 | childMain = dlsym( handle, "main" ); | ||
175 | if ( ( error = dlerror() ) != NULL ) | ||
176 | fputs( error, stderr ), kill( callingPid, SIGUSR2 ), exit( 1 ); | ||
177 | retVal = (*childMain)( argc, (char**)argv ); | ||
178 | |||
179 | // Notify caller that we have finished | ||
180 | saveRetVal( retVal ); | ||
181 | kill( callingPid, SIGUSR2 ); | ||
182 | |||
183 | // When we are done, close the shared object | ||
184 | dlclose( handle ); | ||
185 | return retVal; | ||
186 | } | ||
187 | |||
188 | |||
189 | void finishedHandler( int signal ) { | ||
190 | // We have been notified of the completion of the task | ||
191 | exit( loadRetVal() ); | ||
192 | } | ||
193 | |||
194 | |||
195 | void cleanUpHandler( int signal ) { | ||
196 | // Cleanup and exit if we have been told to quit | ||
197 | cleanUp(); | ||
198 | exit(1); | ||
199 | } | ||
200 | |||
201 | |||
202 | void signalHandler( int signal ) { | ||
203 | //printf("got a signal of %i\n", signal ); | ||
204 | |||
205 | if ( fork() == 0 ) { | ||
206 | // We are the child process | ||
207 | |||
208 | /* | ||
209 | while ( librariesFinishedLoading != 1 ) { | ||
210 | printf("waiting for libraries to load\n"); | ||
211 | sleep(1); | ||
212 | } | ||
213 | */ | ||
214 | // Close file handles and open others etc | ||
215 | |||
216 | // Execute the command and return when done | ||
217 | exit( execCmd() ); | ||
218 | } | ||
219 | |||
220 | // Parent process, just continue | ||
221 | sleep( 1 ); // Need to yield to child process | ||
222 | } | ||
223 | |||
224 | |||
225 | void loadLibraries( char *listFile ) { | ||
226 | FILE *fh = fopen( listFile, "r" ); | ||
227 | char line[1024]; | ||
228 | if ( !fh ) | ||
229 | fputs("error opening library list file", stderr), exit(1); | ||
230 | while ( fgets( line, 1024, fh ) ) { | ||
231 | line[strlen( line ) - 1] = '\0'; | ||
232 | printf("loading library: --%s--\n", line); | ||
233 | handleCount++; | ||
234 | handles = realloc( handles, handleCount * sizeof( void * ) ); | ||
235 | handles[ handleCount - 1 ] = dlopen( line, RTLD_NOW ); | ||
236 | if ( !handles[ handleCount - 1 ] ) | ||
237 | fputs( dlerror(), stderr ), exit( 1 ); | ||
238 | } | ||
239 | fclose( fh ); | ||
240 | librariesFinishedLoading = 1; | ||
241 | } | ||
242 | |||
diff --git a/quickexec/johns/so_stub.c b/quickexec/johns/so_stub.c new file mode 100644 index 0000000..fe71f9c --- a/dev/null +++ b/quickexec/johns/so_stub.c | |||
@@ -0,0 +1,23 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <dlfcn.h> | ||
4 | |||
5 | |||
6 | int main( int argc, char *argv[] ) { | ||
7 | char module[1024]; | ||
8 | int (*loadedMain)( int argc, char *argv[] ); | ||
9 | char *error; | ||
10 | int retVal = 0; | ||
11 | void *handle; | ||
12 | strcpy( module, argv[0] ); | ||
13 | strcat( module, ".so" ); | ||
14 | if ( !(handle = dlopen( module, RTLD_LAZY ) ) ) | ||
15 | fputs( dlerror(), stderr ), exit( 1 ); | ||
16 | loadedMain = dlsym( handle, "main" ); | ||
17 | if ( ( error = dlerror() ) != NULL ) | ||
18 | fputs( error, stderr ), exit( 1 ); | ||
19 | retVal = (*loadedMain)( argc, argv ); | ||
20 | dlclose( handle ); | ||
21 | return retVal; | ||
22 | } | ||
23 | |||