Ejemplo n.º 1
0
Archivo: kld.c Proyecto: 2asoft/freebsd
int
kld_load(const char *name)
{
	if (kldload(name) == -1 && errno != EEXIST)
		return (-1);
	return (0);
}
Ejemplo n.º 2
0
/*
 * Load a FreeBSD kernel module.
 * This is used by the DRI/DRM to load a DRM kernel module when
 * the X server starts.  It could be used for other purposes in the future.
 * Input:
 *    modName - name of the kernel module (Ex: "tdfx")
 * Return:
 *    0 for failure, 1 for success
 */
int xf86LoadKernelModule(const char *modName)
{
    if (kldload(modName) != -1)
	return 1;
    else
	return 0;
}
Ejemplo n.º 3
0
static int
disc_setup(void)
{
	struct ifreq ifr;
	int s;

	if (kldload("if_disc") < 0) {
		switch (errno) {
		case EEXIST:
			break;
		default:
			warn("disc_setup: kldload(if_disc)");
			return (-1);
		}
	}

	s = socket(PF_INET, SOCK_RAW, 0);
	if (s < 0) {
		warn("disc_setup: socket(PF_INET, SOCK_RAW, 0)");
		return (-1);
	}

	bzero(&ifr, sizeof(ifr));
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", DISC_IFNAME,
	    DISC_IFUNIT);

	if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
		warn("disc_setup: ioctl(%s, SIOCIFCREATE)", ifr.ifr_name);
		close(s);
		return (-1);
	}

	close(s);
	return (0);
}
Ejemplo n.º 4
0
static int
set_charset(struct iovec **iov, int *iovlen, const char *localcs)
{
	int error;
	char *cs_disk;	/* disk charset for Joliet cs conversion */
	char *cs_local;	/* local charset for Joliet cs conversion */

	cs_disk = NULL;
	cs_local = NULL;

	if (modfind("cd9660_iconv") < 0)
		if (kldload("cd9660_iconv") < 0 || modfind("cd9660_iconv") < 0) {
			warnx( "cannot find or load \"cd9660_iconv\" kernel module");
			return (-1);
		}

	if ((cs_disk = malloc(ICONV_CSNMAXLEN)) == NULL)
		return (-1);
	if ((cs_local = malloc(ICONV_CSNMAXLEN)) == NULL) {
		free(cs_disk);
		return (-1);
	}
	strncpy(cs_disk, ENCODING_UNICODE, ICONV_CSNMAXLEN);
	strncpy(cs_local, kiconv_quirkcs(localcs, KICONV_VENDOR_MICSFT),
	    ICONV_CSNMAXLEN);
	error = kiconv_add_xlat16_cspairs(cs_disk, cs_local);
	if (error)
		return (-1);
	
	build_iovec(iov, iovlen, "cs_disk", cs_disk, (size_t)-1);
	build_iovec(iov, iovlen, "cs_local", cs_local, (size_t)-1);

	return (0);
}
Ejemplo n.º 5
0
int load_kld(const char *kldname)
{
	if (path_check(kldname) == 0) {
		return kldload(kldname);
	}
	return (-1);
}
Ejemplo n.º 6
0
/*
 * Load the if_bridge.ko module in kernel if not already there.
 */
int
bridge_kmod_load(void)
{
	int fileid, modid;
	const char mod_name[] = "if_bridge";
	struct module_stat mstat;

	/* Scan files in kernel. */
	mstat.version = sizeof(struct module_stat);
	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
		/* Scan modules in file. */
		for (modid = kldfirstmod(fileid); modid > 0;
			modid = modfnext(modid)) {

			if (modstat(modid, &mstat) < 0)
				continue;

			if (strcmp(mod_name, mstat.name) == 0)
				return (0);
		}
	}

	/* Not present - load it. */
	if (kldload(mod_name) < 0) {
		syslog(LOG_ERR, "failed to load %s kernel module", mod_name);
		return (-1);
	}

	return (1);
}
Ejemplo n.º 7
0
int
main(int argc __unused, char *argv[])
{

	/* Prevent foot shooting. */
	if (getpid() != 1)
		return (1);

	if (modfind("tmpfs") == -1 && kldload("tmpfs") == -1)
		die("error loading tmpfs");

	/* Extract FreeBSD installation in a tmpfs. */
	domount(tmpfs, sizeof(tmpfs) / sizeof(char *));
	extract("/root.txz");
	domount(devfs, sizeof(devfs) / sizeof(char *));

	/* chroot() into system and continue boot process. */
	if (chroot("/rw") != 0)
		die("chroot");
	chdir("/");

	/* Execute the real /sbin/init. */
	execv(argv[0], argv);
	die("execv");
	return (1);
}
Ejemplo n.º 8
0
int
set_charset(struct iovec **iov, int *iovlen, const char *cs_local, const char *cs_dos)
{
	int error;

	if (modfind("msdosfs_iconv") < 0)
		if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) {
			warnx("cannot find or load \"msdosfs_iconv\" kernel module");
			return (-1);
		}

	build_iovec_argf(iov, iovlen, "cs_win", ENCODING_UNICODE);
	error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local);
	if (error && errno != EEXIST)
		return (-1);
	if (cs_dos != NULL) {
		error = kiconv_add_xlat16_cspairs(cs_dos, cs_local);
		if (error && errno != EEXIST)
			return (-1);
	} else {
		build_iovec_argf(iov, iovlen, "cs_dos", cs_local);
		error = kiconv_add_xlat16_cspair(cs_local, cs_local,
				KICONV_FROM_UPPER | KICONV_LOWER);
		if (error && errno != EEXIST)
			return (-1);
	}

	return (0);
}
Ejemplo n.º 9
0
Archivo: id.c Proyecto: coyizumi/cs111
int
ID0kldload(const char *dev)
{
  int result;

  ID0set0();
  result = kldload(dev);
  log_Printf(LogID0, "%d = kldload(\"%s\")\n", result, dev);
  ID0setuser();
  return result;
}
Ejemplo n.º 10
0
void
ifmaybeload(const char *name)
{
#ifndef __rtems__
#define MOD_PREFIX_LEN		3	/* "if_" */
	struct module_stat mstat;
	int fileid, modid;
	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
	const char *cp;

	/* loading suppressed by the user */
	if (noload)
		return;

	/* trim the interface number off the end */
	strlcpy(ifname, name, sizeof(ifname));
	for (dp = ifname; *dp != 0; dp++)
		if (isdigit(*dp)) {
			*dp = 0;
			break;
		}

	/* turn interface and unit into module name */
	strcpy(ifkind, "if_");
	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
	    sizeof(ifkind) - MOD_PREFIX_LEN);

	/* scan files in kernel */
	mstat.version = sizeof(struct module_stat);
	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
		/* scan modules in file */
		for (modid = kldfirstmod(fileid); modid > 0;
		     modid = modfnext(modid)) {
			if (modstat(modid, &mstat) < 0)
				continue;
			/* strip bus name if present */
			if ((cp = strchr(mstat.name, '/')) != NULL) {
				cp++;
			} else {
				cp = mstat.name;
			}
			/* already loaded? */
			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
				return;
		}
	}

	/* not present, we should try to load it */
	kldload(ifkind);
#endif
}
Ejemplo n.º 11
0
static int
LoadModules(void)
{
  const char *module[] = { "netgraph", "ng_socket", "ng_ether", "ng_pppoe" };
  int f;

  for (f = 0; f < sizeof module / sizeof *module; f++)
    if (modfind(module[f]) == -1 && kldload(module[f]) == -1) {
      fprintf(stderr, "kldload: %s: %s\n", module[f], strerror(errno));
      return 0;
    }

  return 1;
}
Ejemplo n.º 12
0
int set_charset( char **cs_disk, char **cs_local, const char *localcs ) {
    int error;
    if ( modfind( "udf_iconv" ) < 0 ) if ( kldload( "udf_iconv" ) < 0 || modfind( "udf_iconv" ) < 0 ) {
            warnx( "cannot find or load \"udf_iconv\" kernel module" );
            return ( -1 );
        }
    if ( ( *cs_disk = malloc( ICONV_CSNMAXLEN ) ) == NULL ) return ( -1 );
    if ( ( *cs_local = malloc( ICONV_CSNMAXLEN ) ) == NULL ) return ( -1 );
    strncpy( *cs_disk, ENCODING_UNICODE, ICONV_CSNMAXLEN );
    strncpy( *cs_local, localcs, ICONV_CSNMAXLEN );
    error = kiconv_add_xlat16_cspairs( *cs_disk, *cs_local );
    if ( error ) return ( -1 );
    return ( 0 );
}
Ejemplo n.º 13
0
int ggate_drv_load() {
  if (modfind("g_gate") != -1) {
    /* Present in kernel. */
    return 0;
  }

  if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
    if (errno != EEXIST) {
      err("failed to load geom_gate module");
      return -errno;
    }
  }
  return 0;
}
Ejemplo n.º 14
0
/**
 * Load the MD driver if it isn't loaded already.
 */
