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