home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / mush6.0 / part03 / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-04-12  |  8.3 KB  |  307 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 somesort, then expand it.  find out what sort of
  8.  * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error
  9.  * return final path. If an error occurrs, 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.     (void) sprintf(buf, "%s/", MAILDIR);
  56.     if (!*++p || *p == ' ' || *p == '\t')
  57.         (void) strcat(buf, login);
  58.     else
  59.         (void) strcat(buf, p);
  60.     } else if (*p == '+') {
  61.     register char *p2 = do_set(set_options, "folder");
  62.     if (!p2 || !*p2)
  63.         p2 = DEF_FOLDER;
  64.     (void) sprintf(buf, "%s/%s", p2, ++p);
  65.     if (*buf == '~') {
  66.         int t_isdir = *isdir;
  67.         char *t, tmp[256];
  68.         (void) strcpy(tmp, buf);
  69.         t = getpath(tmp, &t_isdir);
  70.         if (t_isdir == -1) {
  71.         *isdir = -1;
  72.         return t;
  73.         }
  74.         /* strcpy(buf, t); --buf already has info because it's static */
  75.     }
  76.     } else {  /* allow \ to escape the special chars, +, %, ~ */
  77.     if (*p == '\\')
  78.         p++;
  79.     (void) strcpy(buf, p);
  80.     }
  81.     if (stat(buf, &stat_buf)) {
  82.     (void) access(buf, F_OK); /* set errno to the "real" reason */
  83.     if (errno == ENOENT && *isdir == 1) {
  84.         *isdir = 0; /* say it's a regular file even tho it doesn't exist */
  85.         return buf; /* it may be wanted for creating */
  86.     }
  87.     *isdir = -1;
  88.     return sys_errlist[errno];
  89.     }
  90.     *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
  91.     return buf;
  92. }
  93.  
  94. /*
  95.  * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
  96.  * opens the file with the mode.
  97.  * If the mode is "r" then we read the file into the file pointer at the
  98.  * end (fseek(fp, 2, 0)).  If the file is opened for writing, then read
  99.  * from the beginning of fp and write it into the file.
  100.  * This is usually called to read .signatures into messages (thus,
  101.  * opening .signture with "r" and writing to the end of fp which is probably
  102.  * the sendmail process or the message file pointer) or to write fortunes into
  103.  * the message buffer: reading fp (the popened fortune) and writing into file.
  104.  */
  105. void
  106. file_to_fp(p, fp, mode)
  107. register char *p;
  108. register FILE *fp;
  109. char *mode;
  110. {
  111.     int     x = 1;
  112.     char     *file, buf[BUFSIZ];
  113.     FILE     *tmp_fp;
  114.  
  115.     if (!p || !*p) {
  116.     print("specify filename");
  117.     return;
  118.     }
  119.     file = getpath(p, &x);
  120.     if (x == -1) { /* on error, file contains error message */
  121.     wprint(file);
  122.     return;
  123.     }
  124.     wprint("%s: ", file);
  125.     if (x)   /* if x == 1, then path is a directory */
  126.     wprint("directory.\n");
  127.     else if (!(tmp_fp = fopen(file, mode))) {
  128.     wprint("%s\n", sys_errlist[errno]);
  129.     return;
  130.     } else if (*mode != 'r') {
  131.     rewind(fp);
  132.     for(x = 0; fgets(buf, BUFSIZ, fp); x++)
  133.         fputs(buf, tmp_fp);
  134.     } else
  135.     for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
  136.         fputs(buf, fp);
  137.     wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
  138.                   x, (x == 1)? "": "s");
  139.     fflush(fp);
  140.     fclose(tmp_fp);
  141. }
  142.  
  143. /* clear all contents of the file.  Careful that the file is opened for
  144.  * _writing_ --tempfile is opened for reading, so don't try to empty it
  145.  * if you're using ftruncate.   Return -1 on error, 0 on success.
  146.  */
  147. emptyfile(fp, fname)
  148. register FILE **fp;
  149. register char *fname;
  150. {
  151.     Debug("Emptying \"%s\"\n", fname);
  152. #ifndef SYSV
  153.     return ftruncate(fileno(*fp), 0L);
  154. #else
  155.     {
  156.     int omask = umask(077), ret;
  157.     fclose(*fp);
  158.     if (!(*fp = fopen(fname, "w")))
  159.         ret = -1;
  160.     ret = 0;
  161.     (void) umask(omask);
  162.     return ret;
  163.     }
  164. #endif /* SYSV */
  165. }
  166.  
  167. /*
  168.  * Finds out how many file descriptors are opened.  Useful for making sure
  169.  * no files got opened in subprocedures which were not subsequently closed.
  170.  */
  171. nopenfiles(argc)
  172. {
  173.     register int nfiles = 0;
  174. #ifdef MAXFILES
  175.     register int size = MAXFILES;
  176. #else
  177.     register int size = getdtablesize();
  178. #endif /* MAXFILES */
  179.  
  180.     if (argc < 2)
  181.     print("open file descriptors:");
  182.     while (--size >= 0)
  183.         if (fcntl(size, F_GETFL, 0) != -1) {
  184.         if (argc < 2)
  185.         print_more(" %d", size);
  186.             ++nfiles;
  187.         }
  188.     if (argc < 2)
  189.     print("\n");
  190.     return nfiles;
  191. }
  192.  
  193. /*
  194.  * Open a path for writing or appending -- return a FILE pointer.
  195.  * If program is TRUE, then use popen, not fopen and don't check 
  196.  * to see if the file is writable.
  197.  */
  198. FILE *
  199. open_file(p, program)
  200. register char *p;
  201. {
  202.     register FILE *newfile = NULL_FILE;
  203.     register char *tmp;
  204.     int x = 1;
  205.  
  206.     if (program || *p == '/')
  207.     tmp = p, x = 0;
  208.     else
  209.     tmp = getpath(p, &x);
  210.     if (x == 1)
  211.     print("%s is a directory.\n", tmp);
  212.     else if (x == -1)
  213.     print("%s: %s\n", p, tmp);
  214.     else {
  215.     register char *mode = NULL;
  216.     /* if it doesn't exist open for "w" */
  217.     if (program || Access(tmp, F_OK))
  218.         mode = "w";
  219.     /* if we can't write to it, forget it */
  220.     else if (Access(tmp, W_OK))
  221.         error(tmp);
  222.     else
  223.         mode = "a";
  224.     if (mode)
  225.         if (program) {
  226.         if (!(newfile = popen(tmp, mode))) {
  227.             error("Can't execute %s\n", tmp);
  228.             return newfile;
  229.         }
  230.         } else
  231.         if (!(newfile = fopen(tmp, mode)))
  232.             error("Can't write to %s", tmp);
  233.         else
  234.         Debug("Successfully opened %s\n", tmp);
  235.     }
  236.     return newfile;
  237. }
  238.  
  239. /*
  240.  * find_files gets a set of addresses and an array of
  241.  * file pointers and the maximum size that array can be.
  242.  * The object is to find the files or programs listed in "s", attempt
  243.  * to fopen/popen them and save their filepointers in the array. If the
  244.  * size is 0, then just extract the file names and give error messages
  245.  * for each one since they will not be opened. Return the number of
  246.  * files opened and delete all files (opened or not) from the list in
  247.  * "s".  Tokens beginning with a "/, ~, or + are files; tokens beginning
  248.  * with a | are programs.
  249.  * The string "s" is modified to be a list of address -- all names AND
  250.  * files are stripped out of the list.
  251.  */
  252. find_files(s, files, size)
  253. register char *s;
  254. FILE *files[];
  255. {
  256.     register int     total = 0, prog;
  257.     char          file[BUFSIZ], buf[BUFSIZ], *start = s, c;
  258.     register char    *p, *b = buf;
  259.  
  260.     do  {
  261.     if (!(p = get_name_n_addr(s, NULL, file)))
  262.         break;
  263.     c = *p, *p = 0;
  264.     /* It's a file -- try to open it.  This doesn't get written back
  265.      * onto "buf" since it is supposed to be extracted anyway.
  266.      */
  267.     if (*file == '+' || *file == '~' || *file == '|' || *file == '/') {
  268.         prog = (*file == '|');
  269.         if (size && total < size) {
  270.         /* either open "file" or &file[1] */
  271.         if (files[total] = open_file(&file[prog], prog))
  272.             total++;
  273.         } else
  274.         print("No open space for %s\n", file);
  275.     } else {
  276.         b += Strcpy(b, s);
  277.         *b++ = ',', *b++ = ' ';
  278.     }
  279.     for (*p = c, s = p; *s == ',' || isspace(*s); s++)
  280.         ;
  281.     } while (*s);
  282.     for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
  283.     *b = 0;
  284.     (void) strcpy(start, buf);
  285.     return total;
  286. }
  287.  
  288. /*
  289.  * access(2) has an undocumented feature which ignores suid.  If you are
  290.  * su'ed and try to read your mail, you will be unable to because access()
  291.  * will give the illusion that you cannot read/write to your mbox.  Solve
  292.  * the problem by using stat() instead.
  293.  */
  294. Access(file, mode)
  295. register char *file;
  296. {
  297.     struct stat buf;
  298.  
  299.     if (stat(file, &buf) == -1)
  300.     return -1;
  301.     if (mode == R_OK)
  302.     return (buf.st_mode & 0400)? 0 : -1;
  303.     if (mode == W_OK)
  304.     return (buf.st_mode & 0200)? 0 : -1;
  305.     return 0;
  306. }
  307.