static void
mdmaybeload(void)
{
	char name1[64], name2[64];

	snprintf(name1, sizeof(name1), "g_%s", MD_NAME);
	snprintf(name2, sizeof(name2), "geom_%s", MD_NAME);
	if (modfind(name1) == -1) {
		/* Not present in kernel, try loading it. */
		if (kldload(name2) == -1 || modfind(name1) == -1) {
			if (errno != EEXIST) {
				errx(EXIT_FAILURE,
				    "%s module not available!", name2);
			}
		}
	}
}
Ejemplo n.º 15
0
int
main(int argc, char **argv)
{
	int line, tokens;
	char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS];

	/* Load the module if necessary. */
	if (modfind(GVINUMMOD) < 0) {
		if (kldload(GVINUMKLD) < 0 && modfind(GVINUMMOD) < 0)
			err(1, GVINUMKLD ": Kernel module not available");
	}

	/* Arguments given on the command line. */
	if (argc > 1) {
		argc--;
		argv++;
		parseline(argc, argv);

	/* Interactive mode. */
	} else {
		for (;;) {
			inputline = readline("gvinum -> ");
			if (inputline == NULL) {
				if (ferror(stdin)) {
					err(1, "can't read input");
				} else {
					printf("\n");
					exit(0);
				}
			} else if (*inputline) {
				add_history(inputline);
				strcpy(buffer, inputline);
				free(inputline);
				line++;		    /* count the lines */
				tokens = gv_tokenize(buffer, token, GV_MAXARGS);
				if (tokens)
					parseline(tokens, token);
			}
		}
	}
	exit(0);
}
Ejemplo n.º 16
0
static void
gcmd_createinsert(struct gctl_req *req, unsigned flags __unused)
{
	const char *reqalgo;
	char name[64];

	if (gctl_has_param(req, "algo"))
		reqalgo = gctl_get_ascii(req, "algo");
	else
		reqalgo = GSCHED_ALGO;

	snprintf(name, sizeof(name), "gsched_%s", reqalgo);
	/*
	 * Do not complain about errors here, gctl_issue()
	 * will fail anyway.
	 */
	if (modfind(name) < 0)
		kldload(name);
	gctl_issue(req);
}
Ejemplo n.º 17
0
void
ifmaybeload(const char *name)
{
    struct module_stat mstat;
    int fileid, modid;
    char ifkind[35], *dp;
    const char *cp;

    /* turn interface and unit into module name */
    strcpy(ifkind, "if_");
    for (cp = name, dp = ifkind + 3;
            (*cp != 0) && !isdigit(*cp); cp++, dp++)
        *dp = *cp;
    *dp = 0;

    /* scan files in kernel */
    mstat.version = sizeof(struct module_stat);
    for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
        /* scan modules in file */
        for (modid = kldfirstmod(fileid); modid > 0;
                modid = modfnext(modid)) {
            if (modstat(modid, &mstat) < 0)
                continue;
            /* strip bus name if present */
            if ((cp = strchr(mstat.name, '/')) != NULL) {
                cp++;
            } else {
                cp = mstat.name;
            }
            /* already loaded? */
            if (strncmp(name, cp, strlen(cp)) == 0 ||
                    strncmp(ifkind, cp, strlen(cp)) == 0)
                return;
        }
    }

    /* not present, we should try to load it */
    kldload(ifkind);
}
Ejemplo n.º 18
0
int
main(int ac, char *av[])
{
	int             ch, res, rv, nread;
	size_t		b_size = MIN_SIZE;
	char            *buf, chb[READB_LEN];
	fd_set          fd_s;

	(void) setlocale(LC_TIME, "");

	if (isatty(std_out))
		opt_interactive = 1;
	else
		opt_interactive = 0;


	while ((ch = getopt(ac, av, "Wciotnf:")) != -1)
		switch (ch) {
		case 'W':
			opt_write = 1;
			break;
		case 'c':
			opt_reconn_close = 1;
			break;
		case 'i':
			opt_interactive = 1;
			break;
		case 'o':
			opt_reconn_oflow = 1;
			break;
		case 't':
			opt_timestamp = 1;
			break;
		case 'n':
			opt_no_switch = 1;
			break;
		case 'f':
			opt_snpdev = optarg;
			break;
		case '?':
		default:
			usage();
		}

	if (modfind("snp") == -1)
		if (kldload("snp") == -1 || modfind("snp") == -1)
			warn("snp module not available");

	signal(SIGINT, cleanup);

	snp_io = open_snp();
	setup_scr();

	if (*(av += optind) == NULL) {
		if (opt_interactive && !opt_no_switch)
			ask_dev(dev_name, MSG_INIT);
		else
			fatal(EX_DATAERR, "no device name given");
	} else
		strncpy(dev_name, *av, DEV_NAME_LEN);

	set_dev(dev_name);

	if (!(buf = (char *) malloc(b_size)))
		fatal(EX_UNAVAILABLE, "malloc failed");

	FD_ZERO(&fd_s);

	while (1) {
		if (opt_interactive)
			FD_SET(std_in, &fd_s);
		FD_SET(snp_io, &fd_s);
		res = select(snp_io + 1, &fd_s, NULL, NULL, NULL);
		if (opt_interactive && FD_ISSET(std_in, &fd_s)) {

			if ((res = ioctl(std_in, FIONREAD, &nread)) != 0)
				fatal(EX_OSERR, "ioctl(FIONREAD)");
			if (nread > READB_LEN)
				nread = READB_LEN;
			rv = read(std_in, chb, nread);
			if (rv == -1 || rv != nread)
				fatal(EX_IOERR, "read (stdin) failed");

			switch (chb[0]) {
			case CHR_CLEAR:
				clear();
				break;
			case CHR_SWITCH:
				if (!opt_no_switch) {
					detach_snp();
					ask_dev(dev_name, MSG_CHANGE);
					set_dev(dev_name);
					break;
				}
			default:
				if (opt_write) {
					rv = write(snp_io, chb, nread);
					if (rv == -1 || rv != nread) {
						detach_snp();
						if (opt_no_switch)
							fatal(EX_IOERR,
							  "write failed");
						ask_dev(dev_name, MSG_NOWRITE);
						set_dev(dev_name);
					}
				}

			}
		}
		if (!FD_ISSET(snp_io, &fd_s))
			continue;

		if ((res = ioctl(snp_io, FIONREAD, &nread)) != 0)
			fatal(EX_OSERR, "ioctl(FIONREAD)");

		switch (nread) {
		case SNP_OFLOW:
			if (opt_reconn_oflow)
				attach_snp();
			else if (opt_interactive && !opt_no_switch) {
				ask_dev(dev_name, MSG_OFLOW);
				set_dev(dev_name);
			} else
				cleanup(-1);
			break;
		case SNP_DETACH:
		case SNP_TTYCLOSE:
			if (opt_reconn_close)
				attach_snp();
			else if (opt_interactive && !opt_no_switch) {
				ask_dev(dev_name, MSG_CLOSED);
				set_dev(dev_name);
			} else
				cleanup(-1);
			break;
		default:
			if (nread < (b_size / 2) && (b_size / 2) > MIN_SIZE) {
				free(buf);
				if (!(buf = (char *) malloc(b_size / 2)))
					fatal(EX_UNAVAILABLE, "malloc failed");
				b_size = b_size / 2;
			}
			if (nread > b_size) {
				b_size = (nread % 2) ? (nread + 1) : (nread);
				free(buf);
				if (!(buf = (char *) malloc(b_size)))
					fatal(EX_UNAVAILABLE, "malloc failed");
			}
			rv = read(snp_io, buf, nread);
			if (rv == -1 || rv != nread)
				fatal(EX_IOERR, "read failed");
			rv = write(std_out, buf, nread);
			if (rv == -1 || rv != nread)
				fatal(EX_IOERR, "write failed");
		}
	}			/* While */
	return(0);
}
Ejemplo n.º 19
0
int
main(int argc, char **argv)
{
    int ch, debug = 0, error, iscsi_fd, maxproc = 30, retval, saved_errno,
            timeout = 60;
    bool dont_daemonize = false;
    struct pidfh *pidfh;
    pid_t pid, otherpid;
    const char *pidfile_path = DEFAULT_PIDFILE;
    struct iscsi_daemon_request request;

    while ((ch = getopt(argc, argv, "P:dl:m:t:")) != -1) {
        switch (ch) {
        case 'P':
            pidfile_path = optarg;
            break;
        case 'd':
            dont_daemonize = true;
            debug++;
            break;
        case 'l':
            debug = atoi(optarg);
            break;
        case 'm':
            maxproc = atoi(optarg);
            break;
        case 't':
            timeout = atoi(optarg);
            break;
        case '?':
        default:
            usage();
        }
    }
    argc -= optind;
    if (argc != 0)
        usage();

    log_init(debug);

    pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
    if (pidfh == NULL) {
        if (errno == EEXIST)
            log_errx(1, "daemon already running, pid: %jd.",
                     (intmax_t)otherpid);
        log_err(1, "cannot open or create pidfile \"%s\"",
                pidfile_path);
    }

    iscsi_fd = open(ISCSI_PATH, O_RDWR);
    if (iscsi_fd < 0 && errno == ENOENT) {
        saved_errno = errno;
        retval = kldload("iscsi");
        if (retval != -1)
            iscsi_fd = open(ISCSI_PATH, O_RDWR);
        else
            errno = saved_errno;
    }
    if (iscsi_fd < 0)
        log_err(1, "failed to open %s", ISCSI_PATH);

    if (dont_daemonize == false) {
        if (daemon(0, 0) == -1) {
            log_warn("cannot daemonize");
            pidfile_remove(pidfh);
            exit(1);
        }
    }

    pidfile_write(pidfh);

    register_sigchld();

    for (;;) {
        log_debugx("waiting for request from the kernel");

        memset(&request, 0, sizeof(request));
        error = ioctl(iscsi_fd, ISCSIDWAIT, &request);
        if (error != 0) {
            if (errno == EINTR) {
                nchildren -= wait_for_children(false);
                assert(nchildren >= 0);
                continue;
            }

            log_err(1, "ISCSIDWAIT");
        }

        if (dont_daemonize) {
            log_debugx("not forking due to -d flag; "
                       "will exit after servicing a single request");
        } else {
            nchildren -= wait_for_children(false);
            assert(nchildren >= 0);

            while (maxproc > 0 && nchildren >= maxproc) {
                log_debugx("maxproc limit of %d child processes hit; "
                           "waiting for child process to exit", maxproc);
                nchildren -= wait_for_children(true);
                assert(nchildren >= 0);
            }
            log_debugx("incoming connection; forking child process #%d",
                       nchildren);
            nchildren++;

            pid = fork();
            if (pid < 0)
                log_err(1, "fork");
            if (pid > 0)
                continue;
        }

        pidfile_close(pidfh);
        handle_request(iscsi_fd, &request, timeout);
    }

    return (0);
}
Ejemplo n.º 20
0
/*
 * Nfs callback server daemon.
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - fork the nfscbd(s)
 * 4 - create callback server socket(s)
 * 5 - set up server socket for rpc
 *
 * For connectionless protocols, just pass the socket into the kernel via.
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via. nfssvc().
 */
int
main(int argc, char *argv[])
{
	struct nfscbd_args nfscbdargs;
	struct nfsd_nfscbd_args nfscbdargs2;
	struct sockaddr_in inetaddr, inetpeer;
	fd_set ready, sockbits;
	int ch, connect_type_cnt, len, maxsock, msgsock, error;
	int nfssvc_flag, on, sock, tcpsock, ret, mustfreeai = 0;
	char *cp, princname[128];
	char myname[MAXHOSTNAMELEN], *myfqdnname = NULL;
	struct addrinfo *aip, hints;
	pid_t pid;
	short myport = NFSV4_CBPORT;

	if (modfind("nfscl") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfscl") < 0 ||
		    modfind("nfscl") < 0)
			errx(1, "nfscl is not available");
	}
	/*
	 * First, get our fully qualified host name, if possible.
	 */
	if (gethostname(myname, MAXHOSTNAMELEN) >= 0) {
		cp = strchr(myname, '.');
		if (cp != NULL && *(cp + 1) != '\0') {
			cp = myname;
		} else {
			/*
			 * No domain on myname, so try looking it up.
			 */
			cp = NULL;
			memset((void *)&hints, 0, sizeof (hints));
			hints.ai_flags = AI_CANONNAME;
			error = getaddrinfo(myname, NULL, &hints, &aip);
			if (error == 0) {
			    if (aip->ai_canonname != NULL &&
				(cp = strchr(aip->ai_canonname, '.')) != NULL
				&& *(cp + 1) != '\0') {
				    cp = aip->ai_canonname;
				    mustfreeai = 1;
			    } else {
				    freeaddrinfo(aip);
			    }
			}
		}
		if (cp == NULL)
			warnx("Can't get fully qualified host name");
		myfqdnname = cp;
	}

	princname[0] = '\0';
