Esempio n. 1
0
File: log.c Progetto: odit/rv042
/* log a line to cur_connection's log */
static void
peerlog(const char *prefix, const char *m)
{
    if (cur_connection == NULL)
    {
	/* we can not log it in this case. Oh well. */
	return;
    }

    if (cur_connection->log_file == NULL)
    {
	open_peerlog(cur_connection);
    }

    /* despite our attempts above, we may not be able to open the file. */
    if (cur_connection->log_file != NULL)
    {
	char datebuf[32];
	time_t n;
	struct tm *t;

	time(&n);
	t = localtime(&n);

	strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
	fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);

	/* now move it to the front of the list */
	CIRCLEQ_REMOVE(&perpeer_list, cur_connection, log_link);
	CIRCLEQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
    }
}
Esempio n. 2
0
void
init_stmem()
{
	int s = splhigh ();
	struct mem_node *mem;

	stmem_total = st_pool_size - sizeof(*mem);
    
	mem = (struct mem_node *)st_pool_virt;
	mem->size = st_pool_size - sizeof(*mem);

	CIRCLEQ_INIT(&st_list);
	CIRCLEQ_INIT(&free_list);
    
	CIRCLEQ_INSERT_HEAD(&st_list, mem, link);
	CIRCLEQ_INSERT_HEAD(&free_list, mem, free_link);
	splx(s);
}
Esempio n. 3
0
File: iod.c Progetto: Yomin/neobox
void add_client(int fd)
{
    struct chain_socket *cs = calloc(1, sizeof(struct chain_socket));
    CIRCLEQ_INSERT_HEAD(&client_list, cs, chain);
    cs->sock = fd;
    if(client_count+4 == pfds_cap)
    {
        pfds_cap += 10;
        pfds = realloc(pfds, pfds_cap*sizeof(struct pollfd));
    }
    pfds[client_count+4].fd = fd;
    pfds[client_count+4].events = POLLIN;
    client_count++;
    DEBUG(printf("Client added [%i]\n", fd));
}
Esempio n. 4
0
int
load_cve (char *path)
{

  FILE *f = fopen (path, "r");
  int i = 0, sz;
  char line[1024];
  if (!f)
    return 1;
  CIRCLEQ_INIT (&head);
  while (!feof (f))
    {
      fgets (line, 1024, f);
      if (strncmp (line, DELIMITER, 10) == 0)
	{
	  entry *en = malloc (sizeof (entry));
	  for (i = 0, sz = 0; i < 20 && !feof (f); i++)
	    {
	      fgets (line, 1024, f);
	      sz += strlen (line);
	      if (strncmp (line, DELIMITER, 10) == 0)
		{

		  CIRCLEQ_INSERT_HEAD (&head, en, entries);

		  break;
		}
	      if (line)
		{
		  en->buf[i] = malloc (strlen (line) + 1);
		  ++en->count;
		  memcpy (en->buf[i], &line, strlen (line) + 1);
		}
	    }

	}



    }
  fclose (f);

  return 0;

}
int
in6_pcballoc(struct socket *so, void *v)
{
	struct inpcbtable *table = v;
	struct in6pcb *in6p;
	int s;
#if defined(IPSEC)
	int error;
#endif

	s = splnet();
	in6p = pool_get(&in6pcb_pool, PR_NOWAIT);
	splx(s);
	if (in6p == NULL)
		return (ENOBUFS);
	memset((void *)in6p, 0, sizeof(*in6p));
	in6p->in6p_af = AF_INET6;
	in6p->in6p_table = table;
	in6p->in6p_socket = so;
	in6p->in6p_hops = -1;	/* use kernel default */
	in6p->in6p_icmp6filt = NULL;
	in6p->in6p_portalgo = PORTALGO_DEFAULT;
	in6p->in6p_bindportonsend = false;
#if defined(IPSEC)
	error = ipsec_init_pcbpolicy(so, &in6p->in6p_sp);
	if (error != 0) {
		s = splnet();
		pool_put(&in6pcb_pool, in6p);
		splx(s);
		return error;
	}
#endif /* IPSEC */
	s = splnet();
	CIRCLEQ_INSERT_HEAD(&table->inpt_queue, (struct inpcb_hdr*)in6p,
	    inph_queue);
	LIST_INSERT_HEAD(IN6PCBHASH_PORT(table, in6p->in6p_lport),
	    &in6p->in6p_head, inph_lhash);
	in6_pcbstate(in6p, IN6P_ATTACHED);
	splx(s);
	if (ip6_v6only)
		in6p->in6p_flags |= IN6P_IPV6_V6ONLY;
	so->so_pcb = (void *)in6p;
	return (0);
}
Esempio n. 6
0
int
in_pcballoc(struct socket *so, void *v)
{
	struct inpcbtable *table = v;
	struct inpcb *inp;
	int s;
#if defined(KAME_IPSEC) || defined(FAST_IPSEC)
	int error;
#endif

	s = splnet();
	inp = pool_get(&inpcb_pool, PR_NOWAIT);
	splx(s);
	if (inp == NULL)
		return (ENOBUFS);
	memset(inp, 0, sizeof(*inp));
	inp->inp_af = AF_INET;
	inp->inp_table = table;
	inp->inp_socket = so;
	inp->inp_errormtu = -1;
	inp->inp_rfc6056algo = RFC6056_ALGO_DEFAULT;
	inp->inp_bindportonsend = false;
#if defined(KAME_IPSEC) || defined(FAST_IPSEC)
	error = ipsec_init_pcbpolicy(so, &inp->inp_sp);
	if (error != 0) {
		s = splnet();
		pool_put(&inpcb_pool, inp);
		splx(s);
		return error;
	}
#endif
	so->so_pcb = inp;
	s = splnet();
	CIRCLEQ_INSERT_HEAD(&table->inpt_queue, &inp->inp_head,
	    inph_queue);
	LIST_INSERT_HEAD(INPCBHASH_PORT(table, inp->inp_lport), &inp->inp_head,
	    inph_lhash);
	in_pcbstate(inp, INP_ATTACHED);
	splx(s);
	return (0);
}
Esempio n. 7
0
File: log.c Progetto: mcr/Openswan
/* log a line to cur_connection's log */
static void
peerlog(const char *prefix, const char *m)
{
    if (cur_connection == NULL)
    {
	/* we can not log it in this case. Oh well. */
	return;
    }

    if (cur_connection->log_file == NULL)
    {
	open_peerlog(cur_connection);
    }

    /* despite our attempts above, we may not be able to open the file. */
    if (cur_connection->log_file != NULL)
    {
	fprintf(cur_connection->log_file, "%s %s%s\n", oswtimestr(), prefix, m);

	/* now move it to the front of the list */
	CIRCLEQ_REMOVE(&perpeer_list, cur_connection, log_link);
	CIRCLEQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
    }
}
Esempio n. 8
0
/*
 * ex_txt --
 *	Get lines from the terminal for ex.
 *
 * PUBLIC: int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t));
 */
