Ejemplo n.º 1
0
static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id,
		      unsigned char *buf)
{
	struct ext2_super_block *es;

	es = (struct ext2_super_block *)buf;

	/* Distinguish between ext3 and ext2 */
	if ((blkid_le32(es->s_feature_compat) &
	      EXT3_FEATURE_COMPAT_HAS_JOURNAL))
		return -BLKID_ERR_PARAM;

	/* Any features which ext2 doesn't understand */
	if ((blkid_le32(es->s_feature_ro_compat) &
	     EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
	    (blkid_le32(es->s_feature_incompat) &
	     EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
		return -BLKID_ERR_PARAM;

	/* 
	 * If ext2 is not present, but ext4 or ext4dev are, then
	 * disclaim we are ext2
	 */
	if (!system_supports_ext2() &&
	    (system_supports_ext4() || system_supports_ext4dev()) &&
	    linux_version_code() >= EXT4_SUPPORTS_EXT2)
		return -BLKID_ERR_PARAM;

	get_ext2_info(probe->dev, id, buf);
	return 0;
}
Ejemplo n.º 2
0
static int nfs_append_sloppy_option(struct mount_options *options)
{
	if (!sloppy || linux_version_code() < MAKE_VERSION(2, 6, 27))
		return 1;

	if (po_append(options, "sloppy") == PO_FAILED)
		return 0;
	return 1;
}
Ejemplo n.º 3
0
int
create_autofs_service(void)
{
  hash_init();

  /* not the best place, but... */
  if (linux_version_code() < KERNEL_VERSION(2,4,0))
    bind_works = 0;

  return 0;
}
Ejemplo n.º 4
0
int
svcgssd_limit_krb5_enctypes(void)
{
	u_int maj_stat, min_stat;
	krb5_enctype old_kernel_enctypes[] = {
		ENCTYPE_DES_CBC_CRC,
		ENCTYPE_DES_CBC_MD5,
		ENCTYPE_DES_CBC_MD4 };
	krb5_enctype new_kernel_enctypes[] = {
		ENCTYPE_AES256_CTS_HMAC_SHA1_96,
		ENCTYPE_AES128_CTS_HMAC_SHA1_96,
		ENCTYPE_DES3_CBC_SHA1,
		ENCTYPE_ARCFOUR_HMAC,
		ENCTYPE_DES_CBC_CRC,
		ENCTYPE_DES_CBC_MD5,
		ENCTYPE_DES_CBC_MD4 };
	krb5_enctype *default_enctypes, *enctypes;
	int default_num_enctypes, num_enctypes;


	if (linux_version_code() < MAKE_VERSION(2, 6, 35)) {
		default_enctypes = old_kernel_enctypes;
		default_num_enctypes =
			sizeof(old_kernel_enctypes) / sizeof(old_kernel_enctypes[0]);
	} else {
		default_enctypes = new_kernel_enctypes;
		default_num_enctypes =
			sizeof(new_kernel_enctypes) / sizeof(new_kernel_enctypes[0]);
	}

	get_kernel_supported_enctypes();

	if (parsed_enctypes != NULL) {
		enctypes = parsed_enctypes;
		num_enctypes = parsed_num_enctypes;
		printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
			"enctypes from the kernel\n", __func__, num_enctypes);
	} else {
		enctypes = default_enctypes;
		num_enctypes = default_num_enctypes;
		printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
			"enctypes from defaults\n", __func__, num_enctypes);
	}

	maj_stat = set_allowable_enctypes(&min_stat, gssd_creds,
			&krb5oid, num_enctypes, enctypes);
	if (maj_stat != GSS_S_COMPLETE) {
		printerr(1, "WARNING: gss_set_allowable_enctypes failed\n");
		pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes",
			maj_stat, min_stat, &krb5oid);
		return -1;
	}
	return 0;
}
Ejemplo n.º 5
0
/*
 * Unfortunately, the kernel prints annoying console messages
 * in case of an unexpected nfs mount version (instead of
 * just returning some error).  Therefore we'll have to try
 * and figure out what version the kernel expects.
 *
 * Variables:
 *	KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
 *	NFS_MOUNT_VERSION: these nfsmount sources at compile time
 *	nfs_mount_version: version this source and running kernel can handle
 */