#define	GETOPT	"p:P:"
#define	USAGE	"[ -p port_num ] [ -P client_principal ]"
	while ((ch = getopt(argc, argv, GETOPT)) != -1)
		switch (ch) {
		case 'p':
			myport = atoi(optarg);
			if (myport < 1) {
				warnx("port# non-positive, reset to %d",
				    NFSV4_CBPORT);
				myport = NFSV4_CBPORT;
			}
			break;
		case 'P':
			cp = optarg;
			if (cp != NULL && strlen(cp) > 0 &&
			    strlen(cp) < sizeof (princname)) {
				if (strchr(cp, '@') == NULL &&
				    myfqdnname != NULL)
					snprintf(princname, sizeof (princname),
					    "%s@%s", cp, myfqdnname);
				else
					strlcpy(princname, cp,
					    sizeof (princname));
			} else {
				warnx("client princ invalid. ignored\n");
			}
			break;
		default:
		case '?':
			usage();
		};
	argv += optind;
	argc -= optind;

	if (argc > 0)
		usage();

	if (mustfreeai)
		freeaddrinfo(aip);
	nfscbdargs2.principal = (const char *)princname;
	if (debug == 0) {
		daemon(0, 0);
		(void)signal(SIGTERM, SIG_IGN);
		(void)signal(SIGHUP, SIG_IGN);
		(void)signal(SIGINT, SIG_IGN);
		(void)signal(SIGQUIT, SIG_IGN);
	}
	(void)signal(SIGSYS, nonfs);
	(void)signal(SIGCHLD, reapchild);

	openlog("nfscbd:", LOG_PID, LOG_DAEMON);

	pid = fork();
	if (pid < 0) {
		syslog(LOG_ERR, "fork: %m");
		nfscbd_exit(1);
	} else if (pid > 0) {
		children = pid;
	} else {
		(void)signal(SIGUSR1, child_cleanup);
		setproctitle("server");
		nfssvc_flag = NFSSVC_NFSCBD;
		if (nfssvc(nfssvc_flag, &nfscbdargs2) < 0) {
			syslog(LOG_ERR, "nfssvc: %m");
			nfscbd_exit(1);
		}
		exit(0);
	}
	(void)signal(SIGUSR1, cleanup);

	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		syslog(LOG_ERR, "can't create udp socket");
		nfscbd_exit(1);
	}
	memset(&inetaddr, 0, sizeof inetaddr);
	inetaddr.sin_family = AF_INET;
	inetaddr.sin_addr.s_addr = INADDR_ANY;
	inetaddr.sin_port = htons(myport);
	inetaddr.sin_len = sizeof(inetaddr);
	ret = bind(sock, (struct sockaddr *)&inetaddr, sizeof(inetaddr));
	/* If bind() fails, this is a restart, so just skip UDP. */
	if (ret == 0) {
		len = sizeof(inetaddr);
		if (getsockname(sock, (struct sockaddr *)&inetaddr, &len) < 0){
			syslog(LOG_ERR, "can't get bound addr");
			nfscbd_exit(1);
		}
		nfscbdargs.port = ntohs(inetaddr.sin_port);
		if (nfscbdargs.port != myport) {
			syslog(LOG_ERR, "BAD PORT#");
			nfscbd_exit(1);
		}
		nfscbdargs.sock = sock;
		nfscbdargs.name = NULL;
		nfscbdargs.namelen = 0;
		if (nfssvc(NFSSVC_CBADDSOCK, &nfscbdargs) < 0) {
			syslog(LOG_ERR, "can't Add UDP socket");
			nfscbd_exit(1);
		}
	}
	(void)close(sock);

	/* Now set up the master server socket waiting for tcp connections. */
	on = 1;
	FD_ZERO(&sockbits);
	connect_type_cnt = 0;
	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		syslog(LOG_ERR, "can't create tcp socket");
		nfscbd_exit(1);
	}
	if (setsockopt(tcpsock,
	    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
		syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
	/* sin_port is already set */
	inetaddr.sin_family = AF_INET;
	inetaddr.sin_addr.s_addr = INADDR_ANY;
	inetaddr.sin_port = htons(myport);
	inetaddr.sin_len = sizeof(inetaddr);
	if (bind(tcpsock,
	    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
		syslog(LOG_ERR, "can't bind tcp addr");
		nfscbd_exit(1);
	}
	if (listen(tcpsock, 5) < 0) {
		syslog(LOG_ERR, "listen failed");
		nfscbd_exit(1);
	}
	FD_SET(tcpsock, &sockbits);
	maxsock = tcpsock;
	connect_type_cnt++;

	setproctitle("master");

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		ready = sockbits;
		if (connect_type_cnt > 1) {
			if (select(maxsock + 1,
			    &ready, NULL, NULL, NULL) < 1) {
				syslog(LOG_ERR, "select failed: %m");
				nfscbd_exit(1);
			}
		}
		if (FD_ISSET(tcpsock, &ready)) {
			len = sizeof(inetpeer);
			if ((msgsock = accept(tcpsock,
			    (struct sockaddr *)&inetpeer, &len)) < 0) {
				syslog(LOG_ERR, "accept failed: %m");
				nfscbd_exit(1);
			}
			memset(inetpeer.sin_zero, 0,
			    sizeof (inetpeer.sin_zero));
			if (setsockopt(msgsock, SOL_SOCKET,
			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
				syslog(LOG_ERR,
				    "setsockopt SO_KEEPALIVE: %m");
			nfscbdargs.sock = msgsock;
			nfscbdargs.name = (caddr_t)&inetpeer;
			nfscbdargs.namelen = sizeof(inetpeer);
			nfssvc(NFSSVC_CBADDSOCK, &nfscbdargs);
			(void)close(msgsock);
		}
	}
}
Ejemplo n.º 21
0
int
main(int argc, char **argv)
{
	int ch, i, s;
	void *nc_handle;
	char *endptr, **hosts_bak;
	struct sigaction sigalarm;
	int grace_period = 30;
	struct netconfig *nconf;
	int have_v6 = 1;
	int maxrec = RPC_MAXDATASIZE;
	in_port_t svcport = 0;
	int attempt_cnt, port_len, port_pos, ret;
	char **port_list;

	while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
		switch (ch) {
		case 'd':
			debug_level = atoi(optarg);
			if (!debug_level) {
				usage();
				/* NOTREACHED */
			}
			break;
		case 'g':
			grace_period = atoi(optarg);
			if (!grace_period) {
				usage();
				/* NOTREACHED */
			}
			break;
		case 'h':
			++nhosts;
			hosts_bak = hosts;
			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
			if (hosts_bak == NULL) {
				if (hosts != NULL) {
					for (i = 0; i < nhosts; i++) 
						free(hosts[i]);
					free(hosts);
					out_of_mem();
				}
			}
			hosts = hosts_bak;
			hosts[nhosts - 1] = strdup(optarg);
			if (hosts[nhosts - 1] == NULL) {
				for (i = 0; i < (nhosts - 1); i++) 
					free(hosts[i]);
				free(hosts);
				out_of_mem();
			}
			break;
		case 'p':
			endptr = NULL;
			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
			if (endptr == NULL || *endptr != '\0' ||
			    svcport == 0 || svcport >= IPPORT_MAX)
				usage();
			svcport_str = strdup(optarg);
			break;
		default:
		case '?':
			usage();
			/* NOTREACHED */
		}
	}
	if (geteuid()) { /* This command allowed only to root */
		fprintf(stderr, "Sorry. You are not superuser\n");
		exit(1);
        }

	kernel_lockd = FALSE;
	kernel_lockd_client = FALSE;
	if (modfind("nfslockd") < 0) {
		if (kldload("nfslockd") < 0) {
			fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n");
		} else {
			kernel_lockd = TRUE;
		}
	} else {
		kernel_lockd = TRUE;
	}
	if (kernel_lockd) {
		if (getosreldate() >= 800040)
			kernel_lockd_client = TRUE;
	}

	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);

	/*
	 * Check if IPv6 support is present.
	 */
	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
	if (s < 0)
		have_v6 = 0;
	else 
		close(s);

	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);

	/*
	 * If no hosts were specified, add a wildcard entry to bind to
	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
	 * list.
	 */
	if (nhosts == 0) {
		hosts = malloc(sizeof(char**));
		if (hosts == NULL)
			out_of_mem();

		hosts[0] = "*";
		nhosts = 1;
	} else {
		hosts_bak = hosts;
		if (have_v6) {
			hosts_bak = realloc(hosts, (nhosts + 2) *
			    sizeof(char *));
			if (hosts_bak == NULL) {
				for (i = 0; i < nhosts; i++)
					free(hosts[i]);
				free(hosts);
				out_of_mem();
			} else
				hosts = hosts_bak;

			nhosts += 2;
			hosts[nhosts - 2] = "::1";
		} else {
			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
			if (hosts_bak == NULL) {
				for (i = 0; i < nhosts; i++)
					free(hosts[i]);

				free(hosts);
				out_of_mem();
			} else {
				nhosts += 1;
				hosts = hosts_bak;
			}
		}
		hosts[nhosts - 1] = "127.0.0.1";
	}

	if (kernel_lockd) {
		if (!kernel_lockd_client) {
			/*
			 * For the case where we have a kernel lockd but it
			 * doesn't provide client locking, we run a cut-down
			 * RPC service on a local-domain socket. The kernel's
			 * RPC server will pass what it can't handle (mainly
			 * client replies) down to us.
			 */
			struct sockaddr_un sun;
			int fd, oldmask;
			SVCXPRT *xprt;

			memset(&sun, 0, sizeof sun);
			sun.sun_family = AF_LOCAL;
			unlink(_PATH_RPCLOCKDSOCK);
			strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
			sun.sun_len = SUN_LEN(&sun);
			fd = socket(AF_LOCAL, SOCK_STREAM, 0);
			if (!fd) {
				err(1, "Can't create local lockd socket");
			}
			oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
			if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
				err(1, "Can't bind local lockd socket");
			}
			umask(oldmask);
			if (listen(fd, SOMAXCONN) < 0) {
				err(1, "Can't listen on local lockd socket");
			}
			xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
			if (!xprt) {
				err(1, "Can't create transport for local lockd socket");
			}
			if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
				err(1, "Can't register service for local lockd socket");
			}
		}

		/*
		 * We need to look up the addresses so that we can
		 * hand uaddrs (ascii encoded address+port strings) to
		 * the kernel.
		 */
		nc_handle = setnetconfig();
		while ((nconf = getnetconfig(nc_handle))) {
			/* We want to listen only on udp6, tcp6, udp, tcp transports */
			if (nconf->nc_flag & NC_VISIBLE) {
				/* Skip if there's no IPv6 support */
				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
					/* DO NOTHING */
				} else {
					lookup_addresses(nconf);
				}
			}
		}
		endnetconfig(nc_handle);
	} else {
		attempt_cnt = 1;
		sock_fdcnt = 0;
		sock_fd = NULL;
		port_list = NULL;
		port_len = 0;
		nc_handle = setnetconfig();
		while ((nconf = getnetconfig(nc_handle))) {
			/* We want to listen only on udp6, tcp6, udp, tcp transports */
			if (nconf->nc_flag & NC_VISIBLE) {
				/* Skip if there's no IPv6 support */
				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
					/* DO NOTHING */
				} else {
					ret = create_service(nconf);
					if (ret == 1)
						/* Ignore this call */
						continue;
					if (ret < 0) {
						/*
						 * Failed to bind port, so close
						 * off all sockets created and
						 * try again if the port# was
						 * dynamically assigned via
						 * bind(2).
						 */
						clearout_service();
						if (mallocd_svcport != 0 &&
						    attempt_cnt <
						    GETPORT_MAXTRY) {
							free(svcport_str);
							svcport_str = NULL;
							mallocd_svcport = 0;
						} else {
							errno = EADDRINUSE;
							syslog(LOG_ERR,
							 "bindresvport_sa: %m");
							exit(1);
						}
	
						/*
						 * Start over at the first
						 * service.
						 */
						free(sock_fd);
						sock_fdcnt = 0;
						sock_fd = NULL;
						nc_handle = setnetconfig();
						attempt_cnt++;
					} else if (mallocd_svcport != 0 &&
					    attempt_cnt == GETPORT_MAXTRY) {
						/*
						 * For the last attempt, allow
						 * different port #s for each
						 * nconf by saving the
						 * svcport_str and setting it
						 * back to NULL.
						 */
						port_list = realloc(port_list,
						    (port_len + 1) *
						    sizeof(char *));
						if (port_list == NULL)
							out_of_mem();
						port_list[port_len++] =
						    svcport_str;
						svcport_str = NULL;
						mallocd_svcport = 0;
					}
				}
			}
		}

		/*
		 * Successfully bound the ports, so call complete_service() to
		 * do the rest of the setup on the service(s).
		 */
		sock_fdpos = 0;
		port_pos = 0;
		nc_handle = setnetconfig();
		while ((nconf = getnetconfig(nc_handle))) {
			/* We want to listen only on udp6, tcp6, udp, tcp transports */
			if (nconf->nc_flag & NC_VISIBLE) {
				/* Skip if there's no IPv6 support */
				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
					/* DO NOTHING */
				} else if (port_list != NULL) {
					if (port_pos >= port_len) {
						syslog(LOG_ERR,
						    "too many port#s");
						exit(1);
					}
					complete_service(nconf,
					    port_list[port_pos++]);
				} else
					complete_service(nconf, svcport_str);
			}
		}
		endnetconfig(nc_handle);
		free(sock_fd);
		if (port_list != NULL) {
			for (port_pos = 0; port_pos < port_len; port_pos++)
				free(port_list[port_pos]);
			free(port_list);
		}
	}

	/*
	 * Note that it is NOT sensible to run this program from inetd - the
	 * protocol assumes that it will run immediately at boot time.
	 */
	if (daemon(0, debug_level > 0)) {
		err(1, "cannot fork");
		/* NOTREACHED */
	}

	openlog("rpc.lockd", 0, LOG_DAEMON);
	if (debug_level)
		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
	else
		syslog(LOG_INFO, "Starting");

	sigalarm.sa_handler = (sig_t) sigalarm_handler;
	sigemptyset(&sigalarm.sa_mask);
	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
	sigalarm.sa_flags |= SA_RESTART;
	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
		    strerror(errno));
		exit(1);
	}

	if (kernel_lockd) {
		if (!kernel_lockd_client) {
			init_nsm();
			client_pid = client_request();

			/*
			 * Create a child process to enter the kernel and then
			 * wait for RPCs on our local domain socket.
			 */
			if (!fork())
				nlm_syscall(debug_level, grace_period,
				    naddrs, addrs);
			else
				svc_run();
		} else {
			/*
			 * The kernel lockd implementation provides
			 * both client and server so we don't need to
			 * do anything else.
			 */
			nlm_syscall(debug_level, grace_period, naddrs, addrs);
		}
	} else {
		grace_expired = 0;
		alarm(grace_period);

		init_nsm();

		client_pid = client_request();

		svc_run();		/* Should never return */
	}
	exit(1);
}
Ejemplo n.º 22
0
int
main(int argc, char *argv[])
{
	int i, j;
	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
	struct nfsd_idargs nid;
	struct passwd *pwd;
	struct group *grp;
	int sock, one = 1;
	SVCXPRT *udptransp;
	u_short portnum;
	sigset_t signew;
	char hostname[MAXHOSTNAMELEN + 1], *cp;
	struct addrinfo *aip, hints;
	static uid_t check_dups[MAXUSERMAX];

	if (modfind("nfscommon") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfscommon") < 0 ||
		    modfind("nfscommon") < 0)
			errx(1, "Experimental nfs subsystem is not available");
	}

	/*
	 * First, figure out what our domain name and Kerberos Realm
	 * seem to be. Command line args may override these later.
	 */
	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
		if ((cp = strchr(hostname, '.')) != NULL &&
		    *(cp + 1) != '\0') {
			dnsname = cp + 1;
		} else {
			memset((void *)&hints, 0, sizeof (hints));
			hints.ai_flags = AI_CANONNAME;
			error = getaddrinfo(hostname, NULL, &hints, &aip);
			if (error == 0) {
			    if (aip->ai_canonname != NULL &&
				(cp = strchr(aip->ai_canonname, '.')) != NULL
				&& *(cp + 1) != '\0') {
					dnsname = cp + 1;
					mustfreeai = 1;
				} else {
					freeaddrinfo(aip);
				}
			}
		}
	}
	nid.nid_usermax = DEFUSERMAX;
	nid.nid_usertimeout = defusertimeout;

	argc--;
	argv++;
	while (argc >= 1) {
		if (!strcmp(*argv, "-domain")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			strncpy(hostname, *argv, MAXHOSTNAMELEN);
			hostname[MAXHOSTNAMELEN] = '\0';
			dnsname = hostname;
		} else if (!strcmp(*argv, "-verbose")) {
			verbose = 1;
		} else if (!strcmp(*argv, "-force")) {
			forcestart = 1;
		} else if (!strcmp(*argv, "-usermax")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			i = atoi(*argv);
			if (i < MINUSERMAX || i > MAXUSERMAX) {
				fprintf(stderr,
				    "usermax %d out of range %d<->%d\n", i,
				    MINUSERMAX, MAXUSERMAX);
				usage();
			}
			nid.nid_usermax = i;
		} else if (!strcmp(*argv, "-usertimeout")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			i = atoi(*argv);
			if (i < 0 || i > 100000) {
				fprintf(stderr,
				    "usertimeout %d out of range 0<->100000\n",
				    i);
				usage();
			}
			nid.nid_usertimeout = defusertimeout = i * 60;
		} else if (nfsuserdcnt == -1) {
			nfsuserdcnt = atoi(*argv);
			if (nfsuserdcnt < 1)
				usage();
			if (nfsuserdcnt > MAXNFSUSERD) {
				warnx("nfsuserd count %d; reset to %d",
				    nfsuserdcnt, DEFNFSUSERD);
				nfsuserdcnt = DEFNFSUSERD;
			}
		} else {
			usage();
		}
		argc--;
		argv++;
	}
	if (nfsuserdcnt < 1)
		nfsuserdcnt = DEFNFSUSERD;

	/*
	 * Strip off leading and trailing '.'s in domain name and map
	 * alphabetics to lower case.
	 */
	while (*dnsname == '.')
		dnsname++;
	if (*dnsname == '\0')
		errx(1, "Domain name all '.'");
	len = strlen(dnsname);
	cp = dnsname + len - 1;
	while (*cp == '.') {
		*cp = '\0';
		len--;
		cp--;
	}
	for (i = 0; i < len; i++) {
		if (!isascii(dnsname[i]))
			errx(1, "Domain name has non-ascii char");
		if (isupper(dnsname[i]))
			dnsname[i] = tolower(dnsname[i]);
	}

	/*
	 * If the nfsuserd died off ungracefully, this is necessary to
	 * get them to start again.
	 */
	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
		errx(1, "Can't do nfssvc() to delete the port");

	if (verbose)
		fprintf(stderr,
		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
		    dnsname, nid.nid_usermax, nid.nid_usertimeout);

	for (i = 0; i < nfsuserdcnt; i++)
		slaves[i] = (pid_t)-1;

	/*
	 * Set up the service port to accept requests via UDP from
	 * localhost (127.0.0.1).
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		err(1, "cannot create udp socket");

	/*
	 * Not sure what this does, so I'll leave it here for now.
	 */
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
	
	if ((udptransp = svcudp_create(sock)) == NULL)
		err(1, "Can't set up socket");

	/*
	 * By not specifying a protocol, it is linked into the
	 * dispatch queue, but not registered with portmapper,
	 * which is just what I want.
	 */
	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
	    nfsuserdsrv, 0))
		err(1, "Can't register nfsuserd");

	/*
	 * Tell the kernel what my port# is.
	 */
	portnum = htons(udptransp->xp_port);