int
ex_txt(SCR *sp, TEXTH *tiqh, ARG_CHAR_T prompt, u_int32_t flags)
{
	EVENT ev;
	GS *gp;
	TEXT ait, *ntp, *tp;
	carat_t carat_st;
	size_t cnt;
	int rval;

	rval = 0;

	/*
	 * Get a TEXT structure with some initial buffer space, reusing the
	 * last one if it's big enough.  (All TEXT bookkeeping fields default
	 * to 0 -- text_init() handles this.)
	 */
	if (tiqh->cqh_first != (void *)tiqh) {
		tp = tiqh->cqh_first;
		if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) {
			text_lfree(tiqh);
			goto newtp;
		}
		tp->len = 0;
	} else {
newtp:		if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
			goto err;
		CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
	}

	/* Set the starting line number. */
	tp->lno = sp->lno + 1;

	/*
	 * If it's a terminal, set up autoindent, put out the prompt, and
	 * set it up so we know we were suspended.  Otherwise, turn off
	 * the autoindent flag, as that requires less special casing below.
	 *
	 * XXX
	 * Historic practice is that ^Z suspended command mode (but, because
	 * it ran in cooked mode, it was unaffected by the autowrite option.)
	 * On restart, any "current" input was discarded, whether in insert
	 * mode or not, and ex was in command mode.  This code matches historic
	 * practice, but not 'cause it's easier.
	 */
	gp = sp->gp;
	if (F_ISSET(gp, G_SCRIPTED))
		LF_CLR(TXT_AUTOINDENT);
	else {
		if (LF_ISSET(TXT_AUTOINDENT)) {
			LF_SET(TXT_EOFCHAR);
			if (v_txt_auto(sp, sp->lno, NULL, 0, tp))
				goto err;
		}
		txt_prompt(sp, tp, prompt, flags);
	}

	for (carat_st = C_NOTSET;;) {
		if (v_event_get(sp, &ev, 0, 0))
			goto err;

		/* Deal with all non-character events. */
		switch (ev.e_event) {
		case E_CHARACTER:
			break;
		case E_ERR:
			goto err;
		case E_REPAINT:
		case E_WRESIZE:
			continue;
		case E_EOF:
			rval = 1;
			/* FALLTHROUGH */
		case E_INTERRUPT:
			/*
			 * Handle EOF/SIGINT events by discarding partially
			 * entered text and returning.  EOF returns failure,
			 * E_INTERRUPT returns success.
			 */
			goto notlast;
		default:
			v_event_err(sp, &ev);
			goto notlast;
		}

		/*
		 * Deal with character events.
		 *
		 * Check to see if the character fits into the input buffer.
		 * (Use tp->len, ignore overwrite and non-printable chars.)
		 */
		BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1);

		switch (ev.e_value) {
		case K_CR:
			/*
			 * !!!
			 * Historically, <carriage-return>'s in the command
			 * weren't special, so the ex parser would return an
			 * unknown command error message.  However, if they
			 * terminated the command if they were in a map.  I'm
			 * pretty sure this still isn't right, but it handles
			 * what I've seen so far.
			 */
			if (!FL_ISSET(ev.e_flags, CH_MAPPED))
				goto ins_ch;
			/* FALLTHROUGH */
		case K_NL:
			/*
			 * '\' can escape <carriage-return>/<newline>.  We
			 * don't discard the backslash because we need it
			 * to get the <newline> through the ex parser.
			 */
			if (LF_ISSET(TXT_BACKSLASH) &&
			    tp->len != 0 && tp->lb[tp->len - 1] == '\\')
				goto ins_ch;

			/*
			 * CR returns from the ex command line.
			 *
			 * XXX
			 * Terminate with a nul, needed by filter.
			 */
			if (LF_ISSET(TXT_CR)) {
				tp->lb[tp->len] = '\0';
				goto done;
			}

			/*
			 * '.' may terminate text input mode; free the current
			 * TEXT.
			 */
			if (LF_ISSET(TXT_DOTTERM) && tp->len == tp->ai + 1 &&
			    tp->lb[tp->len - 1] == '.') {
notlast:			CIRCLEQ_REMOVE(tiqh, tp, q);
				text_free(tp);
				goto done;
			}

			/* Set up bookkeeping for the new line. */
			if ((ntp = text_init(sp, NULL, 0, 32)) == NULL)
				goto err;
			ntp->lno = tp->lno + 1;

			/*
			 * Reset the autoindent line value.  0^D keeps the ai
			 * line from changing, ^D changes the level, even if
			 * there were no characters in the old line.  Note, if
			 * using the current tp structure, use the cursor as
			 * the length, the autoindent characters may have been
			 * erased.
			 */
			if (LF_ISSET(TXT_AUTOINDENT)) {
				if (carat_st == C_NOCHANGE) {
					if (v_txt_auto(sp,
					    OOBLNO, &ait, ait.ai, ntp))
						goto err;
					free(ait.lb);
				} else
					if (v_txt_auto(sp,
					    OOBLNO, tp, tp->len, ntp))
						goto err;
				carat_st = C_NOTSET;
			}
			txt_prompt(sp, ntp, prompt, flags);

			/*
			 * Swap old and new TEXT's, and insert the new TEXT
			 * into the queue.
			 */
			tp = ntp;
			CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
			break;
		case K_CARAT:			/* Delete autoindent chars. */
			if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
				carat_st = C_CARATSET;
			goto ins_ch;
		case K_ZERO:			/* Delete autoindent chars. */
			if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
				carat_st = C_ZEROSET;
			goto ins_ch;
		case K_CNTRLD:			/* Delete autoindent char. */
			/*
			 * !!!
			 * Historically, the ^D command took (but then ignored)
			 * a count.  For simplicity, we don't return it unless
			 * it's the first character entered.  The check for len
			 * equal to 0 is okay, TXT_AUTOINDENT won't be set.
			 */
			if (LF_ISSET(TXT_CNTRLD)) {
				for (cnt = 0; cnt < tp->len; ++cnt)
					if (!isblank(tp->lb[cnt]))
						break;
				if (cnt == tp->len) {
					tp->len = 1;
					tp->lb[0] = ev.e_c;
					tp->lb[1] = '\0';

					/*
					 * Put out a line separator, in case
					 * the command fails.
					 */
					(void)putchar('\n');
					goto done;
				}
			}

			/*
			 * POSIX 1003.1b-1993, paragraph 7.1.1.9, states that
			 * the EOF characters are discarded if there are other
			 * characters to process in the line, i.e. if the EOF
			 * is not the first character in the line.  For this
			 * reason, historic ex discarded the EOF characters,
			 * even if occurring in the middle of the input line.
			 * We match that historic practice.
			 *
			 * !!!
			 * The test for discarding in the middle of the line is
			 * done in the switch, because the CARAT forms are N+1,
			 * not N.
			 *
			 * !!!
			 * There's considerable magic to make the terminal code
			 * return the EOF character at all.  See that code for
			 * details.
			 */
			if (!LF_ISSET(TXT_AUTOINDENT) || tp->len == 0)
				continue;
			switch (carat_st) {
			case C_CARATSET:		/* ^^D */
				if (tp->len > tp->ai + 1)
					continue;

				/* Save the ai string for later. */
				ait.lb = NULL;
				ait.lb_len = 0;
				BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai);
				MEMCPYW(ait.lb, tp->lb, tp->ai);
				ait.ai = ait.len = tp->ai;

				carat_st = C_NOCHANGE;
				goto leftmargin;
			case C_ZEROSET:			/* 0^D */
				if (tp->len > tp->ai + 1)
					continue;

				carat_st = C_NOTSET;
leftmargin:			(void)gp->scr_ex_adjust(sp, EX_TERM_CE);
				tp->ai = tp->len = 0;
				break;
			case C_NOTSET:			/* ^D */
				if (tp->len > tp->ai)
					continue;

				if (txt_dent(sp, tp))
					goto err;
				break;
			default:
				abort();
			}

			/* Clear and redisplay the line. */
			(void)gp->scr_ex_adjust(sp, EX_TERM_CE);
			txt_prompt(sp, tp, prompt, flags);
			break;
		default:
			/*
			 * See the TXT_BEAUTIFY comment in vi/v_txt_ev.c.
			 *
			 * Silently eliminate any iscntrl() character that was
			 * not already handled specially, except for <tab> and
			 * <ff>.
			 */