static void
find_kernel_nfs_mount_version(void) {
	int kernel_version = linux_version_code();

	if (kernel_version) {
	     if (kernel_version < MAKE_VERSION(2,1,32))
		  nfs_mount_version = 1;
	     else
		  nfs_mount_version = 3;
	}
	if (nfs_mount_version > NFS_MOUNT_VERSION)
	     nfs_mount_version = NFS_MOUNT_VERSION;
}
Ejemplo n.º 6
0
static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id,
		      unsigned char *buf)
{
	struct ext2_super_block *es;
	es = (struct ext2_super_block *)buf;

	/* Distinguish from jbd */
	if (blkid_le32(es->s_feature_incompat) &
	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
		return -BLKID_ERR_PARAM;

	/* 
	 * If the filesystem does not have a journal and ext2 is not
	 * present, then force this to be detected as an ext2
	 * filesystem.
	 */
	if (!(blkid_le32(es->s_feature_compat) &
	      EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
	    !system_supports_ext2() && system_supports_ext4() &&
	    linux_version_code() >= EXT4_SUPPORTS_EXT2)
		goto force_ext4;

	/* Ext4 has at least one feature which ext3 doesn't understand */
	if (!(blkid_le32(es->s_feature_ro_compat) &
	      EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
	    !(blkid_le32(es->s_feature_incompat) &
	      EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
		return -BLKID_ERR_PARAM;

force_ext4:
	/*
	 * If the filesystem is a OK for use by in-development
	 * filesystem code, and ext4dev is supported or ext4 is not
	 * supported, then don't call ourselves ext4, so we can redo
	 * the detection and mark the filesystem as ext4dev.
	 *
	 * If the filesystem is marked as in use by production
	 * filesystem, then it can only be used by ext4 and NOT by
	 * ext4dev.
	 */
	if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
		if (system_supports_ext4dev() || !system_supports_ext4())
			return -BLKID_ERR_PARAM;
	}
    	get_ext2_info(probe->dev, id, buf);
	return 0;
}
Ejemplo n.º 7
0
static int probe_ext4dev(struct blkid_probe *probe,
			 struct blkid_magic *id,
			 unsigned char *buf)
{
	struct ext2_super_block *es;
	es = (struct ext2_super_block *)buf;

	/* Distinguish from jbd */
	if (blkid_le32(es->s_feature_incompat) &
	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
		return -BLKID_ERR_PARAM;

	/* 
	 * If the filesystem does not have a journal and ext2 and ext4
	 * is not present, then force this to be detected as an
	 * ext4dev filesystem.
	 */
	if (!(blkid_le32(es->s_feature_compat) &
	      EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
	    !system_supports_ext2() && !system_supports_ext4() &&
	    system_supports_ext4dev() &&
	    linux_version_code() >= EXT4_SUPPORTS_EXT2)
		goto force_ext4dev;

	/*
	 * If the filesystem is marked as OK for use by in-development
	 * filesystem code, but ext4dev is not supported, and ext4 is,
	 * then don't call ourselves ext4dev, since we should be
	 * detected as ext4 in that case.
	 *
	 * If the filesystem is marked as in use by production
	 * filesystem, then it can only be used by ext4 and NOT by
	 * ext4dev, so always disclaim we are ext4dev in that case.
	 */
	if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
		if (!system_supports_ext4dev() && system_supports_ext4())
			return -BLKID_ERR_PARAM;
	} else
		return -BLKID_ERR_PARAM;

force_ext4dev:
    	get_ext2_info(probe->dev, id, buf);
	return 0;
}
Ejemplo n.º 8
0
static int nfs_set_version(struct nfsmount_info *mi)
{
	if (!nfs_nfs_version(mi->options, &mi->version))
		return 0;

	if (strncmp(mi->type, "nfs4", 4) == 0)
		mi->version = 4;

	/*
	 * Before 2.6.32, the kernel NFS client didn't
	 * support "-t nfs vers=4" mounts, so NFS version
	 * 4 cannot be included when autonegotiating
	 * while running on those kernels.
	 */
	if (mi->version == 0 &&
	    linux_version_code() <= MAKE_VERSION(2, 6, 31))
		mi->version = 3;

	/*
	 * If we still don't know, check for version-specific
	 * mount options.
	 */
	if (mi->version == 0) {
		if (po_contains(mi->options, "mounthost") ||
		    po_contains(mi->options, "mountaddr") ||
		    po_contains(mi->options, "mountvers") ||
		    po_contains(mi->options, "mountproto"))
			mi->version = 3;
	}

	/*
	 * If enabled, see if the default version was
	 * set in the config file
	 */
	nfs_default_version(mi);
	
	return 1;
}
Ejemplo n.º 9
0
/*
 * Unfortunately, the kernel prints annoying console messages
 * in case of an unexpected nfs mount version (instead of
 * just returning some error).  Therefore we'll have to try
 * and figure out what version the kernel expects.
 *
 * Variables:
 *	NFS_MOUNT_VERSION: these nfsmount sources at compile time
 *	nfs_mount_version: version this source and running kernel can handle
 */
static int
find_kernel_nfs_mount_version(void) {
	static int kernel_version = -1;
	int nfs_mount_version = NFS_MOUNT_VERSION;

	if (kernel_version == -1)
		kernel_version = linux_version_code();

	if (kernel_version) {
	     if (kernel_version < MAKE_VERSION(2,1,32))
		  nfs_mount_version = 1;
	     else if (kernel_version < MAKE_VERSION(2,2,18))
		  nfs_mount_version = 3;
	     else if (kernel_version < MAKE_VERSION(2,3,0))
		  nfs_mount_version = 4; /* since 2.2.18pre9 */
	     else if (kernel_version < MAKE_VERSION(2,3,99))
		  nfs_mount_version = 3;
	     else
		  nfs_mount_version = 4; /* since 2.3.99pre4 */
	}
	if (nfs_mount_version > NFS_MOUNT_VERSION)
	     nfs_mount_version = NFS_MOUNT_VERSION;
	return nfs_mount_version;
}
Ejemplo n.º 10
0
int nfsmount(const char *spec, const char *node, int *flags,
	     char **extra_opts, char **mount_opts, int running_bg)
{
	static char *prev_bg_host;
	char hostdir[1024];
	CLIENT *mclient;
	char *hostname;
	char *dirname;
	char *old_opts;
	char *mounthost=NULL;
	char new_opts[1024];
	fhandle root_fhandle;
	struct timeval total_timeout;
	enum clnt_stat clnt_stat;
	static struct nfs_mount_data data;
	char *opt, *opteq;
	int val;
	struct hostent *hp;
	struct sockaddr_in server_addr;
	struct sockaddr_in mount_server_addr;
	int msock, fsock;
	struct timeval retry_timeout;
	struct fhstatus status;
	struct stat statbuf;
	char *s;
	int port;
	int mountport;
	int bg;
	int soft;
	int intr;
	int posix;
	int nocto;
	int noac;
	int nolock;
	int retry;
	int tcp;
	int mountprog;
	int mountvers;
	int nfsprog;
	int nfsvers;
	int retval;
	time_t t;
	time_t prevt;
	time_t timeout;

	find_kernel_nfs_mount_version();

	retval = EX_FAIL;
	msock = fsock = -1;
	mclient = NULL;
	if (strlen(spec) >= sizeof(hostdir)) {
		fprintf(stderr, "mount: "
			"excessively long host:dir argument\n");
		goto fail;
	}
	strcpy(hostdir, spec);
	if ((s = (strchr(hostdir, ':')))) {
		hostname = hostdir;
		dirname = s + 1;
		*s = '\0';
	} else {
		fprintf(stderr, "mount: "
			"directory to mount not in host:dir format\n");
		goto fail;
	}

	server_addr.sin_family = AF_INET;
#if 1		/* old libc's do not have inet_aton() -- change 1 to 0 */
	if (!inet_aton(hostname, &server_addr.sin_addr))
#endif
	{
#ifdef EMBED
		fprintf(stderr, "ERROR (%d): no gethostbyname()\n", __LINE__);
#else
		if ((hp = gethostbyname(hostname)) == NULL) {
			fprintf(stderr, "mount: can't get address for %s\n",
				hostname);
			goto fail;
		} else {
			if (hp->h_length > sizeof(struct in_addr)) {
				fprintf(stderr,
					"mount: got bad hp->h_length\n");
				hp->h_length = sizeof(struct in_addr);
			}
			memcpy(&server_addr.sin_addr,
			       hp->h_addr, hp->h_length);
		}
#endif
	}

	memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));

	/* add IP address to mtab options for use when unmounting */

	s = inet_ntoa(server_addr.sin_addr);
	old_opts = *extra_opts;
	if (!old_opts)
		old_opts = "";
	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
		fprintf(stderr, "mount: "
			"excessively long option argument\n");
		goto fail;
	}
	sprintf(new_opts, "%s%saddr=%s",
		old_opts, *old_opts ? "," : "", s);
	*extra_opts = xstrdup(new_opts);

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.retrans	= 3;
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
#if NFS_MOUNT_VERSION >= 2
	data.namlen	= NAME_MAX;
#endif

	bg = 0;
	soft = 0;
	intr = 0;
	posix = 0;
	nocto = 0;
	nolock = 0;
	noac = 0;
	retry = 10000;		/* 10000 minutes ~ 1 week */
	tcp = 0;

	mountprog = MOUNTPROG;
	mountvers = MOUNTVERS;
	port = 0;
	mountport = 0;
	nfsprog = NFS_PROGRAM;
	nfsvers = NFS_VERSION;

	/* parse options */

	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
		if ((opteq = strchr(opt, '='))) {
			val = atoi(opteq + 1);	
			*opteq = '\0';
			if (!strcmp(opt, "rsize"))
				data.rsize = val;
			else if (!strcmp(opt, "wsize"))
				data.wsize = val;
			else if (!strcmp(opt, "timeo"))
				data.timeo = val;
			else if (!strcmp(opt, "retrans"))
				data.retrans = val;
			else if (!strcmp(opt, "acregmin"))
				data.acregmin = val;
			else if (!strcmp(opt, "acregmax"))
				data.acregmax = val;
			else if (!strcmp(opt, "acdirmin"))
				data.acdirmin = val;
			else if (!strcmp(opt, "acdirmax"))
				data.acdirmax = val;
			else if (!strcmp(opt, "actimeo")) {
				data.acregmin = val;
				data.acregmax = val;
				data.acdirmin = val;
				data.acdirmax = val;
			}
			else if (!strcmp(opt, "retry"))
				retry = val;
			else if (!strcmp(opt, "port"))
				port = val;
			else if (!strcmp(opt, "mountport"))
			        mountport = val;
			else if (!strcmp(opt, "mounthost"))
			        mounthost=xstrndup(opteq+1,
						  strcspn(opteq+1," \t\n\r,"));
			else if (!strcmp(opt, "mountprog"))
				mountprog = val;
			else if (!strcmp(opt, "mountvers"))
				mountvers = val;
			else if (!strcmp(opt, "nfsprog"))
				nfsprog = val;
			else if (!strcmp(opt, "nfsvers"))
				nfsvers = val;
			else if (!strcmp(opt, "namlen")) {
#if NFS_MOUNT_VERSION >= 2
				if (nfs_mount_version >= 2)
					data.namlen = val;
				else
#endif
				printf("Warning: Option namlen is not supported.\n");
			}
			else if (!strcmp(opt, "addr"))
				/* ignore */;
			else {
				printf("unknown nfs mount parameter: "
				       "%s=%d\n", opt, val);
				goto fail;
			}
		}
		else {
			val = 1;
			if (!strncmp(opt, "no", 2)) {
				val = 0;
				opt += 2;
			}
			if (!strcmp(opt, "bg")) 
				bg = val;
			else if (!strcmp(opt, "fg")) 
				bg = !val;
			else if (!strcmp(opt, "soft"))
				soft = val;
			else if (!strcmp(opt, "hard"))
				soft = !val;
			else if (!strcmp(opt, "intr"))
				intr = val;
			else if (!strcmp(opt, "posix"))
				posix = val;
			else if (!strcmp(opt, "cto"))
				nocto = !val;
			else if (!strcmp(opt, "ac"))
				noac = !val;
			else if (!strcmp(opt, "tcp"))
				tcp = val;
			else if (!strcmp(opt, "udp"))
				tcp = !val;
			else if (!strcmp(opt, "lock")) {
				if (nfs_mount_version >= 3)
					nolock = !val;
				else
					printf("Warning: option nolock is not supported.\n");
			} else {
				if (!sloppy) {
					printf("unknown nfs mount option: "
					       "%s%s\n", val ? "" : "no", opt);
					goto fail;
				}
			}
		}
	}
	data.flags = (soft ? NFS_MOUNT_SOFT : 0)
		| (intr ? NFS_MOUNT_INTR : 0)
		| (posix ? NFS_MOUNT_POSIX : 0)
		| (nocto ? NFS_MOUNT_NOCTO : 0)
		| (noac ? NFS_MOUNT_NOAC : 0);
#if NFS_MOUNT_VERSION >= 2
	if (nfs_mount_version >= 2)
		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
#endif
#if NFS_MOUNT_VERSION >= 3
	if (nfs_mount_version >= 3)
		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
#endif

	/* Adjust options if none specified */
	if (!data.timeo)
		data.timeo = tcp ? 70 : 7;

#ifdef NFS_MOUNT_DEBUG
	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
		data.rsize, data.wsize, data.timeo, data.retrans);
	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
		data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
		port, bg, retry, data.flags);
	printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
		mountprog, mountvers, nfsprog, nfsvers);
	printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
		(data.flags & NFS_MOUNT_SOFT) != 0,
		(data.flags & NFS_MOUNT_INTR) != 0,
		(data.flags & NFS_MOUNT_POSIX) != 0,
		(data.flags & NFS_MOUNT_NOCTO) != 0,
		(data.flags & NFS_MOUNT_NOAC) != 0);
