4.4BSD/usr/src/contrib/diskless.nfs/diskless_setup.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1989 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Rick Macklem at The University of Guelph.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)diskless_setup.c	5.1 (Berkeley) 7/16/89";
#endif /* not lint */

#include <stdio.h>
#include <fcntl.h>
#include <netdb.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <pwd.h>
#include <grp.h>
#ifdef BSD4_4
#include <sys/socket.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <net/if.h>
#include <netinet/in.h>
#include <nfs/nfsv2.h>
#include <nfs/nfs.h>
#include <nfs/nqnfs.h>
#include <nfs/nfsdiskless.h>
#else
#include "socket.h"
#include "ucred.h"
#include "mount.h"
#include "if.h"
#include "in.h"
#include "nfsv2.h"
#include "nfs.h"
#include "nqnfs.h"
#include "nfsdiskless.h"
#endif	/* BSD4_4 */
#include "pathnames.h"

struct nfs_args def_args = {
	(struct sockaddr *)0,
	sizeof (struct sockaddr_in),
	SOCK_DGRAM,
	0,
	(nfsv2fh_t *)0,
	0,
	NFS_WSIZE,
	NFS_RSIZE,
	NFS_TIMEO,
	NFS_RETRANS,
	NFS_MAXGRPS,
	NFS_DEFRAHEAD,
	NQ_MAXLEASE,
	NQ_DEADTHRESH,
	(char *)0,
};
void nfsargs_hton(), fatal_err();

/*
 * Setup of server to handle a diskless/dataless client. Most of the work is
 * just filling in all the fields of the nfs_diskless data structure.
 * This structure is then either written to a file named "diskless.<host>"
 * or stuffed into the client's vmunix file at the specified offset.
 * For now it is a bare bones tool with command line options only.
 * NB: It will need to be compiled with the sys/<files>.h for a 4.4BSD
 *     kernel, although it should be runable on most nfs Unix servers.
 *     (Except <sys/types.h> and <sys/param.h> which should be native
 *      files for the server OS)
 */