ins_ch:			if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(ev.e_c) &&
			    ev.e_value != K_FORMFEED && ev.e_value != K_TAB)
				break;

			tp->lb[tp->len++] = ev.e_c;
			break;
		}
	}
	/* NOTREACHED */

done:	return (rval);

err:	
alloc_err:
	return (1);
}
Esempio n. 9
0
File: main.c Progetto: fishman/nvi
/*
 * editor --
 *	Main editor routine.
 *
 * PUBLIC: int editor __P((WIN *, int, char *[]));
 */
int
editor(WIN *wp, int argc, char **argv)
{
	extern int optind;
	extern char *optarg;
	const char *p;
	EVENT ev;
	FREF *frp;
	SCR *sp;
	GS *gp;
	size_t len;
	u_int flags;
	int ch, flagchk, lflag, secure, startup, readonly, rval, silent;
	char *tag_f, *wsizearg, path[256];
	CHAR_T *w;
	size_t wlen;

	gp = wp->gp;

	/* Initialize the busy routine, if not defined by the screen. */
	if (gp->scr_busy == NULL)
		gp->scr_busy = vs_busy;
	/* Initialize the message routine, if not defined by the screen. */
	if (wp->scr_msg == NULL)
		wp->scr_msg = vs_msg;

	/* Set initial screen type and mode based on the program name. */
	readonly = 0;
	if (!strcmp(gp->progname, "ex") || !strcmp(gp->progname, "nex"))
		LF_INIT(SC_EX);
	else {
		/* Nview, view are readonly. */
		if (!strcmp(gp->progname, "nview") ||
		    !strcmp(gp->progname, "view"))
			readonly = 1;
		
		/* Vi is the default. */
		LF_INIT(SC_VI);
	}

	/* Convert old-style arguments into new-style ones. */
	if (v_obsolete(gp->progname, argv))
		return (1);

	/* Parse the arguments. */
	flagchk = '\0';
	tag_f = wsizearg = NULL;
	lflag = secure = silent = 0;
	startup = 1;

	/* Set the file snapshot flag. */
	F_SET(gp, G_SNAPSHOT);

#ifdef DEBUG
	while ((ch = getopt(argc, argv, "c:D:eFlRrSsT:t:vw:")) != EOF)
#else
	while ((ch = getopt(argc, argv, "c:eFlRrSst:vw:")) != EOF)
#endif
		switch (ch) {
		case 'c':		/* Run the command. */
			/*
			 * XXX
			 * We should support multiple -c options.
			 */
			if (gp->c_option != NULL) {
				v_estr(gp->progname, 0,
				    "only one -c command may be specified.");
				return (1);
			}
			gp->c_option = optarg;
			break;
#ifdef DEBUG
		case 'D':
			switch (optarg[0]) {
			case 's':
				startup = 0;
				break;
			case 'w':
				attach(gp);
				break;
			default:
				v_estr(gp->progname, 0,
				    "usage: -D requires s or w argument.");
				return (1);
			}
			break;
#endif
		case 'e':		/* Ex mode. */
			LF_CLR(SC_VI);
			LF_SET(SC_EX);
			break;
		case 'F':		/* No snapshot. */
			v_estr(gp->progname, 0, 
			    "-F option no longer supported.");
			break;
		case 'l':		/* Set lisp, showmatch options. */
			lflag = 1;
			break;
		case 'R':		/* Readonly. */
			readonly = 1;
			break;
		case 'r':		/* Recover. */
			if (flagchk == 't') {
				v_estr(gp->progname, 0,
				    "only one of -r and -t may be specified.");
				return (1);
			}
			flagchk = 'r';
			break;
		case 'S':
			secure = 1;
			break;
		case 's':
			silent = 1;
			break;
#ifdef TRACE
		case 'T':		/* Trace. */
			(void)vtrace_init(optarg);
			break;
#endif
		case 't':		/* Tag. */
			if (flagchk == 'r') {
				v_estr(gp->progname, 0,
				    "only one of -r and -t may be specified.");
				return (1);
			}
			if (flagchk == 't') {
				v_estr(gp->progname, 0,
				    "only one tag file may be specified.");
				return (1);
			}
			flagchk = 't';
			tag_f = optarg;
			break;
		case 'v':		/* Vi mode. */
			LF_CLR(SC_EX);
			LF_SET(SC_VI);
			break;
		case 'w':
			wsizearg = optarg;
			break;
		case '?':
		default:
			(void)gp->scr_usage();
			return (1);
		}
	argc -= optind;
	argv += optind;

	/*
	 * -s option is only meaningful to ex.
	 *
	 * If not reading from a terminal, it's like -s was specified.
	 */
	if (silent && !LF_ISSET(SC_EX)) {
		v_estr(gp->progname, 0, "-s option is only applicable to ex.");
		goto err;
	}
	if (LF_ISSET(SC_EX) && F_ISSET(gp, G_SCRIPTED))
		silent = 1;

	/*
	 * Build and initialize the first/current screen.  This is a bit
	 * tricky.  If an error is returned, we may or may not have a
	 * screen structure.  If we have a screen structure, put it on a
	 * display queue so that the error messages get displayed.
	 *
	 * !!!
	 * Everything we do until we go interactive is done in ex mode.
	 */
	if (screen_init(gp, NULL, &sp)) {
		if (sp != NULL) {
			CIRCLEQ_INSERT_HEAD(&wp->scrq, sp, q);
			sp->wp = wp;
		}
		goto err;
	}
	F_SET(sp, SC_EX);
	CIRCLEQ_INSERT_HEAD(&wp->scrq, sp, q);
	sp->wp = wp;

	if (v_key_init(sp))		/* Special key initialization. */
		goto err;

	{ int oargs[5], *oargp = oargs;
	if (lflag) {			/* Command-line options. */
		*oargp++ = O_LISP;
		*oargp++ = O_SHOWMATCH;
	}
	if (readonly)
		*oargp++ = O_READONLY;
	if (secure)
		*oargp++ = O_SECURE;
	*oargp = -1;			/* Options initialization. */
	if (opts_init(sp, oargs))
		goto err;
	}
	if (wsizearg != NULL) {
		ARGS *av[2], a, b;
		(void)snprintf(path, sizeof(path), "window=%s", wsizearg);
		a.bp = (CHAR_T *)path;
		a.len = strlen(path);
		b.bp = NULL;
		b.len = 0;
		av[0] = &a;
		av[1] = &b;
		(void)opts_set(sp, av, NULL);
	}
	if (silent) {			/* Ex batch mode option values. */
		O_CLR(sp, O_AUTOPRINT);
		O_CLR(sp, O_PROMPT);
		O_CLR(sp, O_VERBOSE);
		O_CLR(sp, O_WARN);
		F_SET(sp, SC_EX_SILENT);
	}

	sp->rows = O_VAL(sp, O_LINES);	/* Make ex formatting work. */
	sp->cols = O_VAL(sp, O_COLUMNS);

	if (!silent && startup) {	/* Read EXINIT, exrc files. */
		if (ex_exrc(sp))
			goto err;
		if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
			if (screen_end(sp))
				goto err;
			goto done;
		}
	}

	/*
	 * List recovery files if -r specified without file arguments.
	 * Note, options must be initialized and startup information
	 * read before doing this.
	 */
	if (flagchk == 'r' && argv[0] == NULL) {
		if (rcv_list(sp))
			goto err;
		if (screen_end(sp))
			goto err;
		goto done;
	}

	/*
	 * !!!
	 * Initialize the default ^D, ^U scrolling value here, after the
	 * user has had every opportunity to set the window option.
	 *
	 * It's historic practice that changing the value of the window
	 * option did not alter the default scrolling value, only giving
	 * a count to ^D/^U did that.
	 */
	sp->defscroll = (O_VAL(sp, O_WINDOW) + 1) / 2;

	/*
	 * If we don't have a command-line option, switch into the right
	 * editor now, so that we position default files correctly, and
	 * so that any tags file file-already-locked messages are in the
	 * vi screen, not the ex screen.
	 *
	 * XXX
	 * If we have a command-line option, the error message can end
	 * up in the wrong place, but I think that the combination is
	 * unlikely.
	 */
	if (gp->c_option == NULL) {
		F_CLR(sp, SC_EX | SC_VI);
		F_SET(sp, LF_ISSET(SC_EX | SC_VI));
	}

	/* Open a tag file if specified. */
	if (tag_f != NULL) {
		CHAR2INT(sp, tag_f, strlen(tag_f) + 1, w, wlen);
		if (ex_tag_first(sp, w))
			goto err;
	}

	/*
	 * Append any remaining arguments as file names.  Files are recovery
	 * files if -r specified.  If the tag option or ex startup commands
	 * loaded a file, then any file arguments are going to come after it.
	 */
	if (*argv != NULL) {
		if (sp->frp != NULL) {
			/* Cheat -- we know we have an extra argv slot. */
			MALLOC_NOMSG(sp,
			    *--argv, char *, strlen(sp->frp->name) + 1);
			if (*argv == NULL) {
				v_estr(gp->progname, errno, NULL);
				goto err;
			}
			(void)strcpy(*argv, sp->frp->name);
		}
		sp->argv = sp->cargv = argv;
		F_SET(sp, SC_ARGNOFREE);
		if (flagchk == 'r')
			F_SET(sp, SC_ARGRECOVER);
	}
