utils.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /*
  2. * Copyright (c) 1993 by David I. Bell
  3. * Permission is granted to use, distribute, or modify this source,
  4. * provided that this copyright notice remains intact.
  5. *
  6. * Utility routines.
  7. */
  8. #include "sash.h"
  9. #include <unistd.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <dirent.h>
  13. #include <time.h>
  14. #include <utime.h>
  15. #include <fcntl.h>
  16. #include <fnmatch.h>
  17. #ifdef L_intflag
  18. int intflag;
  19. #endif
  20. #ifdef L_modestring
  21. /*
  22. * Return the standard ls-like mode string from a file mode.
  23. * This is static and so is overwritten on each call.
  24. */
  25. char *
  26. modestring(mode)
  27. {
  28. static char buf[12];
  29. strcpy(buf, "----------");
  30. /*
  31. * Fill in the file type.
  32. */
  33. if (S_ISDIR(mode))
  34. buf[0] = 'd';
  35. if (S_ISCHR(mode))
  36. buf[0] = 'c';
  37. if (S_ISBLK(mode))
  38. buf[0] = 'b';
  39. if (S_ISFIFO(mode))
  40. buf[0] = 'p';
  41. #ifdef S_ISLNK
  42. if (S_ISLNK(mode))
  43. buf[0] = 'l';
  44. #endif
  45. #ifdef S_ISSOCK
  46. if (S_ISSOCK(mode))
  47. buf[0] = 's';
  48. #endif
  49. /*
  50. * Now fill in the normal file permissions.
  51. */
  52. if (mode & S_IRUSR)
  53. buf[1] = 'r';
  54. if (mode & S_IWUSR)
  55. buf[2] = 'w';
  56. if (mode & S_IXUSR)
  57. buf[3] = 'x';
  58. if (mode & S_IRGRP)
  59. buf[4] = 'r';
  60. if (mode & S_IWGRP)
  61. buf[5] = 'w';
  62. if (mode & S_IXGRP)
  63. buf[6] = 'x';
  64. if (mode & S_IROTH)
  65. buf[7] = 'r';
  66. if (mode & S_IWOTH)
  67. buf[8] = 'w';
  68. if (mode & S_IXOTH)
  69. buf[9] = 'x';
  70. /*
  71. * Finally fill in magic stuff like suid and sticky text.
  72. */
  73. if (mode & S_ISUID)
  74. buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
  75. if (mode & S_ISGID)
  76. buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
  77. if (mode & S_ISVTX)
  78. buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
  79. return buf;
  80. }
  81. #endif
  82. #ifdef L_timestring
  83. /*
  84. * Get the time to be used for a file.
  85. * This is down to the minute for new files, but only the date for old files.
  86. * The string is returned from a static buffer, and so is overwritten for
  87. * each call.
  88. */
  89. char *
  90. timestring(t)
  91. long t;
  92. {
  93. long now;
  94. char *str;
  95. static char buf[26];
  96. time(&now);
  97. str = ctime(&t);
  98. strcpy(buf, &str[4]);
  99. buf[12] = '\0';
  100. if ((t > now) || (t < now - 365*24*60*60L)) {
  101. strcpy(&buf[7], &str[20]);
  102. buf[11] = '\0';
  103. }
  104. return buf;
  105. }
  106. #endif
  107. #ifdef L_isadir
  108. /*
  109. * Return TRUE if a filename is a directory.
  110. * Nonexistant files return FALSE.
  111. */
  112. BOOL
  113. isadir(name)
  114. char *name;
  115. {
  116. struct stat statbuf;
  117. if (stat(name, &statbuf) < 0)
  118. return FALSE;
  119. return S_ISDIR(statbuf.st_mode);
  120. }
  121. #endif
  122. #ifdef L_copyfile
  123. /*
  124. * Copy one file to another, while possibly preserving its modes, times,
  125. * and modes. Returns TRUE if successful, or FALSE on a failure with an
  126. * error message output. (Failure is not indicted if the attributes cannot
  127. * be set.)
  128. */
  129. BOOL
  130. copyfile(srcname, destname, setmodes)
  131. char *srcname;
  132. char *destname;
  133. BOOL setmodes;
  134. {
  135. int rfd;
  136. int wfd;
  137. int rcc;
  138. int wcc;
  139. char *bp;
  140. struct stat statbuf1;
  141. struct stat statbuf2;
  142. struct utimbuf times;
  143. int len = 8192-16;
  144. char * buf = 0;
  145. if (stat(srcname, &statbuf1) < 0) {
  146. perror(srcname);
  147. return FALSE;
  148. }
  149. if (stat(destname, &statbuf2) < 0) {
  150. statbuf2.st_ino = -1;
  151. statbuf2.st_dev = -1;
  152. }
  153. if (S_ISREG(statbuf1.st_mode) &&
  154. (statbuf1.st_dev == statbuf2.st_dev) &&
  155. (statbuf1.st_ino == statbuf2.st_ino))
  156. {
  157. fprintf(stderr, "Copying file \"%s\" to itself\n", srcname);
  158. return FALSE;
  159. }
  160. rfd = open(srcname, 0);
  161. if (rfd < 0) {
  162. perror(srcname);
  163. return FALSE;
  164. }
  165. wfd = open(destname, O_WRONLY|O_CREAT|O_TRUNC, statbuf1.st_mode);
  166. if (wfd < 0) {
  167. perror(destname);
  168. close(rfd);
  169. return FALSE;
  170. }
  171. buf = malloc(len);
  172. if (!buf) {
  173. fprintf(stderr,"Unable to allocate buffer of %d bytes\n", len);
  174. return FALSE;
  175. }
  176. while ((rcc = read(rfd, buf, len)) > 0) {
  177. if (intflag) {
  178. close(rfd);
  179. close(wfd);
  180. free(buf);
  181. return FALSE;
  182. }
  183. bp = buf;
  184. while (rcc > 0) {
  185. wcc = write(wfd, bp, rcc);
  186. if (wcc < 0) {
  187. perror(destname);
  188. free(buf);
  189. goto error_exit;
  190. }
  191. bp += wcc;
  192. rcc -= wcc;
  193. }
  194. }
  195. free(buf);
  196. if (rcc < 0) {
  197. perror(srcname);
  198. goto error_exit;
  199. }
  200. close(rfd);
  201. if (close(wfd) < 0) {
  202. perror(destname);
  203. return FALSE;
  204. }
  205. if (setmodes) {
  206. (void) chmod(destname, statbuf1.st_mode);
  207. (void) chown(destname, statbuf1.st_uid, statbuf1.st_gid);
  208. times.actime = statbuf1.st_atime;
  209. times.modtime = statbuf1.st_mtime;
  210. (void) utime(destname, &times);
  211. }
  212. return TRUE;
  213. error_exit:
  214. close(rfd);
  215. close(wfd);
  216. return FALSE;
  217. }
  218. #endif
  219. #ifdef L_buildname
  220. /*
  221. * Build a path name from the specified directory name and file name.
  222. * If the directory name is NULL, then the original filename is returned.
  223. * The built path is in a static area, and is overwritten for each call.
  224. */
  225. char *
  226. buildname(dirname, filename)
  227. char *dirname;
  228. char *filename;
  229. {
  230. char *cp;
  231. static char buf[PATHLEN];
  232. if ((dirname == NULL) || (*dirname == '\0'))
  233. return filename;
  234. cp = strrchr(filename, '/');
  235. if (cp)
  236. filename = cp + 1;
  237. strcpy(buf, dirname);
  238. strcat(buf, "/");
  239. strcat(buf, filename);
  240. return buf;
  241. }
  242. #endif
  243. #ifdef L_expandwildcards
  244. /*
  245. * Expand the wildcards in a filename, if any.
  246. * Returns an argument list with matching filenames in sorted order.
  247. * The expanded names are stored in memory chunks which can later all
  248. * be freed at once. Returns zero if the name is not a wildcard, or
  249. * returns the count of matched files if the name is a wildcard and
  250. * there was at least one match, or returns -1 if too many filenames
  251. * matched (with an error output).
  252. * If the name is a wildcard and no names match, returns 0 as
  253. * if the name were not a wildcard.
  254. */
  255. int
  256. expandwildcards(name, maxargc, retargv)
  257. char *name;
  258. int maxargc;
  259. char *retargv[];
  260. {
  261. char *last;
  262. char *cp1, *cp2, *cp3;
  263. DIR *dirp;
  264. struct dirent *dp;
  265. int dirlen;
  266. int matches;
  267. char dirname[PATHLEN];
  268. last = strrchr(name, '/');
  269. if (last)
  270. last++;
  271. else
  272. last = name;
  273. cp1 = strchr(name, '*');
  274. cp2 = strchr(name, '?');
  275. cp3 = strchr(name, '[');
  276. if ((cp1 == NULL) && (cp2 == NULL) && (cp3 == NULL))
  277. return 0;
  278. if ((cp1 && (cp1 < last)) || (cp2 && (cp2 < last)) ||
  279. (cp3 && (cp3 < last)))
  280. {
  281. fprintf(stderr, "Wildcards only implemented for last filename component\n");
  282. return -1;
  283. }
  284. dirname[0] = '.';
  285. dirname[1] = '\0';
  286. if (last != name) {
  287. memcpy(dirname, name, last - name);
  288. dirname[last - name - 1] = '\0';
  289. if (dirname[0] == '\0') {
  290. dirname[0] = '/';
  291. dirname[1] = '\0';
  292. }
  293. }
  294. dirp = opendir(dirname);
  295. if (dirp == NULL) {
  296. perror(dirname);
  297. return -1;
  298. }
  299. dirlen = strlen(dirname);
  300. if (last == name) {
  301. dirlen = 0;
  302. dirname[0] = '\0';
  303. } else if (dirname[dirlen - 1] != '/') {
  304. dirname[dirlen++] = '/';
  305. dirname[dirlen] = '\0';
  306. }
  307. matches = 0;
  308. while ((dp = readdir(dirp)) != NULL) {
  309. if ((strcmp(dp->d_name, ".") == 0) ||
  310. (strcmp(dp->d_name, "..") == 0))
  311. continue;
  312. if (!match(dp->d_name, last))
  313. continue;
  314. if (matches >= maxargc) {
  315. fprintf(stderr, "Too many filename matches\n");
  316. closedir(dirp);
  317. return -1;
  318. }
  319. cp1 = getchunk(dirlen + strlen(dp->d_name) + 1);
  320. if (cp1 == NULL) {
  321. fprintf(stderr, "No memory for filename\n");
  322. closedir(dirp);
  323. return -1;
  324. }
  325. if (dirlen)
  326. memcpy(cp1, dirname, dirlen);
  327. strcpy(cp1 + dirlen, dp->d_name);
  328. retargv[matches++] = cp1;
  329. }
  330. closedir(dirp);
  331. if (matches == 0) {
  332. return 0;
  333. }
  334. qsort((char *) retargv, matches, sizeof(char *), namesort);
  335. return matches;
  336. }
  337. #endif
  338. #ifdef L_namesort
  339. /*
  340. * Sort routine for list of filenames.
  341. */
  342. int
  343. namesort(p1, p2)
  344. char **p1;
  345. char **p2;
  346. {
  347. return strcmp(*p1, *p2);
  348. }
  349. #endif
  350. #ifdef L_match
  351. /*
  352. * Routine to see if a text string is matched by a wildcard pattern.
  353. * Returns TRUE if the text is matched, or FALSE if it is not matched
  354. * or if the pattern is invalid.
  355. * * matches zero or more characters
  356. * ? matches a single character
  357. * [abc] matches 'a', 'b' or 'c'
  358. * \c quotes character c
  359. * Adapted from code written by Ingo Wilken.
  360. */
  361. BOOL
  362. match(text, pattern)
  363. char *text;
  364. char *pattern;
  365. {
  366. return fnmatch(pattern, text, 0) == 0;
  367. }
  368. #endif
  369. #ifdef L_makeargs
  370. /*
  371. * Take a command string, and break it up into an argc, argv list.
  372. * The returned argument list and strings are in static memory, and so
  373. * are overwritten on each call. The argument array is ended with an
  374. * extra NULL pointer for convenience. Returns TRUE if successful,
  375. * or FALSE on an error with a message already output.
  376. *
  377. * Note that leading quotes are *not* removed at this point, but
  378. * trailing quotes are.
  379. */
  380. BOOL
  381. makeargs(cmd, argcptr, argvptr)
  382. char *cmd;
  383. int *argcptr;
  384. char ***argvptr;
  385. {
  386. char *cp;
  387. int argc;
  388. static char strings[CMDLEN+1];
  389. static char *argtable[MAXARGS+1];
  390. static char quoted[MAXARGS+1];
  391. /*
  392. * Copy the command string and then break it apart
  393. * into separate arguments.
  394. */
  395. strcpy(strings, cmd);
  396. argc = 0;
  397. cp = strings;
  398. while (*cp) {
  399. if (argc >= MAXARGS) {
  400. fprintf(stderr, "Too many arguments\n");
  401. return FALSE;
  402. }
  403. quoted[argc] = 0;
  404. argtable[argc++] = cp;
  405. while (*cp && !isblank(*cp)) {
  406. if (*cp == '"' || *cp == '\'') {
  407. char *sp = cp++;
  408. while (*cp && *cp != *sp)
  409. cp++;
  410. if (*cp == *sp) {
  411. /* Chop off the trailing quote, but leave the leading quote
  412. * so that later processing will know the argument is quoted
  413. */
  414. *cp++ = 0;
  415. }
  416. } else
  417. cp++;
  418. }
  419. while (isblank(*cp))
  420. *cp++ = '\0';
  421. }
  422. argtable[argc] = NULL;
  423. *argcptr = argc;
  424. *argvptr = argtable;
  425. return TRUE;
  426. }
  427. #endif
  428. #ifdef L_makestring
  429. /*
  430. * Make a NULL-terminated string out of an argc, argv pair.
  431. * Returns TRUE if successful, or FALSE if the string is too long,
  432. * with an error message given. This does not handle spaces within
  433. * arguments correctly.
  434. */
  435. BOOL
  436. makestring(argc, argv, buf, buflen)
  437. char **argv;
  438. char *buf;
  439. {
  440. int len;
  441. while (argc-- > 0) {
  442. len = strlen(*argv);
  443. if (len >= buflen) {
  444. fprintf(stderr, "Argument string too long\n");
  445. return FALSE;
  446. }
  447. strcpy(buf, *argv++);
  448. buf += len;
  449. buflen -= len;
  450. if (argc)
  451. *buf++ = ' ';
  452. buflen--;
  453. }
  454. *buf = '\0';
  455. return TRUE;
  456. }
  457. #endif
  458. #ifdef L_chunks
  459. typedef struct chunk CHUNK;
  460. #define CHUNKINITSIZE 4
  461. struct chunk {
  462. CHUNK *next;
  463. char data[CHUNKINITSIZE]; /* actually of varying length */
  464. };
  465. static CHUNK * chunklist;
  466. /*
  467. * Allocate a chunk of memory (like malloc).
  468. * The difference, though, is that the memory allocated is put on a
  469. * list of chunks which can be freed all at one time. You CAN NOT free
  470. * an individual chunk.
  471. */
  472. char *
  473. getchunk(size)
  474. {
  475. CHUNK *chunk;
  476. if (size < CHUNKINITSIZE)
  477. size = CHUNKINITSIZE;
  478. chunk = (CHUNK *) malloc(size + sizeof(CHUNK) - CHUNKINITSIZE);
  479. if (chunk == NULL)
  480. return NULL;
  481. chunk->next = chunklist;
  482. chunklist = chunk;
  483. return chunk->data;
  484. }
  485. /*
  486. * Free all chunks of memory that had been allocated since the last
  487. * call to this routine.
  488. */
  489. void
  490. freechunks()
  491. {
  492. CHUNK *chunk;
  493. while (chunklist) {
  494. chunk = chunklist;
  495. chunklist = chunk->next;
  496. free((char *) chunk);
  497. }
  498. }
  499. #endif
  500. #ifdef L_expandenvvar
  501. /* Expand environment variables
  502. * Variable names must use a-z, A-Z, 0-9, or _
  503. * Backslashes are also interpreted to preserve the literal value of the
  504. * next character.
  505. * Returns NULL if there is an error, otherwise returns a pointer
  506. * to a static buffer containing the expand command line.
  507. *
  508. * Makes a lame attempt to not expand inside single quotes.
  509. */
  510. char *
  511. expandenvvar(cmd)
  512. char *cmd;
  513. {
  514. static char newcmd[CMDLEN+1];
  515. char* newp = newcmd;
  516. int freelength = CMDLEN; /* Don't include final terminator */
  517. char varname[CMDLEN+1];
  518. char* varp;
  519. char* value;
  520. int valuelength;
  521. int quoted = 0;
  522. if (cmd == NULL) {
  523. return NULL;
  524. }
  525. if (strlen(cmd) > freelength) {
  526. fprintf(stderr, "Variable expansion too long\n");
  527. return NULL;
  528. }
  529. while (*cmd) {
  530. int copy = 1;
  531. switch (*cmd) {
  532. case '$':
  533. if (!quoted) {
  534. copy = 0;
  535. cmd++;
  536. varp = varname;
  537. while (isalnum(*cmd) || (*cmd == '_') || (*cmd == '?')) {
  538. *varp++ = *cmd++;
  539. }
  540. *varp = '\0';
  541. if ((*varname) && (value = getenv(varname))) {
  542. valuelength = strlen(value);
  543. if (valuelength > freelength) {
  544. fprintf(stderr, "Variable expansion too long\n");
  545. return NULL;
  546. }
  547. strncpy(newp, value, valuelength);
  548. newp += valuelength;
  549. freelength -= valuelength;
  550. }
  551. }
  552. break;
  553. case '\'':
  554. quoted = !quoted;
  555. break;
  556. case '\\':
  557. cmd++;
  558. break;
  559. }
  560. if (copy) {
  561. if (freelength < 1) {
  562. fprintf(stderr, "Variable expansion too long\n");
  563. return NULL;
  564. }
  565. *newp++ = *cmd++;
  566. freelength--;
  567. }
  568. }
  569. *newp = '\0';
  570. return newcmd;
  571. }
  572. #endif
  573. /* END CODE */