main(argc, argv)
	int argc;
	char *argv[];
{
	int fd = -1, c, i, j, sblks, sfd;
	register struct hostent *hp;
	register struct sockaddr_in *claddr, *cmaddr, *cbaddr;
	struct nfs_diskless nd;
	struct stat sb;
	struct passwd *pwd;
	struct group *grp;
	struct timeval tv;
	char **cpp;
	short ngroups;
	u_long taddr;
	char fname[MAXPATHLEN], servernm[MAXHOSTNAMELEN], *cp, buf[10240];
	u_char fh[100];
	extern int optind;
	extern char *optarg;

	/*
	 * First initialize nd with all the defaults.
	 */
	if (gethostname(servernm, MAXHOSTNAMELEN) < 0)
		fatal_err("Can't get server host name\n");
	if ((hp = gethostbyname(servernm)) == NULL)
		fatal_err("Can't get host addr\n");
	nfsargs_hton(&def_args);
	nd.swap_args = def_args;
	nd.swap_saddr.sin_addr.s_addr = *((u_long *) *hp->h_addr_list);
	nd.swap_saddr.sin_len = sizeof (struct sockaddr_in);
	nd.swap_saddr.sin_family = AF_INET;
	nd.swap_saddr.sin_port = htons(NFS_PORT);
	strncpy(nd.swap_hostnam, hp->h_name, MNAMELEN - 1);
	nd.swap_hostnam[MNAMELEN - 1] = '\0';
	nd.swap_nblks = 0;
	nd.root_args = def_args;
	nd.root_saddr.sin_len = sizeof (struct sockaddr_in);
	nd.root_saddr.sin_family = AF_INET;
	nd.root_saddr.sin_addr.s_addr = *((u_long *) *hp->h_addr_list);
	nd.root_saddr.sin_port = htons(NFS_PORT);
	strncpy(nd.root_hostnam, hp->h_name, MNAMELEN - 1);
	nd.root_hostnam[MNAMELEN - 1] = '\0';

	/*
	 * Put the current time in the structure. This should be replaced
	 * by the bootstrap server, if possible.
	 */
	gettimeofday(&tv, (struct timezone *)0);
	nd.root_time = htonl(tv.tv_sec);
	if (*argv[argc - 1] == '-' ||
		(hp = gethostbyname(argv[argc - 1])) == NULL)
		fatal_err("Can't get client addr\n");

	if (hp->h_addrtype != AF_INET || *hp->h_addr_list == NULL)
		fatal_err("Bad client hostent\n");
	strncpy(nd.my_hostnam, hp->h_name, MAXHOSTNAMELEN);
	nd.my_hostnam[MAXHOSTNAMELEN - 1] = '\0';
	claddr = (struct sockaddr_in *)&nd.myif.ifra_addr;
	cmaddr = (struct sockaddr_in *)&nd.myif.ifra_mask;
	cbaddr = (struct sockaddr_in *)&nd.myif.ifra_broadaddr;
	claddr->sin_len = sizeof (struct sockaddr_in);
	claddr->sin_family = AF_INET;
	claddr->sin_port = 0;
	cmaddr->sin_len = sizeof (struct sockaddr_in);
	cmaddr->sin_family = AF_INET;
	cmaddr->sin_port = 0;
	cbaddr->sin_len = sizeof (struct sockaddr_in);
	cbaddr->sin_family = AF_INET;
	cbaddr->sin_port = 0;
	claddr->sin_addr.s_addr = *((u_long *) *hp->h_addr_list);
	taddr = ntohl(claddr->sin_addr.s_addr);

	/*
	 * Default net mask to internet address class. Can be overridden
	 * by using the -m option.
	 */
	if (IN_CLASSA(taddr))
		cmaddr->sin_addr.s_addr = inet_addr("255.0.0.0");
	else if (IN_CLASSB(taddr))
		cmaddr->sin_addr.s_addr = inet_addr("255.255.0.0");
	else
		cmaddr->sin_addr.s_addr = inet_addr("255.255.255.0");
	nd.myif.ifra_name[0] = '\0';
	nd.mygateway.sin_len = 0;

	/*
	 * Now, process all the command line options and override defaults.
	 */
	while ((c = getopt(argc, argv, "os:h:m:a:g:l:x:r:c:")) != EOF) {
		switch (c) {
		case 'o':
			fd = 1;
			break;
		case 's':
			sblks = atoi(optarg);
			if (sblks < 0 || sblks > 500000)
				fatal_err("Swap size out of range\n");
			strcpy(fname, _PATH_SWAP);
			strcat(fname, ".");
			strcat(fname, hp->h_name);
			if ((sfd = open(fname, O_WRONLY | O_CREAT | O_TRUNC,
				0600)) < 0)
				fatal_err("Can't create swapfile\n");
			if (fchmod(sfd, 0600) < 0)
				fatal_err("Can't chmod swap file\n");
			if (fchown(sfd, -2, -2) < 0)
				fatal_err("Can't chown swap file\n");
			for (i = 0; i < sblks; ) {
				j = MIN(sblks - i, 20);
				if (write(sfd, buf, j * 512) < 0)
					fatal_err("Swapfile out of space\n");
				i += j * 512;
			}
			close(sfd);
			nd.swap_nblks = htonl(sblks);
			bzero((caddr_t)fh, 100);
			if (getfh(fname, fh) < 0)
				fatal_err("Can't get swap fh\n");
			bcopy((caddr_t)fh, nd.swap_fh, NFS_FHSIZE);
			break;
		case 'h':
			if ((taddr = inet_addr(optarg)) == -1)
				fatal_err("Bad -h addr\n");
			claddr->sin_addr.s_addr = taddr;
			break;
		case 'm':
			if ((taddr = inet_addr(optarg)) == -1)
				fatal_err("Bad -m addr\n");
			cmaddr->sin_addr.s_addr = taddr;
			break;
		case 'a':
			if ((taddr = inet_addr(optarg)) == -1)
				fatal_err("Bad -a addr\n");
			nd.swap_saddr.sin_addr.s_addr = taddr;
			nd.root_saddr.sin_addr.s_addr = taddr;
			break;
		case 'g':
			if ((taddr = inet_addr(optarg)) == -1)
				fatal_err("Bad -g addr\n");
			nd.mygateway.sin_addr.s_addr = taddr;
			nd.mygateway.sin_len = sizeof (struct sockaddr_in);
			nd.mygateway.sin_family = AF_INET;
			nd.mygateway.sin_port = 0;
			break;
		case 'l':
			strncpy(nd.myif.ifra_name, optarg, IFNAMSIZ - 1);
			nd.myif.ifra_name[IFNAMSIZ - 1] = '\0';
			break;
		case 'x':
			if ((cp = index(optarg, ':')) == (char *)0)
				fatal_err("No : in -x arg\n");
			*cp++ = '\0';
			i = atoi(cp);
			if ((fd = open(optarg, O_RDWR, 0)) < 0)
				fatal_err("Can't open for -x\n");
			if (i < 0 || fstat(fd, &sb) < 0 ||
				i > (sb.st_size - sizeof (struct nfs_diskless)))
				fatal_err("Bad -x arg\n");
			lseek(fd, i, 0);
			break;
		case 'r':
			bzero((caddr_t)fh, 100);
			if (getfh(optarg, fh) < 0)
				fatal_err("Can't get root fh\n");
			bcopy((caddr_t)fh, nd.root_fh, NFS_FHSIZE);
			break;
		case 'c':
			if (pwd = getpwnam(optarg)) {
			    nd.swap_ucred.cr_uid = htonl(pwd->pw_uid);
			    nd.swap_ucred.cr_groups[0] = htonl(pwd->pw_gid);
			    ngroups = 1;
			    setgrent();
			    while (grp = getgrent()) {
				if (grp->gr_gid == pwd->pw_gid)
				    continue;
				cpp = grp->gr_mem;
				while (*cpp) {
				    if (!strcmp(*cpp, pwd->pw_name))
					break;
				    cpp++;
				}
				if (*cpp) {
				    nd.swap_ucred.cr_groups[ngroups++] =
					htonl(grp->gr_gid);
				    if (ngroups == NGROUPS)
					break;
				}
			    }
			    endgrent();
			    nd.swap_ucred.cr_ngroups = htons(ngroups);
			} else
			    fatal_err("Swap_username bad\n");
			break;
		default:
			fprintf(stderr, "Bad arg %c\n", c);
			exit(1);
		};
	}

	/*
	 * Finish up and write it out.
	 */
	cbaddr->sin_addr.s_addr =
		(claddr->sin_addr.s_addr & cmaddr->sin_addr.s_addr) |
		 ~(cmaddr->sin_addr.s_addr);
	if (fd == -1) {
		strcpy(fname, _PATH_DISKLESS);
		strcat(fname, ".");
		strcat(fname, hp->h_name);
		if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) 
			fatal_err("Can't create diskless file\n");
	}
	if (write(fd, &nd, sizeof (nd)) != sizeof (nd))
		fatal_err("Can't write diskless file\n");
}

/*
 * Convert the integer fields of the nfs_args structure from host byte order
 * to net byte order.
 */
void
nfsargs_hton(nfsp)
	register struct nfs_args *nfsp;
{

	nfsp->sotype = htonl(nfsp->sotype);
	nfsp->proto = htonl(nfsp->proto);
	nfsp->flags = htonl(nfsp->flags);
	nfsp->wsize = htonl(nfsp->wsize);
	nfsp->rsize = htonl(nfsp->rsize);
	nfsp->timeo = htonl(nfsp->timeo);
	nfsp->retrans = htonl(nfsp->retrans);
	nfsp->maxgrouplist = htonl(nfsp->maxgrouplist);
	nfsp->readahead = htonl(nfsp->readahead);
	nfsp->leaseterm = htonl(nfsp->leaseterm);
	nfsp->deadthresh = htonl(nfsp->deadthresh);
}

/*
 * Just print out an error message and exit.
 */
void
fatal_err(str)
	char *str;
{

	fprintf(stderr, str);
	exit(1);
}