1 |
#ifndef URLADER |
2 |
# define URLADER "urlader" |
3 |
#endif |
4 |
#define URLADER_VERSION "1.0" // a decimal number, not a version string |
5 |
|
6 |
#define MAX_ARGC 32 |
7 |
#define MAX_ARGS 256 |
8 |
|
9 |
#include <stdio.h> |
10 |
#include <stdlib.h> |
11 |
#include <unistd.h> |
12 |
#include <errno.h> |
13 |
#include <string.h> |
14 |
#include <time.h> |
15 |
#include <fcntl.h> |
16 |
|
17 |
#include "liblzf/lzf_d.c" |
18 |
|
19 |
#define TAIL_MAGIC "SCHMORPPACK0" |
20 |
|
21 |
#ifdef _WIN32 |
22 |
|
23 |
#include <windows.h> |
24 |
//#include <winbase.h> |
25 |
#include <shlobj.h> |
26 |
#include <shlwapi.h> |
27 |
#include <wininet.h> |
28 |
|
29 |
static DWORD dword; |
30 |
|
31 |
#define u_handle HANDLE |
32 |
#define u_invalid_handle 0 |
33 |
#define u_valid(handle) (!!handle) |
34 |
|
35 |
#define u_setenv(name,value) SetEnvironmentVariable (name, value) |
36 |
#define u_mkdir(path) !CreateDirectory (path, NULL) |
37 |
#define u_chdir(path) !SetCurrentDirectory (path) |
38 |
#define u_rename(fr,to) !MoveFile (fr, to) |
39 |
#define u_open(path) CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
40 |
#define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
41 |
#define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
42 |
#define u_close(handle) CloseHandle (handle) |
43 |
#define u_append(path,add) PathAppend (path, add) |
44 |
#define u_write(handle,data,len) (WriteFile (handle, data, len, &dword, 0) ? dword : -1) |
45 |
|
46 |
#define u_fsync(handle) FlushFileBuffers (handle) |
47 |
#define u_sync() |
48 |
|
49 |
#define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) |
50 |
#define u_cloexec(handle) |
51 |
|
52 |
#else |
53 |
|
54 |
#define _GNU_SOURCE 1 |
55 |
#define _BSD_SOURCE 1 |
56 |
// the above increases our chances of getting MAP_ANONYMOUS |
57 |
|
58 |
#include <sys/mman.h> |
59 |
#include <sys/types.h> |
60 |
#include <sys/stat.h> |
61 |
#include <unistd.h> |
62 |
#include <pwd.h> |
63 |
|
64 |
#if defined (MAP_ANON) && !defined (MAP_ANONYMOUS) |
65 |
#define MAP_ANONYMOUS MAP_ANON |
66 |
#endif |
67 |
|
68 |
#ifdef PATH_MAX |
69 |
#define MAX_PATH (PATH_MAX < 4096 ? 4096 : PATH_MAX) |
70 |
#else |
71 |
#define MAX_PATH 4096 |
72 |
#endif |
73 |
|
74 |
#define u_handle int |
75 |
#define u_invalid_handle -1 |
76 |
#define u_valid(fd) ((fd) >= 0) |
77 |
|
78 |
#define u_setenv(name,value) setenv (name, value, 1) |
79 |
#define u_mkdir(path) mkdir (path, 0777) |
80 |
#define u_chdir(path) chdir (path) |
81 |
#define u_rename(fr,to) rename (fr, to) |
82 |
#define u_open(path) open (path, O_RDONLY) |
83 |
#define u_creat(path,exec) open (path, O_WRONLY | O_CREAT | O_TRUNC, (exec) ? 0777 : 0666) |
84 |
#define u_close(handle) close (handle) |
85 |
#define u_append(path,add) strcat (strcat (path, "/"), add) |
86 |
#define u_write(handle,data,len) write (handle, data, len) |
87 |
|
88 |
// on a mostly idle system, a sync at the end is certainly faster, hope for the best |
89 |
#define u_fsync(handle) |
90 |
#define u_sync() sync () |
91 |
|
92 |
#define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666) |
93 |
#define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC) |
94 |
|
95 |
#endif |
96 |
|
97 |
#define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1]) |
98 |
#define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3]) |
99 |
|
100 |
/* some simple? dynamic memory management for paths might save ltos of ram */ |
101 |
static u_handle pack_handle; |
102 |
static u_handle lock_handle; |
103 |
static char tmppath[MAX_PATH]; |
104 |
static char currdir[MAX_PATH]; |
105 |
static char datadir[MAX_PATH]; // %AppData%/urlader |
106 |
static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID |
107 |
static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER |
108 |
static char exe_id[MAX_PATH]; |
109 |
static char exe_ver[MAX_PATH]; |
110 |
|
111 |
static int exe_argc; |
112 |
static const char *exe_argv[MAX_ARGC]; |
113 |
static char exe_args[MAX_ARGS]; /* actual arguments strings copied here */ |
114 |
static unsigned int exe_argo; |
115 |
|
116 |
static void |
117 |
fatal (const char *msg) |
118 |
{ |
119 |
#ifdef _WIN32 |
120 |
MessageBox (0, msg, URLADER, 0); |
121 |
#else |
122 |
write (2, URLADER ": ", sizeof (URLADER ": ") - 1); |
123 |
write (2, msg, strlen (msg)); |
124 |
write (2, "\n", 1); |
125 |
#endif |
126 |
|
127 |
_exit (1); |
128 |
} |
129 |
|
130 |
static void * |
131 |
u_malloc (unsigned int size) |
132 |
{ |
133 |
void *addr; |
134 |
|
135 |
#ifdef _WIN32 |
136 |
HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL); |
137 |
|
138 |
if (!handle) |
139 |
return 0; |
140 |
|
141 |
addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size); |
142 |
|
143 |
CloseHandle (handle); |
144 |
#elif defined (MAP_ANONYMOUS) |
145 |
addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); |
146 |
|
147 |
if (addr == (void *)-1) |
148 |
addr = 0; |
149 |
#else |
150 |
addr = malloc (size); |
151 |
#endif |
152 |
|
153 |
return addr; |
154 |
} |
155 |
|
156 |
static void |
157 |
u_free (void *addr, unsigned int size) |
158 |
{ |
159 |
#ifdef _WIN32 |
160 |
UnmapViewOfFile (addr); |
161 |
#elif defined (MAP_ANONYMOUS) |
162 |
munmap (addr, size); |
163 |
#else |
164 |
free (addr); |
165 |
#endif |
166 |
} |
167 |
|
168 |
static void * |
169 |
u_mmap (u_handle h, unsigned int size) |
170 |
{ |
171 |
void *addr; |
172 |
|
173 |
#ifdef _WIN32 |
174 |
HANDLE handle = CreateFileMapping (h, 0, PAGE_READONLY, 0, size, NULL); |
175 |
|
176 |
if (!handle) |
177 |
return 0; |
178 |
|
179 |
addr = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, size); |
180 |
|
181 |
CloseHandle (handle); |
182 |
#else |
183 |
addr = mmap (0, size, PROT_READ, MAP_SHARED, h, 0); |
184 |
|
185 |
if (addr == (void *)-1) |
186 |
addr = 0; |
187 |
#endif |
188 |
|
189 |
return addr; |
190 |
} |
191 |
|
192 |
static void |
193 |
u_munmap (void *addr, unsigned int len) |
194 |
{ |
195 |
#ifdef _WIN32 |
196 |
UnmapViewOfFile (addr); |
197 |
#else |
198 |
munmap (addr, len); |
199 |
#endif |
200 |
} |
201 |
|
202 |
static void |
203 |
tmpdir (const char *dir) |
204 |
{ |
205 |
static int cnt; |
206 |
|
207 |
for (;;) |
208 |
{ |
209 |
// #ifdef _WIN32 |
210 |
// sprintf (tmppath, "%s/%x_%x.tmp", dir, (unsigned int)GetCurrentProcessId (), ++cnt); |
211 |
// #else |
212 |
sprintf (tmppath, "%s/t-%x_%x.tmp", dir, (unsigned int)getpid () , ++cnt); |
213 |
// #endif |
214 |
|
215 |
if (!u_mkdir (tmppath)) |
216 |
return; |
217 |
} |
218 |
} |
219 |
|
220 |
static u_handle |
221 |
u_lock (const char *path, int excl, int dowait) |
222 |
{ |
223 |
u_handle h; |
224 |
|
225 |
h = u_lockfile (path); |
226 |
if (!u_valid (h)) |
227 |
return h; |
228 |
|
229 |
u_cloexec (h); |
230 |
|
231 |
for (;;) |
232 |
{ |
233 |
int success; |
234 |
|
235 |
// acquire the lock |
236 |
#ifdef _WIN32 |
237 |
OVERLAPPED ov = { 0 }; |
238 |
|
239 |
success = LockFileEx (h, |
240 |
(excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) |
241 |
| (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), |
242 |
0, |
243 |
1, 0, |
244 |
&ov); |
245 |
#else |
246 |
struct flock lck = { 0 }; |
247 |
|
248 |
lck.l_type = excl ? F_WRLCK : F_RDLCK; |
249 |
lck.l_whence = SEEK_SET; |
250 |
lck.l_len = 1; |
251 |
|
252 |
success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck); |
253 |
#endif |
254 |
|
255 |
if (!success) |
256 |
break; |
257 |
|
258 |
// we have the lock, now verify that the lockfile still exists |
259 |
|
260 |
#ifdef _WIN32 |
261 |
// apparently, we have to open the file to get its info :( |
262 |
BY_HANDLE_FILE_INFORMATION s1, s2; |
263 |
u_handle h2 = u_lockfile (path); |
264 |
if (!u_valid (h)) |
265 |
break; |
266 |
|
267 |
success = GetFileInformationByHandle (h, &s1) |
268 |
&& GetFileInformationByHandle (h2, &s2); |
269 |
|
270 |
u_close (h2); |
271 |
|
272 |
if (!success) |
273 |
break; |
274 |
|
275 |
success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber |
276 |
&& s1.nFileIndexHigh == s2.nFileIndexHigh |
277 |
&& s1.nFileIndexLow == s2.nFileIndexLow; |
278 |
#else |
279 |
struct stat s1, s2; |
280 |
|
281 |
if (fstat (h, &s1) || stat (path, &s2)) |
282 |
break; |
283 |
|
284 |
success = s1.st_dev == s2.st_dev |
285 |
&& s1.st_ino == s2.st_ino; |
286 |
#endif |
287 |
|
288 |
if (success) |
289 |
return h; // lock successfully acquired |
290 |
|
291 |
// files differ, close and retry - should be very rare |
292 |
u_close (h); |
293 |
} |
294 |
|
295 |
// failure |
296 |
u_close (h); |
297 |
return u_invalid_handle; |
298 |
} |
299 |
|
300 |
static void |
301 |
systemv (const char *const argv[]) |
302 |
{ |
303 |
#ifdef _WIN32 |
304 |
_spawnv (P_WAIT, argv [0], argv); |
305 |
#else |
306 |
pid_t pid = fork (); |
307 |
|
308 |
if (pid < 0) |
309 |
fatal ("fork failure"); |
310 |
|
311 |
if (!pid) |
312 |
{ |
313 |
execv (argv [0], (void *)argv); |
314 |
_exit (124); |
315 |
} |
316 |
|
317 |
int status; |
318 |
waitpid (pid, &status, 0); |
319 |
#endif |
320 |
} |
321 |
|
322 |
static void |
323 |
deltree (const char *path) |
324 |
{ |
325 |
#ifdef _WIN32 |
326 |
char buf[MAX_PATH * 2 + 64]; |
327 |
const char *argv[] = { getenv ("COMSPEC"), "/c", "rd", "/s", "/q", buf, 0 }; |
328 |
sprintf (buf, "\"%s\"", path); |
329 |
#else |
330 |
const char *argv[] = { "/bin/rm", "-rf", path, 0 }; |
331 |
#endif |
332 |
systemv (argv); |
333 |
} |
334 |
|
335 |
enum |
336 |
{ |
337 |
T_NULL, // 5 |
338 |
T_META, // 1 : exe_id, exe_ver |
339 |
T_ENV, // 2 : name, value |
340 |
T_ARG, // 3 : arg |
341 |
T_DIR, // 4+: path |
342 |
T_FILE, // 4+: path, data |
343 |
T_NUM |
344 |
}; |
345 |
|
346 |
enum |
347 |
{ |
348 |
F_EXEC = 1, |
349 |
F_LZF = 2, |
350 |
F_NULL = 0 |
351 |
}; |
352 |
|
353 |
struct hdr |
354 |
{ |
355 |
unsigned char type; |
356 |
unsigned char flags; |
357 |
unsigned char namelen[2]; |
358 |
unsigned char datalen[4]; |
359 |
}; |
360 |
|
361 |
struct tail { |
362 |
unsigned char max_filesize[4]; |
363 |
unsigned char size[4]; |
364 |
char magic[12]; |
365 |
}; |
366 |
|
367 |
static char *pack_base, *pack_end; |
368 |
static struct hdr *pack_cur; |
369 |
static char *scratch; |
370 |
static unsigned int scratch_size; |
371 |
|
372 |
#define PACK_NAME ((char *)(pack_cur + 1)) |
373 |
#define PACK_DATA (PACK_NAME + u_16 (pack_cur->namelen) + 1) |
374 |
#define PACK_VALID pack_cur->type |
375 |
|
376 |
static void |
377 |
pack_next (void) |
378 |
{ |
379 |
unsigned int d = u_32 (pack_cur->datalen); |
380 |
|
381 |
pack_cur = (struct hdr *)(PACK_DATA + d); |
382 |
} |
383 |
|
384 |
static void |
385 |
pack_unmap (void) |
386 |
{ |
387 |
if (pack_base) |
388 |
{ |
389 |
u_munmap (pack_base, pack_end - pack_base); |
390 |
pack_base = 0; |
391 |
} |
392 |
|
393 |
if (scratch) |
394 |
{ |
395 |
u_free (scratch, scratch_size); |
396 |
scratch = 0; |
397 |
} |
398 |
} |
399 |
|
400 |
static int |
401 |
pack_map (void) |
402 |
{ |
403 |
char *addr; |
404 |
unsigned int size; |
405 |
|
406 |
#ifdef _WIN32 |
407 |
BY_HANDLE_FILE_INFORMATION fi; |
408 |
|
409 |
if (!GetFileInformationByHandle (pack_handle, &fi)) |
410 |
return 0; |
411 |
|
412 |
size = fi.nFileSizeLow; |
413 |
#else |
414 |
size = lseek (pack_handle, 0, SEEK_END); |
415 |
#endif |
416 |
|
417 |
addr = u_mmap (pack_handle, size); |
418 |
if (!addr) |
419 |
return 0; |
420 |
|
421 |
pack_unmap (); |
422 |
|
423 |
pack_base = addr; |
424 |
pack_end = pack_base + size; |
425 |
|
426 |
struct tail *tail; |
427 |
|
428 |
tail = (void *)(pack_end - sizeof (*tail)); |
429 |
|
430 |
if (memcmp (tail->magic, TAIL_MAGIC, sizeof (TAIL_MAGIC) - 1)) |
431 |
return 0; |
432 |
|
433 |
pack_cur = (struct hdr *)(pack_end - u_32 (tail->size)); |
434 |
|
435 |
scratch = u_malloc (scratch_size = u_32 (tail->max_filesize)); |
436 |
if (!scratch) |
437 |
return 0; |
438 |
|
439 |
return 1; |
440 |
} |
441 |
|
442 |
static void |
443 |
exe_info (void) |
444 |
{ |
445 |
if (!pack_map ()) |
446 |
fatal ("unable to locate packfile in executable - executable corrupted?"); |
447 |
|
448 |
if (pack_cur->type != T_META) |
449 |
fatal ("unable to locate executable metadata - executable corrupted?"); |
450 |
|
451 |
strcpy (exe_id, PACK_NAME); |
452 |
} |
453 |
|
454 |
static void |
455 |
load (void) |
456 |
{ |
457 |
u_mkdir (datadir); |
458 |
|
459 |
strcpy (exe_dir, datadir); |
460 |
u_append (exe_dir, exe_id); |
461 |
u_mkdir (exe_dir); |
462 |
|
463 |
if (u_chdir (exe_dir)) |
464 |
fatal ("unable to change to application data directory"); |
465 |
|
466 |
u_handle h = u_open ("override"); |
467 |
if (u_valid (h)) |
468 |
{ |
469 |
u_handle oh = pack_handle; |
470 |
|
471 |
pack_handle = h; |
472 |
if (!pack_map ()) |
473 |
{ |
474 |
pack_handle = oh; |
475 |
oh = h; |
476 |
} |
477 |
|
478 |
u_close (oh); |
479 |
} |
480 |
|
481 |
if (pack_cur->type != T_META) |
482 |
fatal ("unable to locate override metadata"); |
483 |
|
484 |
strcpy (exe_ver, PACK_DATA); |
485 |
pack_next (); |
486 |
|
487 |
for (;;) |
488 |
{ |
489 |
if (pack_cur->type == T_ENV) |
490 |
u_setenv (PACK_NAME, PACK_DATA); |
491 |
else if (pack_cur->type == T_ARG) |
492 |
{ |
493 |
int len = u_16 (pack_cur->namelen) + 1; |
494 |
exe_argv [exe_argc++] = exe_args + exe_argo; |
495 |
memcpy (exe_args + exe_argo, PACK_NAME, len); |
496 |
exe_argo += len; |
497 |
} |
498 |
else |
499 |
break; |
500 |
|
501 |
pack_next (); |
502 |
} |
503 |
|
504 |
done_env_arg: |
505 |
strcpy (execdir, exe_dir); |
506 |
u_append (execdir, "i-"); |
507 |
strcat (execdir, exe_ver); |
508 |
|
509 |
strcat (strcpy (tmppath, execdir), ".lck"); |
510 |
lock_handle = u_lock (tmppath, 0, 1); |
511 |
if (!lock_handle) |
512 |
fatal ("unable to lock application instance"); |
513 |
|
514 |
if (access (execdir, F_OK)) |
515 |
{ |
516 |
// does not exist yet, so unpack and move |
517 |
tmpdir (exe_dir); |
518 |
|
519 |
if (u_chdir (tmppath)) |
520 |
fatal ("unable to change to new instance directory"); |
521 |
|
522 |
for (;;) |
523 |
{ |
524 |
switch (pack_cur->type) |
525 |
{ |
526 |
case T_DIR: |
527 |
u_mkdir (PACK_NAME); |
528 |
break; |
529 |
|
530 |
case T_FILE: |
531 |
{ |
532 |
u_handle h = u_creat (PACK_NAME, pack_cur->flags & F_EXEC); |
533 |
unsigned int dlen, len = u_32 (pack_cur->datalen); |
534 |
char *data = PACK_DATA; |
535 |
|
536 |
if (pack_cur->flags & F_LZF) |
537 |
if (dlen = lzf_decompress (data, len, scratch, scratch_size)) |
538 |
{ |
539 |
data = scratch; |
540 |
len = dlen; |
541 |
} |
542 |
else |
543 |
fatal ("unable to uncompress file data - pack corrupted?"); |
544 |
|
545 |
if (!u_valid (h)) |
546 |
fatal ("unable to unpack file from packfile - disk full?"); |
547 |
|
548 |
if (u_write (h, data, len) != len) |
549 |
fatal ("unable to unpack file from packfile - disk full?"); |
550 |
|
551 |
u_fsync (h); |
552 |
u_close (h); |
553 |
} |
554 |
break; |
555 |
|
556 |
case T_NULL: |
557 |
goto done; |
558 |
} |
559 |
|
560 |
pack_next (); |
561 |
} |
562 |
|
563 |
done: |
564 |
if (u_chdir (datadir)) |
565 |
fatal ("unable to change to data directory"); |
566 |
|
567 |
u_sync (); |
568 |
|
569 |
if (u_rename (tmppath, execdir)) |
570 |
deltree (tmppath); // if move fails, delete new, assume other process created it independently |
571 |
} |
572 |
|
573 |
pack_unmap (); |
574 |
u_close (pack_handle); |
575 |
|
576 |
if (u_chdir (execdir)) |
577 |
fatal ("unable to change to application instance directory"); |
578 |
|
579 |
u_setenv ("URLADER_VERSION", URLADER_VERSION); |
580 |
u_setenv ("URLADER_DATADIR", datadir); |
581 |
u_setenv ("URLADER_EXECDIR", execdir); |
582 |
u_setenv ("URLADER_EXE_ID" , exe_id); |
583 |
u_setenv ("URLADER_EXE_DIR", exe_dir); |
584 |
u_setenv ("URLADER_EXE_VER", exe_ver); |
585 |
|
586 |
#if 0 |
587 |
// yes, this is overkill |
588 |
u_setenv ("SHLIB_PATH" , execdir); // hpux |
589 |
u_setenv ("LIBPATH" , execdir); // aix |
590 |
u_setenv ("LD_LIBRARY_PATH" , execdir); // most elf systems |
591 |
u_setenv ("LD_LIBRARY_PATH_32", execdir); // solaris |
592 |
u_setenv ("LD_LIBRARY_PATH_64", execdir); // solaris |
593 |
u_setenv ("LD_LIBRARYN32_PATH", execdir); // irix |
594 |
u_setenv ("LD_LIBRARY64_PATH" , execdir); // irix |
595 |
u_setenv ("DYLD_LIBRARY_PATH" , execdir); // os sucks from apple |
596 |
#endif |
597 |
} |
598 |
|
599 |
static void |
600 |
execute (void) |
601 |
{ |
602 |
exe_argv [exe_argc] = 0; |
603 |
systemv (exe_argv); |
604 |
} |
605 |
|
606 |
#ifdef _WIN32 |
607 |
|
608 |
int APIENTRY |
609 |
WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show) |
610 |
{ |
611 |
if (!GetModuleFileName (hI, tmppath, sizeof (tmppath))) |
612 |
fatal ("unable to find executable pack"); |
613 |
|
614 |
pack_handle = u_open (tmppath); |
615 |
if (!u_valid (pack_handle)) |
616 |
fatal ("unable to open executable pack"); |
617 |
|
618 |
exe_info (); |
619 |
|
620 |
if (!GetCurrentDirectory (sizeof (currdir), currdir)) |
621 |
strcpy (currdir, "."); |
622 |
|
623 |
if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK) |
624 |
fatal ("unable to find application data directory"); |
625 |
|
626 |
u_mkdir (datadir); |
627 |
u_append (datadir, URLADER); |
628 |
|
629 |
load (); |
630 |
execute (); |
631 |
|
632 |
return 0; |
633 |
} |
634 |
|
635 |
#else |
636 |
|
637 |
int |
638 |
main (int argc, char *argv[]) |
639 |
{ |
640 |
char *home = getenv ("HOME"); |
641 |
|
642 |
pack_handle = u_open (argv [0]); |
643 |
if (!u_valid (pack_handle)) |
644 |
fatal ("unable to open executable pack"); |
645 |
|
646 |
exe_info (); |
647 |
|
648 |
if (!home) |
649 |
{ |
650 |
struct passwd *pw; |
651 |
|
652 |
if ((pw = getpwuid (getuid ()))) |
653 |
home = pw->pw_dir; |
654 |
else |
655 |
home = "/tmp"; |
656 |
} |
657 |
|
658 |
if (!getcwd (currdir, sizeof (currdir))) |
659 |
strcpy (currdir, "."); |
660 |
|
661 |
u_mkdir (home); |
662 |
//strcat (strcat (strcpy (datadir, home), "/."), URLADER); |
663 |
sprintf (datadir, "%s/.%s", home, URLADER); |
664 |
u_mkdir (datadir); |
665 |
|
666 |
#if 0 |
667 |
if (gethostname (tmppath, sizeof (tmppath))) |
668 |
strcpy (tmppath, "default"); |
669 |
|
670 |
u_append (datadir, tmppath); |
671 |
#endif |
672 |
|
673 |
load (); |
674 |
execute (); |
675 |
|
676 |
return 0; |
677 |
} |
678 |
|
679 |
#endif |
680 |
|