summaryrefslogtreecommitdiff
path: root/quickexec/johns/qinit_srv.c
blob: 03c6cd39ec1f37de6a720b0379fcc4acb26c725b (plain)
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;
}