#ifdef DEBUG
	printf("portnum=0x%x\n", portnum);
#else
	if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
		if (errno == EPERM) {
			fprintf(stderr,
			    "Can't start nfsuserd when already running");
			fprintf(stderr,
			    " If not running, use the -force option.\n");
		} else {
			fprintf(stderr, "Can't do nfssvc() to add port\n");
		}
		exit(1);
	}
#endif

	pwd = getpwnam(defaultuser);
	if (pwd)
		nid.nid_uid = pwd->pw_uid;
	else
		nid.nid_uid = defaultuid;
	grp = getgrnam(defaultgroup);
	if (grp)
		nid.nid_gid = grp->gr_gid;
	else
		nid.nid_gid = defaultgid;
	nid.nid_name = dnsname;
	nid.nid_namelen = strlen(nid.nid_name);
	nid.nid_flag = NFSID_INITIALIZE;
#ifdef DEBUG
	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 
	    nid.nid_name);
#else
	error = nfssvc(NFSSVC_IDNAME, &nid);
	if (error)
		errx(1, "Can't initialize nfs user/groups");
#endif

	i = 0;
	/*
	 * Loop around adding all groups.
	 */
	setgrent();
	while (i < nid.nid_usermax && (grp = getgrent())) {
		nid.nid_gid = grp->gr_gid;
		nid.nid_name = grp->gr_name;
		nid.nid_namelen = strlen(grp->gr_name);
		nid.nid_flag = NFSID_ADDGID;
#ifdef DEBUG
		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
#else
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error)
			errx(1, "Can't add group %s", grp->gr_name);
