ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Urlader/urlader.c
Revision: 1.13
Committed: Tue Jan 17 18:38:37 2012 UTC (12 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +36 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.13 /*
2     * Copyright (c) 2012 Marc Alexander Lehmann <schmorp@schmorp.de>
3     *
4     * Redistribution and use in source and binary forms, with or without modifica-
5     * tion, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright notice,
8     * this list of conditions and the following disclaimer.
9     *
10     * 2. Redistributions in binary form must reproduce the above copyright
11     * notice, this list of conditions and the following disclaimer in the
12     * documentation and/or other materials provided with the distribution.
13     *
14     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
16     * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17     * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
18     * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
22     * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23     * OF THE POSSIBILITY OF SUCH DAMAGE.
24     *
25     * Alternatively, the contents of this file may be used under the terms of
26     * the GNU General Public License ("GPL") version 2 or any later version,
27     * in which case the provisions of the GPL are applicable instead of
28     * the above. If you wish to allow the use of your version of this file
29     * only under the terms of the GPL and not to allow others to use your
30     * version of this file under the BSD license, indicate your decision
31     * by deleting the provisions above and replace them with the notice
32     * and other provisions required by the GPL. If you do not delete the
33     * provisions above, a recipient may use your version of this file under
34     * either the BSD or the GPL.
35     */
36    
37 root 1.9 #include "urlib.h"
38 root 1.8 #include "urlib.c"
39 root 1.6
40 root 1.1 #include <stdio.h>
41     #include <stdlib.h>
42     #include <unistd.h>
43     #include <errno.h>
44     #include <string.h>
45     #include <time.h>
46    
47 root 1.2 #include "liblzf/lzf_d.c"
48 root 1.1
49 root 1.6 /* some simple? dynamic memory management for paths might save ltos of ram */
50 root 1.1 static u_handle pack_handle;
51 root 1.6 static u_handle lock_handle;
52 root 1.1 static char tmppath[MAX_PATH];
53    
54     static int exe_argc;
55 root 1.12 static u_dynbuf exe_argv;
56     static u_dynbuf exe_args; /* actual arguments strings copied here */
57 root 1.1
58     static void
59     tmpdir (const char *dir)
60     {
61     static int cnt;
62    
63     for (;;)
64     {
65     // #ifdef _WIN32
66     // sprintf (tmppath, "%s/%x_%x.tmp", dir, (unsigned int)GetCurrentProcessId (), ++cnt);
67     // #else
68     sprintf (tmppath, "%s/t-%x_%x.tmp", dir, (unsigned int)getpid () , ++cnt);
69     // #endif
70    
71     if (!u_mkdir (tmppath))
72     return;
73     }
74     }
75    
76     static void
77 root 1.6 systemv (const char *const argv[])
78 root 1.1 {
79     #ifdef _WIN32
80     _spawnv (P_WAIT, argv [0], argv);
81     #else
82 root 1.6 pid_t pid = fork ();
83 root 1.1
84     if (pid < 0)
85 root 1.9 u_fatal ("fork failure");
86 root 1.1
87     if (!pid)
88     {
89     execv (argv [0], (void *)argv);
90     _exit (124);
91     }
92    
93     int status;
94     waitpid (pid, &status, 0);
95     #endif
96     }
97    
98     static void
99     deltree (const char *path)
100     {
101     #ifdef _WIN32
102     char buf[MAX_PATH * 2 + 64];
103     const char *argv[] = { getenv ("COMSPEC"), "/c", "rd", "/s", "/q", buf, 0 };
104     sprintf (buf, "\"%s\"", path);
105     #else
106     const char *argv[] = { "/bin/rm", "-rf", path, 0 };
107     #endif
108 root 1.6 systemv (argv);
109 root 1.1 }
110    
111     static char *pack_base, *pack_end;
112 root 1.12 static struct u_pack_tail *pack_tail;
113 root 1.8 static struct u_pack_hdr *pack_cur;
114 root 1.2 static char *scratch;
115 root 1.6 static unsigned int scratch_size;
116 root 1.1
117     #define PACK_NAME ((char *)(pack_cur + 1))
118     #define PACK_DATA (PACK_NAME + u_16 (pack_cur->namelen) + 1)
119     #define PACK_VALID pack_cur->type
120    
121     static void
122     pack_next (void)
123     {
124     unsigned int d = u_32 (pack_cur->datalen);
125    
126 root 1.8 pack_cur = (struct u_pack_hdr *)(PACK_DATA + d);
127 root 1.1 }
128    
129     static void
130     pack_unmap (void)
131     {
132 root 1.6 if (pack_base)
133     {
134     u_munmap (pack_base, pack_end - pack_base);
135     pack_base = 0;
136     }
137 root 1.1
138 root 1.6 if (scratch)
139     {
140     u_free (scratch, scratch_size);
141     scratch = 0;
142     }
143 root 1.1 }
144    
145     static int
146     pack_map (void)
147     {
148 root 1.6 char *addr;
149     unsigned int size;
150    
151 root 1.1 #ifdef _WIN32
152     BY_HANDLE_FILE_INFORMATION fi;
153    
154     if (!GetFileInformationByHandle (pack_handle, &fi))
155     return 0;
156    
157 root 1.6 size = fi.nFileSizeLow;
158     #else
159     size = lseek (pack_handle, 0, SEEK_END);
160     #endif
161 root 1.1
162 root 1.6 addr = u_mmap (pack_handle, size);
163     if (!addr)
164 root 1.1 return 0;
165    
166 root 1.12 /*pack_unmap ();*/
167 root 1.1
168 root 1.6 pack_base = addr;
169     pack_end = pack_base + size;
170 root 1.1
171 root 1.12 pack_tail = (void *)(pack_end - sizeof (*pack_tail));
172    
173     if (memcmp (pack_tail->magic, TAIL_MAGIC, sizeof (TAIL_MAGIC) - 1))
174     return 0;
175 root 1.1
176 root 1.12 pack_cur = (struct u_pack_hdr *)(pack_end - u_32 (pack_tail->size));
177 root 1.1
178 root 1.12 if (pack_cur->type != T_META)
179 root 1.1 return 0;
180    
181 root 1.12 scratch = u_malloc (scratch_size = u_32 (pack_tail->max_uncompressed));
182 root 1.6 if (!scratch)
183     return 0;
184 root 1.2
185 root 1.1 return 1;
186     }
187    
188     static void
189 root 1.12 add_arg (char *arg, unsigned int len)
190 root 1.1 {
191 root 1.12 char *addr = u_dynbuf_append (&exe_args, arg, len);
192     u_dynbuf_append (&exe_argv, &addr, sizeof (addr));
193 root 1.1 }
194    
195     static void
196     load (void)
197     {
198 root 1.12 strcpy (exe_id , PACK_NAME);
199     strcpy (exe_ver, PACK_DATA);
200     u_set_exe_info ();
201    
202 root 1.1 if (u_chdir (exe_dir))
203 root 1.9 u_fatal ("unable to change to application data directory");
204 root 1.1
205     u_handle h = u_open ("override");
206 root 1.5 if (u_valid (h))
207 root 1.1 {
208     u_handle oh = pack_handle;
209    
210 root 1.12 pack_unmap ();
211 root 1.1 pack_handle = h;
212 root 1.12
213     if (pack_map ()
214     && strcmp (exe_id , PACK_NAME) == 0
215     && strcmp (exe_ver, PACK_DATA) <= 0)
216 root 1.11 u_setenv ("URLADER_OVERRIDE", "override");
217     else
218 root 1.1 {
219 root 1.12 pack_unmap ();
220 root 1.1 pack_handle = oh;
221     oh = h;
222 root 1.12 pack_map ();
223 root 1.1 }
224    
225     u_close (oh);
226     }
227    
228     strcpy (exe_ver, PACK_DATA);
229 root 1.9 u_set_exe_info ();
230 root 1.1 pack_next ();
231    
232 root 1.4 for (;;)
233 root 1.1 {
234 root 1.9 if (pack_cur->type == T_ENV)
235 root 1.4 u_setenv (PACK_NAME, PACK_DATA);
236 root 1.9 else if (pack_cur->type == T_ARG)
237 root 1.12 add_arg (PACK_NAME, u_16 (pack_cur->namelen) + 1);
238 root 1.4 else
239     break;
240 root 1.1
241     pack_next ();
242     }
243 root 1.4
244     done_env_arg:
245 root 1.1
246 root 1.6 strcat (strcpy (tmppath, execdir), ".lck");
247 root 1.7 lock_handle = u_lock (tmppath, 0, 1);
248 root 1.6 if (!lock_handle)
249 root 1.9 u_fatal ("unable to lock application instance");
250 root 1.6
251 root 1.1 if (access (execdir, F_OK))
252     {
253     // does not exist yet, so unpack and move
254     tmpdir (exe_dir);
255    
256     if (u_chdir (tmppath))
257 root 1.9 u_fatal ("unable to change to new instance directory");
258 root 1.1
259     for (;;)
260     {
261     switch (pack_cur->type)
262     {
263 root 1.9 case T_DIR:
264 root 1.1 u_mkdir (PACK_NAME);
265     break;
266    
267 root 1.9 case T_FILE:
268 root 1.1 {
269 root 1.9 u_handle h = u_creat (PACK_NAME, pack_cur->flags & F_EXEC);
270 root 1.2 unsigned int dlen, len = u_32 (pack_cur->datalen);
271     char *data = PACK_DATA;
272    
273 root 1.9 if (pack_cur->flags & F_LZF)
274 root 1.6 if (dlen = lzf_decompress (data, len, scratch, scratch_size))
275 root 1.2 {
276     data = scratch;
277     len = dlen;
278     }
279     else
280 root 1.9 u_fatal ("unable to uncompress file data - pack corrupted?");
281 root 1.1
282 root 1.5 if (!u_valid (h))
283 root 1.9 u_fatal ("unable to unpack file from packfile - disk full?");
284 root 1.1
285 root 1.2 if (u_write (h, data, len) != len)
286 root 1.9 u_fatal ("unable to unpack file from packfile - disk full?");
287 root 1.1
288 root 1.4 u_fsync (h);
289 root 1.1 u_close (h);
290     }
291     break;
292    
293 root 1.9 case T_NULL:
294 root 1.1 goto done;
295     }
296    
297     pack_next ();
298     }
299    
300     done:
301     if (u_chdir (datadir))
302 root 1.9 u_fatal ("unable to change to data directory");
303 root 1.1
304 root 1.3 u_sync ();
305    
306 root 1.1 if (u_rename (tmppath, execdir))
307     deltree (tmppath); // if move fails, delete new, assume other process created it independently
308     }
309    
310     pack_unmap ();
311     u_close (pack_handle);
312    
313 root 1.2 if (u_chdir (execdir))
314 root 1.9 u_fatal ("unable to change to application instance directory");
315 root 1.2
316 root 1.1 u_setenv ("URLADER_VERSION", URLADER_VERSION);
317    
318 root 1.5 #if 0
319 root 1.1 // yes, this is overkill
320     u_setenv ("SHLIB_PATH" , execdir); // hpux
321     u_setenv ("LIBPATH" , execdir); // aix
322     u_setenv ("LD_LIBRARY_PATH" , execdir); // most elf systems
323     u_setenv ("LD_LIBRARY_PATH_32", execdir); // solaris
324     u_setenv ("LD_LIBRARY_PATH_64", execdir); // solaris
325     u_setenv ("LD_LIBRARYN32_PATH", execdir); // irix
326     u_setenv ("LD_LIBRARY64_PATH" , execdir); // irix
327     u_setenv ("DYLD_LIBRARY_PATH" , execdir); // os sucks from apple
328 root 1.5 #endif
329 root 1.1 }
330    
331 root 1.2 static void
332     execute (void)
333     {
334 root 1.12 char *null = 0;
335     u_dynbuf_append (&exe_argv, &null, sizeof (null));
336     systemv ((const char *const *)exe_argv.addr);
337 root 1.2 }
338    
339 root 1.12 // this argc/argv is without argv [0]
340 root 1.9 static void
341 root 1.12 doit (int argc, char *argv[])
342 root 1.9 {
343 root 1.12 int i;
344    
345     u_setenv ("URLADER_CURRDIR", currdir);
346    
347 root 1.9 u_set_datadir ();
348     u_mkdir (datadir);
349    
350 root 1.12 if (!pack_map ())
351     u_fatal ("unable to map pack file - executable corrupted?");
352 root 1.9
353     load ();
354 root 1.12
355     while (argc--)
356     {
357     add_arg (*argv, strlen (*argv) + 1);
358     ++argv;
359     }
360    
361 root 1.9 execute ();
362     }
363    
364 root 1.1 #ifdef _WIN32
365    
366     int APIENTRY
367     WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show)
368     {
369     if (!GetModuleFileName (hI, tmppath, sizeof (tmppath)))
370 root 1.9 u_fatal ("unable to find executable pack");
371 root 1.1
372 root 1.12 u_setenv ("URLADER_EXEPATH", tmppath);
373    
374 root 1.5 pack_handle = u_open (tmppath);
375     if (!u_valid (pack_handle))
376 root 1.9 u_fatal ("unable to open executable pack");
377 root 1.1
378     if (!GetCurrentDirectory (sizeof (currdir), currdir))
379     strcpy (currdir, ".");
380    
381 root 1.12 doit (1, &argv);
382 root 1.11
383 root 1.1 return 0;
384     }
385    
386     #else
387    
388     int
389     main (int argc, char *argv[])
390     {
391 root 1.12 u_setenv ("URLADER_EXEPATH", argv [0]);
392    
393 root 1.5 pack_handle = u_open (argv [0]);
394     if (!u_valid (pack_handle))
395 root 1.9 u_fatal ("unable to open executable pack");
396 root 1.1
397     if (!getcwd (currdir, sizeof (currdir)))
398     strcpy (currdir, ".");
399    
400 root 1.5 #if 0
401 root 1.11 /* intersperse hostname, for whatever reason */
402    
403 root 1.1 if (gethostname (tmppath, sizeof (tmppath)))
404     strcpy (tmppath, "default");
405    
406     u_append (datadir, tmppath);
407 root 1.5 #endif
408 root 1.1
409 root 1.12 doit (argc - 1, argv + 1);
410 root 1.1
411     return 0;
412     }
413    
414     #endif
415