#if NFS_MOUNT_VERSION >= 2
	printf("tcp = %d\n",
		(data.flags & NFS_MOUNT_TCP) != 0);
#endif
#endif

	data.version = nfs_mount_version;
	*mount_opts = (char *) &data;

	if (*flags & MS_REMOUNT)
		return 0;

	/*
	 * If the previous mount operation on the same host was
	 * backgrounded, and the "bg" for this mount is also set,
	 * give up immediately, to avoid the initial timeout.
	 */
	if (bg && !running_bg &&
	    prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
		if (retry > 0)
			retval = EX_BG;
		return retval;
	}

	/* create mount deamon client */
	/* See if the nfs host = mount host. */
	if (mounthost) {
	  if (mounthost[0] >= '0' && mounthost[0] <= '9') {
	    mount_server_addr.sin_family = AF_INET;
	    mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
	  } else {
#ifdef EMBED
		  fprintf(stderr, "ERROR (%d): no gethostbyname()\n", __LINE__);
#else
		  if ((hp = gethostbyname(mounthost)) == NULL) {
			  fprintf(stderr, "mount: can't get address for %s\n",
				  hostname);
			  goto fail;
		  } else {
			  if (hp->h_length > sizeof(struct in_addr)) {
				  fprintf(stderr,
					  "mount: got bad hp->h_length?\n");
				  hp->h_length = sizeof(struct in_addr);
			  }
			  mount_server_addr.sin_family = AF_INET;
			  memcpy(&mount_server_addr.sin_addr,
				 hp->h_addr, hp->h_length);
		  }
#endif
	  }
	}

	/*
	 * The following loop implements the mount retries. On the first
	 * call, "running_bg" is 0. When the mount times out, and the
	 * "bg" option is set, the exit status EX_BG will be returned.
	 * For a backgrounded mount, there will be a second call by the
	 * child process with "running_bg" set to 1.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 *
	 * Only the first error message will be displayed.
	 */
	retry_timeout.tv_sec = 3;
	retry_timeout.tv_usec = 0;
	total_timeout.tv_sec = 20;
	total_timeout.tv_usec = 0;
	timeout = time(NULL) + 60 * retry;
	prevt = 0;
	t = 30;
	val = 1;
	for (;;) {
		if (bg && stat(node, &statbuf) == -1) {
			if (running_bg) {
				sleep(val);	/* 1, 2, 4, 8, 16, 30, ... */
				val *= 2;
				if (val > 30)
					val = 30;
			}
		} else {
			/* be careful not to use too many CPU cycles */
			if (t - prevt < 30)
				sleep(30);

			/* contact the mount daemon via TCP */
			mount_server_addr.sin_port = htons(mountport);
			msock = RPC_ANYSOCK;
			mclient = clnttcp_create(&mount_server_addr,
						 mountprog, mountvers,
						 &msock, 0, 0);

			/* if this fails, contact the mount daemon via UDP */
			if (!mclient) {
				mount_server_addr.sin_port = htons(mountport);
				msock = RPC_ANYSOCK;
				mclient = clntudp_create(&mount_server_addr,
							 mountprog, mountvers,
							 retry_timeout, &msock);
			}
			if (mclient) {
				/* try to mount hostname:dirname */
				mclient->cl_auth = authunix_create_default();
				clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
					(xdrproc_t) xdr_dirpath, (caddr_t) &dirname,
					(xdrproc_t) xdr_fhstatus, (caddr_t) &status,
					total_timeout);
				if (clnt_stat == RPC_SUCCESS)
					break;		/* we're done */
				if (errno != ECONNREFUSED) {
					clnt_perror(mclient, "mount");
					goto fail;	/* don't retry */
				}
				if (!running_bg && prevt == 0)
					clnt_perror(mclient, "mount");
				auth_destroy(mclient->cl_auth);
				clnt_destroy(mclient);
				mclient = 0;
				close(msock);
			} else {
				if (!running_bg && prevt == 0)
					clnt_pcreateerror("mount");
			}
			prevt = t;
		}
		if (!bg)
		        goto fail;
		if (!running_bg) {
			prev_bg_host = xstrdup(hostname);
			if (retry > 0)
				retval = EX_BG;
			goto fail;
		}
		t = time(NULL);
		if (t >= timeout)
			goto fail;
	}

	if (status.fhs_status != 0) {
		fprintf(stderr,
			"mount: %s:%s failed, reason given by server: %s\n",
			hostname, dirname, nfs_strerror(status.fhs_status));
		goto fail;
	}
	memcpy((char *) &root_fhandle, (char *) status.fhstatus_u.fhs_fhandle,
		sizeof (root_fhandle));

	/* create nfs socket for kernel */

	if (tcp) {
		if (nfs_mount_version < 3) {
	     		printf("NFS over TCP is not supported.\n");
			goto fail;
		}
		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	} else
		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fsock < 0) {
		perror("nfs socket");
		goto fail;
	}
	if (bindresvport(fsock, 0) < 0) {
		perror("nfs bindresvport");
		goto fail;
	}
	if (port == 0) {
		server_addr.sin_port = PMAPPORT;
		port = pmap_getport(&server_addr, nfsprog, nfsvers,
			tcp ? IPPROTO_TCP : IPPROTO_UDP);
		if (port == 0)
			port = NFS_PORT;
#ifdef NFS_MOUNT_DEBUG
		else
			printf("used portmapper to find NFS port\n");
#endif
	}
