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