ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Urlader/urlader.c
Revision: 1.15
Committed: Mon Jun 10 06:46:32 2013 UTC (10 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.14: +4 -4 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
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 #include "urlib.h"
38 #include "urlib.c"
39
40 #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 #include "liblzf/lzf_d.c"
48
49 /* some simple? dynamic memory management for paths might save ltos of ram */
50 static u_handle pack_handle;
51 static u_handle lock_handle;
52 static char tmppath[MAX_PATH];
53
54 static int exe_argc;
55 static u_dynbuf exe_argv;
56 static u_dynbuf exe_args; /* actual arguments strings copied here */
57
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 systemv (const char *const argv[])
78 {
79 #ifdef _WIN32
80 _spawnv (P_WAIT, argv [0], argv);
81 #else
82 pid_t pid = fork ();
83
84 if (pid < 0)
85 u_fatal ("fork failure");
86
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 systemv (argv);
109 }
110
111 static char *pack_base, *pack_end;
112 static struct u_pack_tail *pack_tail;
113 static struct u_pack_hdr *pack_cur;
114 static char *scratch;
115 static unsigned int scratch_size;
116
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 pack_cur = (struct u_pack_hdr *)(PACK_DATA + d);
127 }
128
129 static void
130 pack_unmap (void)
131 {
132 if (pack_base)
133 {
134 u_munmap (pack_base, pack_end - pack_base);
135 pack_base = 0;
136 }
137
138 if (scratch)
139 {
140 u_free (scratch, scratch_size);
141 scratch = 0;
142 }
143 }
144
145 static int
146 pack_map (void)
147 {
148 char *addr;
149 unsigned int size;
150
151 #ifdef _WIN32
152 BY_HANDLE_FILE_INFORMATION fi;
153
154 if (!GetFileInformationByHandle (pack_handle, &fi))
155 return 0;
156
157 size = fi.nFileSizeLow;
158 #else
159 size = lseek (pack_handle, 0, SEEK_END);
160 #endif
161
162 addr = u_mmap (pack_handle, size);
163 if (!addr)
164 return 0;
165
166 /*pack_unmap ();*/
167
168 pack_base = addr;
169 pack_end = pack_base + size;
170
171 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
176 pack_cur = (struct u_pack_hdr *)(pack_end - u_32 (pack_tail->size));
177
178 if (pack_cur->type != T_META)
179 return 0;
180
181 scratch = u_malloc (scratch_size = u_32 (pack_tail->max_uncompressed));
182 if (!scratch)
183 return 0;
184
185 return 1;
186 }
187
188 static void
189 add_arg (char *arg, unsigned int len)
190 {
191 char *addr = u_dynbuf_append (&exe_args, arg, len);
192 u_dynbuf_append (&exe_argv, &addr, sizeof (addr));
193 }
194
195 static void
196 load (void)
197 {
198 strcpy (exe_id , PACK_NAME);
199 strcpy (exe_ver, PACK_DATA);
200 u_set_exe_info ();
201
202 if (u_chdir (exe_dir))
203 u_fatal ("unable to change to application data directory");
204
205 u_handle h = u_open ("override");
206 if (u_valid (h))
207 {
208 u_handle oh = pack_handle;
209
210 pack_unmap ();
211 pack_handle = h;
212
213 if (pack_map ()
214 && strcmp (exe_id , PACK_NAME) == 0
215 && strcmp (exe_ver, PACK_DATA) <= 0)
216 u_setenv ("URLADER_OVERRIDE", "override");
217 else
218 {
219 pack_unmap ();
220 pack_handle = oh;
221 oh = h;
222 pack_map ();
223 }
224
225 u_close (oh);
226 }
227
228 strcpy (exe_ver, PACK_DATA);
229 u_set_exe_info ();
230 pack_next ();
231
232 for (;;)
233 {
234 if (pack_cur->type == T_ENV)
235 u_setenv (PACK_NAME, PACK_DATA);
236 else if (pack_cur->type == T_ARG)
237 add_arg (PACK_NAME, u_16 (pack_cur->namelen) + 1);
238 else
239 break;
240
241 pack_next ();
242 }
243
244 done_env_arg:
245
246 strcat (strcpy (tmppath, execdir), ".lck");
247 lock_handle = u_lock (tmppath, 0, 1);
248 if (!lock_handle)
249 u_fatal ("unable to lock application instance");
250
251 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 u_fatal ("unable to change to new instance directory");
258
259 for (;;)
260 {
261 switch (pack_cur->type)
262 {
263 case T_DIR:
264 u_mkdir (PACK_NAME);
265 break;
266
267 case T_FILE:
268 {
269 u_handle h = u_creat (PACK_NAME, pack_cur->flags & F_EXEC);
270 unsigned int dlen, len = u_32 (pack_cur->datalen);
271 char *data = PACK_DATA;
272
273 if (pack_cur->flags & F_LZF)
274 if (dlen = lzf_decompress (data, len, scratch, scratch_size))
275 {
276 data = scratch;
277 len = dlen;
278 }
279 else
280 u_fatal ("unable to uncompress file data - pack corrupted?");
281
282 if (!u_valid (h))
283 u_fatal ("unable to unpack file from packfile - disk full?");
284
285 if (u_write (h, data, len) != len)
286 u_fatal ("unable to unpack file from packfile - disk full?");
287
288 u_fsync (h);
289 u_close (h);
290 }
291 break;
292
293 case T_NULL:
294 goto done;
295 }
296
297 pack_next ();
298 }
299
300 done:
301 if (u_chdir (datadir))
302 u_fatal ("unable to change to data directory");
303
304 u_sync ();
305
306 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 if (u_chdir (execdir))
314 u_fatal ("unable to change to application instance directory");
315
316 u_setenv ("URLADER_VERSION", URLADER_VERSION);
317
318 #if 0
319 // 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 #endif
329 }
330
331 static void
332 execute (void)
333 {
334 char *null = 0;
335 u_dynbuf_append (&exe_argv, &null, sizeof (null));
336 systemv ((const char *const *)exe_argv.addr);
337 }
338
339 // this argc/argv is without argv [0]
340 static void
341 doit (int argc, char *argv[])
342 {
343 int i;
344
345 u_setenv ("URLADER_CURRDIR", currdir);
346
347 u_set_datadir ();
348 u_mkdir (datadir);
349
350 if (!pack_map ())
351 u_fatal ("unable to map pack file - executable corrupted?");
352
353 load ();
354
355 while (argc--)
356 {
357 add_arg (*argv, strlen (*argv) + 1);
358 ++argv;
359 }
360
361 execute ();
362 }
363
364 #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 u_fatal ("unable to find executable pack");
371
372 u_setenv ("URLADER_EXEPATH", tmppath);
373
374 pack_handle = u_open (tmppath);
375 if (!u_valid (pack_handle))
376 u_fatal ("unable to open executable pack");
377
378 if (!GetCurrentDirectory (sizeof (currdir), currdir))
379 strcpy (currdir, ".");
380
381 doit (1, &argv);
382
383 return 0;
384 }
385
386 #else
387
388 int
389 main (int argc, char *argv[])
390 {
391 if (!getcwd (currdir, sizeof (currdir)))
392 strcpy (currdir, ".");
393
394 {
395 const char *exe_path = 0;
396
397 if (strchr (argv [0], '/'))
398 exe_path = argv [0];
399 else
400 {
401 const char *p, *path = getenv ("PATH");
402
403 if (!path)
404 u_fatal ("unable to find executable, try running with full path.");
405
406 for (p = path; ; )
407 {
408 const char *e = p;
409 int l;
410
411 while (*e && *e != ':')
412 ++e;
413
414 l = e - p;
415 memcpy (tmppath, p, l);
416
417 if (!l)
418 tmppath [l++] = '.';
419
420 tmppath [l++] = '/';
421
422 strcpy (tmppath + l, argv [0]);
423
424 if (!access (tmppath, X_OK))
425 break;
426
427 p = e;
428 if (!*p)
429 u_fatal ("unable to find executable, try running with full path.");
430
431 ++p;
432 }
433
434 exe_path = tmppath;
435 }
436
437 pack_handle = u_open (exe_path);
438 if (!u_valid (pack_handle))
439 u_fatal ("unable to open executable for reading - permissions problem?");
440
441 u_setenv ("URLADER_EXEPATH", exe_path);
442 }
443
444 #if 0
445 /* intersperse hostname, for whatever reason */
446
447 if (gethostname (tmppath, sizeof (tmppath)))
448 strcpy (tmppath, "default");
449
450 u_append (datadir, tmppath);
451 #endif
452
453 doit (argc - 1, argv + 1);
454
455 return 0;
456 }
457
458 #endif
459