Update .travis.yml
[appimagekit/gsi.git] / runtime.c
blob2b7abaf6924451bbc9bcc92225d5bbe339e6a5d1
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 exit (1);
266 res = dup2 (dir_fd, 1023);
267 if (res == -1) {
268 perror ("dup2 error: ");
269 exit (1);
271 close (dir_fd);
273 strcpy (filename, mount_dir);
274 strcat (filename, "/AppRun");
276 real_argv = malloc (sizeof (char *) * (argc + 1));
277 for (i = 0; i < argc; i++) {
278 real_argv[i] = argv[i];
280 real_argv[i] = NULL;
284 /* ======================================================== Start icon extraction */
286 int length;
287 char fullpath[FILE_MAX];
288 length = readlink("/proc/self/exe", fullpath, sizeof(fullpath));
289 fullpath[length] = '\0';
290 /* printf("%s\n", fullpath); */
291 char theuri[URI_MAX];
292 uri_from_filename(fullpath, theuri);
293 /* printf("%s\n", theuri); */
294 char path_to_thumbnail[URI_MAX];
295 char thumbname[URI_MAX];
296 thumbname_from_uri(theuri, thumbname);
297 sprintf(path_to_thumbnail, "%s%s", thumbnails_medium_dir, thumbname);
299 FILE *from, *to;
300 char ch;
302 char diricon[FILE_MAX];
303 sprintf (diricon, "%s/.DirIcon", mount_dir);
305 /* open source file */
306 if((from = fopen(diricon, "rb"))==NULL) {
307 printf("Cannot open %s\n", diricon);
308 exit(1);
311 /* open destination file */
312 char mkcmd[FILE_MAX];
313 char iconsdir[FILE_MAX];
315 sprintf(mkcmd, "mkdir -p '%s'", thumbnails_medium_dir);
316 system(mkcmd);
317 if((to = fopen(path_to_thumbnail, "wb"))==NULL) {
318 printf("Cannot open %s for writing\n", path_to_thumbnail);
320 } else {
322 /* copy the file */
323 while(!feof(from)) {
324 ch = fgetc(from);
325 if(ferror(from)) {
326 printf("Error reading source file\n");
327 exit(1);
329 if(!feof(from)) fputc(ch, to);
330 if(ferror(to)) {
331 printf("Error writing destination file\n");
332 exit(1);
336 if(fclose(from)==EOF) {
337 printf("Error closing source file\n");
338 exit(1);
341 if(fclose(to)==EOF) {
342 printf("Error closing destination file\n");
343 exit(1);
347 /* If called with --icon, then do not run the main app, just print print a message and exit after extracting the icon */
348 char * arg;
349 arg=getArg(argc,argv,'-');
350 if (arg && strcmp(arg,"icon")==0) {
351 printf("Written %s\n", path_to_thumbnail);
352 exit(0);
355 /* ======================================================== End icon extraction */
357 /* Setting some environment variables that the app "inside" might use */
358 setenv( "APPIMAGE", fullpath, 0 );
359 setenv( "APPDIR", mount_dir, 0 );
360 execv (filename, real_argv);
361 /* Error if we continue here */
362 perror ("execv error: ");
363 exit (1);
366 return 0;