#endif
		i++;
	}

	/*
	 * Loop around adding all users.
	 */
	start_uidpos = i;
	setpwent();
	while (i < nid.nid_usermax && (pwd = getpwent())) {
		fnd_dup = 0;
		/*
		 * Yes, this is inefficient, but it is only done once when
		 * the daemon is started and will run in a fraction of a second
		 * for nid_usermax at 10000. If nid_usermax is cranked up to
		 * 100000, it will take several seconds, depending on the CPU.
		 */
		for (j = 0; j < (i - start_uidpos); j++)
			if (check_dups[j] == pwd->pw_uid) {
				/* Found another entry for uid, so skip it */
				fnd_dup = 1;
				break;
			}
		if (fnd_dup != 0)
			continue;
		check_dups[i - start_uidpos] = pwd->pw_uid;
		nid.nid_uid = pwd->pw_uid;
		nid.nid_name = pwd->pw_name;
		nid.nid_namelen = strlen(pwd->pw_name);
		nid.nid_flag = NFSID_ADDUID;
#ifdef DEBUG
		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
#else
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error)
			errx(1, "Can't add user %s", pwd->pw_name);
#endif
		i++;
	}

	/*
	 * I should feel guilty for not calling this for all the above exit()
	 * upon error cases, but I don't.
	 */
	if (mustfreeai)
		freeaddrinfo(aip);

#ifdef DEBUG
	exit(0);
#endif
	/*
	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
	 * end up bogus.
	 */
	sigemptyset(&signew);
	sigaddset(&signew, SIGUSR1);
	sigaddset(&signew, SIGCHLD);
	sigprocmask(SIG_BLOCK, &signew, NULL);

	daemon(0, 0);
	(void)signal(SIGHUP, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGTERM, SIG_IGN);
	(void)signal(SIGUSR1, cleanup_term);
	(void)signal(SIGCHLD, cleanup_term);

	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);

	/*
	 * Fork off the slave daemons that do the work. All the master
	 * does is kill them off and cleanup.
	 */
	for (i = 0; i < nfsuserdcnt; i++) {
		slaves[i] = fork();
		if (slaves[i] == 0) {
			im_a_slave = 1;
			setproctitle("slave");
			sigemptyset(&signew);
			sigaddset(&signew, SIGUSR1);
			sigprocmask(SIG_UNBLOCK, &signew, NULL);

			/*
			 * and away we go.
			 */
			svc_run();
			syslog(LOG_ERR, "nfsuserd died: %m");
			exit(1);
		} else if (slaves[i] < 0) {
			syslog(LOG_ERR, "fork: %m");
		}
	}

	/*
	 * Just wait for SIGUSR1 or a child to die and then...
	 * As the Governor of California would say, "Terminate them".
	 */
	setproctitle("master");
	sigemptyset(&signew);
	while (1)
		sigsuspend(&signew);
}
Ejemplo n.º 23
0
int
main(int argc, char *argv[])
{
	int ch, options = 0, action = CCD_CONFIG;

	while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) {
		switch (ch) {
		case 'c':
			action = CCD_CONFIG;
			++options;
			break;

		case 'C':
			action = CCD_CONFIGALL;
			++options;
			break;

		case 'f':
			ccdconf = optarg;
			break;

		case 'g':
			action = CCD_DUMP;
			break;

		case 'u':
			action = CCD_UNCONFIG;
			++options;
			break;

		case 'U':
			action = CCD_UNCONFIGALL;
			++options;
			break;

		case 'v':
			verbose = 1;
			break;

		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (options > 1)
		usage();

	if (modfind("g_ccd") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("geom_ccd") < 0 || modfind("g_ccd") < 0)
			warn("geom_ccd module not available!");
	}

	switch (action) {
		case CCD_CONFIG:
		case CCD_UNCONFIG:
			exit(do_single(argc, argv, action));
			/* NOTREACHED */

		case CCD_CONFIGALL:
		case CCD_UNCONFIGALL:
			exit(do_all(action));
			/* NOTREACHED */

		case CCD_DUMP:
			exit(dump_ccd(argc, argv));
			/* NOTREACHED */
	}
	/* NOTREACHED */
	return (0);
}
Ejemplo n.º 24
0
/*
 * Create a socket type node and give it the supplied name.
 * Return data and control sockets corresponding to the node.
 * Returns -1 if error and sets errno.
 */
int
NgMkSockNode(const char *name, int *csp, int *dsp)
{
	char namebuf[NG_NODESIZ];
	int cs = -1;		/* control socket */
	int ds = -1;		/* data socket */
	int errnosv;

	/* Empty name means no name */
	if (name && *name == 0)
		name = NULL;

	/* Create control socket; this also creates the netgraph node.
	   If we get an EPROTONOSUPPORT then the socket node type is
	   not loaded, so load it and try again. */
	if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
		if (errno == EPROTONOSUPPORT) {
			if (kldload(NG_SOCKET_KLD) < 0) {
				errnosv = errno;
				if (_gNgDebugLevel >= 1)
					NGLOG("can't load %s", NG_SOCKET_KLD);
				goto errout;
			}
			cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
			if (cs >= 0)
				goto gotNode;
		}
		errnosv = errno;
		if (_gNgDebugLevel >= 1)
			NGLOG("socket");
		goto errout;
	}

gotNode:
	/* Assign the node the desired name, if any */
	if (name != NULL) {
		u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;

		/* Assign name */
		strlcpy(sg->sg_data, name, NG_NODESIZ);
		sg->sg_family = AF_NETGRAPH;
		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
		if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("bind(%s)", sg->sg_data);
			goto errout;
		}

		/* Save node name */
		strlcpy(namebuf, name, sizeof(namebuf));
	} else if (dsp != NULL) {
		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
		struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
		struct nodeinfo *const ni = (struct nodeinfo *) resp->data;

		/* Find out the node ID */
		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
		    NGM_NODEINFO, NULL, 0) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("send nodeinfo");
			goto errout;
		}
		if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("recv nodeinfo");
			goto errout;
		}

		/* Save node "name" */
		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
	}

	/* Create data socket if desired */
	if (dsp != NULL) {
		u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;

		/* Create data socket, initially just "floating" */
		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("socket");
			goto errout;
		}

		/* Associate the data socket with the node */
		snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
		sg->sg_family = AF_NETGRAPH;
		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("connect(%s)", sg->sg_data);
			goto errout;
		}
	}

	/* Return the socket(s) */
	if (csp)
		*csp = cs;
	else
		close(cs);
	if (dsp)
		*dsp = ds;
	return (0);