Esempio n. 10
0
/*
 * ypdb_open_db
 */
DBM *
ypdb_open_db(const char *domain, const char *map, u_int *status,
	     struct opt_map **map_info)
{
	static const char *domain_key = YP_INTERDOMAIN_KEY;
	static const char *secure_key = YP_SECURE_KEY;
	char map_path[MAXPATHLEN];
	struct stat finfo;
	struct opt_domain *d = NULL;
	struct opt_map *m = NULL;
	DBM *db;
	datum k, v;

	*status = YP_TRUE;	/* defaults to true */

	/*
	 * check for illegal domain and map names
	 */
	if (_yp_invalid_domain(domain)) {
		*status = YP_NODOM;
		return (NULL);
	}
	if (_yp_invalid_map(map)) {
		*status = YP_NOMAP;
		return (NULL);
	}

	/*
	 * check for domain, file.
	 */
	(void)snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain);
	if (stat(map_path, &finfo) < 0 || !S_ISDIR(finfo.st_mode)) {
#ifdef DEBUG
		syslog(LOG_DEBUG,
		    "ypdb_open_db: no domain %s (map=%s)", domain, map);
#endif
		*status = YP_NODOM;
	} else {
		(void)snprintf(map_path, sizeof(map_path), "%s/%s/%s%s",
		    YP_DB_PATH, domain, map, YPDB_SUFFIX);
		if (stat(map_path, &finfo) < 0) {
#ifdef DEBUG
			syslog(LOG_DEBUG,
			    "ypdb_open_db: no map %s (domain=%s)", map,
			    domain);
#endif
			*status = YP_NOMAP;
		}
	}

	/*
	 * check for preloaded domain, map
	 */
	for (d = doms.lh_first; d != NULL; d = d->domsl.le_next)
		if (strcmp(domain, d->domain) == 0)
			break;

	if (d)
		for (m = d->dmaps.lh_first; m != NULL; m = m->mapsl.le_next)
			if (strcmp(map, m->map) == 0)
				break;

	/*
	 * map found open?
	 */
	if (m) {
#ifdef DEBUG
		syslog(LOG_DEBUG,
		    "ypdb_open_db: cached open: domain=%s, map=%s, db=%p,",
		    domain, map, m->db);
		syslog(LOG_DEBUG,
		    "\tdbdev %d new %d; dbino %d new %d; dbmtime %ld new %ld",
		    m->dbdev, finfo.st_dev, m->dbino, finfo.st_ino,
		    (long) m->dbmtime, (long) finfo.st_mtime);
#endif
		/*
		 * if status != YP_TRUE, then this cached database is now
		 * non-existent
		 */
		if (*status != YP_TRUE) {
#ifdef DEBUG
			syslog(LOG_DEBUG,
			    "ypdb_open_db: cached db is now unavailable - "
			    "closing: status %s",
			    yperr_string(ypprot_err(*status)));
#endif
			ypdb_close_map(m);
			return (NULL);
		}

		/*
		 * is this the same db?
		 */
		if (finfo.st_dev == m->dbdev && finfo.st_ino == m->dbino &&
		    finfo.st_mtime == m->dbmtime) {
			CIRCLEQ_REMOVE(&maps, m, mapsq); /* adjust LRU queue */
			CIRCLEQ_INSERT_HEAD(&maps, m, mapsq);
			if (map_info)
				*map_info = m;
			return (m->db);
		} else {
#ifdef DEBUG
			syslog(LOG_DEBUG,
			    "ypdb_open_db: db changed; closing");
#endif
			ypdb_close_map(m);
			m = NULL;
		}
	}

	/*
	 * not cached and non-existent, return
	 */
	if (*status != YP_TRUE)	
		return (NULL);

	/*
	 * open map
	 */
	(void)snprintf(map_path, sizeof(map_path), "%s/%s/%s",
	    YP_DB_PATH, domain, map);
#ifdef OPTIMIZE_DB
retryopen:
#endif /* OPTIMIZE_DB */
	db = ypdb_open(map_path);
#ifdef OPTIMIZE_DB
	if (db == NULL) {
#ifdef DEBUG
		syslog(LOG_DEBUG,
		    "ypdb_open_db: errno %d (%s)", errno, strerror(errno));
#endif /* DEBUG */
		if ((errno == ENFILE) || (errno == EMFILE)) {
			ypdb_close_last();
			goto retryopen;
		}
	}
