New exec(disco-t) for more flexible pnd exec. PXML may specify appdata dirname, and...
[pandora-libraries.git] / lib / pnd_apps.c
1
2 #include <stdio.h> /* for FILE etc */
3 #include <stdlib.h> /* for malloc */
4 #include <string.h> /* for memset */
5 #include <unistd.h> /* for fork/exec */
6 #include <limits.h>
7
8 #include <sys/types.h> /* for wait */
9 #include <sys/wait.h> /* for wait */
10
11 #include "pnd_container.h"
12 #include "pnd_pxml.h"
13 #include "pnd_apps.h"
14 #include "pnd_logger.h"
15
16 static char apps_exec_runline [ 1024 ];
17
18 char *pnd_apps_exec_runline ( void ) {
19   return ( apps_exec_runline );
20 }
21
22 unsigned char pnd_apps_exec_disco ( char *pndrun, pnd_disco_t *app,
23                                     unsigned int options, void *reserved )
24 {
25   char *argv [ 60 ];
26   char fullpath [ PATH_MAX ] = "";
27   int f;
28
29   //printf ( "Entering pnd_apps_exec\n" );
30
31   if ( ! pndrun ) {
32     return ( 0 );
33   }
34
35   if ( ! app -> unique_id ) {
36     return ( 0 );
37   }
38
39   if ( ! app -> exec ) {
40     return ( 0 );
41   }
42
43   // determine path to pnd-file
44   sprintf ( fullpath, "%s/%s", app -> object_path, app -> object_filename );
45
46   // nail down argv for the app
47   //
48   memset ( argv, '\0', sizeof(char*) * 20 );
49
50   f = 0;
51   argv [ f++ ] = pndrun;
52   argv [ f++ ] = "-p";
53   argv [ f++ ] = fullpath;
54   argv [ f++ ] = "-e";
55   argv [ f++ ] = app -> exec;
56   if ( app -> startdir ) {
57     argv [ f++ ] = "-s";
58     argv [ f++ ] = app -> startdir;
59   }
60   if ( app -> execargs ) {
61     argv [ f++ ] = "-a";
62     argv [ f++ ] = app -> execargs;
63   }
64   if ( app -> appdata_dirname ) {
65     argv [ f++ ] = "-b";
66     argv [ f++ ] = app -> appdata_dirname;
67   } else {
68     argv [ f++ ] = "-b";
69     argv [ f++ ] = app -> unique_id;
70   }
71   if ( app -> clockspeed ) {
72     argv [ f++ ] = "-c";
73     argv [ f++ ] = app -> clockspeed;
74   }
75
76   // skip -a (arguments) for now
77
78   if ( options & PND_EXEC_OPTION_NOUNION ) {
79     argv [ f++ ] = "-n"; // no union for now
80   }
81
82   if ( options & PND_EXEC_OPTION_NOX11 ) {
83     argv [ f++ ] = "-x"; // shut down X!
84   }
85
86   // finish
87   argv [ f++ ] = NULL; // for execv
88
89   // stop here?
90   if ( options & PND_EXEC_OPTION_NORUN ) {
91     unsigned char i;
92     bzero ( apps_exec_runline, 1024 );
93     //pnd_log ( PND_LOG_DEFAULT, "Norun %u\n", f );
94     unsigned char quotenext = 0;
95     for ( i = 0; i < ( f - 1 ); i++ ) {
96       //pnd_log ( PND_LOG_DEFAULT, "Norun %u: %s\n", i, argv [ i ] );
97
98       // add spacing between args
99       if ( i > 0 ) {
100         strncat ( apps_exec_runline, " ", 1000 );
101       }
102
103       // quoting
104       if ( quotenext ) {
105         strncat ( apps_exec_runline, "\"", 1000 );
106       }
107
108       // arg
109       strncat ( apps_exec_runline, argv [ i ], 1000 );
110
111       // unquoting
112       if ( quotenext ) {
113         strncat ( apps_exec_runline, "\"", 1000 );
114       }
115
116       // clear quoting
117       if ( quotenext ) {
118         quotenext = 0;
119       } else {
120         // if this is for -a, we need to wrap with quotes
121         if ( strcmp ( argv [ i ], "-a" ) == 0 ) {
122           quotenext = 1;
123         }
124       }
125
126     } // for
127     return ( 1 );
128   }
129
130   // debug
131 #if 0
132   int i;
133   for ( i = 0; i < f; i++ ) {
134     printf ( "exec's argv %u [ %s ]\n", i, argv [ i ] );
135   }
136 #endif
137
138   // invoke it!
139
140   if ( ( f = fork() ) < 0 ) {
141     // error forking
142   } else if ( f > 0 ) {
143     // parent
144   } else {
145     // child, do it
146     execv ( pndrun, argv );
147   } 
148
149   // by definition, either error occurred or we are the original application.
150
151   // do we wish to wait until the child process completes? (we don't
152   // care if it crashed, was killed, was suspended, whatever.)
153   if ( options & PND_EXEC_OPTION_BLOCK ) {
154     int status = 0;
155     waitpid ( f, &status, 0 /* no options */ );
156     //wait ( &status );
157   }
158
159   // printf ( "Exiting pnd_apps_exec\n" );
160
161   return ( 1 );
162 }
163
164 unsigned char pnd_apps_exec ( char *pndrun, char *fullpath, char *unique_id,
165                               char *rel_exec, char *rel_startdir,
166                               char *args,
167                               unsigned int clockspeed, unsigned int options )
168 {
169   pnd_disco_t d;
170   bzero ( &d, sizeof(pnd_disco_t) );
171
172   char cpuspeed [ 10 ];
173   sprintf ( cpuspeed, "%u", clockspeed );
174
175   char hackpath [ PATH_MAX ];
176   strncpy ( hackpath, fullpath, PATH_MAX );
177   char *c = strrchr ( hackpath, '/' );
178   if ( c ) {
179     *c = '\0';
180     d.object_path = hackpath;
181     d.object_filename = c + 1;
182   } else {
183     d.object_path = fullpath;
184   }
185
186   d.unique_id = unique_id;
187   d.exec = rel_exec;
188   d.startdir = rel_startdir;
189   d.execargs = args;
190   if ( clockspeed ) {
191     d.clockspeed = cpuspeed;
192   } else {
193     d.clockspeed = NULL;
194   }
195
196   return ( pnd_apps_exec_disco ( pndrun, &d, options, NULL ) );
197 }
198
199 void pnd_get_ro_mountpoint ( char *fullpath, char *unique_id, char *r_mountpoint, unsigned int mountpoint_len ) {
200
201   if ( ! r_mountpoint ) {
202     return; // sillyness
203   }
204
205   snprintf ( r_mountpoint, mountpoint_len, "%s/%s/", PND_MOUNT_PATH, unique_id );
206
207   return;
208 }
209
210 unsigned char pnd_get_appdata_path ( char *fullpath, char *unique_id, char *r_path, unsigned int path_len ) {
211   // you know, determining the 'mount point' used is sort of a pain in the rear
212   // use df <file>, skip header line, grab first token. Cheap and should work.
213   // (Rather than just assume first two path chunks in path, say, which would be pretty darned
214   // accurate, but whose to say they're not using NFS or crazy mountpoints?)
215   FILE *df;
216   char cmdbuf [ 1024 ];
217
218   snprintf ( cmdbuf, 1023, "/bin/df %s", fullpath );
219
220   df = popen ( cmdbuf, "r" );
221
222   if ( ! df ) {
223     return ( 0 ); // tunefs: you can tune a filesystem but you can't tune a fish
224   }
225
226   // fetch and discard header
227   if ( ! fgets ( cmdbuf, 1023, df ) ) {
228     pclose ( df );
229     return ( 0 );
230   }
231
232   // grab df result line
233   if ( ! fgets ( cmdbuf, 1023, df ) ) {
234     pclose ( df );
235     return ( 0 );
236   }
237
238   pclose ( df );
239
240   // parse
241   char *ws = strchr ( cmdbuf, ' ' );
242
243   if ( ! ws ) {
244     return ( 0 );
245   }
246
247   *ws = '\0';
248
249   if ( r_path && path_len ) {
250     snprintf ( r_path, path_len, "%s/pandora/appdata/%s/", cmdbuf, unique_id );
251   }
252
253   return ( 1 );
254 }