Update runtime.c
[appimagekit/gsi.git] / runtime.c
blobbc835681e82cbb56087d7fe0f76f8647448d1b16
1 /**************************************************************************
3 Copyright (c) 2005-13 Simon Peter
4 Copyright (c) 2007 Alexander Larsson
6 All Rights Reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
26 **************************************************************************/
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <pthread.h>
37 #include <errno.h>
40 /* ======================================================== Start helper functions for icon extraction */
41 /*
42 Constructs the name of the thumbnail image for $HOME/.thumbnails for the executable that is itself
43 See http://people.freedesktop.org/~vuntz/thumbnail-spec-cache/
44 Partly borrowed from
45 http://www.google.com/codesearch#n76pnUnMG18/trunk/blender/imbuf/intern/thumbs.c&q=.thumbnails/normal%20lang:c%20md5&type=cs
48 #include "md5.h"
49 #include "md5.c"
50 #include <ctype.h>
51 #include <time.h>
53 #define FILE_MAX 240
54 #define URI_MAX FILE_MAX*3 + 8
56 /* --- begin of adapted code from glib ---
57 * The following code is adapted from function g_escape_uri_string from the gnome glib
58 * Source: http://svn.gnome.org/viewcvs/glib/trunk/glib/gconvert.c?view=markup
59 * released under the Gnu General Public License.
60 * NOTE THIS DOESN'T WORK PROPERLY FOR öäüß - FIXME
63 typedef enum {
64 UNSAFE_ALL = 0x1, /* Escape all unsafe characters */
65 UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */
66 UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
67 UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */
68 UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */
69 } UnsafeCharacterSet;
71 static const unsigned char acceptable[96] = {
72 /* A table of the ASCII chars from space (32) to DEL (127) */
73 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
74 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
75 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
76 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
77 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
78 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
81 static const char hex[17] = "0123456789abcdef";
83 void escape_uri_string (const char *string, char* escaped_string, int len,UnsafeCharacterSet mask)
85 #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
87 const char *p;
88 char *q;
89 int c;
90 UnsafeCharacterSet use_mask;
91 use_mask = mask;
93 for (q = escaped_string, p = string; (*p != '\0') && len; p++) {
94 c = (unsigned char) *p;
95 len--;
97 if (!ACCEPTABLE (c)) {
98 *q++ = '%'; /* means hex coming */
99 *q++ = hex[c >> 4];
100 *q++ = hex[c & 15];
101 } else {
102 *q++ = *p;
106 *q = '\0';
109 void to_hex_char(char* hexbytes, const unsigned char* bytes, int len)
111 const unsigned char *p;
112 char *q;
114 for (q = hexbytes, p = bytes; len; p++) {
115 const unsigned char c = (unsigned char) *p;
116 len--;
117 *q++ = hex[c >> 4];
118 *q++ = hex[c & 15];
122 /* --- end of adapted code from glib --- */
124 static int uri_from_filename( const char *dir, char *newuri )
126 char uri[URI_MAX];
127 sprintf (uri, "file://%s", dir);
128 char newstring[URI_MAX];
129 strncpy(newstring, uri, URI_MAX);
130 newstring[URI_MAX - 1] = 0;
131 unsigned int i = 0;
132 escape_uri_string(newstring, newuri, FILE_MAX*3+8, UNSAFE_PATH);
133 return 1;
137 static void thumbname_from_uri(const char* uri, char* thumb)
139 char hexdigest[33];
140 unsigned char digest[16];
141 md5_buffer( uri, strlen(uri), digest);
142 hexdigest[0] = '\0';
143 to_hex_char(hexdigest, digest, 16);
144 hexdigest[32] = '\0';
145 sprintf(thumb, "%s.png", hexdigest);
149 /* ======================================================== End helper functions for icon extraction */
151 extern int ext2_main(int argc, char *argv[], void (*mounted) (void));
152 extern void ext2_quit(void);
154 static pid_t fuse_pid;
155 static int keepalive_pipe[2];
157 static void *
158 write_pipe_thread (void *arg)
160 char c[32];
161 int res;
162 // sprintf(stderr, "Called write_pipe_thread");
163 memset (c, 'x', sizeof (c));
164 while (1) {
165 /* Write until we block, on broken pipe, exit */
166 res = write (keepalive_pipe[1], c, sizeof (c));
167 if (res == -1) {
168 kill (fuse_pid, SIGHUP);
169 break;
172 return NULL;
175 void
176 run_when_fuse_fs_mounted (void)
179 // sprintf(stderr, "Called run_when_fuse_fs_mounted");
180 pthread_t thread;
181 int res;
183 fuse_pid = getpid();
184 res = pthread_create(&thread, NULL, write_pipe_thread, keepalive_pipe);
187 char* getArg(int argc, char *argv[],char chr)
189 int i;
190 for (i=1; i<argc; ++i)
191 if ((argv[i][0]=='-') && (argv[i][1]==chr))
192 return &(argv[i][2]);
193 return NULL;
198 main (int argc, char *argv[])
200 int dir_fd, res;
201 char mount_dir[] = "/tmp/.mount_XXXXXX"; /* create mountpoint */
202 char filename[100]; /* enough for mount_dir + "/AppRun" */
203 pid_t pid;
204 char **real_argv;
205 int i;
207 // We are using glib anyway for fuseiso, so we can use it here too to make our life easier
208 char *xdg_cache_home;
209 char thumbnails_medium_dir[FILE_MAX];
210 xdg_cache_home = (getenv("XDG_CACHE_HOME") == NULL
211 ? g_build_filename(g_get_home_dir(), ".cache", NULL)
212 : g_strdup(getenv("XDG_CACHE_HOME")));
213 sprintf(thumbnails_medium_dir, "%s/thumbnails/normal/", xdg_cache_home);
214 /* printf("%s\n", thumbnails_medium_dir); */
216 if (mkdtemp(mount_dir) == NULL) {
217 exit (1);
220 if (pipe (keepalive_pipe) == -1) {
221 perror ("pipe error: ");
222 exit (1);
225 pid = fork ();
226 if (pid == -1) {
227 perror ("fork error: ");
228 exit (1);
231 if (pid == 0) {
232 /* in child */
234 char *child_argv[5];
236 /* close read pipe */
237 close (keepalive_pipe[0]);
240 char *dir = realpath( "/proc/self/exe", NULL );
242 child_argv[0] = dir;
243 child_argv[1] = mount_dir;
244 child_argv[2] = "-o";
245 child_argv[3] = "ro";
246 child_argv[4] = NULL;
248 ext2_main (4, child_argv, NULL);
249 } else {
250 /* in parent, child is $pid */
251 int c;
253 /* close write pipe */
254 close (keepalive_pipe[1]);
256 /* Pause until mounted */
257 read (keepalive_pipe[0], &c, 1);
260 dir_fd = open (mount_dir, O_RDONLY);
261 if (dir_fd == -1) {
262 // perror ("open dir error: ");
263 printf("Could not mount AppImage\n");
264 printf("Please see https://github.com/probonopd/AppImageKit/wiki/FUSE\n");
265 exit (1);
268 res = dup2 (dir_fd, 1023);
269 if (res == -1) {
270 perror ("dup2 error: ");
271 exit (1);
273 close (dir_fd);
275 strcpy (filename, mount_dir);
276 strcat (filename, "/AppRun");
278 real_argv = malloc (sizeof (char *) * (argc + 1));
279 for (i = 0; i < argc; i++) {
280 real_argv[i] = argv[i];
282 real_argv[i] = NULL;
286 /* ======================================================== Start icon extraction */
288 int length;
289 char fullpath[FILE_MAX];
290 length = readlink("/proc/self/exe", fullpath, sizeof(fullpath));
291 fullpath[length] = '\0';
292 /* printf("%s\n", fullpath); */
293 char theuri[URI_MAX];
294 uri_from_filename(fullpath, theuri);
295 /* printf("%s\n", theuri); */
296 char path_to_thumbnail[URI_MAX];
297 char thumbname[URI_MAX];
298 thumbname_from_uri(theuri, thumbname);
299 sprintf(path_to_thumbnail, "%s%s", thumbnails_medium_dir, thumbname);
301 FILE *from, *to;
302 char ch;
304 char diricon[FILE_MAX];
305 sprintf (diricon, "%s/.DirIcon", mount_dir);
307 /* open source file */
308 if((from = fopen(diricon, "rb"))==NULL) {
309 printf("Cannot open %s\n", diricon);
310 exit(1);
313 /* open destination file */
314 char mkcmd[FILE_MAX];
315 char iconsdir[FILE_MAX];
317 sprintf(mkcmd, "mkdir -p '%s'", thumbnails_medium_dir);
318 system(mkcmd);
319 if((to = fopen(path_to_thumbnail, "wb"))==NULL) {
320 printf("Cannot open %s for writing\n", path_to_thumbnail);
322 } else {
324 /* copy the file */
325 while(!feof(from)) {
326 ch = fgetc(from);
327 if(ferror(from)) {
328 printf("Error reading source file\n");
329 exit(1);
331 if(!feof(from)) fputc(ch, to);
332 if(ferror(to)) {
333 printf("Error writing destination file\n");
334 exit(1);
338 if(fclose(from)==EOF) {
339 printf("Error closing source file\n");
340 exit(1);
343 if(fclose(to)==EOF) {
344 printf("Error closing destination file\n");
345 exit(1);
349 /* If called with --icon, then do not run the main app, just print print a message and exit after extracting the icon */
350 char * arg;
351 arg=getArg(argc,argv,'-');
352 if (arg && strcmp(arg,"icon")==0) {
353 printf("Written %s\n", path_to_thumbnail);
354 exit(0);
357 /* ======================================================== End icon extraction */
359 /* Setting some environment variables that the app "inside" might use */
360 setenv( "APPIMAGE", fullpath, 0 );
361 setenv( "APPDIR", mount_dir, 0 );
362 execv (filename, real_argv);
363 /* Error if we continue here */
364 perror ("execv error: ");
365 exit (1);
368 return 0;