#endif /* OPTIMIZE_DB */

	*status = YP_NOMAP;	/* see note below */

	if (db == NULL) {
#ifdef DEBUG
		syslog(LOG_DEBUG,
		    "ypdb_open_db: ypdb_open FAILED: map %s (domain=%s)",
		    map, domain);
#endif
		return (NULL);
	}

	/*
	 * note: status now YP_NOMAP
	 */
	if (d == NULL) {	/* allocate new domain? */
		d = (struct opt_domain *) malloc(sizeof(*d));
		if (d)
			d->domain = strdup(domain);
		if (d == NULL || d->domain == NULL) {
			syslog(LOG_ERR,
			    "ypdb_open_db: MALLOC failed");
			ypdb_close(db);
			if (d)
				free(d);
			return (NULL);
		}
		LIST_INIT(&d->dmaps);
		LIST_INSERT_HEAD(&doms, d, domsl);
#ifdef DEBUG
		syslog(LOG_DEBUG,
		    "ypdb_open_db: NEW DOMAIN %s", domain);
#endif
	}

	/*
	 * m must be NULL since we couldn't find a map.  allocate new one
	 */
	m = (struct opt_map *) malloc(sizeof(*m));
	if (m)
		m->map = strdup(map);

	if (m == NULL || m->map == NULL) {
		if (m)
			free(m);
		syslog(LOG_ERR, "ypdb_open_db: MALLOC failed");
		ypdb_close(db);
		return (NULL);
	}
	m->db = db;
	m->dom = d;
	m->host_lookup = FALSE;
	m->dbdev = finfo.st_dev;
	m->dbino = finfo.st_ino;
	m->dbmtime = finfo.st_mtime;
	CIRCLEQ_INSERT_HEAD(&maps, m, mapsq);
	LIST_INSERT_HEAD(&d->dmaps, m, mapsl);
	if (strcmp(map, YP_HOSTNAME) == 0 || strcmp(map, YP_HOSTADDR) == 0) {
		if (!usedns) {
			k.dptr = domain_key;
			k.dsize = YP_INTERDOMAIN_LEN;
			v = ypdb_fetch(db, k);
			if (v.dptr)
				m->host_lookup = TRUE;
		} else
			m->host_lookup = TRUE;
	}

	m->secure = FALSE;
	k.dptr = secure_key;
	k.dsize = YP_SECURE_LEN;
	v = ypdb_fetch(db, k);
	if (v.dptr != NULL)
		m->secure = TRUE;

	*status = YP_TRUE;

	if (map_info)
		*map_info = m;

#ifdef DEBUG
	syslog(LOG_DEBUG,
	    "ypdb_open_db: NEW MAP domain=%s, map=%s, hl=%d, s=%d, db=%p",
	    domain, map, m->host_lookup, m->secure, m->db);
#endif

	return (m->db);
}
Esempio n. 11
0
File: log.c Progetto: odit/rv042
/* open the per-peer log */
static void
open_peerlog(struct connection *c)
{
    syslog(LOG_INFO, "opening log file for conn %s", c->name);

    if (c->log_file_name == NULL)
    {
	char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
	int  peernamelen, lf_len;

	addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
	peernamelen = strlen(peername);

	/* copy IP address, turning : and . into / */
	{
	    char c, *p, *q;

	    p = peername;
	    q = dname;
	    do {
		c = *p++;
		if (c == '.' || c == ':')
		    c = '/';
		*q++ = c;
	    } while (c != '\0');
	}

	lf_len = peernamelen * 2
	    + strlen(base_perpeer_logdir)
	    + sizeof("//.log")
	    + 1;
	c->log_file_name = alloc_bytes(lf_len, "per-peer log file name");

	fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
		, base_perpeer_logdir, dname, peername);
	snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
		 , base_perpeer_logdir, dname, peername);

	syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
    }

    /* now open the file, creating directories if necessary */

    {  /* create the directory */
	char *dname;
	int   bpl_len = strlen(base_perpeer_logdir);
	char *slashloc;

	dname = clone_str(c->log_file_name, "temp copy of file name");
	dname = dirname(dname);

	if (access(dname, W_OK) != 0)
	{
	    if (errno != ENOENT)
	    {
		if (c->log_file_err)
		{
		    syslog(LOG_CRIT, "can not write to %s: %s"
			   , dname, strerror(errno));
		    c->log_file_err = TRUE;
		    pfree(dname);
		    return;
		}
	    }

	    /* directory does not exist, walk path creating dirs */
	    /* start at base_perpeer_logdir */
	    slashloc = dname + bpl_len;
	    slashloc++;    /* since, by construction there is a slash
			      right there */

	    while (*slashloc != '\0')
	    {
		char saveslash;

		/* look for next slash */
		while (*slashloc != '\0' && *slashloc != '/') slashloc++;

		saveslash = *slashloc;

		*slashloc = '\0';

		if (mkdir(dname, 0750) != 0 && errno != EEXIST)
		{
		    syslog(LOG_CRIT, "can not create dir %s: %s"
			   , dname, strerror(errno));
		    c->log_file_err = TRUE;
		    pfree(dname);
		    return;
		}
		syslog(LOG_DEBUG, "created new directory %s", dname);
		*slashloc = saveslash;
		slashloc++;
	    }
	}

	pfree(dname);
    }

    c->log_file = fopen(c->log_file_name, "a");
    if (c->log_file == NULL)
    {
	if (c->log_file_err)
	{
	    syslog(LOG_CRIT, "logging system can not open %s: %s"
		   , c->log_file_name, strerror(errno));
	    c->log_file_err = TRUE;
	}
	return;
    }

    /* look for a connection to close! */
    while (perpeer_count >= MAX_PEERLOG_COUNT)
    {
	/* can not be NULL because perpeer_count > 0 */
	passert(perpeer_list.cqh_last != (void *)&perpeer_list);

	perpeer_logclose(perpeer_list.cqh_last);
    }

    /* insert this into the list */
    CIRCLEQ_INSERT_HEAD(&perpeer_list, c, log_link);
    passert(c->log_file != NULL);
    perpeer_count++;
}
Esempio n. 12
0
/* open the per-peer log
 *
 * NOTE: this routine must not call our own logging facilities to report
 * an error since those routines are not re-entrant and such a call
 * would be recursive.
 */
