Example #1
0
/*
 * init_internet_gateway_search:
 * Initialization of the igs.c code.
 */
void
init_internet_gateway_search(void)
{
	inet_prefix new_gw;
	char new_gw_dev[IFNAMSIZ];

	pthread_t ping_thread;
	pthread_attr_t t_attr;
	int i, ret, res, e;

	active_gws = 0;
	igw_multi_gw_disabled = 0;
	setzero(multigw_nh, sizeof(igw_nexthop) * MAX_MULTIPATH_ROUTES);

	/*
	 * Just return if we aren't in restricted mode or if the user doesn't
	 * want to use shared internet connections
	 */
	if (!restricted_mode || (!server_opt.use_shared_inet &&
							 !server_opt.share_internet))
		return;

	loginfo("Activating the Internet Gateway Search engine");

	init_igws(&me.igws, &me.igws_counter, GET_LEVELS(my_family));
	init_tunnels_ifs();

	/* delete all the old tunnels */
	del_all_tunnel_ifs(0, 0, 0, NTK_TUNL_PREFIX);

	/*
	 * Bring tunl0 up (just to test if the ipip module is loaded)
	 */
	loginfo("Checking if \"" DEFAULT_TUNL_IF "\" exists");
	if (tunnel_change(0, 0, 0, DEFAULT_TUNL_PREFIX, DEFAULT_TUNL_NUMBER) <
		0) {
		printf("Cannot read \"" DEFAULT_TUNL_IF "\". "
			   "Is the \"ipip\" kernel module loaded?\n"
			   "  If you don't care about using the shared internet "
			   "connections of the ntk nodes\n"
			   "  around you, disable the \"use_shared_inet\" option "
			   "in netsukuku.conf");
		del_resolv_conf("nameserver 127.0.0.1", "/etc/resolv.conf");
		exit(1);
	}
	ifs_del_all_name(me.cur_ifs, &me.cur_ifs_n, NTK_TUNL_PREFIX);
	ifs_del_all_name(me.cur_ifs, &me.cur_ifs_n, DEFAULT_TUNL_PREFIX);

	/*
	 * Delete old routing rules
	 */
	reset_igw_rules();

	/*
	 * Init netfilter
	 */
	res = mark_init(server_opt.share_internet);
	if (res) {
		error(err_str);
		error("Cannot set the netfilter rules needed for the multi-igw. "
			  "This feature will be disabled");
		igw_multi_gw_disabled = 1;
	}

	/*
	 * Check anomalies: from this point we initialize stuff only if we
	 * have an Inet connection
	 */
	if (!server_opt.inet_connection)
		return;
	if (!server_opt.inet_hosts)
		fatal("You didn't specified any Internet hosts in the "
			  "configuration file. What hosts should I ping?");

	/*
	 * If we are sharing our internet connection, activate the
	 * masquerading.
	 */
	if (server_opt.share_internet) {
		igw_exec_masquerade_sh(server_opt.ip_masq_script, 0);
		if (!server_opt.ip_masq_script)
			fatal("No masquerading script was configured!");
	};

	/*
	 * Get the default gateway route currently set in the kernel routing
	 * table
	 */
	setzero(&new_gw, sizeof(inet_prefix));
	ret = rt_get_default_gw(&new_gw, new_gw_dev);

	/*
	 * If there is no IP set in the route, fetch it at least from the
	 * device included in it.
	 */
	if (!new_gw.family && *new_gw_dev) {
		if (get_dev_ip(&new_gw, my_family, new_gw_dev) < 0)
			(*new_gw_dev) = 0;
	}

	if (ret < 0 || (!*new_gw_dev && !new_gw.family)) {
		/* Nothing useful has been found  */

		loginfo("The retrieval of the default gw from the kernel failed.");

		if (!server_opt.inet_gw.data[0])
			fatal("The default gw isn't set in the kernel and you "
				  "didn't specified it in netsukuku.conf. "
				  "Cannot continue!");
	} else if (!server_opt.inet_gw_dev ||
			   strncmp(new_gw_dev, server_opt.inet_gw_dev, IFNAMSIZ) ||
			   memcmp(new_gw.data, server_opt.inet_gw.data, MAX_IP_SZ)) {

		if (server_opt.inet_gw.data[0])
			loginfo("Your specified Internet gateway doesn't match with "
					"the one currently stored in the kernel routing table."
					"I'm going to use the kernel gateway: %s dev %s",
					inet_to_str(new_gw), new_gw_dev);

		if (!server_opt.inet_gw_dev)
			server_opt.inet_gw_dev = xstrdup(new_gw_dev);
		else
			strncpy(server_opt.inet_gw_dev, new_gw_dev, IFNAMSIZ);
		memcpy(&server_opt.inet_gw, &new_gw, sizeof(inet_prefix));

		/* Delete the default gw, we are replacing it */
		rt_delete_def_gw(0);
	}

	loginfo("Using \"%s dev %s\" as your first Internet gateway.",
			inet_to_str(server_opt.inet_gw), server_opt.inet_gw_dev);
	if (rt_replace_def_gw(server_opt.inet_gw_dev, server_opt.inet_gw, 0))
		fatal("Cannot set the default gw to %s %s",
			  inet_to_str(server_opt.inet_gw), server_opt.inet_gw_dev);
	active_gws++;

	/*
	 * Activate the anti-loop multi-igw shield
	 */
	if (server_opt.share_internet) {
		rule_add(0, 0, 0, 0, FWMARK_ALISHIELD, RTTABLE_ALISHIELD);
		if (rt_replace_def_gw(server_opt.inet_gw_dev, server_opt.inet_gw,
							  RTTABLE_ALISHIELD)) {
			error("Cannot set the default route in the ALISHIELD table. "
				  "Disabling the multi-inet_gw feature");
			igw_multi_gw_disabled = 1;
		}
	}


	/*
	 * Activate the traffic shaping for the `server_opt.inet_gw_dev'
	 * device
	 */
	if (server_opt.shape_internet)
		igw_exec_tcshaper_sh(server_opt.tc_shaper_script, 0,
							 server_opt.inet_gw_dev,
							 server_opt.my_upload_bw,
							 server_opt.my_dnload_bw);

	for (i = 0; i < me.cur_ifs_n; i++)
		if (!strcmp(me.cur_ifs[i].dev_name, server_opt.inet_gw_dev)) {
			for (e = 0; e < server_opt.ifs_n; e++)
				if (!strcmp(server_opt.ifs[i], server_opt.inet_gw_dev))
					fatal("You specified the \"%s\" interface"
						  " in the options, but this device is also"
						  " part of the primary Internet gw route."
						  " Don't include \"%s\" in the list of "
						  "interfaces utilised by the daemon",
						  server_opt.inet_gw_dev, server_opt.inet_gw_dev);

			loginfo("Deleting the \"%s\" interface from the device "
					"list since it is part of the primary Internet"
					" gw route.", me.cur_ifs[i].dev_name);

			ifs_del(me.cur_ifs, &me.cur_ifs_n, i);
			if (me.cur_ifs_n <= 0)
				fatal
					("The deleted interface cannot be used by NetsukukuD because it is part\n"
					 "  of your primary Internet gw route. You have to specify another\n"
					 "  interface with the -i option or you won't be able share your"
					 "  Internet connection");
		}

	loginfo("Launching the first ping to the Internet hosts");
	if (!server_opt.disable_andna)
		internet_hosts_to_ip();
	me.inet_connected = igw_check_inet_conn();
	if (me.inet_connected)
		loginfo("The Internet connection is up & running");
	else
		loginfo("The Internet connection appears to be down");
	if (!me.inet_connected && server_opt.share_internet)
		fatal("We are not connected to the Internet, but you want to "
			  "share your connection. Please check your options");

	debug(DBG_SOFT, "Evoking the Internet ping daemon.");
	pthread_attr_init(&t_attr);
	pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED);
	pthread_create(&ping_thread, &t_attr, igw_check_inet_conn_t, 0);
}
Example #2
0
File: exf.c Project: 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);
}