home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / mush6.4 / part05 / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-12  |  9.4 KB  |  359 lines

  1. /* file.c -- Copyright (1988) Dan Heller */
  2.  
  3. #include "mush.h"
  4. #include <pwd.h>
  5.  
  6. /* takes string 'p' and address of int (isdir).  If p uses the ~ to reference
  7.  * a home directory of some sort, then expand it.  find out what sort of
  8.  * file final path is. set isdir to 1 if a directory, 0 if not, -1 on error
  9.  * return final path. If an error occurs, return string indicating error.
  10.  * if isdir has a value of 1 when passed, it ignores "No such file or directory"
  11.  */
  12. char *
  13. getpath(p, isdir)
  14. register char *p;
  15. int *isdir;
  16. {
  17.     static char buf[BUFSIZ];
  18.     struct stat stat_buf;
  19.  
  20.     if (!p || !*p || !strcmp(p, "~")) {
  21.     char *home = do_set(set_options, "home");
  22.     if (!home || !*home)
  23.         home = ALTERNATE_HOME;
  24.     (void) strcpy(buf, home);  /* no arg means home */
  25.     } else if (*p == '~') {
  26.     if (p[1] != '/') {
  27.         /* not our home, but someone else's
  28.          * look for ~user or ~user/subpath
  29.          * if '/' exists, separate into tmp="user" p="subpath"
  30.          */
  31.         struct passwd *ent, *getpwnam();
  32.         char *p2 = p+1;
  33.         if (p = index(p2, '/'))
  34.         *p++ = 0;
  35.         if (!(ent = getpwnam(p2))) {
  36.         *isdir = -1;
  37.         return sprintf(buf, "no such user: %s", p2);
  38.         }
  39.         /* append subpath to pathname */
  40.         if (p && *p)
  41.         (void) sprintf(buf, "%s/%s", ent->pw_dir, p);
  42.         /* if *p == NULL, pathname is done (buf), set isdir = 1 */
  43.         else {
  44.         *isdir = 1;
  45.         return strcpy(buf, ent->pw_dir);
  46.         }
  47.     } else {
  48.         char *home = do_set(set_options, "home");
  49.         if (!home || !*home)
  50.         home = ALTERNATE_HOME;
  51.         (void) sprintf(buf, "%s/%s", home, p+2);
  52.     }
  53.     } else if (*p == '%') {
  54.     /* if %user, append user name... else, it's just us */
  55.     if (!*++p || *p == ' ' || *p == '\t')
  56.         (void) strcpy(buf, spoolfile);
  57.     else
  58. #ifndef HOMEMAIL
  59.         (void) sprintf(buf, "%s/%s", MAILDIR, p);
  60. #else /* HOMEMAIL */
  61.     {
  62.         char *p2 = do_set(set_options, "home");
  63.         (void) sprintf(buf, "%s/%s", p2 ? p2 : ALTERNATE_HOME, MAILFILE);
  64.     } else {
  65.         int t_isdir = *isdir;
  66.         char *t, tmp[256];
  67.         (void) sprintf(tmp, "~%s/%s", p, MAILFILE);
  68.         t = getpath(tmp, &t_isdir);
  69.         if (t_isdir == -1) {
  70.         *isdir = -1;
  71.         return t;
  72.         }
  73.         /* strcpy(buf, t); --buf already has info because it's static */
  74.     }
  75. #endif /* HOMEMAIL */
  76.     } else if (*p == '+') {
  77.     register char *p2 = do_set(set_options, "folder");
  78.     if (!p2 || !*p2)
  79.         p2 = DEF_FOLDER;
  80.     (void) sprintf(buf, "%s/%s", p2, ++p);
  81.     if (*buf != '/') {
  82.         int t_isdir = *isdir;
  83.         char *t, tmp[256];
  84.         if (*buf != '~')
  85.         (void) sprintf(tmp, "~/%s", buf);
  86.         else
  87.         (void) strcpy(tmp, buf);
  88.         t = getpath(tmp, &t_isdir);
  89.         if (t_isdir == -1) {
  90.         *isdir = -1;
  91.         return t;
  92.         }
  93.         /* strcpy(buf, t); --buf already has info because it's static */
  94.     }
  95.     } else {  /* allow \ to escape the special chars, +, %, ~ */
  96.     if (*p == '\\')
  97.         p++;
  98.     (void) strcpy(buf, p);
  99.     }
  100.     if (stat(buf, &stat_buf)) {
  101.     (void) access(buf, F_OK); /* set errno to the "real" reason */
  102.     if (errno == ENOENT && *isdir == 1) {
  103.         *isdir = 0; /* say it's a regular file even tho it doesn't exist */
  104.         return buf; /* it may be wanted for creating */
  105.     }
  106.     *isdir = -1;
  107.     return sys_errlist[errno];
  108.     }
  109.     *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
  110.     return buf;
  111. }
  112.  
  113. /*
  114.  * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
  115.  * opens the file with the mode.
  116.  * If the mode is "r" then we read the file into the file pointer at the
  117.  * end (fseek(fp, 2, 0)).  If the file is opened for writing, then read
  118.  * from the beginning of fp and write it into the file.
  119.  * This is usually called to read .signatures into messages (thus,
  120.  * opening .signature with "r" and writing to the end of fp which is probably
  121.  * the sendmail process or the message file pointer) or to write fortunes into
  122.  * the message buffer: reading fp (the popened fortune) and writing into file.
  123.  */
  124. void
  125. file_to_fp(p, fp, mode)
  126. register char *p;
  127. register FILE *fp;
  128. char *mode;
  129. {
  130.     int     x = 1;
  131.     char     *file, buf[BUFSIZ];
  132.     FILE     *tmp_fp;
  133.  
  134.     if (!p || !*p) {
  135.     print("specify filename");
  136.     return;
  137.     }
  138.     file = getpath(p, &x);
  139.     if (x == -1) { /* on error, file contains error message */
  140.     wprint(file);
  141.     return;
  142.     }
  143.     wprint("%s: ", file);
  144.     if (x)   /* if x == 1, then path is a directory */
  145.     wprint("directory.\n");
  146.     else if (!(tmp_fp = fopen(file, mode))) {
  147.     wprint("%s\n", sys_errlist[errno]);
  148.     return;
  149.     } else if (*mode != 'r') {
  150.     rewind(fp);
  151.     for(x = 0; fgets(buf, BUFSIZ, fp); x++)
  152.         fputs(buf, tmp_fp);
  153.     } else
  154.     for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
  155.         fputs(buf, fp);
  156.     wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
  157.                   x, (x == 1)? "": "s");
  158.     fflush(fp);
  159.     fclose(tmp_fp);
  160. }
  161.  
  162. /* clear all contents of the file.  Careful that the file is opened for
  163.  * _writing_ --tempfile is opened for reading, so don't try to empty it
  164.  * if you're using ftruncate.   Return -1 on error, 0 on success.
  165.  */
  166. emptyfile(fp, fname)
  167. register FILE **fp;
  168. register char *fname;
  169. {
  170.     Debug("Emptying \"%s\"\n", fname);
  171. #ifndef SYSV
  172.     return ftruncate(fileno(*fp), 0L);
  173. #else
  174.     {
  175.     int omask = umask(077), ret;
  176.     fclose(*fp);
  177.     if (!(*fp = fopen(fname, "w")))
  178.         ret = -1;
  179.     ret = 0;
  180.     (void) umask(omask);
  181.     return ret;
  182.     }
  183. #endif /* SYSV */
  184. }
  185.  
  186. /*
  187.  * Finds out how many file descriptors are opened.  Useful for making sure
  188.  * no files got opened in subprocedures which were not subsequently closed.
  189.  */
  190. nopenfiles(argc)
  191. {
  192.     register int nfiles = 0;
  193. #ifdef MAXFILES
  194.     register int size = MAXFILES;
  195. #else
  196.     register int size = getdtablesize();
  197. #endif /* MAXFILES */
  198.  
  199.     if (argc < 2)
  200.     print("open file descriptors:");
  201.     while (--size >= 0)
  202.         if (fcntl(size, F_GETFL, 0) != -1) {
  203.         if (argc < 2)
  204.         print_more(" %d", size);
  205.             ++nfiles;
  206.         }
  207.     if (argc < 2)
  208.     print("\n");
  209.     return nfiles;
  210. }
  211.  
  212. /*
  213.  * Close all "extraneous" file descriptors; return the number closed
  214.  */
  215. closefileds (n)
  216. {
  217.     register int nfiles = 0;
  218. #ifdef MAXFILES
  219.     register int size = MAXFILES;
  220. #else
  221.     register int size = getdtablesize();
  222. #endif /* MAXFILES */
  223.  
  224.     while (--size >= n)
  225.         if (fcntl(size, F_GETFL, 0) != -1) {
  226.         (void) close(size);
  227.             ++nfiles;
  228.         }
  229.     return nfiles;
  230. }
  231.  
  232. /*
  233.  * Open a path for writing or appending -- return a FILE pointer.
  234.  * If program is TRUE, then use popen, not fopen and don't check 
  235.  * to see if the file is writable.
  236.  */
  237. FILE *
  238. open_file(p, program)
  239. register char *p;
  240. {
  241.     register FILE *newfile = NULL_FILE;
  242.     register char *tmp;
  243.     int x = 1;
  244.  
  245.     if (program || *p == '/')
  246.     tmp = p, x = 0;
  247.     else
  248.     tmp = getpath(p, &x);
  249.     if (x == 1)
  250.     print("%s is a directory.\n", tmp);
  251.     else if (x == -1)
  252.     print("%s: %s\n", p, tmp);
  253.     else {
  254.     register char *mode = NULL;
  255.     /* if it doesn't exist open for "w" */
  256.     if (program || Access(tmp, F_OK))
  257.         mode = "w";
  258.     /* if we can't write to it, forget it */
  259.     else if (Access(tmp, W_OK))
  260.         error(tmp);
  261.     else
  262.         mode = "a";
  263.     if (mode)
  264.         if (program) {
  265.         if (!(newfile = popen(tmp, mode))) {
  266.             error("Can't execute %s\n", tmp);
  267.             return newfile;
  268.         }
  269.         } else
  270.         if (!(newfile = mask_fopen(tmp, mode)))
  271.             error("Can't write to %s", tmp);
  272.         else
  273.         Debug("Successfully opened %s\n", tmp);
  274.     }
  275.     return newfile;
  276. }
  277.  
  278. /*
  279.  * find_files gets a set of addresses and an array of
  280.  * file pointers and the maximum size that array can be.
  281.  * The object is to find the files or programs listed in "s", attempt
  282.  * to fopen/popen them and save their file pointers in the array. If the
  283.  * size is 0, then just extract the file names and give error messages
  284.  * for each one since they will not be opened. Return the number of
  285.  * files opened and delete all files (opened or not) from the list in
  286.  * "s".  Tokens beginning with a "/, ~, or + are files; tokens beginning
  287.  * with a | are programs.
  288.  * The string "s" is modified to be a list of address -- all names AND
  289.  * files are stripped out of the list.
  290.  */
  291. find_files(s, files, size)
  292. register char *s;
  293. FILE *files[];
  294. {
  295.     register int     total = 0, prog;
  296.     char          file[MAXPATHLEN], buf[HDRSIZ], *start = s, c;
  297.     register char    *p, *b = buf;
  298.  
  299.     do  {
  300.     if (!(p = get_name_n_addr(s, NULL, file)))
  301.         break;
  302.     c = *p, *p = 0;
  303.     /* It's a file -- try to open it.  This doesn't get written back
  304.      * onto "buf" since it is supposed to be extracted anyway.
  305.      */
  306.     if (*file == '+' || *file == '~' || *file == '|' || *file == '/') {
  307.         prog = (*file == '|');
  308.         if (size && total < size) {
  309.         /* either open "file" or &file[1] */
  310.         if (files[total] = open_file(&file[prog], prog))
  311.             total++;
  312.         } else
  313.         print("No open space for %s\n", file);
  314.     } else {
  315.         b += Strcpy(b, s);
  316.         *b++ = ',', *b++ = ' ';
  317.     }
  318.     for (*p = c, s = p; *s == ',' || isspace(*s); s++)
  319.         ;
  320.     } while (*s);
  321.     for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
  322.     *b = 0;
  323.     (void) strcpy(start, buf);
  324.     return total;
  325. }
  326.  
  327. /*
  328.  * access(2) has an undocumented feature which ignores suid.  If you are
  329.  * su'ed and try to read your mail, you will be unable to because access()
  330.  * will give the illusion that you cannot read/write to your mbox.  Solve
  331.  * the problem by using stat() instead.
  332.  */
  333. Access(file, mode)
  334. register char *file;
  335. {
  336.     struct stat buf;
  337.  
  338.     if (stat(file, &buf) == -1)
  339.     return -1;
  340.     if (mode == R_OK)
  341.     return (buf.st_mode & 0400)? 0 : -1;
  342.     if (mode == W_OK)
  343.     return (buf.st_mode & 0200)? 0 : -1;
  344.     return 0;
  345. }
  346.  
  347. /*
  348.  * Open a file for read/write/whatever but make sure umask is rw by user only.
  349.  */
  350. FILE *
  351. mask_fopen(file, mode)
  352. char *file, *mode;
  353. {
  354.     int omask = umask(077);
  355.     FILE *fp = fopen(file, mode);
  356.     (void) umask(omask);
  357.     return fp;
  358. }
  359.