static void open_peerlog(struct connection *c)
{
	/* syslog(LOG_INFO, "opening log file for conn %s", c->name); */

	if (c->log_file_name == NULL) {
		char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
		int peernamelen, lf_len;

		addrtot(&c->spd.that.host_addr, 'Q', peername,
			sizeof(peername));
		peernamelen = strlen(peername);

		/* copy IP address, turning : and . into / */
		{
			char ch, *p, *q;

			p = peername;
			q = dname;
			do {
				ch = *p++;
				if (ch == '.' || ch == ':')
					ch = '/';
				*q++ = ch;
			} while (ch != '\0');
		}

		lf_len = peernamelen * 2 +
			 strlen(base_perpeer_logdir) +
			 sizeof("//.log") +
			 1;
		c->log_file_name =
			alloc_bytes(lf_len, "per-peer log file name");

#if 0
		fprintf(stderr, "base dir |%s| dname |%s| peername |%s|",
			base_perpeer_logdir, dname, peername);
#endif
		snprintf(c->log_file_name, lf_len, "%s/%s/%s.log",
			 base_perpeer_logdir, dname, peername);

		/* syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); */
	}

	/* now open the file, creating directories if necessary */

	c->log_file_err = !ensure_writeable_parent_directory(c->log_file_name);
	if (c->log_file_err)
		return;

	c->log_file = fopen(c->log_file_name, "w");
	if (c->log_file == NULL) {
		if (c->log_file_err) {
			syslog(LOG_CRIT, "logging system can not open %s: %s",
			       c->log_file_name, strerror(errno));
			c->log_file_err = TRUE;
		}
		return;
	}

	/* look for a connection to close! */
	while (perpeer_count >= MAX_PEERLOG_COUNT) {
		/* can not be NULL because perpeer_count > 0 */
		passert(perpeer_list.cqh_last != (void *)&perpeer_list);

		perpeer_logclose(perpeer_list.cqh_last);
	}

	/* insert this into the list */
	CIRCLEQ_INSERT_HEAD(&perpeer_list, c, log_link);
	passert(c->log_file != NULL);
	perpeer_count++;
}
Esempio n. 13
0
File: exf.c Progetto: fishman/nvi
/*
 * file_end --
 *	Stop editing a file.
 *
 * PUBLIC: int file_end __P((SCR *, EXF *, int));
 */
int
file_end(SCR *sp, EXF *ep, int force)
{
    FREF *frp;

    /*
     * !!!
     * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
     * (If argument ep is NULL, use sp->ep.)
     *
     * If multiply referenced, just decrement the count and return.
     */
    if (ep == NULL)
        ep = sp->ep;
    CIRCLEQ_REMOVE(&ep->scrq, sp, eq);
    if (--ep->refcnt != 0)
        return (0);

    /*
     *
     * Clean up the FREF structure.
     *
     * Save the cursor location.
     *
     * XXX
     * It would be cleaner to do this somewhere else, but by the time
     * ex or vi knows that we're changing files it's already happened.
     */
    frp = sp->frp;
    frp->lno = sp->lno;
    frp->cno = sp->cno;
    F_SET(frp, FR_CURSORSET);

    /*
     * We may no longer need the temporary backing file, so clean it
     * up.  We don't need the FREF structure either, if the file was
     * never named, so lose it.
     *
     * !!!
     * Re: FR_DONTDELETE, see the comment above in file_init().
     */
    if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) {
        if (unlink(frp->tname))
            msgq_str(sp, M_SYSERR, frp->tname, "240|%s: remove");
        free(frp->tname);
        frp->tname = NULL;
        if (F_ISSET(frp, FR_TMPFILE)) {
            CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q);
            if (frp->name != NULL)
                free(frp->name);
            free(frp);
        }
        sp->frp = NULL;
    }

    /*
     * Clean up the EXF structure.
     *
     * Close the db structure.
     */
    if (ep->db->close != NULL) {
        if ((sp->db_error = ep->db->close(ep->db, DB_NOSYNC)) != 0 &&
                !force) {
            msgq_str(sp, M_DBERR, frp->name, "241|%s: close");
            CIRCLEQ_INSERT_HEAD(&ep->scrq, sp, eq);
            ++ep->refcnt;
            return (1);
        }
        ep->db = NULL;
    }

    /* COMMITTED TO THE CLOSE.  THERE'S NO GOING BACK... */

    /* Stop logging. */
    (void)log_end(sp, ep);

    /* Free up any marks. */
    (void)mark_end(sp, ep);

    if (ep->env) {
        DB_ENV *env;

        ep->env->close(ep->env, 0);
        ep->env = 0;
        if ((sp->db_error = db_env_create(&env, 0)))
            msgq(sp, M_DBERR, "env_create");
        if ((sp->db_error = db_env_remove(env, ep->env_path, 0)))
            msgq(sp, M_DBERR, "env->remove");
        if (ep->env_path != NULL && rmdir(ep->env_path))
            msgq_str(sp, M_SYSERR, ep->env_path, "242|%s: remove");
    }

    /*
     * Delete recovery files, close the open descriptor, free recovery
     * memory.  See recover.c for a description of the protocol.
     *
     * XXX
     * Unlink backup file first, we can detect that the recovery file
     * doesn't reference anything when the user tries to recover it.
     * There's a race, here, obviously, but it's fairly small.
     */
    if (!F_ISSET(ep, F_RCV_NORM)) {
        if (ep->rcv_path != NULL && unlink(ep->rcv_path))
            msgq_str(sp, M_SYSERR, ep->rcv_path, "242|%s: remove");
        if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath))
            msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove");
    }
    CIRCLEQ_REMOVE(&sp->gp->exfq, ep, q);
    if (ep->fd != -1)
        (void)close(ep->fd);
    if (ep->fcntl_fd != -1)
        (void)close(ep->fcntl_fd);
    if (ep->rcv_fd != -1)
        (void)close(ep->rcv_fd);
    if (ep->env_path != NULL)
        free(ep->env_path);
    if (ep->rcv_path != NULL)
        free(ep->rcv_path);
    if (ep->rcv_mpath != NULL)
        free(ep->rcv_mpath);

    free(ep);
    return (0);
}
Esempio n. 14
0
File: exf.c Progetto: fishman/nvi
/*
 * file_init --
 *	Start editing a file, based on the FREF structure.  If successsful,
 *	let go of any previous file.  Don't release the previous file until
 *	absolutely sure we have the new one.
 *
 * PUBLIC: int file_init __P((SCR *, FREF *, char *, int));
 */
