syscyg.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /* syscyg.c Copyright (C) 1989-98 Codemist Ltd */
  2. /*
  3. * System-specific code for use with the "cygwin" compilers and
  4. * libraries that provide a sort of Unix work-alike environment while
  5. * hosted on Windows (95, 98 or NT).
  6. */
  7. /* Signature: 57128fa5 07-Mar-2000 */
  8. #include "machine.h"
  9. #include <sys/stat.h>
  10. #ifndef NO_UNISTD_AVAILABLE
  11. /*
  12. * Posix mandates a header <unistd.h>, which is why I feel entitled to
  13. * include it here. But for systems that do not I can assert
  14. * NO_UNISTD_AVAILABLE in machine.h and worry about other ways to
  15. * reference the relevant facilities...
  16. */
  17. #include <unistd.h>
  18. #endif
  19. #include <stdarg.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <sys/types.h>
  24. #include <dirent.h>
  25. #include <errno.h>
  26. #include "tags.h"
  27. #include "externs.h"
  28. #include "sys.h"
  29. #ifdef TIMEOUT
  30. #include "timeout.h"
  31. #endif
  32. #include "filename.c"
  33. int change_directory(char *filename, char *old, size_t n)
  34. {
  35. process_file_name(filename, old, n);
  36. if (*filename == 0) return 1;
  37. if (chdir(filename))
  38. { char err_buf[LONGEST_LEGAL_FILENAME+100];
  39. char *msg;
  40. switch (errno)
  41. {
  42. case ENOTDIR:
  43. msg = "A component of %s is not a directory.";
  44. break;
  45. case ENOENT:
  46. msg = "The directory %s does not exist.";
  47. break;
  48. case EACCES:
  49. msg = "Insufficient permission for %s.";
  50. break;
  51. /*
  52. * This symbol seems not to be available under HP versions of Unix.
  53. * Since I am just producing pretty error messages here the loss of
  54. * functionality missing it out is pretty minor...
  55. */
  56. case ELOOP:
  57. msg = "Pathname %s has too many symbolic links.";
  58. break;
  59. case ENAMETOOLONG:
  60. msg = "The pathname %s is too long.";
  61. break;
  62. default:
  63. msg = "Cannot change directory to %s.";
  64. break;
  65. }
  66. sprintf(err_buf, msg, filename);
  67. aerror0(err_buf);
  68. return 1;
  69. }
  70. else return 0;
  71. }
  72. int create_directory(char *filename, char *old, size_t n)
  73. {
  74. process_file_name(filename, old, n);
  75. if (*filename == 0) return 1;
  76. return mkdir(filename, 0770);
  77. }
  78. static void remove_files(char *name, int dirp, long int size)
  79. /* Remove a file, or a directory and all its contents */
  80. {
  81. switch (dirp)
  82. {
  83. case 0: /* SCAN_FILE */
  84. remove(name);
  85. return;
  86. case 2: /* SCAN_ENDDIR */
  87. rmdir(name);
  88. return;
  89. default: /* 1 == SCAN_STARTDIR */
  90. return;
  91. }
  92. }
  93. int delete_file(char *filename, char *old, size_t n)
  94. {
  95. process_file_name(filename, old, n);
  96. if (*filename == 0) return 0;
  97. /*
  98. * We cannot simply use remove here, since this will not
  99. * work with directories and their contents. Hence the
  100. * use of scan_directory.
  101. */
  102. scan_directory(filename, remove_files);
  103. return 0;
  104. }
  105. /* extern char *getcwd(char *s, size_t n); in case unistd not used */
  106. int get_current_directory(char *s, int n)
  107. {
  108. #ifdef NO_GETCWD
  109. aerror0("cannot get current directory name.");
  110. *s = 0;
  111. return 0;
  112. #else
  113. if (getcwd(s, n) == 0)
  114. { switch(errno)
  115. {
  116. case ERANGE:
  117. aerror0("the pathname of the current directory is too long.");
  118. break;
  119. case EACCES:
  120. aerror0("insufficient permission to get pathname.");
  121. break;
  122. default:
  123. aerror0("cannot get current directory name.");
  124. break;
  125. }
  126. *s = 0;
  127. return 0;
  128. }
  129. else return strlen(s);
  130. #endif
  131. }
  132. #ifndef S_IFMT
  133. #ifdef __S_IFMT
  134. #define S_IFMT __S_IFMT
  135. #endif
  136. #endif
  137. #ifndef S_IFDIR
  138. #ifdef __S_IFDIR
  139. #define S_IFDIR __S_IFDIR
  140. #endif
  141. #endif
  142. int directoryp(char *filename, char *old, size_t n)
  143. {
  144. struct stat buf;
  145. process_file_name(filename, old, n);
  146. if (*filename == 0) return 0;
  147. if (stat(filename,&buf) == -1) return 0;
  148. return ((buf.st_mode & S_IFMT) == S_IFDIR);
  149. }
  150. char *get_truename(char *filename, char *old, size_t n)
  151. {
  152. struct stat buf;
  153. char *temp, *fn, *dir, *pwd;
  154. process_file_name(filename, old, n);
  155. if (*filename == 0) aerror("truename");
  156. /* Find out whether we have a file or a directory */
  157. if (stat(filename,&buf) == -1) aerror0("truename: cannot stat file");
  158. /* Store current directory */
  159. /* /*
  160. * The next line is UNSATISFACTORY because Posix explicitly says (at least in
  161. * in the copy of 1003.1 that I have) that getcwd has undefined behaviour
  162. * if its first argument is NULL.
  163. */
  164. if ((pwd = (char *)getcwd((char *)NULL, LONGEST_LEGAL_FILENAME)) == NULL)
  165. aerror0("truename: cannot get current working directory");
  166. if ((buf.st_mode & S_IFMT) == S_IFDIR)
  167. { /* We have a directory */
  168. char *dir = (char*) malloc(LONGEST_LEGAL_FILENAME);
  169. if (chdir(filename) != 0)
  170. aerror0("truename: cannot change directory");
  171. if (getcwd(dir,LONGEST_LEGAL_FILENAME) == NULL)
  172. aerror0("truename: cannot get current working directory");
  173. if (chdir(pwd) != 0)
  174. aerror0("truename: cannot change directory");
  175. free(pwd);
  176. /*
  177. * Axiom-specific hack: truename preserves '/' at the end of
  178. * a path
  179. */
  180. if (old[n-1] == '/' && dir[strlen(dir)-1] != '/')
  181. { n = strlen(dir);
  182. dir[n] = '/';
  183. dir[n+1] = '\0';
  184. }
  185. return dir;
  186. }
  187. else
  188. { /* Assume we have some kind of file */
  189. temp = strrchr(filename,'/');
  190. if (temp)
  191. { /* Found a directory component */
  192. fn = (char *)malloc(1+strlen(temp));
  193. strcpy(fn, temp); /* strdup(temp); */
  194. *temp = '\0';
  195. /* fn is now "/file" and filename is the directory */
  196. if (chdir(filename) != 0)
  197. aerror0("truename: cannot change directory");
  198. /* /* getcwd(NULL,...) invalid */
  199. if ((temp = (char *)getcwd((char *)NULL,LONGEST_LEGAL_FILENAME)) == NULL)
  200. aerror0("truename: cannot get current working directory");
  201. if (chdir(pwd) != 0)
  202. aerror0("truename: cannot change directory");
  203. dir = (char *)malloc((strlen(temp) + strlen(fn) + 1)*sizeof(char));
  204. /* /*
  205. * No check for malloc failure...
  206. */
  207. strcpy(dir, temp);
  208. free(temp);
  209. free(pwd);
  210. strcat(dir, fn);
  211. free(fn);
  212. return dir;
  213. }
  214. else
  215. { dir = (char *)malloc((strlen(pwd) + strlen(filename) + 2)*sizeof(char));
  216. /* /* No check for malloc failure */
  217. strcpy(dir,pwd);
  218. strcat(dir, "/");
  219. strcat(dir, filename);
  220. free(pwd);
  221. return dir;
  222. }
  223. }
  224. }
  225. #ifndef DO_NOT_USE_STAT
  226. int file_readable(char *filename, char *old, size_t n)
  227. {
  228. struct stat buf;
  229. process_file_name(filename, old, n);
  230. if (*filename == 0) return 0;
  231. if (stat(filename,&buf) == -1)
  232. return 0; /* File probably does not exist */
  233. else if (geteuid() == buf.st_uid)
  234. return (buf.st_mode & S_IRUSR);
  235. else if (getegid() == buf.st_gid)
  236. return (buf.st_mode & S_IRGRP);
  237. else
  238. return (buf.st_mode & S_IROTH);
  239. }
  240. int file_writeable(char *filename, char *old, size_t n)
  241. {
  242. struct stat buf;
  243. process_file_name(filename, old, n);
  244. if (*filename == 0) return 0;
  245. if (stat(filename,&buf) == -1)
  246. return 0; /* Should we check to see if the directory is writeable? */
  247. else if (geteuid() == buf.st_uid)
  248. return (buf.st_mode & S_IWUSR);
  249. else if (getegid() == buf.st_gid)
  250. return (buf.st_mode & S_IWGRP);
  251. else
  252. return (buf.st_mode & S_IWOTH);
  253. }
  254. #else
  255. int file_readable(char *filename, char *old, size_t n)
  256. {
  257. FILE *fp;
  258. process_file_name(filename, old, n);
  259. if (*filename == 0) return 0;
  260. /* The "correct" way to do this is via stat, but this is much simpler! */
  261. fp = fopen(filename,"r");
  262. if (fp == NULL) return 0;
  263. else
  264. { fclose(fp);
  265. return 1;
  266. }
  267. }
  268. int file_writeable(char *filename, char *old, size_t n)
  269. {
  270. FILE *fp;
  271. process_file_name(filename, old, n);
  272. if (*filename == 0) return 0;
  273. fp = fopen(filename,"a");
  274. if (fp == NULL) return 0;
  275. else
  276. { fclose(fp);
  277. return 1;
  278. }
  279. }
  280. #endif
  281. int rename_file(char *from_name, char *from_old, size_t from_size,
  282. char *to_name, char *to_old, size_t to_size)
  283. {
  284. process_file_name(from_name, from_old, from_size);
  285. process_file_name(to_name, to_old, to_size);
  286. if (*from_name == 0 || *to_name == 0) return 0;
  287. return rename(from_name,to_name);
  288. }
  289. #ifdef NAG_VERSION
  290. int list_directory_members(char *filename, char *old, char **filelist[],
  291. size_t n)
  292. { struct dirent **namelist;
  293. int number_of_entries, i;
  294. char **files;
  295. process_file_name(filename, old, n);
  296. /* scandir expects "." for the current directory */
  297. if (*filename == 0) number_of_entries = scandir(".",&namelist,NULL,NULL);
  298. else number_of_entries = scandir(filename,&namelist,NULL,NULL);
  299. /*
  300. * If the scandir failed then return now, since we make an assumption later
  301. * that we found at least two entries: "." and "..".
  302. */
  303. if (number_of_entries == -1) return -1;
  304. files=(char **)malloc(number_of_entries*sizeof(char *));
  305. for (i=0;i<number_of_entries;++i)
  306. { files[i] = strdup(namelist[i]->d_name);
  307. free(namelist[i]);
  308. }
  309. free(namelist);
  310. *filelist = files;
  311. /*
  312. * When we return we will prepend the directory name to the files, so we
  313. * must make sure it is suitable for that. This is done here since it is
  314. * platform dependent (i.e. in DOS we would need to ensure the last
  315. * character was "\").
  316. */
  317. /*
  318. i=strlen(filename);
  319. if (i > 0 && filename[i-1] != '/')
  320. { filename[i]='/';
  321. filename[i+1]='\0';
  322. }
  323. */
  324. return number_of_entries;
  325. }
  326. #else
  327. void list_directory_members(char *filename, char *old,
  328. size_t n, directory_callback *fn)
  329. {
  330. process_file_name(filename, old, n);
  331. scan_files(filename, fn);
  332. }
  333. #endif
  334. CSLbool file_exists(char *filename, char *old, size_t n, char *tt)
  335. /*
  336. * This returns YES if the file exists, and as a side-effect copies a
  337. * textual form of the last-changed-time of the file into the buffer tt.
  338. */
  339. {
  340. struct stat statbuff;
  341. process_file_name(filename, old, n);
  342. if (*filename == 0) return NO;
  343. if (stat(filename, &statbuff) != 0) return NO;
  344. strcpy(tt, ctime(&(statbuff.st_mtime)));
  345. return YES;
  346. }
  347. /*
  348. * getenv() is a mild pain in two respects - firstly Ultrix uses
  349. * a non-ANSI definition (using 2 args not 1), and the MSDOS seems
  350. * to have a strong preference for upper case names. To allow for
  351. * all this I do not call getenv() directly but go via the following
  352. * code that can patch things up.
  353. *
  354. * It APPEARS that the cygwin environment wants parameter names to be passed
  355. * in upper case regardless of anything. This is similar to the DOS/Windows
  356. * situation.
  357. */
  358. #ifdef TWO_ARG_GETENV
  359. char *my_getenv(char *s)
  360. {
  361. char uppercasename[LONGEST_LEGAL_FILENAME];
  362. char *p = uppercasename;
  363. int c;
  364. while ((c = *s++) != 0) *p++ = toupper(c);
  365. *p = 0;
  366. static char value[LONGEST_LEGAL_FILENAME];
  367. getenv(uppercasename, value);
  368. return value;
  369. }
  370. #else
  371. char *my_getenv(char *s)
  372. {
  373. char uppercasename[LONGEST_LEGAL_FILENAME];
  374. char *p = uppercasename;
  375. int c;
  376. while ((c = *s++) != 0) *p++ = toupper(c);
  377. *p = 0;
  378. return getenv(uppercasename);
  379. }
  380. #endif
  381. int my_system(char *s)
  382. {
  383. return system(s);
  384. }
  385. FILE *my_popen(char *a, char *b)
  386. {
  387. #ifdef NCC_LIB
  388. return NULL;
  389. #else
  390. return (FILE *)popen(a, b);
  391. #endif
  392. }
  393. void my_pclose(FILE *a)
  394. {
  395. #ifndef NCC_LIB
  396. pclose(a);
  397. #endif
  398. }
  399. #ifndef DO_NOT_USE_GETUID
  400. /*
  401. * "machine.h" should set DO_NOT_USE_GETUID if that function is not
  402. * properly available. Not having it will make the treatment of
  403. * (eg) "~xxx/..." in filenames less satisfactory.
  404. */
  405. #include <pwd.h>
  406. int get_home_directory(char *b, int len)
  407. {
  408. int i;
  409. struct passwd *pw = getpwuid(getuid());
  410. strcpy(b, pw->pw_dir);
  411. i = strlen(b);
  412. /* Here the directory handed back has "/" forced in as its final character */
  413. if ( b[i-1] != '/')
  414. { b[i++] = '/';
  415. b[i] = 0;
  416. }
  417. return i;
  418. }
  419. int get_users_home_directory(char *b, int len)
  420. {
  421. struct passwd *pw = getpwnam(b);
  422. if (pw != NULL) strcpy(b, pw->pw_dir);
  423. else strcpy(b, "."); /* use current directory if getpwnam() fails */
  424. return strlen(b);
  425. }
  426. #else /* USE_GETUID */
  427. int get_home_directory(char *b, int len)
  428. {
  429. int i;
  430. strcpy(b, getenv("HOME")); /* Probably works with most shells */
  431. i = strlen(b);
  432. if ( b[i-1] != '/')
  433. { b[i++] = '/';
  434. b[i] = 0;
  435. }
  436. return i;
  437. }
  438. int get_users_home_directory(char *b, int len)
  439. {
  440. strcpy(b, "."); /* use current directory if getpwnam() no available */
  441. return 1;
  442. }
  443. #endif /* USE_GETUID */
  444. #ifdef UNIX_TIMES
  445. /*
  446. * This is a BSD-style clock facility, possibly giving a resolution of
  447. * only 1/100 second. I believe that Portable Standard Lisp typically
  448. * reports user time, which is why I do this. A further nasty here
  449. * is that I am probably compiling this file in ANSI mode, and on
  450. * at least some computers this makes #include <sys/times.h> fairly
  451. * ineffective (ugh), so I declare all the structures and functions I
  452. * want directly (ugh ugh) and hope they are as needed. Consider this
  453. * when you port to a new machine.
  454. */
  455. clock_t read_clock(void)
  456. {
  457. struct my_tms {
  458. clock_t tms_utime;
  459. clock_t tms_stime;
  460. clock_t tms_cutime;
  461. clock_t tms_cstime;
  462. } tmsbuf;
  463. clock_t w1, w2, w3;
  464. extern void times(/*struct my_tms * */);
  465. times(&tmsbuf);
  466. w1 = tmsbuf.tms_utime; /* User time in UNIX_TIMES ticks */
  467. w2 = CLOCKS_PER_SEC;
  468. w3 = UNIX_TIMES;
  469. return (clock_t)((double)w1 * ((double)w2/(double)w3));
  470. }
  471. #endif
  472. void accept_tick()
  473. {
  474. }
  475. #ifdef __kcm
  476. extern int _ttyhandle;
  477. int batchp()
  478. {
  479. return (_ttyhandle != 0);
  480. }
  481. #else
  482. #ifdef NCC_LIB
  483. int batchp()
  484. {
  485. extern int _fisatty(FILE*);
  486. return !_fisatty(stdin);
  487. }
  488. #else
  489. #if BSD_LIB
  490. int batchp()
  491. {
  492. return !isatty(fileno(stdin));
  493. }
  494. #else
  495. #error "Unknown Library type"
  496. #endif /* BSD_LIB */
  497. #endif /* NCC_LIB */
  498. #endif /* __kcm */
  499. /*
  500. * The next procedure is responsible for establishing information about
  501. * where the main checkpoint image should be recovered from, and where
  502. * and fasl files should come from.
  503. */
  504. char *find_image_directory(int argc, char *argv[])
  505. {
  506. char image[LONGEST_LEGAL_FILENAME];
  507. char pgmname[LONGEST_LEGAL_FILENAME];
  508. char *w;
  509. /*
  510. * Here I assume Unix, or something sufficiently like it, and
  511. * if the current program is called xxx, then I want an environment
  512. * variable called xxx.img to tell me where to find the image file
  513. * and the fasl directory.
  514. */
  515. #ifdef PUBLIC
  516. strcpy(pgmname, "/usr/local/lib/reduce"); /* fixed name */
  517. w = my_getenv("reduceimg");
  518. if (w != NULL) strcpy(image, w);
  519. else strcpy(image, pgmname);
  520. #else
  521. if (argc > 0 && argv[0] != NULL)
  522. { int i, j, k;
  523. w = argv[0];
  524. i = j = k = strlen(w);
  525. while (i > 0 && w[i-1] != '/') i--;
  526. /*
  527. * There is some question (in the cygnus world) whether the file name of
  528. * an executable does or doe snot have ".exe" on the end of it. Just to be on
  529. * the safe side here I will strip off any suffix that might be present!
  530. */
  531. while (j > i && w[j] != '.') j--;
  532. if (j <= i) j = k;
  533. sprintf(pgmname, "%.*s.img", j-i, &w[i]); /* final component of argv[0] */
  534. sprintf(program_name, "%.*s", j-i, &w[i]);
  535. }
  536. else strcpy(pgmname, "csl.img"); /* even argv[0] is not available! */
  537. w = my_getenv(pgmname);
  538. #endif
  539. if (w != NULL) strcpy(image, w);
  540. else strcpy(image, pgmname);
  541. /*
  542. * I copy from local vectors into malloc'd space to hand my
  543. * answer back.
  544. */
  545. w = (char *)malloc(1+strlen(image));
  546. /*
  547. * The error exit here seem unsatisfactory...
  548. */
  549. if (w == NULL)
  550. { fprintf(stderr, "\n+++ Panic - run out of space\n");
  551. exit(EXIT_FAILURE);
  552. }
  553. strcpy(w, image);
  554. return w;
  555. }
  556. /*
  557. * The following function controls memory allocation policy
  558. */
  559. int32 ok_to_grab_memory(int32 current)
  560. {
  561. #ifdef COMMON
  562. return current;
  563. #else
  564. return 3*current + 2;
  565. #endif
  566. }
  567. #include "fileops.c"
  568. #include "scandir.c"
  569. /* end of syscyg.c */