ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Urlader/urlader.c
Revision: 1.5
Committed: Fri Dec 30 09:34:20 2011 UTC (12 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +19 -11 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #ifndef URLADER
2     # define URLADER "urlader"
3     #endif
4 root 1.5 #define URLADER_VERSION "1.0" // a decimal number, not a version string
5 root 1.1
6     #include <stdio.h>
7     #include <stdlib.h>
8     #include <unistd.h>
9     #include <errno.h>
10     #include <string.h>
11     #include <time.h>
12     #include <fcntl.h>
13    
14 root 1.2 #include "liblzf/lzf_d.c"
15 root 1.1
16     #define TAIL_MAGIC "SCHMORPPACK0"
17    
18     #ifdef _WIN32
19    
20     #include <windows.h>
21     //#include <winbase.h>
22     #include <shlobj.h>
23     #include <shlwapi.h>
24     #include <wininet.h>
25    
26     static DWORD dword;
27    
28     #define u_handle HANDLE
29 root 1.5 #define u_valid(handle) (!!handle)
30    
31 root 1.1 #define u_setenv(name,value) SetEnvironmentVariable (name, value)
32     #define u_mkdir(path) !CreateDirectory (path, NULL)
33     #define u_chdir(path) !SetCurrentDirectory (path)
34     #define u_rename(fr,to) !MoveFile (fr, to)
35     #define u_open(path) CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)
36     #define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)
37     #define u_close(handle) CloseHandle (handle)
38     #define u_append(path,add) PathAppend (path, add)
39     #define u_write(handle,data,len) (WriteFile (handle, data, len, &dword, 0) ? dword : -1)
40 root 1.4
41     #define u_fsync(handle) FlushFileBuffers (handle)
42     #define u_sync()
43 root 1.1
44     #else
45    
46     #include <sys/mman.h>
47     #include <sys/types.h>
48     #include <pwd.h>
49    
50     #ifdef PATH_MAX
51     #define MAX_PATH (PATH_MAX < 4096 ? 4096 : PATH_MAX)
52     #else
53     #define MAX_PATH 4096
54     #endif
55    
56     #define u_handle int
57 root 1.5 #define u_valid(fd) ((fd) >= 0)
58    
59 root 1.1 #define u_setenv(name,value) setenv (name, value, 1)
60     #define u_mkdir(path) mkdir (path, 0777)
61     #define u_chdir(path) chdir (path)
62     #define u_rename(fr,to) rename (fr, to)
63 root 1.5 #define u_open(path) open (path, O_RDONLY)
64     #define u_creat(path,exec) open (path, O_WRONLY | O_CREAT | O_TRUNC, (exec) ? 0777 : 0666)
65     #define u_close(handle) close (handle)
66 root 1.1 #define u_append(path,add) strcat (strcat (path, "/"), add)
67 root 1.5 #define u_write(handle,data,len) write (handle, data, len)
68 root 1.4
69     // on a mostly idle system, a sync at the end is certainly faster, hope for the best
70     #define u_fsync(handle)
71 root 1.3 #define u_sync() sync ()
72 root 1.1
73     #endif
74    
75     #define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1])
76     #define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3])
77    
78     static u_handle pack_handle;
79     static char tmppath[MAX_PATH];
80     static char currdir[MAX_PATH];
81     static char datadir[MAX_PATH]; // %AppData%/urlader
82     static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID
83     static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER
84     static char exe_id[MAX_PATH];
85     static char exe_ver[MAX_PATH];
86    
87     static int exe_argc;
88     static const char *exe_argv[32];
89    
90     static void
91     fatal (const char *msg)
92     {
93     #ifdef _WIN32
94     MessageBox (0, msg, URLADER, 0);
95     #else
96     fprintf (stderr, "%s: %s\n", URLADER, msg);
97     #endif
98    
99     _exit (1);
100     }
101    
102     static void
103     tmpdir (const char *dir)
104     {
105     static int cnt;
106    
107     for (;;)
108     {
109     // #ifdef _WIN32
110     // sprintf (tmppath, "%s/%x_%x.tmp", dir, (unsigned int)GetCurrentProcessId (), ++cnt);
111     // #else
112     sprintf (tmppath, "%s/t-%x_%x.tmp", dir, (unsigned int)getpid () , ++cnt);
113     // #endif
114    
115     if (!u_mkdir (tmppath))
116     return;
117     }
118     }
119    
120     static void
121 root 1.2 systemv (const char *const argv[], int dowait)
122 root 1.1 {
123     #ifdef _WIN32
124     _spawnv (P_WAIT, argv [0], argv);
125     #else
126 root 1.2 pid_t pid = dowait ? fork () : 0;
127 root 1.1
128     if (pid < 0)
129     fatal ("fork failure");
130    
131     if (!pid)
132     {
133     execv (argv [0], (void *)argv);
134     _exit (124);
135     }
136    
137     int status;
138     waitpid (pid, &status, 0);
139     #endif
140     }
141    
142     static void
143     deltree (const char *path)
144     {
145     #ifdef _WIN32
146     char buf[MAX_PATH * 2 + 64];
147     const char *argv[] = { getenv ("COMSPEC"), "/c", "rd", "/s", "/q", buf, 0 };
148     sprintf (buf, "\"%s\"", path);
149     #else
150     const char *argv[] = { "/bin/rm", "-rf", path, 0 };
151     #endif
152 root 1.2 systemv (argv, 1);
153 root 1.1 }
154    
155     enum
156     {
157     T_NULL, // 5
158     T_META, // 1 : exe_id, exe_ver
159 root 1.4 T_ENV, // 2 : name, value
160     T_ARG, // 3 : arg
161 root 1.1 T_DIR, // 4+: path
162     T_FILE, // 4+: path, data
163     T_NUM
164     };
165    
166     enum
167     {
168     F_EXEC = 1,
169     F_LZF = 2,
170     F_NULL = 0
171     };
172    
173     struct hdr
174     {
175     unsigned char type;
176     unsigned char flags;
177     unsigned char namelen[2];
178     unsigned char datalen[4];
179     };
180    
181     struct tail {
182     unsigned char max_filesize[4];
183     unsigned char size[4];
184     char magic[12];
185     };
186    
187     static char *pack_base, *pack_end;
188     static struct hdr *pack_cur;
189 root 1.2 static char *scratch;
190     static unsigned int scratch_len;
191 root 1.1
192     #define PACK_NAME ((char *)(pack_cur + 1))
193     #define PACK_DATA (PACK_NAME + u_16 (pack_cur->namelen) + 1)
194     #define PACK_VALID pack_cur->type
195    
196     static void
197     pack_next (void)
198     {
199     unsigned int d = u_32 (pack_cur->datalen);
200    
201     pack_cur = (struct hdr *)(PACK_DATA + d);
202     }
203    
204     static void
205     pack_unmap (void)
206     {
207     if (!pack_base)
208     return;
209    
210 root 1.2 free (scratch);
211    
212 root 1.1 #ifdef _WIN32
213     UnmapViewOfFile (pack_base);
214     #else
215     munmap (pack_base, pack_end - pack_base);
216     #endif
217     }
218    
219     static int
220     pack_map (void)
221     {
222     #ifdef _WIN32
223     BY_HANDLE_FILE_INFORMATION fi;
224    
225     if (!GetFileInformationByHandle (pack_handle, &fi))
226     return 0;
227    
228     if (fi.nFileSizeHigh) // too big
229     return 0;
230    
231     HANDLE handle = CreateFileMapping (pack_handle, 0, PAGE_READONLY, 0, fi.nFileSizeLow, NULL);
232    
233     if (!handle)
234     return 0;
235    
236     pack_unmap ();
237    
238     pack_base = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, fi.nFileSizeLow);
239    
240     CloseHandle (handle);
241    
242     pack_end = pack_base + fi.nFileSizeLow;
243     #else
244     off_t len = lseek (pack_handle - 1, 0, SEEK_END);
245    
246     pack_unmap ();
247    
248     pack_base = mmap (0, len, PROT_READ, MAP_SHARED, pack_handle - 1, 0);
249     if (pack_base == (void *)-1)
250     pack_base = 0;
251    
252     pack_end = pack_base + len;
253     #endif
254    
255     if (!pack_base)
256     return 0;
257    
258     struct tail *tail;
259    
260     tail = (void *)(pack_end - sizeof (*tail));
261    
262     if (memcmp (tail->magic, TAIL_MAGIC, sizeof (TAIL_MAGIC) - 1))
263     return 0;
264    
265     pack_cur = (struct hdr *)(pack_end - u_32 (tail->size));
266    
267 root 1.2 free (scratch);
268     scratch = malloc (scratch_len = u_32 (tail->max_filesize));
269    
270 root 1.1 return 1;
271     }
272    
273     static void
274     exe_info (void)
275     {
276     if (!pack_map ())
277     fatal ("unable to locate packfile in executable - executable corrupted?");
278    
279     if (pack_cur->type != T_META)
280     fatal ("unable to locate executable metadata - executable corrupted?");
281    
282     strcpy (exe_id, PACK_NAME);
283     }
284    
285     static void
286     load (void)
287     {
288     u_mkdir (datadir);
289    
290     strcpy (exe_dir, datadir);
291     u_append (exe_dir, exe_id);
292     u_mkdir (exe_dir);
293    
294     if (u_chdir (exe_dir))
295     fatal ("unable to change to application data directory");
296    
297     u_handle h = u_open ("override");
298 root 1.5 if (u_valid (h))
299 root 1.1 {
300     u_handle oh = pack_handle;
301    
302     pack_handle = h;
303     if (!pack_map ())
304     {
305     pack_handle = oh;
306     oh = h;
307     }
308    
309     u_close (oh);
310     }
311    
312     if (pack_cur->type != T_META)
313     fatal ("unable to locate override metadata");
314    
315     strcpy (exe_ver, PACK_DATA);
316     pack_next ();
317    
318 root 1.4 for (;;)
319 root 1.1 {
320 root 1.4 if (pack_cur->type == T_ENV)
321     u_setenv (PACK_NAME, PACK_DATA);
322     else if (pack_cur->type == T_ARG)
323     exe_argv [exe_argc++] = strdup (PACK_NAME);
324     else
325     break;
326 root 1.1
327     pack_next ();
328     }
329 root 1.4
330     done_env_arg:
331 root 1.1 strcpy (execdir, exe_dir);
332     u_append (execdir, "i-");
333     strcat (execdir, exe_ver);
334    
335     if (access (execdir, F_OK))
336     {
337     // does not exist yet, so unpack and move
338     tmpdir (exe_dir);
339    
340     if (u_chdir (tmppath))
341     fatal ("unable to change to new instance directory");
342    
343     for (;;)
344     {
345     switch (pack_cur->type)
346     {
347     case T_DIR:
348     u_mkdir (PACK_NAME);
349     break;
350    
351     case T_FILE:
352     {
353     u_handle h = u_creat (PACK_NAME, pack_cur->flags & F_EXEC);
354 root 1.2 unsigned int dlen, len = u_32 (pack_cur->datalen);
355     char *data = PACK_DATA;
356    
357     if (pack_cur->flags & F_LZF)
358     if (dlen = lzf_decompress (data, len, scratch, scratch_len))
359     {
360     data = scratch;
361     len = dlen;
362     }
363     else
364     fatal ("unable to uncompress file data - pack corrupted?");
365 root 1.1
366 root 1.5 if (!u_valid (h))
367 root 1.1 fatal ("unable to unpack file from packfile - disk full?");
368    
369 root 1.2 if (u_write (h, data, len) != len)
370 root 1.1 fatal ("unable to unpack file from packfile - disk full?");
371    
372 root 1.4 u_fsync (h);
373 root 1.1 u_close (h);
374     }
375     break;
376    
377     case T_NULL:
378     goto done;
379     }
380    
381     pack_next ();
382     }
383    
384     done:
385     if (u_chdir (datadir))
386     fatal ("unable to change to data directory");
387    
388 root 1.3 u_sync ();
389    
390 root 1.1 if (u_rename (tmppath, execdir))
391     deltree (tmppath); // if move fails, delete new, assume other process created it independently
392     }
393    
394     pack_unmap ();
395     u_close (pack_handle);
396    
397 root 1.2 if (u_chdir (execdir))
398     fatal ("unable to change to application instance directory");
399    
400 root 1.1 u_setenv ("URLADER_VERSION", URLADER_VERSION);
401     u_setenv ("URLADER_DATADIR", datadir);
402     u_setenv ("URLADER_EXECDIR", execdir);
403     u_setenv ("URLADER_EXE_ID" , exe_id);
404     u_setenv ("URLADER_EXE_DIR", exe_dir);
405     u_setenv ("URLADER_EXE_VER", exe_ver);
406    
407 root 1.5 #if 0
408 root 1.1 // yes, this is overkill
409     u_setenv ("SHLIB_PATH" , execdir); // hpux
410     u_setenv ("LIBPATH" , execdir); // aix
411     u_setenv ("LD_LIBRARY_PATH" , execdir); // most elf systems
412     u_setenv ("LD_LIBRARY_PATH_32", execdir); // solaris
413     u_setenv ("LD_LIBRARY_PATH_64", execdir); // solaris
414     u_setenv ("LD_LIBRARYN32_PATH", execdir); // irix
415     u_setenv ("LD_LIBRARY64_PATH" , execdir); // irix
416     u_setenv ("DYLD_LIBRARY_PATH" , execdir); // os sucks from apple
417 root 1.5 #endif
418 root 1.1 }
419    
420 root 1.2 static void
421     execute (void)
422     {
423     exe_argv [exe_argc] = 0;
424     systemv (exe_argv, 0);
425     }
426    
427 root 1.1 #ifdef _WIN32
428    
429     int APIENTRY
430     WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show)
431     {
432     if (!GetModuleFileName (hI, tmppath, sizeof (tmppath)))
433     fatal ("unable to find executable pack");
434    
435 root 1.5 pack_handle = u_open (tmppath);
436     if (!u_valid (pack_handle))
437 root 1.1 fatal ("unable to open executable pack");
438    
439     exe_info ();
440    
441     if (!GetCurrentDirectory (sizeof (currdir), currdir))
442     strcpy (currdir, ".");
443    
444     if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK)
445     fatal ("unable to find application data directory");
446    
447     u_mkdir (datadir);
448     u_append (datadir, URLADER);
449    
450     load ();
451     execute ();
452    
453     return 0;
454     }
455    
456     #else
457    
458     int
459     main (int argc, char *argv[])
460     {
461     char *home = getenv ("HOME");
462    
463 root 1.5 pack_handle = u_open (argv [0]);
464     if (!u_valid (pack_handle))
465 root 1.1 fatal ("unable to open executable pack");
466    
467     exe_info ();
468    
469     if (!home)
470     {
471     struct passwd *pw;
472    
473     if ((pw = getpwuid (getuid ())))
474     home = pw->pw_dir;
475     else
476     home = "/tmp";
477     }
478    
479     if (!getcwd (currdir, sizeof (currdir)))
480     strcpy (currdir, ".");
481    
482     u_mkdir (home);
483     sprintf (datadir, "%s/.%s", home, URLADER);
484     u_mkdir (datadir);
485    
486 root 1.5 #if 0
487 root 1.1 if (gethostname (tmppath, sizeof (tmppath)))
488     strcpy (tmppath, "default");
489    
490     u_append (datadir, tmppath);
491 root 1.5 #endif
492 root 1.1
493     load ();
494     execute ();
495    
496     return 0;
497     }
498    
499     #endif
500