home *** CD-ROM | disk | FTP | other *** search
- /* file.c -- Copyright (1988) Dan Heller */
-
- #include "mush.h"
- #include <pwd.h>
-
- /* takes string 'p' and address of int (isdir). If p uses the ~ to reference
- * a home directory of somesort, then expand it. find out what sort of
- * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error
- * return final path. If an error occurrs, return string indicating error.
- * if isdir has a value of 1 when passed, it ignores "No such file or directory"
- */
- char *
- getpath(p, isdir)
- register char *p;
- int *isdir;
- {
- static char buf[BUFSIZ];
- struct stat stat_buf;
-
- if (!p || !*p || !strcmp(p, "~")) {
- char *home = do_set(set_options, "home");
- if (!home || !*home)
- home = ALTERNATE_HOME;
- (void) strcpy(buf, home); /* no arg means home */
- } else if (*p == '~') {
- if (p[1] != '/') {
- /* not our home, but someone else's
- * look for ~user or ~user/subpath
- * if '/' exists, separate into tmp="user" p="subpath"
- */
- struct passwd *ent, *getpwnam();
- char *p2 = p+1;
- if (p = index(p2, '/'))
- *p++ = 0;
- if (!(ent = getpwnam(p2))) {
- *isdir = -1;
- return sprintf(buf, "no such user: %s", p2);
- }
- /* append subpath to pathname */
- if (p && *p)
- (void) sprintf(buf, "%s/%s", ent->pw_dir, p);
- /* if *p == NULL, pathname is done (buf), set isdir = 1 */
- else {
- *isdir = 1;
- return strcpy(buf, ent->pw_dir);
- }
- } else {
- char *home = do_set(set_options, "home");
- if (!home || !*home)
- home = ALTERNATE_HOME;
- (void) sprintf(buf, "%s/%s", home, p+2);
- }
- } else if (*p == '%') {
- /* if %user, append user name... else, it's just us */
- (void) sprintf(buf, "%s/", MAILDIR);
- if (!*++p || *p == ' ' || *p == '\t')
- (void) strcat(buf, login);
- else
- (void) strcat(buf, p);
- } else if (*p == '+') {
- register char *p2 = do_set(set_options, "folder");
- if (!p2 || !*p2)
- p2 = DEF_FOLDER;
- (void) sprintf(buf, "%s/%s", p2, ++p);
- if (*buf == '~') {
- int t_isdir = *isdir;
- char *t, tmp[256];
- (void) strcpy(tmp, buf);
- t = getpath(tmp, &t_isdir);
- if (t_isdir == -1) {
- *isdir = -1;
- return t;
- }
- /* strcpy(buf, t); --buf already has info because it's static */
- }
- } else { /* allow \ to escape the special chars, +, %, ~ */
- if (*p == '\\')
- p++;
- (void) strcpy(buf, p);
- }
- if (stat(buf, &stat_buf)) {
- (void) access(buf, F_OK); /* set errno to the "real" reason */
- if (errno == ENOENT && *isdir == 1) {
- *isdir = 0; /* say it's a regular file even tho it doesn't exist */
- return buf; /* it may be wanted for creating */
- }
- *isdir = -1;
- return sys_errlist[errno];
- }
- *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
- return buf;
- }
-
- /*
- * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
- * opens the file with the mode.
- * If the mode is "r" then we read the file into the file pointer at the
- * end (fseek(fp, 2, 0)). If the file is opened for writing, then read
- * from the beginning of fp and write it into the file.
- * This is usually called to read .signatures into messages (thus,
- * opening .signture with "r" and writing to the end of fp which is probably
- * the sendmail process or the message file pointer) or to write fortunes into
- * the message buffer: reading fp (the popened fortune) and writing into file.
- */
- void
- file_to_fp(p, fp, mode)
- register char *p;
- register FILE *fp;
- char *mode;
- {
- int x = 1;
- char *file, buf[BUFSIZ];
- FILE *tmp_fp;
-
- if (!p || !*p) {
- print("specify filename");
- return;
- }
- file = getpath(p, &x);
- if (x == -1) { /* on error, file contains error message */
- wprint(file);
- return;
- }
- wprint("%s: ", file);
- if (x) /* if x == 1, then path is a directory */
- wprint("directory.\n");
- else if (!(tmp_fp = fopen(file, mode))) {
- wprint("%s\n", sys_errlist[errno]);
- return;
- } else if (*mode != 'r') {
- rewind(fp);
- for(x = 0; fgets(buf, BUFSIZ, fp); x++)
- fputs(buf, tmp_fp);
- } else
- for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
- fputs(buf, fp);
- wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
- x, (x == 1)? "": "s");
- fflush(fp);
- fclose(tmp_fp);
- }
-
- /* clear all contents of the file. Careful that the file is opened for
- * _writing_ --tempfile is opened for reading, so don't try to empty it
- * if you're using ftruncate. Return -1 on error, 0 on success.
- */
- emptyfile(fp, fname)
- register FILE **fp;
- register char *fname;
- {
- Debug("Emptying \"%s\"\n", fname);
- #ifndef SYSV
- return ftruncate(fileno(*fp), 0L);
- #else
- {
- int omask = umask(077), ret;
- fclose(*fp);
- if (!(*fp = fopen(fname, "w")))
- ret = -1;
- ret = 0;
- (void) umask(omask);
- return ret;
- }
- #endif /* SYSV */
- }
-
- /*
- * Finds out how many file descriptors are opened. Useful for making sure
- * no files got opened in subprocedures which were not subsequently closed.
- */
- nopenfiles(argc)
- {
- register int nfiles = 0;
- #ifdef MAXFILES
- register int size = MAXFILES;
- #else
- register int size = getdtablesize();
- #endif /* MAXFILES */
-
- if (argc < 2)
- print("open file descriptors:");
- while (--size >= 0)
- if (fcntl(size, F_GETFL, 0) != -1) {
- if (argc < 2)
- print_more(" %d", size);
- ++nfiles;
- }
- if (argc < 2)
- print("\n");
- return nfiles;
- }
-
- /*
- * Open a path for writing or appending -- return a FILE pointer.
- * If program is TRUE, then use popen, not fopen and don't check
- * to see if the file is writable.
- */
- FILE *
- open_file(p, program)
- register char *p;
- {
- register FILE *newfile = NULL_FILE;
- register char *tmp;
- int x = 1;
-
- if (program || *p == '/')
- tmp = p, x = 0;
- else
- tmp = getpath(p, &x);
- if (x == 1)
- print("%s is a directory.\n", tmp);
- else if (x == -1)
- print("%s: %s\n", p, tmp);
- else {
- register char *mode = NULL;
- /* if it doesn't exist open for "w" */
- if (program || Access(tmp, F_OK))
- mode = "w";
- /* if we can't write to it, forget it */
- else if (Access(tmp, W_OK))
- error(tmp);
- else
- mode = "a";
- if (mode)
- if (program) {
- if (!(newfile = popen(tmp, mode))) {
- error("Can't execute %s\n", tmp);
- return newfile;
- }
- } else
- if (!(newfile = fopen(tmp, mode)))
- error("Can't write to %s", tmp);
- else
- Debug("Successfully opened %s\n", tmp);
- }
- return newfile;
- }
-
- /*
- * find_files gets a set of addresses and an array of
- * file pointers and the maximum size that array can be.
- * The object is to find the files or programs listed in "s", attempt
- * to fopen/popen them and save their filepointers in the array. If the
- * size is 0, then just extract the file names and give error messages
- * for each one since they will not be opened. Return the number of
- * files opened and delete all files (opened or not) from the list in
- * "s". Tokens beginning with a "/, ~, or + are files; tokens beginning
- * with a | are programs.
- * The string "s" is modified to be a list of address -- all names AND
- * files are stripped out of the list.
- */
- find_files(s, files, size)
- register char *s;
- FILE *files[];
- {
- register int total = 0, prog;
- char file[BUFSIZ], buf[BUFSIZ], *start = s, c;
- register char *p, *b = buf;
-
- do {
- if (!(p = get_name_n_addr(s, NULL, file)))
- break;
- c = *p, *p = 0;
- /* It's a file -- try to open it. This doesn't get written back
- * onto "buf" since it is supposed to be extracted anyway.
- */
- if (*file == '+' || *file == '~' || *file == '|' || *file == '/') {
- prog = (*file == '|');
- if (size && total < size) {
- /* either open "file" or &file[1] */
- if (files[total] = open_file(&file[prog], prog))
- total++;
- } else
- print("No open space for %s\n", file);
- } else {
- b += Strcpy(b, s);
- *b++ = ',', *b++ = ' ';
- }
- for (*p = c, s = p; *s == ',' || isspace(*s); s++)
- ;
- } while (*s);
- for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
- *b = 0;
- (void) strcpy(start, buf);
- return total;
- }
-
- /*
- * access(2) has an undocumented feature which ignores suid. If you are
- * su'ed and try to read your mail, you will be unable to because access()
- * will give the illusion that you cannot read/write to your mbox. Solve
- * the problem by using stat() instead.
- */
- Access(file, mode)
- register char *file;
- {
- struct stat buf;
-
- if (stat(file, &buf) == -1)
- return -1;
- if (mode == R_OK)
- return (buf.st_mode & 0400)? 0 : -1;
- if (mode == W_OK)
- return (buf.st_mode & 0200)? 0 : -1;
- return 0;
- }
-