int
file_init(SCR *sp, FREF *frp, char *rcv_name, int flags)
{
    EXF *ep;
    struct stat sb;
    size_t psize;
    int fd, exists, open_err, readonly, stolen;
    char *oname, tname[MAXPATHLEN];

    stolen = open_err = readonly = 0;

    /*
     * If the file is a recovery file, let the recovery code handle it.
     * Clear the FR_RECOVER flag first -- the recovery code does set up,
     * and then calls us!  If the recovery call fails, it's probably
     * because the named file doesn't exist.  So, move boldly forward,
     * presuming that there's an error message the user will get to see.
     */
    if (F_ISSET(frp, FR_RECOVER)) {
        F_CLR(frp, FR_RECOVER);
        return (rcv_read(sp, frp));
    }

    /*
     * Required FRP initialization; the only flag we keep is the
     * cursor information.
     */
    F_CLR(frp, ~FR_CURSORSET);

    /*
     * Scan the user's path to find the file that we're going to
     * try and open.
     */
    if (file_spath(sp, frp, &sb, &exists))
        return (1);

    /*
     * Check whether we already have this file opened in some
     * other screen.
     */
    if (exists) {
        EXF *exfp;
        for (exfp = sp->gp->exfq.cqh_first;
                exfp != (EXF *)&sp->gp->exfq; exfp = exfp->q.cqe_next) {
            if (exfp->mdev == sb.st_dev &&
                    exfp->minode == sb.st_ino &&
                    (exfp != sp->ep || exfp->refcnt > 1)) {
                ep = exfp;
                goto postinit;
            }
        }
    }

    /*
     * Required EXF initialization:
     *	Flush the line caches.
     *	Default recover mail file fd to -1.
     *	Set initial EXF flag bits.
     */
    CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));
    CIRCLEQ_INIT(&ep->scrq);
    sp->c_lno = ep->c_nlines = OOBLNO;
    ep->rcv_fd = ep->fcntl_fd = -1;
    F_SET(ep, F_FIRSTMODIFY);

    /*
     * If no name or backing file, for whatever reason, create a backing
     * temporary file, saving the temp file name so we can later unlink
     * it.  If the user never named this file, copy the temporary file name
     * to the real name (we display that until the user renames it).
     */
    oname = frp->name;
    if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) {
        if (opts_empty(sp, O_TMP_DIRECTORY, 0))
            goto err;
        (void)snprintf(tname, sizeof(tname),
                       "%s/vi.XXXXXX", O_STR(sp, O_TMP_DIRECTORY));
        if ((fd = mkstemp(tname)) == -1) {
            msgq(sp, M_SYSERR,
                 "237|Unable to create temporary file");
            goto err;
        }
        (void)close(fd);

        if (frp->name == NULL)
            F_SET(frp, FR_TMPFILE);
        if ((frp->tname = strdup(tname)) == NULL ||
                (frp->name == NULL &&
                 (frp->name = strdup(tname)) == NULL)) {
            if (frp->tname != NULL) {
                free(frp->tname);
            }
            msgq(sp, M_SYSERR, NULL);
            (void)unlink(tname);
            goto err;
        }
        oname = frp->tname;
        psize = 1024;
        if (!LF_ISSET(FS_OPENERR))
            F_SET(frp, FR_NEWFILE);

        time(&ep->mtime);
    } else {
        /*
         * XXX
         * A seat of the pants calculation: try to keep the file in
         * 15 pages or less.  Don't use a page size larger than 10K
         * (vi should have good locality) or smaller than 1K.
         */
        psize = ((sb.st_size / 15) + 1023) / 1024;
        if (psize > 10)
            psize = 10;
        if (psize == 0)
            psize = 1;
        psize *= 1024;

        F_SET(ep, F_DEVSET);
        ep->mdev = sb.st_dev;
        ep->minode = sb.st_ino;

        ep->mtime = sb.st_mtime;

        if (!S_ISREG(sb.st_mode))
            msgq_str(sp, M_ERR, oname,
                     "238|Warning: %s is not a regular file");
    }

    /* Set up recovery. */
    if (rcv_name == NULL) {
        /* ep->rcv_path NULL if rcv_tmp fails */
        rcv_tmp(sp, ep, frp->name);
    } else {
        if ((ep->rcv_path = strdup(rcv_name)) == NULL) {
            msgq(sp, M_SYSERR, NULL);
            goto err;
        }
        F_SET(ep, F_MODIFIED);
    }

    if (db_setup(sp, ep))
        goto err;

    /* Open a db structure. */
    if ((sp->db_error = db_create(&ep->db, 0, 0)) != 0) {
        msgq(sp, M_DBERR, "db_create");
        goto err;
    }

    ep->db->set_re_delim(ep->db, '\n');		/* Always set. */
    ep->db->set_pagesize(ep->db, psize);
    ep->db->set_flags(ep->db, DB_RENUMBER | DB_SNAPSHOT);
    if (rcv_name == NULL)
        ep->db->set_re_source(ep->db, oname);

    /*
     * Don't let db use mmap when using fcntl for locking
     */
#ifdef HAVE_LOCK_FCNTL
#define NOMMAPIFFCNTL DB_NOMMAP
#else
#define NOMMAPIFFCNTL 0
#endif

#define _DB_OPEN_MODE	S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH

    if ((sp->db_error = db_open(ep->db, ep->rcv_path, DB_RECNO,
                                ((rcv_name == 0) ? DB_TRUNCATE : 0) | VI_DB_THREAD | NOMMAPIFFCNTL,
                                _DB_OPEN_MODE)) != 0) {
        msgq_str(sp,
                 M_DBERR, rcv_name == NULL ? oname : rcv_name, "%s");
        /*
         * !!!
         * Historically, vi permitted users to edit files that couldn't
         * be read.  This isn't useful for single files from a command
         * line, but it's quite useful for "vi *.c", since you can skip
         * past files that you can't read.
         */
        ep->db = NULL; /* Don't close it; it wasn't opened */

        if (LF_ISSET(FS_OPENERR))
            goto err;

        open_err = 1;
        goto oerr;
    }

    /* re_source is loaded into the database.
     * Close it and reopen it in the environment.
     */
    if ((sp->db_error = ep->db->close(ep->db, 0))) {
        msgq(sp, M_DBERR, "close");
        goto err;
    }
    if ((sp->db_error = db_create(&ep->db, ep->env, 0)) != 0) {
        msgq(sp, M_DBERR, "db_create 2");
        goto err;
    }
    if ((sp->db_error = db_open(ep->db, ep->rcv_path, DB_RECNO,
                                VI_DB_THREAD | NOMMAPIFFCNTL, _DB_OPEN_MODE)) != 0) {
        msgq_str(sp,
                 M_DBERR, ep->rcv_path, "%s");
        goto err;
    }

    /*
     * Do the remaining things that can cause failure of the new file,
     * mark and logging initialization.
     */
    if (mark_init(sp, ep) || log_init(sp, ep))
        goto err;