#ifdef NFS_MOUNT_DEBUG
	printf("using port %d for nfs deamon\n", port);
#endif
	server_addr.sin_port = htons(port);
	 /*
	  * connect() the socket for kernels 1.3.10 and below only,
	  * to avoid problems with multihomed hosts.
	  * --Swen
	  */
	if (linux_version_code() <= 66314
	    && connect(fsock, (struct sockaddr *) &server_addr,
		       sizeof (server_addr)) < 0) {
		perror("nfs connect");
		goto fail;
	}

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.root, (char *) &root_fhandle,
		sizeof (root_fhandle));
	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

	/* clean up */

	auth_destroy(mclient->cl_auth);
	clnt_destroy(mclient);
	close(msock);
	return 0;

	/* abort */

fail:
	if (msock != -1) {
		if (mclient) {
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
		}
		close(msock);
	}
	if (fsock != -1)
		close(fsock);
	return retval;
}	
Ejemplo n.º 11
0
int nfsmount(const char *spec, const char *node, int *flags,
	     char **extra_opts, char **mount_opts, int *nfs_mount_vers,
	     int running_bg)
{
	static char *prev_bg_host;
	char hostdir[1024];
	CLIENT *mclient;
	char *hostname, *dirname, *old_opts, *mounthost = NULL;
	char new_opts[1024];
	struct timeval total_timeout;
	enum clnt_stat clnt_stat;
	static struct nfs_mount_data data;
	char *opt, *opteq;
	int nfs_mount_version;
	int val;
	struct hostent *hp;
	struct sockaddr_in server_addr;
	struct sockaddr_in mount_server_addr;
	struct pmap *pm_mnt;
	int msock, fsock;
	struct timeval retry_timeout;
	union {
		struct fhstatus nfsv2;
		struct mountres3 nfsv3;
	} status;
	struct stat statbuf;
	char *s;
	int port, mountport, proto, bg, soft, intr;
	int posix, nocto, noac, nolock, broken_suid;
	int retry, tcp;
	int mountprog, mountvers, nfsprog, nfsvers;
	int retval;
	time_t t;
	time_t prevt;
	time_t timeout;

	/* The version to try is either specified or 0
	   In case it is 0 we tell the caller what we tried */
	if (!*nfs_mount_vers)
		*nfs_mount_vers = find_kernel_nfs_mount_version();
	nfs_mount_version = *nfs_mount_vers;

	retval = EX_FAIL;
	msock = fsock = -1;
	mclient = NULL;
	if (strlen(spec) >= sizeof(hostdir)) {
		fprintf(stderr, _("mount: "
				  "excessively long host:dir argument\n"));
		goto fail;
	}
	strcpy(hostdir, spec);
	if ((s = strchr(hostdir, ':'))) {
		hostname = hostdir;
		dirname = s + 1;
		*s = '\0';
		/* Ignore all but first hostname in replicated mounts
		   until they can be fully supported. ([email protected]) */
		if ((s = strchr(hostdir, ','))) {
			*s = '\0';
			fprintf(stderr,
				_("mount: warning: "
				  "multiple hostnames not supported\n"));
		}
	} else {
		fprintf(stderr,
			_("mount: "
			  "directory to mount not in host:dir format\n"));
		goto fail;
	}

	server_addr.sin_family = AF_INET;
#ifdef HAVE_inet_aton
	if (!inet_aton(hostname, &server_addr.sin_addr))
#endif
	{
		if ((hp = gethostbyname(hostname)) == NULL) {
			fprintf(stderr, _("mount: can't get address for %s\n"),
				hostname);
			goto fail;
		} else {
			if (hp->h_length > sizeof(struct in_addr)) {
				fprintf(stderr,
					_("mount: got bad hp->h_length\n"));
				hp->h_length = sizeof(struct in_addr);
			}
			memcpy(&server_addr.sin_addr,
			       hp->h_addr, hp->h_length);
		}
	}

	memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));

	/* add IP address to mtab options for use when unmounting */

	s = inet_ntoa(server_addr.sin_addr);
	old_opts = *extra_opts;
	if (!old_opts)
		old_opts = "";
	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
		fprintf(stderr, _("mount: "
				  "excessively long option argument\n"));
		goto fail;
	}
	sprintf(new_opts, "%s%saddr=%s",
		old_opts, *old_opts ? "," : "", s);
	*extra_opts = xstrdup(new_opts);

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.retrans	= 3;
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
#if NFS_MOUNT_VERSION >= 2
	data.namlen	= NAME_MAX;