errout:
	/* Failed */
	if (cs >= 0)
		close(cs);
	if (ds >= 0)
		close(ds);
	errno = errnosv;
	return (-1);
}
Ejemplo n.º 25
0
int
load_gre_module(void)
{
#if defined(__APPLE__)
	fprintf(stderr, "OSX, kextload GRE.kext\n");
	int pid;
	if ((pid = fork()) < 0)
		return -1;

	if (pid == 0) {
		execle("/sbin/kextload", "kextload", "/Library/Extensions/GRE.kext", NULL, NULL);
		exit(EXIT_FAILURE);
	}

	while (waitpid(pid, 0, 0) < 0) {
		if (errno == EINTR)
			continue;
		return -1;
	}
	return 0;
#else
#if defined(__FreeBSD__)
	if (modfind("if_gre") < 0) {
#ifdef DEBUG
		fprintf(stderr, "FreeBSD, kldload if_gre\n");
#endif
		if (kldload("if_gre") < 0) {
			perror("can't load if_gre");
			return -1;
		}
	}
	return 0;
#else
#if defined(__linux__)
	fprintf(stderr, "Linux, insmod ip_gre\n");
	int fd;
	if ((fd = open("/proc/modules", O_RDONLY)) < 0) {
		perror("open(\"proc/modules\")");
		return -1;
	}
	
	int i;
	char buff[128];
	bzero(buff, sizeof(buff));
	while ((i = read(fd, buff, sizeof(buff) - 1)) > 0) {
		if (strstr(buff, "ip_gre")) {
			close(fd);
			return 0;
		}
		bzero(buff, sizeof(buff));
	}
	close(fd);
	/* module ip_gre not found, try to load ip_gre */
	fprintf(stderr, "load ip_gre...\n");
	int pid;
	if ((pid = fork()) < 0)
		return -1;

	if (pid == 0) {
		execle("/sbin/modprobe", "modprobe", "ip_gre", NULL, NULL);
		execle("/sbin/insmod", "insmod", "ip_gre", NULL, NULL);
		exit(1);
	}

	while (waitpid(pid, 0, 0) < 0) {
		if (errno == EINTR)
			continue;
		return -1;
	}
	return 0;
#else
	fprintf(stderr, "%s: Your OS is not supported yet\n", __FUNCTION__);
	return -1;
#endif
#endif
#endif
}
Ejemplo n.º 26
0
int
main(int argc, char *argv[])
{
	int ch;
	struct xvfsconf vfc;
	int error;
	unsigned int iodmin, iodmax, num_servers;
	size_t len;

	error = getvfsbyname("nfs", &vfc);
	if (error) {
		if (kldload("nfs") == -1)
			err(1, "kldload(nfs)");
		error = getvfsbyname("nfs", &vfc);
	}
	if (error)
		errx(1, "NFS support is not available in the running kernel");

	num_servers = 0;
	while ((ch = getopt(argc, argv, "n:")) != -1)
		switch (ch) {
		case 'n':
			num_servers = atoi(optarg);
			if (num_servers < 1) {
				warnx("nfsiod count %u; reset to %d",
				    num_servers, 1);
				num_servers = 1;
			}
			if (num_servers > MAXNFSDCNT) {
				warnx("nfsiod count %u; reset to %d",
				    num_servers, MAXNFSDCNT);
				num_servers = MAXNFSDCNT;
			}
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc > 0)
		usage();

	len = sizeof iodmin;
	error = sysctlbyname("vfs.nfs.iodmin", &iodmin, &len, NULL, 0);
	if (error < 0)
		err(1, "sysctlbyname(\"vfs.nfs.iodmin\")");
	len = sizeof iodmax;
	error = sysctlbyname("vfs.nfs.iodmax", &iodmax, &len, NULL, 0);
	if (error < 0)
		err(1, "sysctlbyname(\"vfs.nfs.iodmax\")");
	if (num_servers == 0) {		/* no change */
		printf("vfs.nfs.iodmin=%u\nvfs.nfs.iodmax=%u\n",
		    iodmin, iodmax);
		exit(0);
	}
	/* Catch the case where we're lowering num_servers below iodmin */
	if (iodmin > num_servers) {
		iodmin = num_servers;
		error = sysctlbyname("vfs.nfs.iodmin", NULL, 0, &iodmin,
		    sizeof iodmin);
		if (error < 0)
			err(1, "sysctlbyname(\"vfs.nfs.iodmin\")");
	}
	iodmax = num_servers;
	error = sysctlbyname("vfs.nfs.iodmax", NULL, 0, &iodmax, sizeof iodmax);
	if (error < 0)
		err(1, "sysctlbyname(\"vfs.nfs.iodmax\")");
	exit (0);
}
Ejemplo n.º 27
0
int
main(int cc, char **vv)
{
     int	ch, disco;
     char	*pname, *p, *q, *ta, *kw;
     isc_opt_t	*op;
     FILE	*fd;

     /* Try to load iscsi_initiator module before starting its operation */
     if (modfind(INITIATORMOD) < 0) {
	     if (kldload(INITIATORMOD) < 0 || modfind(INITIATORMOD) < 0) {
		     perror(INITIATORMOD ": Error while handling kernel module");
		     return 1;
	     }
     }

     op = &opvals;
     iscsidev = "/dev/"ISCSIDEV;
     fd = NULL;
     pname = vv[0];
     if((p = strrchr(pname, '/')) != NULL)
	  pname = p + 1;

     kw = ta = NULL;
     disco = 0;

     while((ch = getopt(cc, vv, OPTIONS)) != -1) {
	  switch(ch) {
	  case 'v':
	       vflag++;
	       break;
	  case 'c':
	       fd = fopen(optarg, "r");
	       if(fd == NULL) {
		    perror(optarg);
		    exit(1);
	       }
	       break;
	  case 'd':
	       disco = 1;
	       break;
	  case 't':
	       ta = optarg;
	       break;
	  case 'n':
	       kw = optarg;
	       break;
	  default:
	  badu:
	       fprintf(stderr, "Usage: %s %s\n", pname, USAGE);
	       exit(1);
	  }
     }
     if(fd == NULL)
	  fd = fopen("/etc/iscsi.conf", "r");

     if(fd != NULL) {
	  parseConfig(fd, kw, op);
	  fclose(fd);
     }
     cc -= optind;
     vv += optind;
     if(cc > 0) {
	  if(vflag)
	       printf("adding '%s'\n", *vv);
	  parseArgs(cc, vv, op);
     }
     if(ta)
	  op->targetAddress = ta;

     if(op->targetAddress == NULL) {
	  fprintf(stderr, "No target!\n");
	  goto badu;
     }
     q = op->targetAddress;
     if(*q == '[' && (q = strchr(q, ']')) != NULL) {
	  *q++ = '\0';
	  op->targetAddress++;
     } else
	  q = op->targetAddress;
     if((p = strchr(q, ':')) != NULL) {
	  *p++ = 0;
	  op->port = atoi(p);
	  p = strchr(p, ',');
     }
     if(p || ((p = strchr(q, ',')) != NULL)) {
	  *p++ = 0;
	  op->targetPortalGroupTag = atoi(p);
     }
     if(op->initiatorName == 0) {
	  char	hostname[256];

	  if(op->iqn) {
	       if(gethostname(hostname, sizeof(hostname)) == 0)
		    asprintf(&op->initiatorName, "%s:%s", op->iqn, hostname);
	       else
		    asprintf(&op->initiatorName, "%s:%d", op->iqn, (int)time(0) & 0xff); // XXX:
	  }
	  else {
	       if(gethostname(hostname, sizeof(hostname)) == 0)
		    asprintf(&op->initiatorName, "%s", hostname);
	       else
		    asprintf(&op->initiatorName, "%d", (int)time(0) & 0xff); // XXX:
	  }
     }
     if(disco) {
	  op->sessionType = "Discovery";
	  op->targetName = 0;
     }

     fsm(op);

     exit(0);
}
Ejemplo n.º 28
0
int
main(int argc, char *argv[], char *envp[])
{
    struct stat histstat;

    if (modfind(VINUMMOD) < 0) {
	/* need to load the vinum module */
	if (kldload(VINUMMOD) < 0 || modfind(VINUMMOD) < 0) {
	    perror(VINUMMOD ": Kernel module not available");
	    return 1;
	}
    }
    dateformat = getenv("VINUM_DATEFORMAT");
    if (dateformat == NULL)
	dateformat = "%e %b %Y %H:%M:%S";
    historyfile = getenv("VINUM_HISTORY");
    if (historyfile == NULL)
	historyfile = DEFAULT_HISTORYFILE;
    if (stat(historyfile, &histstat) == 0) {		    /* history file exists */
	if ((histstat.st_mode & S_IFMT) != S_IFREG) {
	    fprintf(stderr,
		"Vinum history file %s must be a regular file\n",
		historyfile);
	    exit(1);
	}
    } else if ((errno != ENOENT)			    /* not "not there",  */
    &&(errno != EROFS)) {				    /* and not read-only file system */
	fprintf(stderr,
	    "Can't open %s: %s (%d)\n",
	    historyfile,
	    strerror(errno),
	    errno);
	exit(1);
    }
    hist = fopen(historyfile, "a+");
    if (hist != NULL) {
	timestamp();
	fprintf(hist, "*** " VINUMMOD " started ***\n");
	fflush(hist);				    /* before we start the daemon */
    }
    superdev = open(VINUM_SUPERDEV_NAME, O_RDWR);	    /* open vinum superdevice */
    if (superdev < 0) {					    /* no go */
	if (errno == ENODEV) {				    /* not configured, */
	    superdev = open(VINUM_WRONGSUPERDEV_NAME, O_RDWR); /* do we have a debug mismatch? */
	    if (superdev >= 0) {			    /* yup! */
#if VINUMDEBUG
		fprintf(stderr,
		    "This program is compiled with debug support, but the kernel module does\n"
		    "not have debug support.  This program must be matched with the kernel\n"
		    "module.  Please alter /usr/src/sbin/" VINUMMOD "/Makefile and remove\n"
		    "the option -DVINUMDEBUG from the CFLAGS definition, or alternatively\n"
		    "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and add the option\n"
		    "-DVINUMDEBUG to the CFLAGS definition.  Then rebuild the component\n"
		    "of your choice with 'make clean all install'.  If you rebuild the kernel\n"
		    "module, you must stop " VINUMMOD " and restart it\n");
#else
		fprintf(stderr,
		    "This program is compiled without debug support, but the kernel module\n"
		    "includes debug support.  This program must be matched with the kernel\n"
		    "module.  Please alter /usr/src/sbin/" VINUMMOD "/Makefile and add\n"
		    "the option -DVINUMDEBUG to the CFLAGS definition, or alternatively\n"
		    "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and remove the option\n"
		    "-DVINUMDEBUG from the CFLAGS definition.  Then rebuild the component\n"
		    "of your choice with 'make clean all install'.  If you rebuild the kernel\n"
		    "module, you must stop " VINUMMOD " and restart it\n");
#endif
		return 1;
	    }
	} else if (errno == ENOENT)			    /* we don't have our node, */
	    make_devices();				    /* create them first */
	if (superdev < 0) {
	    perror("Can't open " VINUM_SUPERDEV_NAME);
	    return 1;
	}
    }
    /* Check if the dæmon is running.  If not, start it in the
     * background */
    start_daemon();

    if (argc > 1) {					    /* we have a command on the line */
	if (setjmp(command_fail) != 0)			    /* long jumped out */
	    return -1;
	parseline(argc - 1, &argv[1]);			    /* do it */
    } else {
	/*
	 * Catch a possible race condition which could cause us to
	 * longjmp() into nowhere if we receive a SIGINT in the next few
	 * lines.
	 */
	if (setjmp(command_fail))			    /* come back here on catastrophic failure */
	    return 1;
	setsigs();					    /* set signal handler */
	for (;;) {					    /* ugh */
	    char *c;
	    int childstatus;				    /* from wait4 */

	    if (setjmp(command_fail) == 2)		    /* come back here on catastrophic failure */
		fprintf(stderr, "*** interrupted ***\n");   /* interrupted */

	    while (wait4(-1, &childstatus, WNOHANG, NULL) > 0);	/* wait for all dead children */
	    c = readline(VINUMMOD " -> ");		    /* get an input */
	    if (c == NULL) {				    /* EOF or error */
		if (ferror(stdin)) {
		    fprintf(stderr, "Can't read input: %s (%d)\n", strerror(errno), errno);
		    return 1;
		} else {				    /* EOF */
		    printf("\n");
		    return 0;
		}
	    } else if (*c) {				    /* got something there */
		add_history(c);				    /* save it in the history */
		strcpy(buffer, c);			    /* put it where we can munge it */
		free(c);
		line++;					    /* count the lines */
		tokens = tokenize(buffer, token);
		/* got something potentially worth parsing */
		if (tokens)
		    parseline(tokens, token);		    /* and do what he says */
	    }
	    if (hist)
		fflush(hist);
	}
    }
    return 0;						    /* normal completion */
}
Ejemplo n.º 29
0
/*
 * Nfs server daemon mostly just a user context for nfssvc()
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - fork the nfsd(s)
 * 3 - create server socket(s)
 * 4 - register socket with rpcbind
 *
 * For connectionless protocols, just pass the socket into the kernel via.
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via. nfssvc().
 * The arguments are:
 *	-r - reregister with rpcbind
 *	-d - unregister with rpcbind
 *	-t - support tcp nfs clients
 *	-u - support udp nfs clients
 *	-e - forces it to run a server that supports nfsv4
 * followed by "n" which is the number of nfsds' to fork off
 */
