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