postinit:
    /*
     * Set the alternate file name to be the file we're discarding.
     *
     * !!!
     * Temporary files can't become alternate files, so there's no file
     * name.  This matches historical practice, although it could only
     * happen in historical vi as the result of the initial command, i.e.
     * if vi was executed without a file name.
     */
    if (LF_ISSET(FS_SETALT))
        set_alt_name(sp, sp->frp == NULL ||
                     F_ISSET(sp->frp, FR_TMPFILE) ? NULL : sp->frp->name);

    /*
     * Close the previous file; if that fails, close the new one and run
     * for the border.
     *
     * !!!
     * There's a nasty special case.  If the user edits a temporary file,
     * and then does an ":e! %", we need to re-initialize the backing
     * file, but we can't change the name.  (It's worse -- we're dealing
     * with *names* here, we can't even detect that it happened.)  Set a
     * flag so that the file_end routine ignores the backing information
     * of the old file if it happens to be the same as the new one.
     *
     * !!!
     * Side-effect: after the call to file_end(), sp->frp may be NULL.
     */
    if (sp->ep != NULL) {
        F_SET(frp, FR_DONTDELETE);
        if (file_end(sp, NULL, LF_ISSET(FS_FORCE))) {
            (void)file_end(sp, ep, 1);
            goto err;
        }
        sp->ep = NULL;
        F_CLR(frp, FR_DONTDELETE);
    }

    /*
     * Lock the file; if it's a recovery file, it should already be
     * locked.  Note, we acquire the lock after the previous file
     * has been ended, so that we don't get an "already locked" error
     * for ":edit!".
     *
     * XXX
     * While the user can't interrupt us between the open and here,
     * there's a race between the dbopen() and the lock.  Not much
     * we can do about it.
     *
     * XXX
     * We don't make a big deal of not being able to lock the file.  As
     * locking rarely works over NFS, and often fails if the file was
     * mmap(2)'d, it's far too common to do anything like print an error
     * message, let alone make the file readonly.  At some future time,
     * when locking is a little more reliable, this should change to be
     * an error.
     */
    if (rcv_name == NULL && ep->refcnt == 0) {
        if ((ep->fd = open(oname, O_RDWR)) == -1)
            goto no_lock;

        switch (file_lock(sp, oname, &ep->fcntl_fd, ep->fd, 1)) {
        case LOCK_FAILED:
no_lock:
            F_SET(frp, FR_UNLOCKED);
            break;
        case LOCK_UNAVAIL:
            readonly = 1;
            msgq_str(sp, M_INFO, oname,
                     "239|%s already locked, session is read-only");
            break;
        case LOCK_SUCCESS:
            break;
        }
    }

    /*
         * Historically, the readonly edit option was set per edit buffer in
         * vi, unless the -R command-line option was specified or the program
         * was executed as "view".  (Well, to be truthful, if the letter 'w'
         * occurred anywhere in the program name, but let's not get into that.)
     * So, the persistant readonly state has to be stored in the screen
     * structure, and the edit option value toggles with the contents of
     * the edit buffer.  If the persistant readonly flag is set, set the
     * readonly edit option.
     *
     * Otherwise, try and figure out if a file is readonly.  This is a
     * dangerous thing to do.  The kernel is the only arbiter of whether
     * or not a file is writeable, and the best that a user program can
     * do is guess.  Obvious loopholes are files that are on a file system
     * mounted readonly (access catches this one on a few systems), or
     * alternate protection mechanisms, ACL's for example, that we can't
     * portably check.  Lots of fun, and only here because users whined.
     *
     * !!!
     * Historic vi displayed the readonly message if none of the file
     * write bits were set, or if an an access(2) call on the path
     * failed.  This seems reasonable.  If the file is mode 444, root
     * users may want to know that the owner of the file did not expect
     * it to be written.
     *
     * Historic vi set the readonly bit if no write bits were set for
     * a file, even if the access call would have succeeded.  This makes
     * the superuser force the write even when vi expects that it will
     * succeed.  I'm less supportive of this semantic, but it's historic
     * practice and the conservative approach to vi'ing files as root.
     *
     * It would be nice if there was some way to update this when the user
     * does a "^Z; chmod ...".  The problem is that we'd first have to
     * distinguish between readonly bits set because of file permissions
     * and those set for other reasons.  That's not too hard, but deciding
     * when to reevaluate the permissions is trickier.  An alternative
     * might be to turn off the readonly bit if the user forces a write
     * and it succeeds.
     *
     * XXX
     * Access(2) doesn't consider the effective uid/gid values.  This
     * probably isn't a problem for vi when it's running standalone.
     */
    if (readonly || F_ISSET(sp, SC_READONLY) ||
            (!F_ISSET(frp, FR_NEWFILE) &&
             (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||
              access(frp->name, W_OK))))
        O_SET(sp, O_READONLY);
    else
        O_CLR(sp, O_READONLY);

    /* Switch... */
    ++ep->refcnt;
    CIRCLEQ_INSERT_HEAD(&ep->scrq, sp, eq);
    sp->ep = ep;
    sp->frp = frp;

    /* Set the initial cursor position, queue initial command. */
    file_cinit(sp);

    /* Report conversion errors again. */
    F_CLR(sp, SC_CONV_ERROR);

    /* Redraw the screen from scratch, schedule a welcome message. */
    F_SET(sp, SC_SCR_REFORMAT | SC_STATUS);

    if (frp->lno == OOBLNO)
        F_SET(sp, SC_SCR_TOP);

    /* Append into the chain of file structures. */
    if (ep->refcnt == 1)
        CIRCLEQ_INSERT_TAIL(&sp->gp->exfq, ep, q);

    return (0);

err:
    if (frp->name != NULL) {
        free(frp->name);
        frp->name = NULL;
    }
    if (frp->tname != NULL) {
        (void)unlink(frp->tname);
        free(frp->tname);
        frp->tname = NULL;
    }

oerr:
    if (F_ISSET(ep, F_RCV_ON))
        (void)unlink(ep->rcv_path);
    if (ep->rcv_path != NULL) {
        free(ep->rcv_path);
        ep->rcv_path = NULL;
    }
    if (ep->db != NULL) {
        (void)ep->db->close(ep->db, DB_NOSYNC);
        ep->db = NULL;
    }
    free(ep);

    return (open_err && !LF_ISSET(FS_OPENERR) ?
            file_init(sp, frp, rcv_name, flags | FS_OPENERR) : 1);
}
Esempio n. 15
0
/*
 * vfs_mountrootfs
 *
 * Common entry point for root mounts
 *
 * PARAMETERS:
 * 		NONE
 *
 * RETURNS:	0	Success
 *		!0	error number (errno.h)
 *
 * LOCK STATE:
 *		ENTRY
 *			<no locks held>
 *		EXIT
 *			<no locks held>
 *
 * NOTES:
 *		This code is currently supported only for use for
 *		the FFS file system type.  This is a matter of
 *		fixing the other file systems, not this code!
 */
static void
vfs_mountrootfs(void *unused)
{
	struct mount		*mp;
	int			i, err;
	struct proc		*p = curproc;	/* XXX */
	dev_t			orootdev;

#ifdef BOOTP
	bootpc_init();
#endif
	/*
	 *  New root mount structure
	 */
	if ((err = vfs_rootmountalloc(mountrootfsname, ROOTNAME, &mp))) {
		printf("error %d: ", err);
		panic("cannot mount root\n");
		return ;
	}
	mp->mnt_flag		|= MNT_ROOTFS;

	/*
	 * Attempt the mount
	 */
	err = ENXIO;
	orootdev = rootdev;
	if (rootdevs[0] == NODEV)
		rootdevs[0] = rootdev;
	for (i = 0; i < sizeof(rootdevs) / sizeof(rootdevs[0]); i++) {
		if (rootdevs[i] == NODEV)
			break;
		rootdev = rootdevs[i];
		if (rootdev != orootdev) {
			printf("changing root device to %s\n", rootdevnames[i]);
			orootdev = rootdev;
		}
		strncpy(mp->mnt_stat.f_mntfromname,
		    rootdevnames[i] ? rootdevnames[i] : ROOTNAME, MNAMELEN - 1);
		err = VFS_MOUNT(mp, NULL, NULL, NULL, p);
		if (err != ENXIO)
			break;
	}
	if (err) {
		/*
		 * XXX should ask the user for the name in some cases.
		 * Why do we call vfs_unbusy() here and not after ENXIO
		 * is returned above?
		 */
		vfs_unbusy(mp, p);
		/*
		 * free mount struct before failing
		 * (hardly worthwhile with the PANIC eh?)
		 */
		free( mp, M_MOUNT);
		printf("error %d: ", err);
		panic("cannot mount root (2)\n");
		return;
	}

	simple_lock(&mountlist_slock);

	/*
	 * Add fs to list of mounted file systems
	 */
	CIRCLEQ_INSERT_HEAD(&mountlist, mp, mnt_list);

	simple_unlock(&mountlist_slock);
	vfs_unbusy(mp, p);

	/* root mount, update system time from FS specific data*/
	inittodr(mp->mnt_time);
	return;
}