Пример #1
0
/*
 *	make_directory(char *path)
 *
 *	Make a directory if it doesn't exist.
 */
static int
make_directory(const char *path)
{
    int rc;
    struct stat statbuf;
    char fullpath[PATH_MAX];
    const char *destination = _nc_tic_dir(0);

    if (path == destination || *path == '/') {
	if (strlen(path) + 1 > sizeof(fullpath))
	    return (-1);
	(void) strcpy(fullpath, path);
    } else {
	if (strlen(destination) + strlen(path) + 2 > sizeof(fullpath))
	    return (-1);
	(void) sprintf(fullpath, "%s/%s", destination, path);
    }

    if ((rc = stat(path, &statbuf)) < 0) {
	rc = mkdir(path, 0777);
    } else {
	if (_nc_access(path, R_OK | W_OK | X_OK) < 0) {
	    rc = -1;		/* permission denied */
	} else if (!(S_ISDIR(statbuf.st_mode))) {
	    rc = -1;		/* not a directory */
	}
    }
    return rc;
}
Пример #2
0
trace(const unsigned int tracelevel GCC_UNUSED)
{
    static bool been_here = FALSE;
    static char my_name[] = "trace";

    if (!been_here && tracelevel) {
	been_here = TRUE;

	_nc_tracing = tracelevel;
	if (_nc_access(my_name, W_OK) < 0
	    || (tracefp = fopen(my_name, "wb")) == 0) {
	    perror("curses: Can't open 'trace' file: ");
	    exit(EXIT_FAILURE);
	}
	/* Try to set line-buffered mode, or (failing that) unbuffered,
	 * so that the trace-output gets flushed automatically at the
	 * end of each line.  This is useful in case the program dies. 
	 */
#if HAVE_SETVBUF		/* ANSI */
	(void) setvbuf(tracefp, (char *) 0, _IOLBF, 0);
#elif HAVE_SETBUF		/* POSIX */
	(void) setbuffer(tracefp, (char *) 0);
#endif
	_tracef("TRACING NCURSES version %s (tracelevel=%#x)",
		curses_version(), tracelevel);
    } else if (_nc_tracing != tracelevel) {
	_nc_tracing = tracelevel;
	_tracef("tracelevel=%#x", tracelevel);
    }
}
Пример #3
0
NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file)
{
    FILE *fp = 0;
    int code = ERR;

    T((T_CALLED("scr_init(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));

    if (SP_PARM != 0 &&
#ifdef USE_TERM_DRIVER
	InfoOf(SP_PARM).caninit
#else
	!(exit_ca_mode && non_rev_rmcup)
#endif
	) {
	if (_nc_access(file, R_OK) >= 0
	    && (fp = fopen(file, "rb")) != 0) {
	    delwin(CurScreen(SP_PARM));
	    CurScreen(SP_PARM) = getwin(fp);
#if !USE_REENTRANT
	    curscr = CurScreen(SP_PARM);
#endif
	    (void) fclose(fp);
	    if (CurScreen(SP_PARM) != 0) {
		code = OK;
	    }
	}
    }
    returnCode(code);
}
Пример #4
0
/*
 * Make a database-root if it doesn't exist.
 */
static int
make_db_root(const char *path)
{
    int rc;
    char fullpath[PATH_MAX];

    if ((rc = make_db_path(fullpath, path, sizeof(fullpath))) == 0) {
#if USE_HASHED_DB
	DB *capdbp;

	if ((capdbp = _nc_db_open(fullpath, TRUE)) == NULL)
	    rc = -1;
	else if (_nc_db_close(capdbp) < 0)
	    rc = -1;
#else
	struct stat statbuf;

	if ((rc = stat(path, &statbuf)) < 0) {
	    rc = mkdir(path, 0777);
	} else if (_nc_access(path, R_OK | W_OK | X_OK) < 0) {
	    rc = -1;		/* permission denied */
	} else if (!(S_ISDIR(statbuf.st_mode))) {
	    rc = -1;		/* not a directory */
	}
#endif
    }
    return rc;
}
Пример #5
0
static int add_tc(char *termpaths[], char *path, int count)
{
	if (count < MAXPATHS
	 && _nc_access(path, R_OK) == 0)
		termpaths[count++] = path;
	termpaths[count] = 0;
	return count;
}
Пример #6
0
static void write_file(char *filename, TERMTYPE *tp)
{
	FILE *fp = (_nc_access(filename, W_OK) == 0) ? fopen(filename, "wb") : 0;
	if (fp == 0) {
		perror(filename);
		_nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename);
	}
	DEBUG(1, ("Created %s", filename));

	if (write_object(fp, tp) == ERR) {
		_nc_syserr_abort("error writing %s/%s", _nc_tic_dir(0), filename);
	}
	fclose(fp);
}
Пример #7
0
trace(const unsigned int tracelevel)
{
    if ((TraceFP == 0) && tracelevel) {
	const char *mode = _nc_globals.init_trace ? "ab" : "wb";

	if (TracePath[0] == '\0') {
	    int size = sizeof(TracePath) - 12;
	    if (getcwd(TracePath, size) == 0) {
		perror("curses: Can't get working directory");
		exit(EXIT_FAILURE);
	    }
	    TracePath[size] = '\0';
	    assert(strlen(TracePath) <= size);
	    strlcat(TracePath, "/trace", sizeof(TracePath));
	    if (_nc_is_dir_path(TracePath)) {
		strlcat(TracePath, ".log", sizeof(TracePath));
	    }
	}

	_nc_globals.init_trace = TRUE;
	_nc_tracing = tracelevel;
	if (_nc_access(TracePath, W_OK) < 0
	    || (TraceFP = fopen(TracePath, mode)) == 0) {
	    perror("curses: Can't open 'trace' file");
	    exit(EXIT_FAILURE);
	}
	/* Try to set line-buffered mode, or (failing that) unbuffered,
	 * so that the trace-output gets flushed automatically at the
	 * end of each line.  This is useful in case the program dies. 
	 */
#if HAVE_SETVBUF		/* ANSI */
	(void) setvbuf(TraceFP, (char *) 0, _IOLBF, 0);
#elif HAVE_SETBUF		/* POSIX */
	(void) setbuffer(TraceFP, (char *) 0);
#endif
	_tracef("TRACING NCURSES version %s.%d (tracelevel=%#x)",
		NCURSES_VERSION,
		NCURSES_VERSION_PATCH,
		tracelevel);
    } else if (tracelevel == 0) {
	if (TraceFP != 0) {
	    fclose(TraceFP);
	    TraceFP = 0;
	}
	_nc_tracing = tracelevel;
    } else if (_nc_tracing != tracelevel) {
	_nc_tracing = tracelevel;
	_tracef("tracelevel=%#x", tracelevel);
    }
}
Пример #8
0
scr_dump(const char *file)
{
    FILE *fp = 0;

    T((T_CALLED("scr_dump(%s)"), _nc_visbuf(file)));

    if (_nc_access(file, W_OK) < 0
	|| (fp = fopen(file, "wb")) == 0) {
	returnCode(ERR);
    } else {
	(void) putwin(newscr, fp);
	(void) fclose(fp);
	returnCode(OK);
    }
}
Пример #9
0
scr_restore(const char *file)
{
    FILE *fp = 0;

    T((T_CALLED("scr_restore(%s)"), _nc_visbuf(file)));

    if (_nc_access(file, R_OK) < 0
	|| (fp = fopen(file, "rb")) == 0) {
	returnCode(ERR);
    } else {
	delwin(newscr);
	SP->_newscr = newscr = getwin(fp);
	(void) fclose(fp);
	returnCode(OK);
    }
}
Пример #10
0
scr_init(const char *file)
{
    FILE *fp = 0;

    T((T_CALLED("scr_init(%s)"), _nc_visbuf(file)));

    if (exit_ca_mode && non_rev_rmcup)
	returnCode(ERR);

    if (_nc_access(file, R_OK) < 0
	|| (fp = fopen(file, "rb")) == 0) {
	returnCode(ERR);
    } else {
	delwin(curscr);
	SP->_curscr = curscr = getwin(fp);
	(void) fclose(fp);
	returnCode(OK);
    }
}
NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file)
{
    FILE *fp = 0;

    T((T_CALLED("scr_restore(%s)"), _nc_visbuf(file)));

    if (_nc_access(file, R_OK) < 0
	|| (fp = fopen(file, "rb")) == 0) {
	returnCode(ERR);
    } else {
	delwin(newscr);
	SP_PARM->_newscr = getwin(fp);
#if !USE_REENTRANT
	newscr = SP_PARM->_newscr;
#endif
	(void) fclose(fp);
	returnCode(OK);
    }
}
Пример #12
0
NCURSES_SP_NAME(scr_restore) (NCURSES_SP_DCLx const char *file)
{
    FILE *fp = 0;
    int code = ERR;

    T((T_CALLED("scr_restore(%p,%s)"), (void *) SP_PARM, _nc_visbuf(file)));

    if (_nc_access(file, R_OK) >= 0
	&& (fp = fopen(file, "rb")) != 0) {
	delwin(NewScreen(SP_PARM));
	NewScreen(SP_PARM) = getwin(fp);
#if !USE_REENTRANT
	newscr = NewScreen(SP_PARM);
#endif
	(void) fclose(fp);
	if (NewScreen(SP_PARM) != 0) {
	    code = OK;
	}
    }
    returnCode(code);
}
Пример #13
0
static void
write_file(char *filename, TERMTYPE *tp)
{
    char buffer[MAX_ENTRY_SIZE];
    unsigned limit = sizeof(buffer);
    unsigned offset = 0;

    FILE *fp = (_nc_access(filename, W_OK) == 0) ? fopen(filename, "wb") : 0;
    if (fp == 0) {
	perror(filename);
	_nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename);
    }
    DEBUG(1, ("Created %s", filename));

    if (write_object(tp, buffer, &offset, limit) == ERR
	|| fwrite(buffer, sizeof(char), offset, fp) != offset) {
	_nc_syserr_abort("error writing %s/%s", _nc_tic_dir(0), filename);
    }

    fclose(fp);
}
Пример #14
0
scr_init(const char *file)
{
    FILE *fp = 0;
    struct stat stb;

    T((T_CALLED("scr_init(%s)"), _nc_visbuf(file)));

    if (exit_ca_mode && non_rev_rmcup)
	returnCode(ERR);

    if (_nc_access(file, R_OK) < 0
	|| (fp = fopen(file, "rb")) == 0)
	returnCode(ERR);
    else if (fstat(STDOUT_FILENO, &stb) || stb.st_mtime > dumptime)
	returnCode(ERR);
    else {
	delwin(curscr);
	curscr = getwin(fp);
	(void) fclose(fp);
	returnCode(OK);
    }
}
NCURSES_SP_NAME(scr_init) (NCURSES_SP_DCLx const char *file)
{
    FILE *fp = 0;

    T((T_CALLED("scr_init(%s)"), _nc_visbuf(file)));

    if (exit_ca_mode && non_rev_rmcup)
	returnCode(ERR);

    if (_nc_access(file, R_OK) < 0
	|| (fp = fopen(file, "rb")) == 0) {
	returnCode(ERR);
    } else {
	delwin(curscr);
	SP_PARM->_curscr = getwin(fp);
#if !USE_REENTRANT
	curscr = SP_PARM->_curscr;
#endif
	(void) fclose(fp);
	returnCode(OK);
    }
}
Пример #16
0
/*
 * Getent implements the functions of cgetent.  If fd is non-negative,
 * *db_array has already been opened and fd is the open file descriptor.  We
 * do this to save time and avoid using up file descriptors for tc=
 * recursions.
 *
 * Getent returns the same success/failure codes as cgetent.  On success, a
 * pointer to a malloc'd capability record with all tc= capabilities fully
 * expanded and its length (not including trailing ASCII NUL) are left in
 * *cap and *len.
 *
 * Basic algorithm:
 *	+ Allocate memory incrementally as needed in chunks of size BFRAG
 *	  for capability buffer.
 *	+ Recurse for each tc=name and interpolate result.  Stop when all
 *	  names interpolated, a name can't be found, or depth exceeds
 *	  MAX_RECURSION.
 */