#endif

	bg = 0;
	soft = 0;
	intr = 0;
	posix = 0;
	nocto = 0;
	nolock = 0;
	broken_suid = 0;
	noac = 0;
	retry = 10000;		/* 10000 minutes ~ 1 week */
	tcp = 0;

	mountprog = MOUNTPROG;
	mountvers = 0;
	port = 0;
	mountport = 0;
	nfsprog = NFS_PROGRAM;
	nfsvers = 0;

	/* parse options */

	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
		if ((opteq = strchr(opt, '='))) {
			val = atoi(opteq + 1);	
			*opteq = '\0';
			if (!strcmp(opt, "rsize"))
				data.rsize = val;
			else if (!strcmp(opt, "wsize"))
				data.wsize = val;
			else if (!strcmp(opt, "timeo"))
				data.timeo = val;
			else if (!strcmp(opt, "retrans"))
				data.retrans = val;
			else if (!strcmp(opt, "acregmin"))
				data.acregmin = val;
			else if (!strcmp(opt, "acregmax"))
				data.acregmax = val;
			else if (!strcmp(opt, "acdirmin"))
				data.acdirmin = val;
			else if (!strcmp(opt, "acdirmax"))
				data.acdirmax = val;
			else if (!strcmp(opt, "actimeo")) {
				data.acregmin = val;
				data.acregmax = val;
				data.acdirmin = val;
				data.acdirmax = val;
			}
			else if (!strcmp(opt, "retry"))
				retry = val;
			else if (!strcmp(opt, "port"))
				port = val;
			else if (!strcmp(opt, "mountport"))
			        mountport = val;
			else if (!strcmp(opt, "mounthost"))
			        mounthost=xstrndup(opteq+1,
						   strcspn(opteq+1," \t\n\r,"));
			else if (!strcmp(opt, "mountprog"))
				mountprog = val;
			else if (!strcmp(opt, "mountvers"))
				mountvers = val;
			else if (!strcmp(opt, "nfsprog"))
				nfsprog = val;
			else if (!strcmp(opt, "nfsvers") ||
				 !strcmp(opt, "vers"))
				nfsvers = val;
			else if (!strcmp(opt, "proto")) {
				if (!strncmp(opteq+1, "tcp", 3))
					tcp = 1;
				else if (!strncmp(opteq+1, "udp", 3))
					tcp = 0;
				else
					printf(_("Warning: Unrecognized proto= option.\n"));
			} else if (!strcmp(opt, "namlen")) {
#if NFS_MOUNT_VERSION >= 2
				if (nfs_mount_version >= 2)
					data.namlen = val;
				else
#endif
					printf(_("Warning: Option namlen is not supported.\n"));
			} else if (!strcmp(opt, "addr")) {
				/* ignore */;
			} else {
				printf(_("unknown nfs mount parameter: "
					 "%s=%d\n"), opt, val);
				goto fail;
			}
		} else {
			val = 1;
			if (!strncmp(opt, "no", 2)) {
				val = 0;
				opt += 2;
			}
			if (!strcmp(opt, "bg")) 
				bg = val;
			else if (!strcmp(opt, "fg")) 
				bg = !val;
			else if (!strcmp(opt, "soft"))
				soft = val;
			else if (!strcmp(opt, "hard"))
				soft = !val;
			else if (!strcmp(opt, "intr"))
				intr = val;
			else if (!strcmp(opt, "posix"))
				posix = val;
			else if (!strcmp(opt, "cto"))
				nocto = !val;
			else if (!strcmp(opt, "ac"))
				noac = !val;
			else if (!strcmp(opt, "tcp"))
				tcp = val;
			else if (!strcmp(opt, "udp"))
				tcp = !val;
			else if (!strcmp(opt, "lock")) {
				if (nfs_mount_version >= 3)
					nolock = !val;
				else
					printf(_("Warning: option nolock is not supported.\n"));
			} else if (!strcmp(opt, "broken_suid")) {
				broken_suid = val;
			} else {
				if (!sloppy) {
					printf(_("unknown nfs mount option: "
						 "%s%s\n"), val ? "" : "no", opt);
					goto fail;
				}
			}
		}
	}
	proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;

	data.flags = (soft ? NFS_MOUNT_SOFT : 0)
		| (intr ? NFS_MOUNT_INTR : 0)
		| (posix ? NFS_MOUNT_POSIX : 0)
		| (nocto ? NFS_MOUNT_NOCTO : 0)
		| (noac ? NFS_MOUNT_NOAC : 0);
#if NFS_MOUNT_VERSION >= 2
	if (nfs_mount_version >= 2)
		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
#endif
#if NFS_MOUNT_VERSION >= 3
	if (nfs_mount_version >= 3)
		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
#endif
#if NFS_MOUNT_VERSION >= 4
	if (nfs_mount_version >= 4)
		data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
#endif
	if (nfsvers > MAX_NFSPROT) {
		fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
		return 0;
	}
	if (mountvers > MAX_NFSPROT) {
		fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
		return 0;
	}
	if (nfsvers && !mountvers)
		mountvers = (nfsvers < 3) ? 1 : nfsvers;
	if (nfsvers && nfsvers < mountvers)
		mountvers = nfsvers;

	/* Adjust options if none specified */
	if (!data.timeo)
		data.timeo = tcp ? 70 : 7;

#ifdef NFS_MOUNT_DEBUG
	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
	       data.rsize, data.wsize, data.timeo, data.retrans);
	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
	       port, bg, retry, data.flags);
	printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
	       mountprog, mountvers, nfsprog, nfsvers);
	printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
	       (data.flags & NFS_MOUNT_SOFT) != 0,
	       (data.flags & NFS_MOUNT_INTR) != 0,
	       (data.flags & NFS_MOUNT_POSIX) != 0,
	       (data.flags & NFS_MOUNT_NOCTO) != 0,
	       (data.flags & NFS_MOUNT_NOAC) != 0);
#if NFS_MOUNT_VERSION >= 2
	printf("tcp = %d\n",
	       (data.flags & NFS_MOUNT_TCP) != 0);