int
main(int argc, char **argv)
{
	struct nfsd_addsock_args addsockargs;
	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
	struct sockaddr_in inetpeer;
	struct sockaddr_in6 inet6peer;
	fd_set ready, sockbits;
	fd_set v4bits, v6bits;
	int ch, connect_type_cnt, i, maxsock, msgsock;
	socklen_t len;
	int on = 1, unregister, reregister, sock;
	int tcp6sock, ip6flag, tcpflag, tcpsock;
	int udpflag, ecode, error, s;
	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
	int nfssvc_addsock;
	int longindex = 0;
	const char *lopt;
	char **bindhost = NULL;
	pid_t pid;

	nfsdcnt = DEFNFSDCNT;
	unregister = reregister = tcpflag = maxsock = 0;
	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
	getopt_shortopts = "ah:n:rdtue";
	getopt_usage =
	    "usage:\n"
	    "  nfsd [-ardtue] [-h bindip]\n"
	    "       [-n numservers] [--minthreads #] [--maxthreads #]\n";
	while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
		    &longindex)) != -1)
		switch (ch) {
		case 'a':
			bindanyflag = 1;
			break;
		case 'n':
			set_nfsdcnt(atoi(optarg));
			break;
		case 'h':
			bindhostc++;
			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
			if (bindhost == NULL) 
				errx(1, "Out of memory");
			bindhost[bindhostc-1] = strdup(optarg);
			if (bindhost[bindhostc-1] == NULL)
				errx(1, "Out of memory");
			break;
		case 'r':
			reregister = 1;
			break;
		case 'd':
			unregister = 1;
			break;
		case 't':
			tcpflag = 1;
			break;
		case 'u':
			udpflag = 1;
			break;
		case 'e':
			/* now a no-op, since this is the default */
			break;
		case 0:
			lopt = longopts[longindex].name;
			if (!strcmp(lopt, "minthreads")) {
				minthreads = atoi(optarg);
			} else if (!strcmp(lopt, "maxthreads")) {
				maxthreads = atoi(optarg);
			}
			break;
		default:
		case '?':
			usage();
		}
	if (!tcpflag && !udpflag)
		udpflag = 1;
	argv += optind;
	argc -= optind;
	if (minthreads_set && maxthreads_set && minthreads > maxthreads)
		errx(EX_USAGE,
		    "error: minthreads(%d) can't be greater than "
		    "maxthreads(%d)", minthreads, maxthreads);

	/*
	 * XXX
	 * Backward compatibility, trailing number is the count of daemons.
	 */
	if (argc > 1)
		usage();
	if (argc == 1)
		set_nfsdcnt(atoi(argv[0]));

	/*
	 * Unless the "-o" option was specified, try and run "nfsd".
	 * If "-o" was specified, try and run "nfsserver".
	 */
	if (modfind("nfsd") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
			errx(1, "NFS server is not available");
	}

	ip6flag = 1;
	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
	if (s == -1) {
		if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
			err(1, "socket");
		ip6flag = 0;
	} else if (getnetconfigent("udp6") == NULL ||
		getnetconfigent("tcp6") == NULL) {
		ip6flag = 0;
	}
	if (s != -1)
		close(s);

	if (bindhostc == 0 || bindanyflag) {
		bindhostc++;
		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
		if (bindhost == NULL) 
			errx(1, "Out of memory");
		bindhost[bindhostc-1] = strdup("*");
		if (bindhost[bindhostc-1] == NULL) 
			errx(1, "Out of memory");
	}

	if (unregister) {
		unregistration();
		exit (0);
	}
	if (reregister) {
		if (udpflag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
			if (ecode != 0)
				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
			nconf_udp = getnetconfigent("udp");
			if (nconf_udp == NULL)
				err(1, "getnetconfigent udp failed");
			nb_udp.buf = ai_udp->ai_addr;
			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp)))
				err(1, "rpcb_set udp failed");
			freeaddrinfo(ai_udp);
		}
		if (udpflag && ip6flag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
			if (ecode != 0)
				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
			nconf_udp6 = getnetconfigent("udp6");
			if (nconf_udp6 == NULL)
				err(1, "getnetconfigent udp6 failed");
			nb_udp6.buf = ai_udp6->ai_addr;
			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6)))
				err(1, "rpcb_set udp6 failed");
			freeaddrinfo(ai_udp6);
		}
		if (tcpflag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
			if (ecode != 0)
				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
			nconf_tcp = getnetconfigent("tcp");
			if (nconf_tcp == NULL)
				err(1, "getnetconfigent tcp failed");
			nb_tcp.buf = ai_tcp->ai_addr;
			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp)))
				err(1, "rpcb_set tcp failed");
			freeaddrinfo(ai_tcp);
		}
		if (tcpflag && ip6flag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
			if (ecode != 0)
				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
			nconf_tcp6 = getnetconfigent("tcp6");
			if (nconf_tcp6 == NULL)
				err(1, "getnetconfigent tcp6 failed");
			nb_tcp6.buf = ai_tcp6->ai_addr;
			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6)))
				err(1, "rpcb_set tcp6 failed");
			freeaddrinfo(ai_tcp6);
		}
		exit (0);
	}
	if (debug == 0) {
		daemon(0, 0);
		(void)signal(SIGHUP, SIG_IGN);
		(void)signal(SIGINT, SIG_IGN);
		/*
		 * nfsd sits in the kernel most of the time.  It needs
		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
		 * as possible during a shutdown, otherwise loopback
		 * mounts will not be able to unmount. 
		 */
		(void)signal(SIGTERM, SIG_IGN);
		(void)signal(SIGQUIT, SIG_IGN);
	}
	(void)signal(SIGSYS, nonfs);
	(void)signal(SIGCHLD, reapchild);
	(void)signal(SIGUSR2, backup_stable);

	openlog("nfsd", LOG_PID | (debug ? LOG_PERROR : 0), LOG_DAEMON);

	/*
	 * For V4, we open the stablerestart file and call nfssvc()
	 * to get it loaded. This is done before the daemons do the
	 * regular nfssvc() call to service NFS requests.
	 * (This way the file remains open until the last nfsd is killed
	 *  off.)
	 * It and the backup copy will be created as empty files
	 * the first time this nfsd is started and should never be
	 * deleted/replaced if at all possible. It should live on a
	 * local, non-volatile storage device that does not do hardware
	 * level write-back caching. (See SCSI doc for more information
	 * on how to prevent write-back caching on SCSI disks.)
	 */
	open_stable(&stablefd, &backupfd);
	if (stablefd < 0) {
		syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
		exit(1);
	}
	/* This system call will fail for old kernels, but that's ok. */
	nfssvc(NFSSVC_BACKUPSTABLE, NULL);
	if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
		syslog(LOG_ERR, "Can't read stable storage file: %m\n");
		exit(1);
	}
	nfssvc_addsock = NFSSVC_NFSDADDSOCK;
	nfssvc_nfsd = NFSSVC_NFSDNFSD;

	if (tcpflag) {
		/*
		 * For TCP mode, we fork once to start the first
		 * kernel nfsd thread. The kernel will add more
		 * threads as needed.
		 */
		pid = fork();
		if (pid == -1) {
			syslog(LOG_ERR, "fork: %m");
			nfsd_exit(1);
		}
		if (pid) {
			children[0] = pid;
		} else {
			(void)signal(SIGUSR1, child_cleanup);
			setproctitle("server");
			start_server(0);
		}
	}

	(void)signal(SIGUSR1, cleanup);
	FD_ZERO(&v4bits);
	FD_ZERO(&v6bits);
	FD_ZERO(&sockbits);
 
	rpcbregcnt = 0;
	/* Set up the socket for udp and rpcb register it. */
	if (udpflag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((sock = socket(ai_udp->ai_family,
				    ai_udp->ai_socktype,
				    ai_udp->ai_protocol)) < 0) {
					syslog(LOG_ERR,
					    "can't create udp socket");
					nfsd_exit(1);
				}
				if (bind(sock, ai_udp->ai_addr,
				    ai_udp->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind udp addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				freeaddrinfo(ai_udp);
				addsockargs.sock = sock;
				addsockargs.name = NULL;
				addsockargs.namelen = 0;
				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
					syslog(LOG_ERR, "can't Add UDP socket");
					nfsd_exit(1);
				}
				(void)close(sock);
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo udp: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_udp = getnetconfigent("udp");
			if (nconf_udp == NULL)
				err(1, "getnetconfigent udp failed");
			nb_udp.buf = ai_udp->ai_addr;
			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp)))
				err(1, "rpcb_set udp failed");
			freeaddrinfo(ai_udp);
		}
	}

	/* Set up the socket for udp6 and rpcb register it. */
	if (udpflag && ip6flag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((sock = socket(ai_udp6->ai_family,
				    ai_udp6->ai_socktype,
				    ai_udp6->ai_protocol)) < 0) {
					syslog(LOG_ERR,
						"can't create udp6 socket");
					nfsd_exit(1);
				}
				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
				    &on, sizeof on) < 0) {
					syslog(LOG_ERR,
					    "can't set v6-only binding for "
					    "udp6 socket: %m");
					nfsd_exit(1);
				}
				if (bind(sock, ai_udp6->ai_addr,
				    ai_udp6->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind udp6 addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				freeaddrinfo(ai_udp6);
				addsockargs.sock = sock;
				addsockargs.name = NULL;
				addsockargs.namelen = 0;
				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
					syslog(LOG_ERR,
					    "can't add UDP6 socket");
					nfsd_exit(1);
				}
				(void)close(sock);    
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo udp6: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_udp6 = getnetconfigent("udp6");
			if (nconf_udp6 == NULL)
				err(1, "getnetconfigent udp6 failed");
			nb_udp6.buf = ai_udp6->ai_addr;
			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6)))
				err(1, "rpcb_set udp6 failed");
			freeaddrinfo(ai_udp6);
		}
	}

	/* Set up the socket for tcp and rpcb register it. */
	if (tcpflag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((tcpsock = socket(AF_INET, SOCK_STREAM,
				    0)) < 0) {
					syslog(LOG_ERR,
					    "can't create tcp socket");
					nfsd_exit(1);
				}
				if (setsockopt(tcpsock, SOL_SOCKET,
				    SO_REUSEADDR,
				    (char *)&on, sizeof(on)) < 0)
					syslog(LOG_ERR,
					     "setsockopt SO_REUSEADDR: %m");
				if (bind(tcpsock, ai_tcp->ai_addr,
				    ai_tcp->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind tcp addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				if (listen(tcpsock, -1) < 0) {
					syslog(LOG_ERR, "listen failed");
					nfsd_exit(1);
				}
				freeaddrinfo(ai_tcp);
				FD_SET(tcpsock, &sockbits);
				FD_SET(tcpsock, &v4bits); 
				maxsock = tcpsock;
				connect_type_cnt++;
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints,
			     &ai_tcp);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo tcp: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_tcp = getnetconfigent("tcp");
			if (nconf_tcp == NULL)
				err(1, "getnetconfigent tcp failed");
			nb_tcp.buf = ai_tcp->ai_addr;
			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp,
			    &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3,
			    nconf_tcp, &nb_tcp)))
				err(1, "rpcb_set tcp failed");
			freeaddrinfo(ai_tcp);
		}
	}

	/* Set up the socket for tcp6 and rpcb register it. */
	if (tcpflag && ip6flag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((tcp6sock = socket(ai_tcp6->ai_family,
				    ai_tcp6->ai_socktype,
				    ai_tcp6->ai_protocol)) < 0) {
					syslog(LOG_ERR,
					    "can't create tcp6 socket");
					nfsd_exit(1);
				}
				if (setsockopt(tcp6sock, SOL_SOCKET,
				    SO_REUSEADDR,
				    (char *)&on, sizeof(on)) < 0)
					syslog(LOG_ERR,
					    "setsockopt SO_REUSEADDR: %m");
				if (setsockopt(tcp6sock, IPPROTO_IPV6,
				    IPV6_V6ONLY, &on, sizeof on) < 0) {
					syslog(LOG_ERR,
					"can't set v6-only binding for tcp6 "
					    "socket: %m");
					nfsd_exit(1);
				}
				if (bind(tcp6sock, ai_tcp6->ai_addr,
				    ai_tcp6->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind tcp6 addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				if (listen(tcp6sock, -1) < 0) {
					syslog(LOG_ERR, "listen failed");
					nfsd_exit(1);
				}
				freeaddrinfo(ai_tcp6);
				FD_SET(tcp6sock, &sockbits);
				FD_SET(tcp6sock, &v6bits);
				if (maxsock < tcp6sock)
					maxsock = tcp6sock;
				connect_type_cnt++;
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo tcp6: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_tcp6 = getnetconfigent("tcp6");
			if (nconf_tcp6 == NULL)
				err(1, "getnetconfigent tcp6 failed");
			nb_tcp6.buf = ai_tcp6->ai_addr;
			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6)))
				err(1, "rpcb_set tcp6 failed");
			freeaddrinfo(ai_tcp6);
		}
	}

	if (rpcbregcnt == 0) {
		syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
		nfsd_exit(1);
	}

	if (tcpflag && connect_type_cnt == 0) {
		syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
		nfsd_exit(1);
	}

	setproctitle("master");
	/*
	 * We always want a master to have a clean way to to shut nfsd down
	 * (with unregistration): if the master is killed, it unregisters and
	 * kills all children. If we run for UDP only (and so do not have to
	 * loop waiting waiting for accept), we instead make the parent
	 * a "server" too. start_server will not return.
	 */
	if (!tcpflag)
		start_server(1);

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		ready = sockbits;
		if (connect_type_cnt > 1) {
			if (select(maxsock + 1,
			    &ready, NULL, NULL, NULL) < 1) {
				error = errno;
				if (error == EINTR)
					continue;
				syslog(LOG_ERR, "select failed: %m");
				nfsd_exit(1);
			}
		}
		for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
			if (FD_ISSET(tcpsock, &ready)) {
				if (FD_ISSET(tcpsock, &v4bits)) {
					len = sizeof(inetpeer);
					if ((msgsock = accept(tcpsock,
					    (struct sockaddr *)&inetpeer, &len)) < 0) {
						error = errno;
						syslog(LOG_ERR, "accept failed: %m");
						if (error == ECONNABORTED ||
						    error == EINTR)
							continue;
						nfsd_exit(1);
					}
					memset(inetpeer.sin_zero, 0,
						sizeof(inetpeer.sin_zero));
					if (setsockopt(msgsock, SOL_SOCKET,
					    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
						syslog(LOG_ERR,
						    "setsockopt SO_KEEPALIVE: %m");
					addsockargs.sock = msgsock;
					addsockargs.name = (caddr_t)&inetpeer;
					addsockargs.namelen = len;
					nfssvc(nfssvc_addsock, &addsockargs);
					(void)close(msgsock);
				} else if (FD_ISSET(tcpsock, &v6bits)) {
					len = sizeof(inet6peer);
					if ((msgsock = accept(tcpsock,
					    (struct sockaddr *)&inet6peer,
					    &len)) < 0) {
						error = errno;
						syslog(LOG_ERR,
						     "accept failed: %m");
						if (error == ECONNABORTED ||
						    error == EINTR)
							continue;
						nfsd_exit(1);
					}
					if (setsockopt(msgsock, SOL_SOCKET,
					    SO_KEEPALIVE, (char *)&on,
					    sizeof(on)) < 0)
						syslog(LOG_ERR, "setsockopt "
						    "SO_KEEPALIVE: %m");
					addsockargs.sock = msgsock;
					addsockargs.name = (caddr_t)&inet6peer;
					addsockargs.namelen = len;
					nfssvc(nfssvc_addsock, &addsockargs);
					(void)close(msgsock);
				}
			}
		}
	}
}
Ejemplo n.º 30
0
int
main(int argc, char *argv[])
{
	struct iovec *iov;
	unsigned int iovlen;
	struct smb_ctx sctx, *ctx = &sctx;
	struct stat st;
#ifdef APPLE
	extern void dropsuid();
	extern int loadsmbvfs();
#else
	struct xvfsconf vfc;
#endif
	char *next, *p, *val;
	int opt, error, mntflags, caseopt, fd;
	uid_t uid;
	gid_t gid;
	mode_t dir_mode, file_mode;
	char errmsg[255] = { 0 };

	iov = NULL;
	iovlen = 0;
	fd = 0;
	uid = (uid_t)-1;
	gid = (gid_t)-1;
	caseopt = 0;
	file_mode = 0;
	dir_mode = 0;

#ifdef APPLE
	dropsuid();
#endif
	if (argc == 2) {
		if (strcmp(argv[1], "-h") == 0) {
			usage();
		}
	}
	if (argc < 3)
		usage();

#ifdef APPLE
	error = loadsmbvfs();
#else
	error = getvfsbyname(smbfs_vfsname, &vfc);
	if (error) {
		if (kldload(smbfs_vfsname) < 0)
			err(EX_OSERR, "kldload(%s)", smbfs_vfsname);
		error = getvfsbyname(smbfs_vfsname, &vfc);
	}
#endif
	if (error)
		errx(EX_OSERR, "SMB filesystem is not available");

	if (smb_lib_init() != 0)
		exit(1);

	mntflags = error = 0;

	caseopt = SMB_CS_NONE;

	if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0)
		exit(1);
	if (smb_ctx_readrc(ctx) != 0)
		exit(1);
	if (smb_rc)
		rc_close(smb_rc);

	while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) {
		switch (opt) {
		    case STDPARAM_ARGS:
			error = smb_ctx_opt(ctx, opt, optarg);
			if (error)
				exit(1);
			break;
		    case 'u': {
			struct passwd *pwd;

			pwd = isdigit(optarg[0]) ?
			    getpwuid(atoi(optarg)) : getpwnam(optarg);
			if (pwd == NULL)
				errx(EX_NOUSER, "unknown user '%s'", optarg);
			uid = pwd->pw_uid;
			break;
		    }
		    case 'g': {
			struct group *grp;

			grp = isdigit(optarg[0]) ?
			    getgrgid(atoi(optarg)) : getgrnam(optarg);
			if (grp == NULL)
				errx(EX_NOUSER, "unknown group '%s'", optarg);
			gid = grp->gr_gid;
			break;
		    }
		    case 'd':
			errno = 0;
			dir_mode = strtol(optarg, &next, 8);
			if (errno || *next != 0)
				errx(EX_DATAERR, "invalid value for directory mode");
			break;
		    case 'f':
			errno = 0;
			file_mode = strtol(optarg, &next, 8);
			if (errno || *next != 0)
				errx(EX_DATAERR, "invalid value for file mode");
			break;
		    case '?':
			usage();
			/*NOTREACHED*/
		    case 'n': {
			char *inp, *nsp;

			nsp = inp = optarg;
			while ((nsp = strsep(&inp, ",;:")) != NULL) {
				if (strcasecmp(nsp, "LONG") == 0) {
					build_iovec(&iov, &iovlen,
					    "nolong", NULL, 0);
				} else {
					errx(EX_DATAERR,
					    "unknown suboption '%s'", nsp);
				}
			}
			break;
		    };
		    case 'o':
			getmntopts(optarg, mopts, &mntflags, 0);
			p = strchr(optarg, '=');
			val = NULL;
			if (p != NULL) {
				*p = '\0';
				val = p + 1;
			}
			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
			break;
		    case 'c':
			switch (optarg[0]) {
			    case 'l':
				caseopt |= SMB_CS_LOWER;
				break;
			    case 'u':
				caseopt |= SMB_CS_UPPER;
				break;
			    default:
		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
				    optarg[0]);
			}
			break;
		    default:
			usage();
		}
	}

	if (optind == argc - 2)
		optind++;
	
	if (optind != argc - 1)
		usage();
	realpath(argv[optind], mount_point);

	if (stat(mount_point, &st) == -1)
		err(EX_OSERR, "could not find mount point %s", mount_point);
	if (!S_ISDIR(st.st_mode)) {
		errno = ENOTDIR;
		err(EX_OSERR, "can't mount on %s", mount_point);
	}
