4.4BSD/usr/src/contrib/diskless.nfs/diskless_setup.c
/*
* 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);
}