static int
_nc_getent(
	char **cap,         /* termcap-content */
	unsigned int *len,  /* length, needed for recursion */
	int *beginning,     /* line-number at match */
	int in_array,       /* index in 'db_array[] */
	char **db_array,    /* list of files to search */
	int fd,
	const char *name,
	int depth,
	char *nfield)
{
	register char *r_end, *rp;
	int myfd = FALSE;
	char *record;
	int tc_not_resolved;
	int current;
	int lineno;

	/*
	 * Return with ``loop detected'' error if we've recurred more than
	 * MAX_RECURSION times.
	 */
	if (depth > MAX_RECURSION)
		return (TC_REF_LOOP);

	/*
	 * Check if we have a top record from cgetset().
	 */
	if (depth == 0 && toprec != 0 && _nc_cgetmatch(toprec, name) == 0) {
		if ((record = malloc (topreclen + BFRAG)) == 0) {
			errno = ENOMEM;
			return (TC_SYS_ERR);
		}
		(void)strcpy(record, toprec);
		rp = record + topreclen + 1;
		r_end = rp + BFRAG;
		current = in_array;
	} else {
		int foundit;

		/*
		 * Allocate first chunk of memory.
		 */
		if ((record = malloc(BFRAG)) == 0) {
			errno = ENOMEM;
			return (TC_SYS_ERR);
		}
		rp = r_end = record + BFRAG;
		foundit = FALSE;

		/*
		 * Loop through database array until finding the record.
		 */
		for (current = in_array; db_array[current] != 0; current++) {
			int eof = FALSE;

			/*
			 * Open database if not already open.
			 */
			if (fd >= 0) {
				(void)lseek(fd, (off_t)0, SEEK_SET);
			} else if (_nc_access(db_array[current], R_OK) < 0
			  || (fd = open(db_array[current], O_RDONLY, 0) < 0)) {
				/* No error on unfound file. */
				if (errno == ENOENT)
					continue;
				free(record);
				return (TC_SYS_ERR);
			} else {
				myfd = TRUE;
			}
			lineno = 0;

			/*
			 * Find the requested capability record ...
			 */
			{
				char buf[2048];
				register char *b_end = buf;
				register char *bp = buf;
				register int c;

				/*
				 * Loop invariants:
				 *	There is always room for one more character in record.
				 *	R_end always points just past end of record.
				 *	Rp always points just past last character in record.
				 *	B_end always points just past last character in buf.
				 *	Bp always points at next character in buf.
				 */

				for (;;) {
					int first = lineno + 1;

					/*
					 * Read in a line implementing (\, newline)
					 * line continuation.
					 */
					rp = record;
					for (;;) {
						if (bp >= b_end) {
							int n;

							n = read(fd, buf, sizeof(buf));
							if (n <= 0) {
								if (myfd)
									(void)close(fd);
								if (n < 0) {
									free(record);
									return (TC_SYS_ERR);
								}
								fd = -1;
								eof = TRUE;
								break;
							}
							b_end = buf+n;
							bp = buf;
						}

						c = *bp++;
						if (c == '\n') {
							lineno++;
							if (rp == record || *(rp-1) != '\\')
								break;
						}
						*rp++ = c;

						/*
						 * Enforce loop invariant: if no room
						 * left in record buffer, try to get
						 * some more.
						 */
						if (rp >= r_end) {
							unsigned int pos;
							size_t newsize;
							char *nrecord;

							pos = rp - record;
							newsize = r_end - record + BFRAG;
							nrecord = realloc(record, newsize);
							if (nrecord == 0) {
								if (record != 0)
									free(nrecord);
								if (myfd)
									(void)close(fd);
								errno = ENOMEM;
								return (TC_SYS_ERR);
							}
							record = nrecord;
							r_end = record + newsize;
							rp = record + pos;
						}
					}
					/* loop invariant lets us do this */
					*rp++ = '\0';

					/*
					 * If encountered eof check next file.
					 */
					if (eof)
						break;

					/*
					 * Toss blank lines and comments.
					 */
					if (*record == '\0' || *record == '#')
						continue;

					/*
					 * See if this is the record we want ...
					 */
					if (_nc_cgetmatch(record, name) == 0
					 && (nfield == 0
					  || !_nc_nfcmp(nfield, record))) {
						foundit = TRUE;
						*beginning = first;
						break;	/* found it! */
					}
				}
			}
			if (foundit)
				break;
		}

		if (!foundit)
			return (TC_NOT_FOUND);
	}

	/*
	 * Got the capability record, but now we have to expand all tc=name
	 * references in it ...
	 */
	{
		register char *newicap, *s;
		register int newilen;
		unsigned int ilen;
		int diff, iret, tclen, oline;
		char *icap, *scan, *tc, *tcstart, *tcend;

		/*
		 * Loop invariants:
		 *	There is room for one more character in record.
		 *	R_end points just past end of record.
		 *	Rp points just past last character in record.
		 *	Scan points at remainder of record that needs to be
		 *	scanned for tc=name constructs.
		 */
		scan = record;
		tc_not_resolved = FALSE;
		for (;;) {
			if ((tc = _nc_cgetcap(scan, "tc", '=')) == 0)
				break;

			/*
			 * Find end of tc=name and stomp on the trailing `:'
			 * (if present) so we can use it to call ourselves.
			 */
			s = tc;
			while (*s != '\0') {
				if (*s++ == ':') {
					*(s - 1) = '\0';
					break;
				}
			}
			tcstart = tc - 3;
			tclen = s - tcstart;
			tcend = s;

			iret = _nc_getent(&icap, &ilen, &oline, current, db_array, fd, tc, depth+1, 0);
			newicap = icap;		/* Put into a register. */
			newilen = ilen;
			if (iret != TC_SUCCESS) {
				/* an error */
				if (iret < TC_NOT_FOUND) {
					if (myfd)
						(void)close(fd);
					free(record);
					return (iret);
				}
				if (iret == TC_UNRESOLVED)
					tc_not_resolved = TRUE;
				/* couldn't resolve tc */
				if (iret == TC_NOT_FOUND) {
					*(s - 1) = ':';
					scan = s - 1;
					tc_not_resolved = TRUE;
					continue;
				}
			}

			/* not interested in name field of tc'ed record */
			s = newicap;
			while (*s != '\0' && *s++ != ':')
				;
			newilen -= s - newicap;
			newicap = s;

			/* make sure interpolated record is `:'-terminated */
			s += newilen;
			if (*(s-1) != ':') {
				*s = ':';	/* overwrite NUL with : */
				newilen++;
			}

			/*
			 * Make sure there's enough room to insert the
			 * new record.
			 */
			diff = newilen - tclen;
			if (diff >= r_end - rp) {
				unsigned int pos, tcpos, tcposend;
				size_t newsize;
				char *nrecord;

				pos = rp - record;
				newsize = r_end - record + diff + BFRAG;
				tcpos = tcstart - record;
				tcposend = tcend - record;
				nrecord = realloc(record, newsize);
				if (record == 0) {
					if (record != 0)
						free(record);
					if (myfd)
						(void)close(fd);
					free(icap);
					errno = ENOMEM;
					return (TC_SYS_ERR);
				}
				record = nrecord;
				r_end = record + newsize;
				rp = record + pos;
				tcstart = record + tcpos;
				tcend = record + tcposend;
			}

			/*
			 * Insert tc'ed record into our record.
			 */
			s = tcstart + newilen;
			memmove(s, tcend, (size_t)(rp - tcend));
			memmove(tcstart, newicap, (size_t)newilen);
			rp += diff;
			free(icap);

			/*
			 * Start scan on `:' so next cgetcap works properly
			 * (cgetcap always skips first field).
			 */
			scan = s-1;
		}
	}

	/*
	 * Close file (if we opened it), give back any extra memory, and
	 * return capability, length and success.
	 */
	if (myfd)
		(void)close(fd);
	*len = rp - record - 1; /* don't count NUL */
	if (r_end > rp) {
		char *nrecord;
		if ((nrecord = realloc(record, (size_t)(rp - record))) == 0) {
			if (record != 0)
				free(record);
			errno = ENOMEM;
			return (TC_SYS_ERR);
		}
		record = nrecord;
	}

	*cap = record;
	if (tc_not_resolved)
		return (TC_UNRESOLVED);
	return (current);
}
Пример #17
0
int _nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp)
{
	int found = FALSE;
	ENTRY	*ep;
#if USE_GETCAP_CACHE
	char	cwd_buf[PATH_MAX];
#endif
#if USE_GETCAP
	char	tc[TBUFSIZ];
	static char	*source;
	static int lineno;

	/* we're using getcap(3) */
	if (_nc_tgetent(tc, &source, &lineno, tn) < 0)
		return (ERR);

	_nc_curr_line = lineno;
	_nc_set_source(source);
	_nc_read_entry_source((FILE *)0, tc, FALSE, FALSE, NULLHOOK);
#else
	/*
	 * Here is what the 4.4BSD termcap(3) page prescribes:
	 *
	 * It will look in the environment for a TERMCAP variable.  If found,
	 * and the value does not begin with a slash, and the terminal type
	 * name is the same as the environment string TERM, the TERMCAP string
	 * is used instead of reading a termcap file.  If it does begin with a
	 * slash, the string is used as a path name of the termcap file to
	 * search.  If TERMCAP does not begin with a slash and name is
	 * different from TERM, tgetent() searches the files $HOME/.termcap and
	 * /usr/share/misc/termcap, in that order, unless the environment
	 * variable TERMPATH exists, in which case it specifies a list of file
	 * pathnames (separated by spaces or colons) to be searched instead.
	 *
	 * It goes on to state:
	 *
	 * Whenever multiple files are searched and a tc field occurs in the
	 * requested entry, the entry it names must be found in the same file
	 * or one of the succeeding files.
	 *
	 * However, this restriction is relaxed in ncurses; tc references to
	 * previous files are permitted.
	 *
	 * This routine returns 1 if an entry is found, 0 if not found, and -1
	 * if the database is not accessible.
	 */
	FILE	*fp;
	char	*tc, *termpaths[MAXPATHS];
	int	filecount = 0;
	bool	use_buffer = FALSE;
	char	tc_buf[1024];
	char	pathbuf[PATH_MAX];

	termpaths[filecount] = 0;
	if ((tc = getenv("TERMCAP")) != 0)
	{
		if (is_pathname(tc))	/* interpret as a filename */
		{
			ADD_TC(tc, 0);
		}
		else if (_nc_name_match(tc, tn, "|:")) /* treat as a capability file */
		{
			use_buffer = TRUE;
			(void) sprintf(tc_buf, "%.*s\n", (int)sizeof(tc_buf)-2, tc);
		}
		else if ((tc = getenv("TERMPATH")) != 0)
		{
			char    *cp;

			for (cp = tc; *cp; cp++)
			{
				if (*cp == ':')
					*cp = '\0';
				else if (cp == tc || cp[-1] == '\0')
				{
					ADD_TC(cp, filecount);
				}
			}
		}
	}
	else	/* normal case */
	{
		char	envhome[PATH_MAX], *h;

		filecount = 0;

		/*
		 * Probably /etc/termcap is a symlink to /usr/share/misc/termcap.
		 * Avoid reading the same file twice.
		 */
		if (_nc_access("/etc/termcap", F_OK) == 0)
			ADD_TC("/etc/termcap", filecount);
		else
			ADD_TC("/usr/share/misc/termcap", filecount);

		if ((h = getenv("HOME")) != NULL && strlen(h) + 9 < PATH_MAX)
		{
		    /* user's .termcap, if any, should override it */
		    (void) strcpy(envhome, h);
		    (void) sprintf(pathbuf, "%s/.termcap", envhome);
		    ADD_TC(pathbuf, filecount);
		}
	}

	/* parse the sources */
	if (use_buffer)
	{
		_nc_set_source("TERMCAP");

		/*
		 * We don't suppress warning messages here.  The presumption is
		 * that since it's just a single entry, they won't be a pain.
		 */
		_nc_read_entry_source((FILE *)0, tc_buf, FALSE, FALSE, NULLHOOK);
	} else {
		int	i;

		for (i = 0; i < filecount; i++) {

			T(("Looking for %s in %s", tn, termpaths[i]));
			if ((fp = fopen(termpaths[i], "r")) != (FILE *)0)
			{
				_nc_set_source(termpaths[i]);

				/*
				 * Suppress warning messages.  Otherwise you
				 * get 400 lines of crap from archaic termcap
				 * files as ncurses complains about all the
				 * obsolete capabilities.
				 */
				_nc_read_entry_source(fp, (char*)0, FALSE, TRUE, NULLHOOK);

				(void) fclose(fp);
			}
		}
	}
#endif /* USE_GETCAP */

	if (_nc_head == 0)
		return(ERR);

	/* resolve all use references */
	_nc_resolve_uses();

	/* find a terminal matching tn, if we can */
#if USE_GETCAP_CACHE
	if (getcwd(cwd_buf, sizeof(cwd_buf)) != 0)
	{
		_nc_set_writedir((char *)0); /* note: this does a chdir */
#endif
		for_entry_list(ep) {
			if (_nc_name_match(ep->tterm.term_names, tn, "|:"))
			{
				/*
				 * Make a local copy of the terminal
				 * capabilities.  Free all entry storage except
				 * the string table for the loaded type (which
				 * we disconnected from the list by NULLing out
				 * ep->tterm.str_table above).
				 */
				memcpy(tp, &ep->tterm, sizeof(TERMTYPE));
				ep->tterm.str_table = (char *)0;

				/*
				 * OK, now try to write the type to user's
				 * terminfo directory.  Next time he loads
				 * this, it will come through terminfo.
				 *
				 * Advantage:  Second and subsequent fetches of
				 * this entry will be very fast.
				 *
				 * Disadvantage:  After the first time a
				 * termcap type is loaded by its user, editing
				 * it in the /etc/termcap file, or in TERMCAP,
				 * or in a local ~/.termcap, will be
				 * ineffective unless the terminfo entry is
				 * explicitly removed.
				 */
#if USE_GETCAP_CACHE
				(void) _nc_write_entry(tp);
#endif
				found = TRUE;
				break;
			}
		}
#if USE_GETCAP_CACHE
		chdir(cwd_buf);
	}
Пример #18
0
void
_nc_write_entry(TERMTYPE * const tp)
{
    struct stat statbuf;
    char name_list[MAX_TERMINFO_LENGTH];
    char *first_name, *other_names;
    char *ptr;
    char filename[PATH_MAX];
    char linkname[PATH_MAX];
#if USE_SYMLINKS
    char symlinkname[PATH_MAX];
#if !HAVE_LINK
#undef HAVE_LINK
#define HAVE_LINK 1
#endif
#endif /* USE_SYMLINKS */
    static int call_count;
    static time_t start_time;	/* time at start of writes */

    if (call_count++ == 0) {
	start_time = 0;
    }

    (void) strcpy(name_list, tp->term_names);
    DEBUG(7, ("Name list = '%s'", name_list));

    first_name = name_list;

    ptr = &name_list[strlen(name_list) - 1];
    other_names = ptr + 1;

    while (ptr > name_list && *ptr != '|')
	ptr--;

    if (ptr != name_list) {
	*ptr = '\0';

	for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++)
	    continue;

	if (*ptr == '\0')
	    other_names = ptr;
	else {
	    *ptr = '\0';
	    other_names = ptr + 1;
	}
    }

    DEBUG(7, ("First name = '%s'", first_name));
    DEBUG(7, ("Other names = '%s'", other_names));

    _nc_set_type(first_name);

    if (strlen(first_name) > sizeof(filename) - 3)
	_nc_warning("terminal name too long.");

    sprintf(filename, "%c/%s", first_name[0], first_name);

    /*
     * Has this primary name been written since the first call to
     * write_entry()?  If so, the newer write will step on the older,
     * so warn the user.
     */
    if (start_time > 0 &&
	stat(filename, &statbuf) >= 0
	&& statbuf.st_mtime >= start_time) {
	_nc_warning("name multiply defined.");
    }

    check_writeable(first_name[0]);
    write_file(filename, tp);

    if (start_time == 0) {
	if (stat(filename, &statbuf) < 0
	    || (start_time = statbuf.st_mtime) == 0) {
	    _nc_syserr_abort("error obtaining time from %s/%s",
			     _nc_tic_dir(0), filename);
	}
    }
    while (*other_names != '\0') {
	ptr = other_names++;
	while (*other_names != '|' && *other_names != '\0')
	    other_names++;

	if (*other_names != '\0')
	    *(other_names++) = '\0';

	if (strlen(ptr) > sizeof(linkname) - 3) {
	    _nc_warning("terminal alias %s too long.", ptr);
	    continue;
	}
	if (strchr(ptr, '/') != 0) {
	    _nc_warning("cannot link alias %s.", ptr);
	    continue;
	}

	check_writeable(ptr[0]);
	sprintf(linkname, "%c/%s", ptr[0], ptr);

	if (strcmp(filename, linkname) == 0) {
	    _nc_warning("self-synonym ignored");
	} else if (stat(linkname, &statbuf) >= 0 &&
		   statbuf.st_mtime < start_time) {
	    _nc_warning("alias %s multiply defined.", ptr);
	} else if (_nc_access(linkname, W_OK) == 0)
#if HAVE_LINK
	{
	    int code;
#if USE_SYMLINKS
	    strcpy(symlinkname, "../");
	    strncat(symlinkname, filename, sizeof(symlinkname) - 4);
	    symlinkname[sizeof(symlinkname) - 1] = '\0';
#endif /* USE_SYMLINKS */
#if HAVE_REMOVE
	    code = remove(linkname);
#else
	    code = unlink(linkname);
#endif
	    if (code != 0 && errno == ENOENT)
		code = 0;
#if USE_SYMLINKS
	    if (symlink(symlinkname, linkname) < 0)
#else
	    if (link(filename, linkname) < 0)
#endif /* USE_SYMLINKS */
	    {
		/*
		 * If there wasn't anything there, and we cannot
		 * link to the target because it is the same as the
		 * target, then the source must be on a filesystem
		 * that uses caseless filenames, such as Win32, etc.
		 */
		if (code == 0 && errno == EEXIST)
		    _nc_warning("can't link %s to %s", filename, linkname);
		else if (code == 0 && (errno == EPERM || errno == ENOENT))
		    write_file(linkname, tp);
		else {
#if MIXEDCASE_FILENAMES
		    _nc_syserr_abort("can't link %s to %s", filename, linkname);
#else
		    _nc_warning("can't link %s to %s (errno=%d)", filename,
				linkname, errno);
#endif
		}
	    } else {
		DEBUG(1, ("Linked %s", linkname));
	    }
	}
#else /* just make copies */
	    write_file(linkname, tp);
#endif /* HAVE_LINK */
    }
}
Пример #19
0
_nc_write_entry(TERMTYPE *const tp)
{
#if USE_HASHED_DB

    char buffer[MAX_ENTRY_SIZE + 1];
    unsigned limit = sizeof(buffer);
    unsigned offset = 0;

#else /* !USE_HASHED_DB */

    struct stat statbuf;
    char filename[PATH_MAX];
    char linkname[PATH_MAX];
#if USE_SYMLINKS
    char symlinkname[PATH_MAX];
#if !HAVE_LINK
#undef HAVE_LINK
#define HAVE_LINK 1
#endif
#endif /* USE_SYMLINKS */

    static int call_count;
    static time_t start_time;	/* time at start of writes */

#endif /* USE_HASHED_DB */

    char name_list[MAX_TERMINFO_LENGTH];
    char *first_name, *other_names;
    char *ptr;

    assert(strlen(tp->term_names) != 0);
    assert(strlen(tp->term_names) < sizeof(name_list));

    (void) strlcpy(name_list, tp->term_names, sizeof(name_list));
    DEBUG(7, ("Name list = '%s'", name_list));

    first_name = name_list;

    ptr = &name_list[strlen(name_list) - 1];
    other_names = ptr + 1;

    while (ptr > name_list && *ptr != '|')
	ptr--;

    if (ptr != name_list) {
	*ptr = '\0';

	for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++)
	    continue;

	if (*ptr == '\0')
	    other_names = ptr;
	else {
	    *ptr = '\0';
	    other_names = ptr + 1;
	}
    }

    DEBUG(7, ("First name = '%s'", first_name));
    DEBUG(7, ("Other names = '%s'", other_names));

    _nc_set_type(first_name);