#endif
#endif

	data.version = nfs_mount_version;
	*mount_opts = (char *) &data;

	if (*flags & MS_REMOUNT)
		return 0;

	/*
	 * If the previous mount operation on the same host was
	 * backgrounded, and the "bg" for this mount is also set,
	 * give up immediately, to avoid the initial timeout.
	 */
	if (bg && !running_bg &&
	    prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
		if (retry > 0)
			retval = EX_BG;
		return retval;
	}

	/* create mount deamon client */
	/* See if the nfs host = mount host. */
	if (mounthost) {
		if (mounthost[0] >= '0' && mounthost[0] <= '9') {
			mount_server_addr.sin_family = AF_INET;
			mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
		} else {
			if ((hp = gethostbyname(mounthost)) == NULL) {
				fprintf(stderr, _("mount: can't get address for %s\n"),
					mounthost);
				goto fail;
			} else {
				if (hp->h_length > sizeof(struct in_addr)) {
					fprintf(stderr,
						_("mount: got bad hp->h_length?\n"));
					hp->h_length = sizeof(struct in_addr);
				}
				mount_server_addr.sin_family = AF_INET;
				memcpy(&mount_server_addr.sin_addr,
				       hp->h_addr, hp->h_length);
			}
		}
	}

	/*
	 * The following loop implements the mount retries. On the first
	 * call, "running_bg" is 0. When the mount times out, and the
	 * "bg" option is set, the exit status EX_BG will be returned.
	 * For a backgrounded mount, there will be a second call by the
	 * child process with "running_bg" set to 1.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 *
	 * Only the first error message will be displayed.
	 */
	retry_timeout.tv_sec = 3;
	retry_timeout.tv_usec = 0;
	total_timeout.tv_sec = 20;
	total_timeout.tv_usec = 0;
	timeout = time(NULL) + 60 * retry;
	prevt = 0;
	t = 30;
	val = 1;

	for (;;) {
		if (bg && stat(node, &statbuf) == -1) {
			/* no mount point yet - sleep */
			if (running_bg) {
				sleep(val);	/* 1, 2, 4, 8, 16, 30, ... */
				val *= 2;
				if (val > 30)
					val = 30;
			}
		} else {
			/* be careful not to use too many CPU cycles */
			if (t - prevt < 30)
				sleep(30);

			pm_mnt = get_mountport(&mount_server_addr,
					       mountprog,
					       mountvers,
					       proto,
					       mountport,
					       nfs_mount_version);

			/* contact the mount daemon via TCP */
			mount_server_addr.sin_port = htons(pm_mnt->pm_port);
			msock = RPC_ANYSOCK;

			switch (pm_mnt->pm_prot) {
			case IPPROTO_UDP:
				mclient = clntudp_create(&mount_server_addr,
							 pm_mnt->pm_prog,
							 pm_mnt->pm_vers,
							 retry_timeout,
							 &msock);
				if (mclient)
					break;
				mount_server_addr.sin_port =
					htons(pm_mnt->pm_port);
				msock = RPC_ANYSOCK;
			case IPPROTO_TCP:
				mclient = clnttcp_create(&mount_server_addr,
							 pm_mnt->pm_prog,
							 pm_mnt->pm_vers,
							 &msock, 0, 0);
				break;
			default:
				mclient = 0;
			}

			if (mclient) {
				/* try to mount hostname:dirname */
				mclient->cl_auth = authunix_create_default();

				/* make pointers in xdr_mountres3 NULL so
				 * that xdr_array allocates memory for us
				 */
				memset(&status, 0, sizeof(status));

				if (pm_mnt->pm_vers == 3)
					clnt_stat = clnt_call(mclient,
						     MOUNTPROC3_MNT,
						     (xdrproc_t) xdr_dirpath,
						     (caddr_t) &dirname,
						     (xdrproc_t) xdr_mountres3,
						     (caddr_t) &status,
						     total_timeout);
				else
					clnt_stat = clnt_call(mclient,
						     MOUNTPROC_MNT,
						     (xdrproc_t) xdr_dirpath,
						     (caddr_t) &dirname,
						     (xdrproc_t) xdr_fhstatus,
						     (caddr_t) &status,
						     total_timeout);

				if (clnt_stat == RPC_SUCCESS)
					break;		/* we're done */
#if 0
				/* errno? who sets errno? */
				/* this fragment breaks bg mounting */
				if (errno != ECONNREFUSED) {
					clnt_perror(mclient, "mount");
					goto fail;	/* don't retry */
				}
#endif
				if (!running_bg && prevt == 0)
					clnt_perror(mclient, "mount");
				auth_destroy(mclient->cl_auth);
				clnt_destroy(mclient);
				mclient = 0;
				close(msock);
			} else {
				if (!running_bg && prevt == 0)
					clnt_pcreateerror("mount");
			}
			prevt = t;
		}

		if (!bg)
		        goto fail;
		if (!running_bg) {
			prev_bg_host = xstrdup(hostname);
			if (retry > 0)
				retval = EX_BG;
			goto fail;
		}
		t = time(NULL);
		if (t >= timeout)
			goto fail;
	}
	nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;

	if (nfsvers == 2) {
		if (status.nfsv2.fhs_status != 0) {
			fprintf(stderr,
				"mount: %s:%s failed, reason given by server: %s\n",
				hostname, dirname,
				nfs_strerror(status.nfsv2.fhs_status));
			goto fail;
		}
		memcpy(data.root.data,
		       (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#if NFS_MOUNT_VERSION >= 4
		data.root.size = NFS_FHSIZE;
		memcpy(data.old_root.data,
		       (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#endif
	} else {
#if NFS_MOUNT_VERSION >= 4
		fhandle3 *fhandle;
		if (status.nfsv3.fhs_status != 0) {
			fprintf(stderr,
				"mount: %s:%s failed, reason given by server: %s\n",
				hostname, dirname,
				nfs_strerror(status.nfsv3.fhs_status));
			goto fail;
		}
		fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
		memset(data.old_root.data, 0, NFS_FHSIZE);
		memset(&data.root, 0, sizeof(data.root));
		data.root.size = fhandle->fhandle3_len;
		memcpy(data.root.data,
		       (char *) fhandle->fhandle3_val,
		       fhandle->fhandle3_len);

		data.flags |= NFS_MOUNT_VER3;
#endif
	}

	/* create nfs socket for kernel */

	if (tcp) {
		if (nfs_mount_version < 3) {
	     		printf(_("NFS over TCP is not supported.\n"));
			goto fail;
		}
		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	} else
		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fsock < 0) {
		perror(_("nfs socket"));
		goto fail;
	}
	if (bindresvport(fsock, 0) < 0) {
		perror(_("nfs bindresvport"));
		goto fail;
	}
	if (port == 0) {
		server_addr.sin_port = PMAPPORT;
		port = pmap_getport(&server_addr, nfsprog, nfsvers,
				    tcp ? IPPROTO_TCP : IPPROTO_UDP);
#if 1
		/* Here we check to see if user is mounting with the
		 * tcp option.  If so, and if the portmap returns a
		 * '0' for port (service unavailable), we then exit,
		 * notifying the user, rather than hanging up mount.
		 */
		if (port == 0 && tcp == 1) {
			perror(_("nfs server reported service unavailable"));
			goto fail;
		}
#endif

		if (port == 0)
			port = NFS_PORT;
#ifdef NFS_MOUNT_DEBUG
		else
			printf(_("used portmapper to find NFS port\n"));
#endif
	}
#ifdef NFS_MOUNT_DEBUG
	printf(_("using port %d for nfs deamon\n"), port);
#endif
	server_addr.sin_port = htons(port);
	/*
	 * connect() the socket for kernels 1.3.10 and below only,
	 * to avoid problems with multihomed hosts.
	 * --Swen
	 */
	if (linux_version_code() <= 66314
	    && connect(fsock, (struct sockaddr *) &server_addr,
		       sizeof (server_addr)) < 0) {
		perror(_("nfs connect"));
		goto fail;
	}

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

	/* clean up */

	auth_destroy(mclient->cl_auth);
	clnt_destroy(mclient);
	close(msock);
	return 0;

	/* abort */

 fail:
	if (msock != -1) {
		if (mclient) {
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
		}
		close(msock);
	}
	if (fsock != -1)
		close(fsock);
	return retval;
}	
Ejemplo n.º 12
0
int
main(int argc, char * argv[]) {
	int read_value = 0xbeefbeef, write_value = 0xbeefbeef, bomb_value = 0xbeefbeef;
	int read_set, write_set, bomb_set, set;
	char * devname;
	int fd;
	blkelv_ioctl_arg_t elevator;

	read_set = write_set = bomb_set = set = 0;

	for (;;) {
		int opt;

		opt = getopt(argc, argv, "r:w:b:hv");
		if (opt == -1)
			break;
		switch (opt) {
		case 'r':
			read_value = atoi(optarg);
			read_set = set = 1;
			break;
		case 'w':
			write_value = atoi(optarg);
			write_set = set = 1;
			break;
		case 'b':
			bomb_value = atoi(optarg);
			bomb_set = set = 1;
			break;

		case 'h':
			usage(), exit(0);
		case 'v':
			version(), exit(0);

		case '?':
		default:
		case ':':
			fprintf(stderr, "parse error\n");
			exit(1);
		}
	}

	if (optind >= argc)
		fprintf(stderr, "missing blockdevice, use -h for help\n"), exit(1);
		
	while (optind < argc) {
		devname = argv[optind++];

		fd = open(devname, O_RDONLY|O_NONBLOCK);
		if (fd < 0) {
			perror("open");
			break;
		}

		/* mmj: If we get EINVAL it's not a 2.4 kernel, so warn about
		   that and exit. It should return ENOTTY however, so check for
		   that as well in case it gets corrected in the future */

		if (ioctl(fd, BLKELVGET, &elevator) < 0) {
			int errsv = errno;
			perror("ioctl get");
			if ((errsv == EINVAL || errsv == ENOTTY) &&
			    linux_version_code() >= MAKE_VERSION(2,5,58)) {
				fprintf(stderr,
					"\nelvtune is only useful on older "
					"kernels;\nfor 2.6 use IO scheduler "
					"sysfs tunables instead..\n");
			}
			break;
		}

		if (set) {
			if (read_set)
				elevator.read_latency = read_value;
			if (write_set)
				elevator.write_latency = write_value;
			if (bomb_set)
				elevator.max_bomb_segments = bomb_value;

			if (ioctl(fd, BLKELVSET, &elevator) < 0) {
				perror("ioctl set");
				break;
			}
			if (ioctl(fd, BLKELVGET, &elevator) < 0) {
				perror("ioctl reget");
				break;
			}
		}

		printf("\n%s elevator ID\t\t%d\n", devname, elevator.queue_ID);
		printf("\tread_latency:\t\t%d\n", elevator.read_latency);
		printf("\twrite_latency:\t\t%d\n", elevator.write_latency);
		printf("\tmax_bomb_segments:\t%d\n\n", elevator.max_bomb_segments);

		if (close(fd) < 0) {
			perror("close");
			break;
		}
	}

	return 0;
}
Ejemplo n.º 13
0
int
nfsmount(const char *spec, const char *node, int flags,
	 char **extra_opts, int fake, int running_bg)
{
	char hostdir[1024];
	char *hostname, *dirname, *old_opts, *mounthost = NULL;
	char new_opts[1024], cbuf[1024];
	static struct nfs_mount_data data;
	int val;
	static int doonce = 0;

	clnt_addr_t mnt_server = { &mounthost, };
	clnt_addr_t nfs_server = { &hostname, };
	struct sockaddr_in *nfs_saddr = &nfs_server.saddr;
	struct pmap  *mnt_pmap = &mnt_server.pmap,
		     *nfs_pmap = &nfs_server.pmap;
	struct pmap  save_mnt, save_nfs;

	int fsock = -1;

	mntres_t mntres;

	struct stat statbuf;
	char *s;
	int bg, retry;
	int retval = EX_FAIL;
	time_t t;
	time_t prevt;
	time_t timeout;

	if (strlen(spec) >= sizeof(hostdir)) {
		nfs_error(_("%s: excessively long host:dir argument"),
				progname);
		goto fail;
	}
	strcpy(hostdir, spec);
	if ((s = strchr(hostdir, ':'))) {
		hostname = hostdir;
		dirname = s + 1;
		*s = '\0';
		/* Ignore all but first hostname in replicated mounts
		   until they can be fully supported. ([email protected]) */
		if ((s = strchr(hostdir, ','))) {
			*s = '\0';
			nfs_error(_("%s: warning: "
				  "multiple hostnames not supported"),
					progname);
		}
	} else {
		nfs_error(_("%s: directory to mount not in host:dir format"),
				progname);
		goto fail;
	}

	if (!nfs_gethostbyname(hostname, nfs_saddr))
		goto fail;
	mounthost = hostname;
	memcpy (&mnt_server.saddr, nfs_saddr, sizeof (mnt_server.saddr));

	/* add IP address to mtab options for use when unmounting */

	s = inet_ntoa(nfs_saddr->sin_addr);
	old_opts = *extra_opts;
	if (!old_opts)
		old_opts = "";

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
#if NFS_MOUNT_VERSION >= 2
	data.namlen	= NAME_MAX;
#endif

	bg = 0;
	retry = -1;

	memset(mnt_pmap, 0, sizeof(*mnt_pmap));
	mnt_pmap->pm_prog = MOUNTPROG;
	memset(nfs_pmap, 0, sizeof(*nfs_pmap));
	nfs_pmap->pm_prog = NFS_PROGRAM;

	/* parse options */
	new_opts[0] = 0;
	if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
			   new_opts, sizeof(new_opts)))
		goto fail;
	if (!nfsmnt_check_compat(nfs_pmap, mnt_pmap))
		goto fail;

	if (retry == -1) {
		if (bg)
			retry = 10000;	/* 10000 mins == ~1 week*/
		else
			retry = 2;	/* 2 min default on fg mounts */
	}

#ifdef NFS_MOUNT_DEBUG
	printf(_("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n"),
	       data.rsize, data.wsize, data.timeo, data.retrans);
	printf(_("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n"),
	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
	printf(_("port = %lu, bg = %d, retry = %d, flags = %.8x\n"),
	       nfs_pmap->pm_port, bg, retry, data.flags);
	printf(_("mountprog = %lu, mountvers = %lu, nfsprog = %lu, nfsvers = %lu\n"),
	       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
	       nfs_pmap->pm_prog, nfs_pmap->pm_vers);
	printf(_("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d"),
	       (data.flags & NFS_MOUNT_SOFT) != 0,
	       (data.flags & NFS_MOUNT_INTR) != 0,
	       (data.flags & NFS_MOUNT_POSIX) != 0,
	       (data.flags & NFS_MOUNT_NOCTO) != 0,
	       (data.flags & NFS_MOUNT_NOAC) != 0);
#if NFS_MOUNT_VERSION >= 2
	printf(_(", tcp = %d"),
	       (data.flags & NFS_MOUNT_TCP) != 0);
#endif
#if NFS_MOUNT_VERSION >= 4
	printf(_(", noacl = %d"), (data.flags & NFS_MOUNT_NOACL) != 0);
#endif
#if NFS_MOUNT_VERSION >= 5
	printf(_(", sec = %u"), data.pseudoflavor);
	printf(_(", readdirplus = %d"), (data.flags & NFS_MOUNT_NORDIRPLUS) != 0);
#endif
	printf("\n");
#endif

	data.version = nfs_mount_data_version;

	if (flags & MS_REMOUNT)
		goto out_ok;

	/* create mount deamon client */

	/*
	 * The following loop implements the mount retries. On the first
	 * call, "running_bg" is 0. When the mount times out, and the
	 * "bg" option is set, the exit status EX_BG will be returned.
	 * For a backgrounded mount, there will be a second call by the
	 * child process with "running_bg" set to 1.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 *
	 * Only the first error message will be displayed.
	 */
	timeout = time(NULL) + 60 * retry;
	prevt = 0;
	t = 30;
	val = 1;

	memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
	memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
	for (;;) {
		if (bg && stat(node, &statbuf) == -1) {
			/* no mount point yet - sleep */
			if (running_bg) {
				sleep(val);	/* 1, 2, 4, 8, 16, 30, ... */
				val *= 2;
				if (val > 30)
					val = 30;
			}
		} else {
			int stat;
			/* be careful not to use too many CPU cycles */
			if (t - prevt < 30)
				sleep(30);

			stat = nfs_call_mount(&mnt_server, &nfs_server,
					      &dirname, &mntres);
			if (stat)
				break;
			memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
			memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
			prevt = t;
		}
		if (!bg) {
			switch(rpc_createerr.cf_stat){
			case RPC_TIMEDOUT:
				break;
			case RPC_SYSTEMERROR:
				if (errno == ETIMEDOUT)
					break;
			default:
				rpc_mount_errors(*nfs_server.hostname, 0, bg);
		        goto fail;
			}
			t = time(NULL);
			if (t >= timeout) {
				rpc_mount_errors(*nfs_server.hostname, 0, bg);
				goto fail;
			}
			rpc_mount_errors(*nfs_server.hostname, 1, bg);
			continue;
		}
		if (!running_bg) {
			if (retry > 0)
				retval = EX_BG;
			goto fail;
		}
		t = time(NULL);
		if (t >= timeout) {
			rpc_mount_errors(*nfs_server.hostname, 0, bg);
			goto fail;
		}
		if (doonce++ < 1)
			rpc_mount_errors(*nfs_server.hostname, 1, bg);
	}

	if (mnt_pmap->pm_vers <= 2) {
		if (mntres.nfsv2.fhs_status != 0) {
			nfs_error(_("%s: %s:%s failed, reason given by server: %s"),
					progname, hostname, dirname,
					nfs_strerror(mntres.nfsv2.fhs_status));
			goto fail;
		}
		memcpy(data.root.data,
		       (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#if NFS_MOUNT_VERSION >= 4
		data.root.size = NFS_FHSIZE;
		memcpy(data.old_root.data,
		       (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#endif
	} else {
#if NFS_MOUNT_VERSION >= 4
		mountres3_ok *mountres;
		fhandle3 *fhandle;
		int i,  n_flavors, *flavor, yum = 0;
		if (mntres.nfsv3.fhs_status != 0) {
			nfs_error(_("%s: %s:%s failed, reason given by server: %s"),
					progname, hostname, dirname,
					nfs_strerror(mntres.nfsv3.fhs_status));
			goto fail;
		}
#if NFS_MOUNT_VERSION >= 5
		mountres = &mntres.nfsv3.mountres3_u.mountinfo;
		n_flavors = mountres->auth_flavors.auth_flavors_len;
		if (n_flavors <= 0)
			goto noauth_flavors;

		flavor = mountres->auth_flavors.auth_flavors_val;
		for (i = 0; i < n_flavors; ++i) {
			/*
			 * Per RFC2623, section 2.7, we should prefer the
			 * flavour listed first.
			 * If no flavour requested, use the first simple
			 * flavour that is offered.
			 */
			if (! (data.flags & NFS_MOUNT_SECFLAVOUR) &&
			    (flavor[i] == AUTH_SYS ||
			     flavor[i] == AUTH_NONE)) {
				data.pseudoflavor = flavor[i];
				data.flags |= NFS_MOUNT_SECFLAVOUR;
			}
			if (flavor[i] == data.pseudoflavor)
				yum = 1;
#ifdef NFS_MOUNT_DEBUG
			printf(_("auth flavor %d: %d\n"), i, flavor[i]);
#endif
		}
		if (!yum) {
			nfs_error(_("%s: %s:%s failed, security flavor "
					"not supported"),
					progname, hostname, dirname);
			/* server has registered us in rmtab, send umount */
			nfs_call_umount(&mnt_server, &dirname);
			goto fail;
		}
noauth_flavors:
#endif
		fhandle = &mntres.nfsv3.mountres3_u.mountinfo.fhandle;
		memset(data.old_root.data, 0, NFS_FHSIZE);
		memset(&data.root, 0, sizeof(data.root));
		data.root.size = fhandle->fhandle3_len;
		memcpy(data.root.data,
		       (char *) fhandle->fhandle3_val,
		       fhandle->fhandle3_len);

		data.flags |= NFS_MOUNT_VER3;
#endif
	}

	if (nfs_mount_data_version == 1) {
		/* create nfs socket for kernel */
		if (nfs_pmap->pm_prot == IPPROTO_TCP)
			fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		else
			fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		if (fsock < 0) {
			perror(_("nfs socket"));
			goto fail;
		}
		if (bindresvport(fsock, 0) < 0) {
			perror(_("nfs bindresvport"));
			goto fail;
		}
	}

#ifdef NFS_MOUNT_DEBUG
	printf(_("using port %lu for nfs deamon\n"), nfs_pmap->pm_port);
#endif
	nfs_saddr->sin_port = htons(nfs_pmap->pm_port);
	/*
	 * connect() the socket for kernels 1.3.10 and below only,
	 * to avoid problems with multihomed hosts.
	 * --Swen
	 */
	if (linux_version_code() <= MAKE_VERSION(1, 3, 10) && fsock != -1
	    && connect(fsock, (struct sockaddr *) nfs_saddr,
		       sizeof (*nfs_saddr)) < 0) {
		perror(_("nfs connect"));
		goto fail;
	}

#if NFS_MOUNT_VERSION >= 2
	if (nfs_pmap->pm_prot == IPPROTO_TCP)
		data.flags |= NFS_MOUNT_TCP;
	else
		data.flags &= ~NFS_MOUNT_TCP;
#endif

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

 out_ok:
	/* Ensure we have enough padding for the following strcat()s */
	if (strlen(new_opts) + strlen(s) + 30 >= sizeof(new_opts)) {
		nfs_error(_("%s: excessively long option argument"),
				progname);
		goto fail;
	}

	snprintf(cbuf, sizeof(cbuf)-1, "addr=%s", s);
	strcat(new_opts, cbuf);

	*extra_opts = xstrdup(new_opts);

	if (!fake && !(data.flags & NFS_MOUNT_NONLM)) {
		if (!start_statd()) {
			nfs_error(_("%s: rpc.statd is not running but is "
				"required for remote locking.\n"
				"   Either use '-o nolock' to keep "
				"locks local, or start statd."),
					progname);
			goto fail;
		}
	}

	if (!fake) {
		if (mount(spec, node, "nfs",
				flags & ~(MS_USER|MS_USERS), &data)) {
			mount_error(spec, node, errno);
			goto fail;
		}
	}

	return EX_SUCCESS;

	/* abort */
 fail:
	if (fsock != -1)
		close(fsock);
	return retval;
}