dwbinit.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. *
  11. * Pathname management routines for DWB C programs.
  12. *
  13. * Applications should initialize a dwbinit array with the string
  14. * pointers and arrays that need to be updated, and then hand that
  15. * array to DWBinit before much else happens in their main program.
  16. * DWBinit calls DWBhome to get the current home directory. DWBhome
  17. * uses the last definition of DWBENV (usually "DWBHOME") in file
  18. * DWBCONFIG (e.g., /usr/lib/dwb3.4) or the value assigned to that
  19. * variable in the environment if the DWBCONFIG file doesn't exist,
  20. * can't be read, or doesn't define DWBENV.
  21. *
  22. * DWBCONFIG must be a simple shell script - comments, a definition
  23. * of DWBHOME, and perhaps an export or echo is about all that's
  24. * allowed. The parsing in DWBhome is simple and makes no attempt
  25. * to duplicate the shell. It only looks for DWBHOME= as the first
  26. * non-white space string on a line, so
  27. *
  28. * #
  29. * # A sample DWBCONFIG shell script
  30. * #
  31. *
  32. * DWBHOME=/usr/add-on/dwb3.4
  33. * export DWBHOME
  34. *
  35. * means DWBhome would return "/usr/add-on/dwb3.4" for the DWB home
  36. * directory. A DWBCONFIG file means there can only be one working
  37. * copy of a DWB release on a system, which seems like a good idea.
  38. * Using DWBCONFIG also means programs will always include correct
  39. * versions of files (e.g., prologues or macro packages).
  40. *
  41. * Relying on an environment variable guarantees nothing. You could
  42. * execute a version of dpost, but your environment might point at
  43. * incorrect font tables or prologues. Despite the obvious problems
  44. * we've also implemented an environment variable approach, but it's
  45. * only used if there's no DWBCONFIG file.
  46. *
  47. * DWBinit calls DWBhome to get the DWB home directory prefix and
  48. * then marches through its dwbinit argument, removing the default
  49. * home directory and prepending the new home. DWBinit stops when
  50. * it reaches an element that has NULL for its address and value
  51. * fields. Pointers in a dwbinit array are reallocated and properly
  52. * initialized; arrays are simply reinitialized if there's room.
  53. * All pathnames that are to be adjusted should be relative. For
  54. * example,
  55. *
  56. * char *fontdir = "lib/font";
  57. * char xyzzy[25] = "etc/xyzzy";
  58. *
  59. * would be represented in a dwbinit array as,
  60. *
  61. * dwbinit allpaths[] = {
  62. * &fontdir, NULL, 0,
  63. * NULL, xyzzy, sizeof(xyzzy),
  64. * NULL, NULL, 0
  65. * };
  66. *
  67. * The last element must have NULL entries for the address and
  68. * value fields. The main() routine would then do,
  69. *
  70. * #include "dwbinit.h"
  71. *
  72. * main() {
  73. *
  74. * DWBinit("program name", allpaths);
  75. * ...
  76. * }
  77. *
  78. * Debugging is enabled if DWBDEBUG is in the environment and has
  79. * the value ON. Output is occasionally useful and probably should
  80. * be documented.
  81. *
  82. */
  83. #include <stdio.h>
  84. #include <ctype.h>
  85. #include <string.h>
  86. #include <stdlib.h>
  87. #include "dwbinit.h"
  88. #ifndef DWBCONFIG
  89. #define DWBCONFIG "/dev/null"
  90. #endif
  91. #ifndef DWBENV
  92. #define DWBENV "DWBHOME"
  93. #endif
  94. #ifndef DWBHOME
  95. #define DWBHOME ""
  96. #endif
  97. #ifndef DWBDEBUG
  98. #define DWBDEBUG "DWBDEBUG"
  99. #endif
  100. #ifndef DWBPREFIX
  101. #define DWBPREFIX "\\*(.P"
  102. #endif
  103. /*****************************************************************************/
  104. void DWBdebug(dwbinit *ptr, int level)
  105. {
  106. char *path;
  107. char *home;
  108. static char *debug = NULL;
  109. /*
  110. *
  111. * Debugging output, but only if DWBDEBUG is defined to be ON in the
  112. * environment. Dumps general info the first time through.
  113. *
  114. */
  115. if ( debug == NULL && (debug = getenv(DWBDEBUG)) == NULL )
  116. debug = "OFF";
  117. if ( strcmp(debug, "ON") == 0 ) {
  118. if ( level == 0 ) {
  119. fprintf(stderr, "Environment variable: %s\n", DWBENV);
  120. fprintf(stderr, "Configuration file: %s\n", DWBCONFIG);
  121. fprintf(stderr, "Default home: %s\n", DWBHOME);
  122. if ( (home = DWBhome()) != NULL )
  123. fprintf(stderr, "Current home: %s\n", home);
  124. } /* End if */
  125. fprintf(stderr, "\n%s pathnames:\n", level == 0 ? "Original" : "Final");
  126. for ( ; ptr->value != NULL || ptr->address != NULL; ptr++ ) {
  127. if ( (path = ptr->value) == NULL ) {
  128. path = *ptr->address;
  129. fprintf(stderr, " pointer: %s\n", path);
  130. } else fprintf(stderr, " array[%d]: %s\n", ptr->length, path);
  131. if ( level == 0 && *path == '/' )
  132. fprintf(stderr, " WARNING - absolute path\n");
  133. } /* End for */
  134. } /* End if */
  135. } /* End of DWBdebug */
  136. /*****************************************************************************/
  137. char *DWBhome(void)
  138. {
  139. FILE *fp;
  140. char *ptr;
  141. char *path;
  142. int len;
  143. char buf[200];
  144. char *home = NULL;
  145. /*
  146. *
  147. * Return the DWB home directory. Uses the last definition of DWBENV
  148. * (usually "DWBHOME") in file DWBCONFIG (perhaps /usr/lib/dwb3.4) or
  149. * the value assigned to the variable named by the DWBENV string in
  150. * the environment if DWBCONFIG doesn't exist or doesn't define DWBENV.
  151. * Skips the file lookup if DWBCONFIG can't be read. Returns NULL if
  152. * there's no home directory.
  153. *
  154. */
  155. if ( (fp = fopen(DWBCONFIG, "r")) != NULL ) {
  156. len = strlen(DWBENV);
  157. while ( fgets(buf, sizeof(buf), fp) != NULL ) {
  158. for ( ptr = buf; isspace(*ptr); ptr++ ) ;
  159. if ( strncmp(ptr, DWBENV, len) == 0 && *(ptr+len) == '=' ) {
  160. path = ptr + len + 1;
  161. for ( ptr = path; !isspace(*ptr) && *ptr != ';'; ptr++ ) ;
  162. *ptr = '\0';
  163. if ( home != NULL )
  164. free(home);
  165. if ( (home = malloc(strlen(path)+1)) != NULL )
  166. strcpy(home, path);
  167. } /* End if */
  168. } /* End while */
  169. fclose(fp);
  170. } /* End if */
  171. if ( home == NULL ) {
  172. if ( (home = getenv(DWBENV)) == NULL ) {
  173. if ( (home = DWBHOME) == NULL || *home == '\0' || *home == ' ' )
  174. home = NULL;
  175. } /* End if */
  176. } /* End if */
  177. while (home && *home == '/' && *(home +1) == '/') /* remove extra slashes */
  178. home++;
  179. return(home);
  180. } /* End of DWBhome */
  181. /*****************************************************************************/
  182. void DWBinit(char *prog, dwbinit *paths)
  183. {
  184. char *prefix;
  185. char *value;
  186. char *path;
  187. int plen;
  188. int length;
  189. dwbinit *opaths = paths;
  190. /*
  191. *
  192. * Adjust the pathnames listed in paths, using the home directory
  193. * returned by DWBhome(). Stops when it reaches an element that has
  194. * NULL address and value fields. Assumes pathnames are relative,
  195. * but changes everything. DWBdebug issues a warning if an original
  196. * path begins with a /.
  197. *
  198. * A non-NULL address refers to a pointer, which is reallocated and
  199. * then reinitialized. A NULL address implies a non-NULL value field
  200. * and describes a character array that we only reinitialize. The
  201. * length field for an array is the size of that array. The length
  202. * field of a pointer is an increment that's added to the length
  203. * required to store the new pathname string - should help when we
  204. * want to change character arrays to pointers in applications like
  205. * troff.
  206. *
  207. */
  208. if ( (prefix = DWBhome()) == NULL ) {
  209. fprintf(stderr, "%s: no DWB home directory\n", prog);
  210. exit(1);
  211. } /* End if */
  212. DWBdebug(opaths, 0);
  213. plen = strlen(prefix);
  214. for ( ; paths->value != NULL || paths->address != NULL; paths++ ) {
  215. if ( paths->address == NULL ) {
  216. length = 0;
  217. value = paths->value;
  218. } else {
  219. length = paths->length;
  220. value = *paths->address;
  221. } /* End else */
  222. length += plen + 1 + strlen(value); /* +1 is for the '/' */
  223. if ( (path = malloc(length+1)) == NULL ) {
  224. fprintf(stderr, "%s: can't allocate pathname memory\n", prog);
  225. exit(1);
  226. } /* End if */
  227. if ( *value != '\0' ) {
  228. char *eop = prefix;
  229. while(*eop++)
  230. ;
  231. eop -= 2;
  232. if (*value != '/' && *eop != '/') {
  233. sprintf(path, "%s/%s", prefix, value);
  234. } else if (*value == '/' && *eop == '/') {
  235. value++;
  236. sprintf(path, "%s%s", prefix, value);
  237. } else
  238. sprintf(path, "%s%s", prefix, value);
  239. } else
  240. sprintf(path, "%s", prefix);
  241. if ( paths->address == NULL ) {
  242. if ( strlen(path) >= paths->length ) {
  243. fprintf(stderr, "%s: no room for %s\n", prog, path);
  244. exit(1);
  245. } /* End if */
  246. strcpy(paths->value, path);
  247. free(path);
  248. } else *paths->address = path;
  249. } /* End for */
  250. DWBdebug(opaths, 1);
  251. } /* End of DWBinit */
  252. /*****************************************************************************/
  253. void DWBprefix(char *prog, char *path, int length)
  254. {
  255. char *home;
  256. char buf[512];
  257. int len = strlen(DWBPREFIX);
  258. /*
  259. *
  260. * Replace a leading DWBPREFIX string in path by the current DWBhome().
  261. * Used by programs that pretend to handle .so requests. Assumes path
  262. * is an array with room for length characters. The implementation is
  263. * not great, but should be good enough for now. Also probably should
  264. * have DWBhome() only do the lookup once, and remember the value if
  265. * called again.
  266. *
  267. */
  268. if ( strncmp(path, DWBPREFIX, len) == 0 ) {
  269. if ( (home = DWBhome()) != NULL ) {
  270. if ( strlen(home) + strlen(path+len) < length ) {
  271. sprintf(buf, "%s%s", home, path+len);
  272. strcpy(path, buf); /* assuming there's room in path */
  273. } else fprintf(stderr, "%s: no room to grow path %s", prog, path);
  274. } /* End if */
  275. } /* End if */
  276. } /* End of DWBprefix */
  277. /*****************************************************************************/