#if USE_HASHED_DB
    if (write_object(tp, buffer + 1, &offset, limit - 1) != ERR) {
	DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE);
	DBT key, data;

	if (capdb != 0) {
	    buffer[0] = 0;

	    memset(&key, 0, sizeof(key));
	    key.data = tp->term_names;
	    key.size = strlen(tp->term_names);

	    memset(&data, 0, sizeof(data));
	    data.data = buffer;
	    data.size = offset + 1;

	    _nc_db_put(capdb, &key, &data);

	    buffer[0] = 2;

	    key.data = name_list;
	    key.size = strlen(name_list);

	    strlcpy(buffer + 1, tp->term_names, sizeof(buffer) - 1);
	    data.size = strlen(tp->term_names) + 1;

	    _nc_db_put(capdb, &key, &data);

	    while (*other_names != '\0') {
		ptr = other_names++;
		while (*other_names != '|' && *other_names != '\0')
		    other_names++;

		if (*other_names != '\0')
		    *(other_names++) = '\0';

		key.data = ptr;
		key.size = strlen(ptr);

		_nc_db_put(capdb, &key, &data);
	    }
	    _nc_db_close(capdb);
	}
    }
#else /* !USE_HASHED_DB */
    if (call_count++ == 0) {
	start_time = 0;
    }

    if (strlen(first_name) >= sizeof(filename) - 3)
	_nc_warning("terminal name too long.");

    snprintf(filename, sizeof(filename), LEAF_FMT "/%s", first_name[0], first_name);

    /*
     * Has this primary name been written since the first call to
     * write_entry()?  If so, the newer write will step on the older,
     * so warn the user.
     */
    if (start_time > 0 &&
	stat(filename, &statbuf) >= 0
	&& statbuf.st_mtime >= start_time) {
	_nc_warning("name multiply defined.");
    }

    check_writeable(first_name[0]);
    write_file(filename, tp);

    if (start_time == 0) {
	if (stat(filename, &statbuf) < 0
	    || (start_time = statbuf.st_mtime) == 0) {
	    _nc_syserr_abort("error obtaining time from %s/%s",
			     _nc_tic_dir(0), filename);
	}
    }
    while (*other_names != '\0') {
	ptr = other_names++;
	assert(ptr < buffer + sizeof(buffer) - 1);
	while (*other_names != '|' && *other_names != '\0')
	    other_names++;

	if (*other_names != '\0')
	    *(other_names++) = '\0';

	if (strlen(ptr) > sizeof(linkname) - 3) {
	    _nc_warning("terminal alias %s too long.", ptr);
	    continue;
	}
	if (strchr(ptr, '/') != 0) {
	    _nc_warning("cannot link alias %s.", ptr);
	    continue;
	}

	check_writeable(ptr[0]);
	snprintf(linkname, sizeof(linkname), LEAF_FMT "/%s", ptr[0], ptr);

	if (strcmp(filename, linkname) == 0) {
	    _nc_warning("self-synonym ignored");
	} else if (stat(linkname, &statbuf) >= 0 &&
		   statbuf.st_mtime < start_time) {
	    _nc_warning("alias %s multiply defined.", ptr);
	} else if (_nc_access(linkname, W_OK) == 0)
#if HAVE_LINK
	{
	    int code;
#if USE_SYMLINKS
            strlcpy(symlinkname, "../", sizeof(symlinkname));
            strlcat(symlinkname, filename, sizeof(symlinkname));
#endif /* USE_SYMLINKS */
#if HAVE_REMOVE
	    code = remove(linkname);
#else
	    code = unlink(linkname);
#endif
	    if (code != 0 && errno == ENOENT)
		code = 0;
#if USE_SYMLINKS
	    if (symlink(symlinkname, linkname) < 0)
#else
	    if (link(filename, linkname) < 0)
#endif /* USE_SYMLINKS */
	    {
		/*
		 * If there wasn't anything there, and we cannot
		 * link to the target because it is the same as the
		 * target, then the source must be on a filesystem
		 * that uses caseless filenames, such as Win32, etc.
		 */
		if (code == 0 && errno == EEXIST)
		    _nc_warning("can't link %s to %s", filename, linkname);
		else if (code == 0 && (errno == EPERM || errno == ENOENT))
		    write_file(linkname, tp);
		else {
#if MIXEDCASE_FILENAMES
		    _nc_syserr_abort("can't link %s to %s", filename, linkname);
#else
		    _nc_warning("can't link %s to %s (errno=%d)", filename,
				linkname, errno);
#endif
		}
	    } else {
		DEBUG(1, ("Linked %s", linkname));
	    }
	}
#else /* just make copies */
	    write_file(linkname, tp);
#endif /* HAVE_LINK */
    }
#endif /* USE_HASHED_DB */
}