c5eec2f43eafc0d2fbb2c655db858bcd2734c2b2
[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   if ( options & PND_EXEC_OPTION_INFO && ! reserved ) {
44     return ( 0 );
45   }
46
47   // determine path to pnd-file
48   sprintf ( fullpath, "%s/%s", app -> object_path, app -> object_filename );
49
50   // nail down argv for the app
51   //
52   memset ( argv, '\0', sizeof(char*) * 20 );
53
54   f = 0;
55   argv [ f++ ] = pndrun;
56   argv [ f++ ] = "-p";
57   argv [ f++ ] = fullpath;
58   argv [ f++ ] = "-e";
59   if ( options & PND_EXEC_OPTION_INFO ) {
60     argv [ f++ ] = ((pnd_apps_exec_info_t*)reserved) -> viewer;
61   } else {
62     argv [ f++ ] = app -> exec;
63   }
64   if ( app -> startdir ) {
65     argv [ f++ ] = "-s";
66     argv [ f++ ] = app -> startdir;
67   }
68   if ( options & PND_EXEC_OPTION_INFO ) {
69     if ( ((pnd_apps_exec_info_t*)reserved) -> args ) {
70       argv [ f++ ] = "-a";
71       argv [ f++ ] = ((pnd_apps_exec_info_t*)reserved) -> args;
72     }
73   } else {
74     if ( app -> execargs ) {
75       argv [ f++ ] = "-a";
76       argv [ f++ ] = app -> execargs;
77     }
78   }
79   if ( app -> appdata_dirname ) {
80     argv [ f++ ] = "-b";
81     argv [ f++ ] = app -> appdata_dirname;
82   } else {
83     argv [ f++ ] = "-b";
84     argv [ f++ ] = app -> unique_id;
85   }
86
87   if ( options & PND_EXEC_OPTION_INFO ) {
88     // we don't need to overclock for showing info :) do we? crazy active .js pages maybe?
89   } else {
90     if ( app -> clockspeed ) {
91       argv [ f++ ] = "-c";
92       argv [ f++ ] = app -> clockspeed;
93     }
94   }
95
96   // skip -a (arguments) for now
97
98   if ( options & PND_EXEC_OPTION_NOUNION ) {
99     argv [ f++ ] = "-n"; // no union for now
100   }
101
102   if ( options & PND_EXEC_OPTION_NOX11 ) {
103     argv [ f++ ] = "-x"; // shut down X!
104   }
105
106   // finish
107   argv [ f++ ] = NULL; // for execv
108
109   // stop here?
110   if ( options & PND_EXEC_OPTION_NORUN ) {
111     unsigned char i;
112     bzero ( apps_exec_runline, 1024 );
113     //pnd_log ( PND_LOG_DEFAULT, "Norun %u\n", f );
114     unsigned char quotenext = 0;
115     for ( i = 0; i < ( f - 1 ); i++ ) {
116       //pnd_log ( PND_LOG_DEFAULT, "Norun %u: %s\n", i, argv [ i ] );
117
118       // add spacing between args
119       if ( i > 0 ) {
120         strncat ( apps_exec_runline, " ", 1000 );
121       }
122
123       // quoting
124       if ( quotenext ) {
125         strncat ( apps_exec_runline, "\"", 1000 );
126       }
127
128       // arg
129       strncat ( apps_exec_runline, argv [ i ], 1000 );
130
131       // unquoting
132       if ( quotenext ) {
133         strncat ( apps_exec_runline, "\"", 1000 );
134       }
135
136       // clear quoting
137       if ( quotenext ) {
138         quotenext = 0;
139       } else {
140         // deprecated; need to handle spaces in some additional args
141         //   if ( strcmp ( argv [ i ], "-a" ) == 0 ) {
142         // if this is for -a, we need to wrap with quotes
143         // ivanovic:
144         // to allow spaces in filenames we have to add quotes around most terms!
145         // terms with quotes:
146         // -a additional arguments
147         // -p fullpath to pnd
148         // -e name of execuatable inside the pnd
149         // -s startdir
150         // -b name for the appdir
151
152         if ( ( strcmp ( argv [ i ], "-a" ) == 0 ) || 
153              ( strcmp ( argv [ i ], "-p" ) == 0 ) ||
154              ( strcmp ( argv [ i ], "-e" ) == 0 ) ||
155              ( strcmp ( argv [ i ], "-s" ) == 0 ) ||
156              ( strcmp ( argv [ i ], "-b" ) == 0 ) )
157         {
158           quotenext = 1;
159         }
160
161       }
162
163     } // for
164     return ( 1 );
165   }
166
167   // debug
168 #if 0
169   int i;
170   for ( i = 0; i < f; i++ ) {
171     printf ( "exec's argv %u [ %s ]\n", i, argv [ i ] );
172   }
173 #endif
174
175   // invoke it!
176
177   if ( ( f = fork() ) < 0 ) {
178     // error forking
179   } else if ( f > 0 ) {
180     // parent
181   } else {
182     // child, do it
183     execv ( pndrun, argv );
184   } 
185
186   // by definition, either error occurred or we are the original application.
187
188   // do we wish to wait until the child process completes? (we don't
189   // care if it crashed, was killed, was suspended, whatever.)
190   if ( options & PND_EXEC_OPTION_BLOCK ) {
191     int status = 0;
192     waitpid ( f, &status, 0 /* no options */ );
193     //wait ( &status );
194   }
195
196   // printf ( "Exiting pnd_apps_exec\n" );
197
198   return ( 1 );
199 }
200
201 unsigned char pnd_apps_exec ( char *pndrun, char *fullpath, char *unique_id,
202                               char *rel_exec, char *rel_startdir,
203                               char *args,
204                               unsigned int clockspeed, unsigned int options )
205 {
206   pnd_disco_t d;
207   bzero ( &d, sizeof(pnd_disco_t) );
208
209   char cpuspeed [ 10 ];
210   sprintf ( cpuspeed, "%u", clockspeed );
211
212   char hackpath [ PATH_MAX ];
213   strncpy ( hackpath, fullpath, PATH_MAX );
214   char *c = strrchr ( hackpath, '/' );
215   if ( c ) {
216     *c = '\0';
217     d.object_path = hackpath;
218     d.object_filename = c + 1;
219   } else {
220     d.object_path = fullpath;
221   }
222
223   d.unique_id = unique_id;
224   d.exec = rel_exec;
225   d.startdir = rel_startdir;
226   d.execargs = args;
227   if ( clockspeed ) {
228     d.clockspeed = cpuspeed;
229   } else {
230     d.clockspeed = NULL;
231   }
232
233   return ( pnd_apps_exec_disco ( pndrun, &d, options, NULL ) );
234 }
235
236 void pnd_get_ro_mountpoint ( char *fullpath, char *unique_id, char *r_mountpoint, unsigned int mountpoint_len ) {
237
238   if ( ! r_mountpoint ) {
239     return; // sillyness
240   }
241
242   snprintf ( r_mountpoint, mountpoint_len, "%s/%s/", PND_MOUNT_PATH, unique_id );
243
244   return;
245 }
246
247 unsigned char pnd_get_appdata_path ( char *fullpath, char *unique_id, char *r_path, unsigned int path_len ) {
248   // you know, determining the 'mount point' used is sort of a pain in the rear
249   // use df <file>, skip header line, grab first token. Cheap and should work.
250   // (Rather than just assume first two path chunks in path, say, which would be pretty darned
251   // accurate, but whose to say they're not using NFS or crazy mountpoints?)
252   FILE *df;
253   char cmdbuf [ 1024 ];
254
255   snprintf ( cmdbuf, 1023, "/bin/df %s", fullpath );
256
257   df = popen ( cmdbuf, "r" );
258
259   if ( ! df ) {
260     return ( 0 ); // tunefs: you can tune a filesystem but you can't tune a fish
261   }
262
263   // fetch and discard header
264   if ( ! fgets ( cmdbuf, 1023, df ) ) {
265     pclose ( df );
266     return ( 0 );
267   }
268
269   // grab df result line
270   if ( ! fgets ( cmdbuf, 1023, df ) ) {
271     pclose ( df );
272     return ( 0 );
273   }
274
275   pclose ( df );
276
277   // parse
278   char *ws = strchr ( cmdbuf, ' ' );
279
280   if ( ! ws ) {
281     return ( 0 );
282   }
283
284   *ws = '\0';
285
286   if ( r_path && path_len ) {
287     snprintf ( r_path, path_len, "%s/pandora/appdata/%s/", cmdbuf, unique_id );
288   }
289
290   return ( 1 );
291 }