/*
	if (smb_getextattr(mount_point, &einfo) == 0)
		errx(EX_OSERR, "can't mount on %s twice", mount_point);
*/
	if (uid == (uid_t)-1)
		uid = st.st_uid;
	if (gid == (gid_t)-1)
		gid = st.st_gid;
	if (file_mode == 0 )
		file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
	if (dir_mode == 0) {
		dir_mode = file_mode;
		if (dir_mode & S_IRUSR)
			dir_mode |= S_IXUSR;
		if (dir_mode & S_IRGRP)
			dir_mode |= S_IXGRP;
		if (dir_mode & S_IROTH)
			dir_mode |= S_IXOTH;
	}
	/*
	 * For now, let connection be private for this mount
	 */
	ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE;
	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */
	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid;
	opt = 0;
	if (dir_mode & S_IXGRP)
		opt |= SMBM_EXECGRP;
	if (dir_mode & S_IXOTH)
		opt |= SMBM_EXECOTH;
	ctx->ct_ssn.ioc_rights |= opt;
	ctx->ct_sh.ioc_rights |= opt;
	error = smb_ctx_resolve(ctx);
	if (error)
		exit(1);
	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
	if (error) {
		exit(1);
	}

	fd = ctx->ct_fd;

	build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1);
	build_iovec(&iov, &iovlen, "fspath", mount_point, -1);
	build_iovec_argf(&iov, &iovlen, "fd", "%d", fd);
	build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1);
	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
	build_iovec_argf(&iov, &iovlen, "gid", "%d", gid);
	build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode);
	build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode);
	build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt);
	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg); 

	error = nmount(iov, iovlen, mntflags);
	smb_ctx_done(ctx);
	if (error) {
		smb_error("mount error: %s %s", error, mount_point, errmsg);
		exit(1);
	}
	return 0;
}