tentative fix for issue 3 (ex 53)
[mplib] / src / texk / kpathsea / progname.c
1 /* progname.c: the executable name we were invoked as; general initialization.
2
3    Copyright 1994, 1996, 1997, 2008 Karl Berry.
4    Copyright 1998-2005 Olaf Weber.
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public License
17    along with this library; if not, see <http://www.gnu.org/licenses/>.  */
18
19 #include <kpathsea/config.h>
20 #include <kpathsea/absolute.h>
21 #include <kpathsea/c-pathch.h>
22 #include <kpathsea/c-stat.h>
23 #include <kpathsea/pathsearch.h>
24 /* For kpse_reset_progname */
25 #include <kpathsea/tex-file.h>
26
27 #if defined (WIN32) || defined (DJGPP)
28 #include <kpathsea/c-pathmx.h>
29 #endif
30
31 #if defined(__i386_pc_gnu__)
32 #ifndef _S_ISUID
33 #define _S_ISUID    04000  /* Set user ID on execution.  */
34 #endif
35 #ifndef _S_ISGID
36 #define _S_ISGID    02000  /* Set group ID on execution.  */
37 #endif
38 #ifndef _S_ISVTX
39 #define _S_ISVTX    01000  /* Save swapped text after use (sticky).  */
40 #endif
41 #ifndef _S_IREAD
42 #define _S_IREAD    0400   /* Read by owner.  */
43 #endif
44 #ifndef _S_IWRITE
45 #define _S_IWRITE   0200   /* Write by owner.  */
46 #endif
47 #ifndef _S_IEXEC
48 #define _S_IEXEC    0100   /* Execute by owner.  */
49 #endif
50 #endif
51
52 /* NeXT does not define the standard macros, but has the equivalent.
53    WIN32 doesn't define them either, and doesn't have them.
54    From: Gregor Hoffleit <flight@mathi.uni-heidelberg.de>.  */
55 #ifndef S_IXUSR
56 #ifdef WIN32
57 #define S_IXUSR 0
58 #define S_IXGRP 0
59 #define S_IXOTH 0
60 #else /* not WIN32 */
61 #define S_IXUSR 0100
62 #endif /* not WIN32 */
63 #endif /* not S_IXUSR */
64 #ifndef S_IXGRP
65 #define S_IXGRP 0010
66 #endif
67 #ifndef S_IXOTH
68 #define S_IXOTH 0001
69 #endif
70
71 #ifndef HAVE_PROGRAM_INVOCATION_NAME
72 /* Don't redefine the variables if glibc already has.  */
73 string program_invocation_name = NULL;
74 string program_invocation_short_name = NULL;
75 #endif
76 /* And the variable for the program we pretend to be. */
77 string kpse_program_name = NULL;
78 \f
79 #ifndef WIN32
80 /* From a standalone program `ll' to expand symlinks written by Kimbo Mundy.
81    Don't bother to compile if we don't have symlinks; thus we can assume
82    / as the separator.  Also don't try to use basename, etc., or
83    handle arbitrary filename length.  Mixed case function names because
84    that's what kimbo liked.  */
85
86 #ifdef S_ISLNK
87 static int ll_verbose = 0;
88 static int ll_loop = 0;
89
90 #undef BSIZE
91 #define BSIZE 2048 /* sorry */
92
93
94 /* Read link FN into SYM.  */
95
96 static void
97 ReadSymLink P2C(char *, fn, char *, sym)
98 {
99   register int n = readlink (fn, sym, BSIZE);
100   if (n < 0) {
101     perror (fn);
102     exit (1);
103   }
104   sym[n] = 0;
105 }
106
107
108 /* Strip first component from S, and also return it in a static buffer.  */
109
110 static char *
111 StripFirst P1C(register char *, s)
112 {
113   static char buf[BSIZE];
114   register char *s1;
115
116   /* Find the end of the first path element */
117   for (s1 = s; *s1 && (*s1 != '/' || s1 == s); s1++)
118     ;
119
120   /* Copy it into buf and null-terminate it. */
121   strncpy (buf, s, s1 - s);
122   buf[s1 - s] = 0;
123
124   /* Skip over the leading / (if any) */
125   if (*s1 == '/')
126     ++s1;
127
128   /* Squeeze out the element */
129   while ((*s++ = *s1++) != 0)
130     ;
131
132   return buf;
133 }
134
135
136 /* Strip last component from S, and also return it in a static buffer.  */
137
138 static char *
139 StripLast P1C(register char *, s)
140 {
141   static char buf[BSIZE];
142   register char *s1;
143
144   for (s1 = s + strlen (s); s1 > s && *s1 != '/'; s1--)
145     ;
146   strcpy (buf, s1 + (*s1 == '/'));
147   *s1 = 0;
148
149   return buf;
150 }
151
152
153 /* Copy first path element from B to A, removing it from B.  */
154
155 static void 
156 CopyFirst P2C(register char *, a, char *, b)
157 {
158   register int length = strlen (a);
159
160    if (length > 0 && a[length - 1] != '/') {
161    a[length] = '/';
162     a[length + 1] = 0;
163   }
164   strcat (a, StripFirst (b));
165 }
166
167 /* Returns NULL on error.  Prints intermediate results if global
168    `ll_verbose' is nonzero.  */
169
170 #define EX(s)           (strlen (s) && strcmp (s, "/") ? "/" : "")
171 #define EXPOS           EX(post)
172 #define EXPRE           EX(pre)
173
174 static char *
175 expand_symlinks P1C(char *, s)
176 {
177   static char pre[BSIZE];       /* return value */
178   char post[BSIZE], sym[BSIZE], tmp[BSIZE], before[BSIZE];
179   char *cp;
180   char a;
181   struct stat st;
182   int done;
183
184   /* Check for symlink loops.  It's difficult to check for all the
185      possibilities ourselves, so let the kernel do it.  And make it
186      conditional so that people can see where the infinite loop is
187      being caused (see engtools#1536).  */
188   if (!ll_loop) {
189     FILE *f = fopen (s, "r");
190     if (!f && errno == ELOOP) {
191       /* Not worried about other errors, we'll get to them in due course.  */
192       perror (s);
193       return NULL;
194     }
195     if (f) fclose (f);
196   }
197
198   strcpy (post, s);
199   strcpy (pre, "");
200
201   while (strlen (post) != 0) {
202     CopyFirst (pre, post);
203
204     if (lstat (pre, &st) != 0) {
205       fprintf (stderr, "lstat(%s) failed ...\n", pre);
206       perror (pre);
207       return NULL;
208     }
209
210     if (S_ISLNK (st.st_mode)) {
211       ReadSymLink (pre, sym);
212
213       if (!strncmp (sym, "/", 1)) {
214         if (ll_verbose)
215           printf ("[%s]%s%s -> [%s]%s%s\n", pre, EXPOS, post, sym, EXPOS,post);
216         strcpy (pre, "");
217
218       } else {
219         a = pre[0];     /* handle links through the root */
220         strcpy (tmp, StripLast (pre));
221         if (!strlen (pre) && a == '/')
222           strcpy (pre, "/");
223
224         if (ll_verbose) {
225           sprintf (before, "%s%s[%s]%s%s", pre, EXPRE, tmp, EXPOS, post);
226           printf ("%s -> %s%s[%s]%s%s\n", before, pre, EXPRE, sym, EXPOS,post);
227         }
228
229         /* Strip "../" path elements from the front of sym; print
230            new result if there were any such elements.  */
231         done = 0;
232         a = pre[0];     /* handle links through the root */
233         while (!strncmp (sym, "..", 2)
234                && (sym[2] == 0 || sym[2] == '/')
235                && strlen (pre) != 0
236                && strcmp (pre, ".")
237                && strcmp (pre, "..")
238                && (strlen (pre) < 3
239                    || strcmp (pre + strlen (pre) - 3, "/.."))) {
240           done = 1;
241           StripFirst (sym);
242           StripLast (pre);
243         }
244
245         if (done && ll_verbose) {
246           for (cp = before; *cp;)
247             *cp++ = ' ';
248           if (strlen (sym))
249             printf ("%s == %s%s%s%s%s\n", before, pre, EXPRE, sym, EXPOS,post);
250           else
251             printf ("%s == %s%s%s\n", before, pre, EXPOS, post);
252         }
253         if (!strlen (pre) && a == '/')
254           strcpy (pre, "/");
255       }
256
257       if (strlen (post) != 0 && strlen (sym) != 0)
258         strcat (sym, "/");
259
260       strcat (sym, post);
261       strcpy (post, sym);
262     }
263   }
264
265   return pre;
266 }
267 #else /* not S_ISLNK */
268 #define expand_symlinks(s) (s)
269 #endif /* not S_ISLNK */
270 \f
271 /* Remove .'s and ..'s in DIR, to avoid problems with relative symlinks
272    as the program name, etc.  This does not canonicalize symlinks.  */
273
274 static string
275 remove_dots P1C(string, dir)
276 {
277 #ifdef AMIGA
278   return dir;
279 #else
280   string c;
281   unsigned len;
282   string ret = (string) ""; /* We always reassign.  */
283   
284   for (c = kpse_filename_component (dir); c;
285        c = kpse_filename_component (NULL)) {
286     if (STREQ (c, ".")) {
287       /* If leading ., replace with cwd.  Else ignore.  */
288       if (*ret == 0) {
289         ret = xgetcwd ();
290       }
291
292     } else if (STREQ (c, "..")) {
293       /* If leading .., start with xdirname (cwd).  Else remove last
294          component from ret, if any.  */
295       if (*ret == 0) {
296         string dot = xgetcwd ();
297         ret = xdirname (dot);
298         free (dot);
299       } else {
300         unsigned last;
301         for (last = strlen (ret);
302              last > (NAME_BEGINS_WITH_DEVICE (ret) ? 2 : 0);
303              last--) {
304           if (IS_DIR_SEP (ret[last - 1])) {
305             /* If we have `/../', that's the same as `/'.  */
306             if (last > 1) {
307               ret[last - 1] = 0;
308             }
309             break;
310           }
311         }
312       }
313
314     } else {
315       /* Not . or ..; just append.  Include a directory separator unless
316          our string already ends with one.  This also changes all directory
317          separators into the canonical DIR_SEP_STRING.  */
318       string temp;
319       len = strlen (ret);
320       temp = concat3 (ret, ((len > 0 && ret[len - 1] == DIR_SEP)
321                             || (NAME_BEGINS_WITH_DEVICE (c) && *ret == 0))
322                            ? "" : DIR_SEP_STRING,
323                       c);
324       if (*ret)
325         free (ret);
326       ret = temp;
327     }
328   }
329   
330   /* Remove a trailing /, just in case it snuck in.  */
331   len = strlen (ret);
332   if (len > 0 && ret[len - 1] == DIR_SEP) {
333     ret[len - 1] = 0;
334   }
335
336   return ret;
337 #endif /* not AMIGA */
338 }
339 \f
340 /* Return directory ARGV0 comes from.  Check PATH if ARGV0 is not
341    absolute.  */
342
343 static string
344 selfdir P1C(const_string, argv0)
345 {
346   string ret = NULL;
347   string self = NULL;
348   
349   if (kpse_absolute_p (argv0, true)) {
350     self = xstrdup (argv0);
351   } else {
352 #ifdef AMIGA
353 #include <dos.h>
354 #include <proto/dos.h>
355 #include <proto/exec.h>
356     BPTR lock;
357     struct DosLibrary *DOSBase
358       = (struct DosLibrary *) OpenLibrary ("dos.library", 0L);
359     assert (DOSBase);
360
361     self = xmalloc (BUFSIZ);
362     lock = findpath (argv0);
363     if (lock != ((BPTR) -1)) {
364       if (getpath (lock, self) == -1) {
365         *self = '\0';
366       } else {
367         strcat (self,DIR_SEP_STRING);
368         strcat (self,argv0); 
369       }
370       UnLock (lock);
371     }
372     CloseLibrary((struct Library *) DOSBase);
373 #else /* not AMIGA */
374     string elt;
375     struct stat s;
376
377     /* Have to check PATH.  But don't call kpse_path_search since we don't
378        want to search any ls-R's or do anything special with //'s.  */
379     for (elt = kpse_path_element (getenv ("PATH")); !self && elt;
380          elt = kpse_path_element (NULL)) {
381       string name;
382       
383       /* UNIX tradition interprets the empty path element as "." */
384       if (*elt == 0) elt = ".";
385       
386       name = concat3 (elt, DIR_SEP_STRING, argv0);
387
388       /* In order to do this perfectly, we'd have to check the owner bits only
389          if we are the file owner, and the group bits only if we belong
390          to the file group.  That's a lot of work, though, and it's not
391          likely that kpathsea will ever be used with a program that's
392          only executable by some classes and not others.  See the
393          `file_status' function in execute_cmd.c in bash for what's
394          necessary if we were to do it right.  */
395       if (stat (name, &s) == 0 && s.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
396         /* Do not stop at directories. */
397         if (!S_ISDIR(s.st_mode)) 
398           self = name;
399       }
400     }
401 #endif /* not AMIGA */
402   }
403   
404   /* If argv0 is somehow dir/exename, `self' will still be NULL.  */
405   if (!self)
406     self = concat3 (".", DIR_SEP_STRING, argv0);
407     
408   ret = xdirname (remove_dots (expand_symlinks (self)));
409
410   free (self);
411   
412   return ret;
413 }
414 #endif /* not WIN32 */
415 \f
416 void
417 kpse_set_program_name P2C(const_string, argv0, const_string, progname)
418 {
419   string ext, sdir, sdir_parent, sdir_grandparent;
420   string s = getenv ("KPATHSEA_DEBUG");
421 #ifdef WIN32
422   string debug_output = getenv("KPATHSEA_DEBUG_OUTPUT");
423   string append_debug_output = getenv("KPATHSEA_DEBUG_APPEND");
424   int err, olderr;
425 #endif
426   
427   /* Set debugging stuff first, in case we end up doing debuggable stuff
428      during this initialization.  */
429   if (s) {
430     kpathsea_debug |= atoi (s);
431   }
432
433 #ifndef HAVE_PROGRAM_INVOCATION_NAME
434 #if defined(WIN32)
435   /* Set various info about user. Among many things,
436      ensure that HOME is set. If debug_paths is on, 
437      turn on some message if $HOME is not found. */
438   if (KPSE_DEBUG_P(KPSE_DEBUG_PATHS)) {
439 #ifndef __MINGW32__
440     set_home_warning();
441 #else
442     extern int output_home_warning;
443     output_home_warning = 1;
444 #endif
445   }
446   init_user_info();
447
448   /* redirect stderr to debug_output. Easier to send logfiles. */
449   if (debug_output) {
450     int flags =  _O_CREAT | _O_TRUNC | _O_RDWR;
451     err = -1;
452     if (_stricmp(debug_output, "con") == 0
453        || _stricmp(debug_output, "con:") == 0) {
454       err = _fileno(stdout);
455     } else {
456       if (append_debug_output) {
457         flags =  _O_CREAT | _O_APPEND | _O_WRONLY;
458       } else {
459         flags =  _O_CREAT | _O_TRUNC | _O_WRONLY;
460         xputenv("KPATHSEA_DEBUG_APPEND", "yes");
461       }
462     }
463
464     if ((err < 0)
465         && (err = _open(debug_output, flags, _S_IREAD | _S_IWRITE)) == -1)
466     {
467       WARNING1("Can't open %s for stderr redirection!\n", debug_output);
468       perror(debug_output);
469     } else if ((olderr = _dup(fileno(stderr))) == -1) {
470       WARNING("Can't dup() stderr!\n");
471       close(err);
472     } else if (_dup2(err, fileno(stderr)) == -1) {
473       WARNING1("Can't redirect stderr to %s!\n", debug_output);
474       close(olderr);
475       close(err);
476     } else {
477       close(err);
478     }
479   }
480   /* Win95 always gives the short filename for argv0, not the long one.
481      There is only this way to catch it. It makes all the selfdir stuff
482      useless for win32. */
483   {
484     char short_path[PATH_MAX], path[PATH_MAX], *fp;
485       
486     /* SearchPath() always gives back an absolute directory */
487     if (SearchPath(NULL, argv0, ".exe", PATH_MAX, short_path, &fp) == 0)
488         FATAL1("Can't determine where the executable %s is.\n", argv0);
489     if (!win32_get_long_filename(short_path, path, sizeof(path))) {
490         FATAL1("This path points to an invalid file : %s\n", short_path);
491     }
492     /* slashify the dirname */
493     for (fp = path; fp && *fp; fp++)
494         if (IS_DIR_SEP(*fp)) *fp = DIR_SEP;
495     /* sdir will be the directory of the executable, ie: c:/TeX/bin */
496     sdir = xdirname(path);
497     program_invocation_name = xstrdup(xbasename(path));
498   }
499
500 #elif defined(__DJGPP__)
501
502   /* DJGPP programs support long filenames on Windows 95, but ARGV0 there
503      is always made with the short 8+3 aliases of all the pathname elements.
504      If long names are supported, we need to convert that to a long name.
505
506      All we really need is to call `_truename', but most of the code
507      below is required to deal with the special case of networked drives.  */
508   if (pathconf (argv0, _PC_NAME_MAX) > 12) {
509     char long_progname[PATH_MAX];
510
511     if (_truename (argv0, long_progname)) {
512       char *fp;
513
514       if (long_progname[1] != ':') {
515         /* A complication: `_truename' returns network-specific string at
516            the beginning of `long_progname' when the program resides on a
517            networked drive, and DOS calls cannot grok such pathnames.  We
518            need to convert the filesystem name back to a drive letter.  */
519         char rootname[PATH_MAX], rootdir[4];
520
521         if (argv0[0] && argv0[1] == ':')
522           rootdir[0] = argv0[0]; /* explicit drive in `argv0' */
523         else
524           rootdir[0] = getdisk () + 'A';
525         rootdir[1] = ':';
526         rootdir[2] = '\\';
527         rootdir[3] = '\0';
528         if (_truename (rootdir, rootname)) {
529           /* Find out where `rootname' ends in `long_progname' and replace
530              it with the drive letter.  */
531           int root_len = strlen (rootname);
532
533           if (IS_DIR_SEP (rootname[root_len - 1]))
534             root_len--; /* keep the trailing slash */
535           long_progname[0] = rootdir[0];
536           long_progname[1] = ':';
537           memmove (long_progname + 2, long_progname + root_len,
538                    strlen (long_progname + root_len) + 1);
539         }
540       }
541
542       /* Convert everything to canonical form.  */
543       if (long_progname[0] >= 'A' && long_progname[0] <= 'Z')
544         long_progname[0] += 'a' - 'A'; /* make drive lower case, for beauty */
545       for (fp = long_progname; *fp; fp++)
546         if (IS_DIR_SEP (*fp))
547           *fp = DIR_SEP;
548
549       program_invocation_name = xstrdup (long_progname);
550     }
551     else
552       /* If `_truename' failed, God help them, because we won't...  */
553       program_invocation_name = xstrdup (argv0);
554   }
555   else
556     program_invocation_name = xstrdup (argv0);
557
558 #else /* !WIN32 && !__DJGPP__ */
559
560   program_invocation_name = xstrdup (argv0);
561
562 #endif
563 #endif /* not HAVE_PROGRAM_INVOCATION_NAME */
564
565   /* We need to find SELFAUTOLOC *before* removing the ".exe" suffix from
566      the program_name, otherwise the PATH search inside selfdir will fail,
567      since `prog' doesn't exists as a file, there's `prog.exe' instead.  */
568 #ifndef WIN32
569   sdir = selfdir (program_invocation_name);
570 #endif
571   /* SELFAUTODIR is actually the parent of the invocation directory,
572      and SELFAUTOPARENT the grandparent.  This is how teTeX did it.  */
573   xputenv ("SELFAUTOLOC", sdir);
574   sdir_parent = xdirname (sdir);
575   xputenv ("SELFAUTODIR", sdir_parent);
576   sdir_grandparent = xdirname (sdir_parent);
577   xputenv ("SELFAUTOPARENT", sdir_grandparent);
578
579   free (sdir);
580   free (sdir_parent);
581   free (sdir_grandparent);
582
583 #ifndef HAVE_PROGRAM_INVOCATION_NAME
584   program_invocation_short_name = (string)xbasename (program_invocation_name);
585 #endif
586
587   if (progname) {
588     kpse_program_name = xstrdup (progname);
589   } else {
590     /* If configured --enable-shared and running from the build directory
591        with the wrapper scripts (e.g., for make check), the binaries will
592        be named foo.exe instead of foo.  Or possibly if we're running on a
593        DOSISH system.  */
594     ext = find_suffix (program_invocation_short_name);
595     if (ext && FILESTRCASEEQ (ext, "exe")) {
596       kpse_program_name = remove_suffix (program_invocation_short_name);
597     } else {
598       kpse_program_name = xstrdup (program_invocation_short_name);
599     }
600   }
601
602   xputenv("progname", kpse_program_name);
603 }
604
605 /* This function is deprecated, because when we pretend to have a different
606    name it will look for _that_ name in the PATH if program_invocation_name
607    is not defined.  */
608 void
609 kpse_set_progname P1C(const_string, argv0)
610 {
611   kpse_set_program_name (argv0, NULL);
612 }
613 \f
614 #ifdef TEST
615 void
616 main (int argc, char **argv)
617 {
618   puts (remove_dots ("/w/kpathsea"));
619   puts (remove_dots ("/w//kpathsea"));
620   puts (remove_dots ("/w/./kpathsea"));
621   puts (remove_dots ("."));
622   puts (remove_dots ("./"));
623   puts (remove_dots ("./."));
624   puts (remove_dots ("../kpathsea"));
625   puts (remove_dots ("/kpathsea/../foo"));
626   puts (remove_dots ("/../w/kpathsea"));
627   puts (remove_dots ("/../w/kpathsea/."));
628   puts (remove_dots ("/te/share/texmf/../../../../bin/gnu"));
629 }
630 /*
631 Local variables:
632 standalone-compile-command: "gcc -g -I. -I.. -DTEST progname.c STATIC/libkpathsea.a"
633 End:
634 */
635 #endif /* TEST */