461 lines
11 KiB
C
461 lines
11 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)sysIDtool.c 1.1 94/10/31 SMI";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1990 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* sysIDtool - semi-automatic installation tool for diskful desktop systems.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <stdio.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/reboot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <termios.h>
|
|
|
|
#include "admin_amcl.h"
|
|
#include "sys_param_names.h"
|
|
#include "admin_messages.h"
|
|
|
|
#define TIMEZONE_MAP_NAME "timezone.byname"
|
|
#define UNCONFIGURED "/etc/.UNCONFIGURED"
|
|
#define YPBIND "/usr/etc/ypbind"
|
|
#define IFCONFIG "/usr/etc/ifconfig -au netmask + broadcast + >/dev/null 2>&1"
|
|
#define TIMEHOST "timehost"
|
|
#define RETURN_KEY '\n'
|
|
#define ESC_KEY '\033'
|
|
#define INPUT_CHAR 0
|
|
#define INPUT_LINE 1
|
|
|
|
extern int gethostname();
|
|
extern char *inet_ntoa();
|
|
extern int admin_add_argp();
|
|
extern void admin_write_err();
|
|
extern char *admin_make_errbuf();
|
|
|
|
extern int sys_nerr;
|
|
extern char *sys_errlist[];
|
|
extern int errno;
|
|
|
|
static void fail_dialog();
|
|
static void kill_ypbind();
|
|
static void save_modes();
|
|
static void restore_modes();
|
|
static void canon_input();
|
|
static void get_input();
|
|
static void admin_perror();
|
|
|
|
static struct termios ttyb;
|
|
static unsigned long flags;
|
|
static char min_chars; /* VMIN control character */
|
|
static char time; /* VTIME control character */
|
|
|
|
int
|
|
main()
|
|
{
|
|
Admin_arg *argp; /* Argument list for admin methods */
|
|
char hostname[MAXHOSTNAMELEN]; /* Hostname to configure */
|
|
char domain[MAXDOMAINLEN]; /* Domain to configure */
|
|
struct ifreq ifr; /* ioctl interface request struct */
|
|
char ether_name[10]; /* name of ethernet interface */
|
|
int s; /* socket for ioctl */
|
|
int i; /* counter while waiting for ypbind */
|
|
int status; /* status from various calls */
|
|
char *tzdata; /* timezone entry from map */
|
|
int timezonelen;
|
|
char timezone[MAXPATHLEN]; /* timezone name */
|
|
char *ipaddr; /* ip address to configure */
|
|
struct sockaddr_in *sinp;
|
|
char *outbuf; /* Pointer to stdout buf from amcl */
|
|
char *errbuf; /* Pointer to stderr buf from amcl */
|
|
char *msgbuf; /* Error message buffer */
|
|
char tmpbuf[4096]; /* Temp msg buffer */
|
|
int ypbind_pid;
|
|
|
|
/*
|
|
* Retrieve name of first ethernet interface, make sure it's up,
|
|
* which means ifconfig with rarp worked, then get address.
|
|
*/
|
|
if (get_ether0name(ether_name, sizeof(ether_name)) == -1) {
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS,
|
|
SYS_ERR_NO_ETHER0);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
sprintf(ifr.ifr_name, "%s0", ether_name);
|
|
if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
|
|
admin_perror(tmpbuf, "ioctl");
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS, tmpbuf);
|
|
fail_dialog(msgbuf);
|
|
} else if (!(ifr.ifr_flags & IFF_UP)) {
|
|
fail_dialog(IP_FAIL_REASONS);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("Parameters for system as determined by sysIDtool\n");
|
|
#endif
|
|
sprintf(ifr.ifr_name, "%s0", ether_name);
|
|
if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
|
|
admin_perror(tmpbuf, "ioctl");
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS, tmpbuf);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
(void) close(s);
|
|
sinp = (struct sockaddr_in *)&ifr.ifr_addr;
|
|
ipaddr = inet_ntoa(sinp->sin_addr);
|
|
#ifdef DEBUG
|
|
printf("\tIP addr is %s\n", ipaddr);
|
|
#endif
|
|
|
|
/*
|
|
* Get hostname, NIS domain. These are set in the kernel by
|
|
* hostconfig which is called from rc.boot.
|
|
*/
|
|
if (gethostname(hostname, sizeof(hostname)) == -1) {
|
|
admin_perror(tmpbuf, "gethostname");
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS, tmpbuf);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("\tHostname is %s\n", hostname);
|
|
#endif
|
|
if (strlen(hostname) == 0)
|
|
fail_dialog(HOSTNAME_FAIL_REASONS);
|
|
|
|
if (getdomainname(domain, sizeof(domain)) == -1) {
|
|
admin_perror(tmpbuf, "getdomainname");
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS, tmpbuf);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("\tdomain is %s\n", domain);
|
|
#endif
|
|
if (strlen(domain) == 0)
|
|
fail_dialog(DOMAINNAME_FAIL_REASONS);
|
|
|
|
/*
|
|
* Start ypbind for the purposes of sysIDtool.
|
|
* We'll later kill this and let it start through normal
|
|
* channels (i.e. rc.local)
|
|
*/
|
|
#ifdef DEBUG
|
|
printf("starting ypbind\n");
|
|
#endif DEBUG
|
|
switch(ypbind_pid = fork()) {
|
|
|
|
case -1:
|
|
admin_make_errbuf(&msgbuf, "sysIDtool: %s", SYS_ERR_YPBIND);
|
|
fail_dialog(msgbuf);
|
|
|
|
case 0:
|
|
/*
|
|
* This is the child - starts ypbind
|
|
*/
|
|
if(system(YPBIND) != 0) {
|
|
admin_write_err(SYS_ERR_YPBIND);
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
default:
|
|
#ifdef DEBUG
|
|
printf("parent: ypbind_pid = %d\n",ypbind_pid);
|
|
#endif DEBUG
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Wait a bit for the ypbind to start and then
|
|
* do an NIS call to force the binding
|
|
*/
|
|
for (i = 0; i < 20; i++) {
|
|
sleep(1);
|
|
if ((status = yp_master(domain, TIMEZONE_MAP_NAME,
|
|
&tzdata)) == 0)
|
|
break;
|
|
else if (status == YPERR_YPBIND) {
|
|
#ifdef DEBUG
|
|
printf("waiting for ypbind\n");
|
|
#endif DEBUG
|
|
continue;
|
|
} else if (status == YPERR_MAP) {
|
|
kill_ypbind(ypbind_pid);
|
|
fail_dialog(TIMEZONE_MAP_REASON);
|
|
} else if (status != 0) {
|
|
admin_make_errbuf(&msgbuf, "yp_master: %s.\n",
|
|
yperr_string(status));
|
|
kill_ypbind(ypbind_pid);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
}
|
|
|
|
if ( i >= 20 && status != 0 ) {
|
|
/*
|
|
* the ypbind never worked, for some reason...
|
|
*/
|
|
admin_make_errbuf(&msgbuf, TIMEZONE_FAIL_REASONS,
|
|
yperr_string(status));
|
|
kill_ypbind(ypbind_pid);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
|
|
|
|
/*
|
|
* Retrieve timezone name for our system from NIS map created for
|
|
* just this purpose. Look first for entry for our system, if none
|
|
* found then look for a domain-wide entry.
|
|
*/
|
|
if ((status = yp_match(domain, TIMEZONE_MAP_NAME, hostname,
|
|
strlen(hostname), &tzdata, &timezonelen)) == YPERR_KEY) {
|
|
if ((status = yp_match(domain, TIMEZONE_MAP_NAME, domain,
|
|
strlen(domain), &tzdata, &timezonelen)) == YPERR_KEY) {
|
|
kill_ypbind(ypbind_pid);
|
|
fail_dialog(TIMEZONE_KEY_REASON);
|
|
}
|
|
}
|
|
if (status != 0) {
|
|
admin_make_errbuf(&msgbuf, TIMEZONE_FAIL_REASONS,
|
|
yperr_string(status));
|
|
kill_ypbind(ypbind_pid);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
|
|
sscanf(tzdata, "%s %*s", timezone);
|
|
|
|
#ifdef DEBUG
|
|
printf("\ttimezone is %s\n", timezone);
|
|
#endif
|
|
/*
|
|
* Do an ifconfig of netmask so if 'timehost' is on another (sub)net
|
|
* we can reach it with 'rdate'.
|
|
*/
|
|
if (system(IFCONFIG) != 0) {
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS,
|
|
SYS_ERR_IFCONFIG);
|
|
fail_dialog(msgbuf);
|
|
}
|
|
|
|
|
|
/*
|
|
* Now build the argument list for the method invocation
|
|
*/
|
|
argp = NULL;
|
|
(void) admin_add_argp(&argp, HOSTNAME_PARAM, ADMIN_STRING,
|
|
strlen(hostname), hostname);
|
|
(void) admin_add_argp(&argp, DOMAIN_PARAM, ADMIN_STRING,
|
|
strlen(domain), domain);
|
|
(void) admin_add_argp(&argp, IPADDR_PARAM, ADMIN_STRING,
|
|
strlen(ipaddr), ipaddr);
|
|
(void) admin_add_argp(&argp, TIMEZONE_PARAM, ADMIN_STRING,
|
|
strlen(timezone), timezone);
|
|
(void) admin_add_argp(&argp, TIMESERVER_PARAM, ADMIN_STRING,
|
|
strlen(TIMEHOST), TIMEHOST);
|
|
|
|
#ifdef DEBUG
|
|
printf("Attempting system add method\n");
|
|
#endif
|
|
if ((status =
|
|
admin_perf_method(SYSTEM_CLASS_PARAM, SYS_ADD_METHOD,
|
|
ADMIN_LOCAL, NULL, argp, &outbuf, &errbuf, ADMIN_END_OPTIONS)) !=
|
|
SUCCESS) {
|
|
admin_make_errbuf(&msgbuf, SETUP_FAIL_REASONS, errbuf);
|
|
kill_ypbind(ypbind_pid);
|
|
fail_dialog(msgbuf);
|
|
} else if ((unlink(UNCONFIGURED) != 0) && (errno != ENOENT)) {
|
|
perror("unlink");
|
|
admin_write_err(SYS_ERR_PLS_RM, UNCONFIGURED);
|
|
}
|
|
#ifdef DEBUG
|
|
printf(outbuf);
|
|
printf("status = %d\n",status);
|
|
#endif
|
|
kill_ypbind(ypbind_pid);
|
|
exit(status);
|
|
}
|
|
|
|
static void kill_ypbind(child_pid)
|
|
int child_pid;
|
|
{
|
|
char pid[20];
|
|
char line[MAXPATHLEN];
|
|
char program[MAXPATHLEN];
|
|
FILE *fp, *popen();
|
|
|
|
/*
|
|
* Find the process ID of ypbind. Note, we have to do it
|
|
* this way because ypbind forks a child to do the real
|
|
* work and we have no way to get the child's pid
|
|
*/
|
|
if((fp = popen("ps ax","r")) == NULL ) {
|
|
}
|
|
|
|
while(fgets(line,MAXPATHLEN,fp) != NULL) {
|
|
|
|
/* The STAT could be different, so scan this line twice */
|
|
sscanf(line,"%s %*s %*s %*s %s %*s %*s %*s",pid,program);
|
|
|
|
if(!strcmp(program,YPBIND)) {
|
|
#ifdef DEBUG
|
|
printf("found ypbind - killing %s!\n",pid);
|
|
#endif DEBUG
|
|
kill(atoi(pid),SIGKILL);
|
|
break;
|
|
}
|
|
else {
|
|
|
|
sscanf(line,"%s %*s %*s %*s %*s %s %*s %*s %*s",pid,program);
|
|
if(!strcmp(program,YPBIND)) {
|
|
#ifdef DEBUG
|
|
printf("found ypbind - killing %s!\n",pid);
|
|
#endif DEBUG
|
|
kill(atoi(pid),SIGKILL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Also kill the child that exec-ed ypbind - if it's still around
|
|
*/
|
|
kill(child_pid,SIGKILL);
|
|
}
|
|
|
|
/*
|
|
* fail_dialog(msgbuf) - Walk user through failure reasons & possible courses
|
|
* action. Never returns, we either exit or halt the system, user's choice.
|
|
*/
|
|
static void fail_dialog(msgbuf)
|
|
char *msgbuf;
|
|
{
|
|
char ib[80];
|
|
|
|
save_modes(0);
|
|
canon_input(0);
|
|
disp_menu:
|
|
printf(FAIL_MENU);
|
|
fflush(stdout);
|
|
for (;;) {
|
|
printf(ENTER_CHOICE);
|
|
fflush(stdout);
|
|
get_input(INPUT_LINE, ib);
|
|
switch (ib[0]) {
|
|
case '1':
|
|
printf(msgbuf);
|
|
fflush(stdout);
|
|
get_input(INPUT_CHAR);
|
|
goto disp_menu;
|
|
case '2':
|
|
printf(MANUAL_INTRO);
|
|
fflush(stdout);
|
|
for (;;) {
|
|
get_input(INPUT_CHAR, ib);
|
|
if (ib[0] == RETURN_KEY) {
|
|
restore_modes(0);
|
|
exit(1);
|
|
} else if (ib[0] == ESC_KEY)
|
|
goto disp_menu;
|
|
else
|
|
printf(BAD_CHOICE_2);
|
|
}
|
|
break;
|
|
case '3':
|
|
restore_modes(0);
|
|
printf(HALTING_MESSAGE);
|
|
fflush(stdout);
|
|
sleep(1);
|
|
reboot(RB_HALT);
|
|
default:
|
|
printf(BAD_CHOICE);
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get_input(key, buf) - Get input from user, either a single key or a complete
|
|
* line depending on the value of 'key'. Input is returned in 'buf'. In line
|
|
* input mode, we ignore whitespace so that the caller is guaranteed that the
|
|
* significant input is at the beginning of the buffer.
|
|
*/
|
|
static void get_input(key, buf)
|
|
int key;
|
|
char *buf;
|
|
{
|
|
char *cp;
|
|
|
|
cp = buf;
|
|
for (;;) {
|
|
(void) read(0, cp, 1);
|
|
if (key == INPUT_CHAR)
|
|
return;
|
|
else if (*cp == RETURN_KEY)
|
|
return;
|
|
else if (isspace(*cp))
|
|
continue;
|
|
else
|
|
++cp;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine turns off canonical mode so that characters
|
|
* can be received as typed
|
|
*/
|
|
static void canon_input(file_des)
|
|
int file_des;
|
|
{
|
|
|
|
ttyb.c_lflag &= ~ICANON;
|
|
ttyb.c_cc[VMIN] = 1;
|
|
ttyb.c_cc[VTIME] = 0;
|
|
(void) ioctl(file_des, TCSETSF, &ttyb);
|
|
}
|
|
|
|
/*
|
|
* Save the terminal modes in the static storage
|
|
*/
|
|
static void save_modes(file_des)
|
|
int file_des;
|
|
{
|
|
|
|
/* Save current terminal modes */
|
|
(void) ioctl(file_des, TCGETS, &ttyb);
|
|
flags = ttyb.c_lflag;
|
|
min_chars = ttyb.c_cc[VMIN];
|
|
time = ttyb.c_cc[VTIME];
|
|
}
|
|
|
|
/*
|
|
* Restore terminal modes from values saved in static storage
|
|
*/
|
|
static void restore_modes(file_des)
|
|
int file_des;
|
|
{
|
|
ttyb.c_lflag = flags;
|
|
ttyb.c_cc[VMIN] = min_chars;
|
|
ttyb.c_cc[VTIME] = time;
|
|
(void) ioctl(file_des, TCSETSW, &ttyb);
|
|
}
|
|
|
|
|
|
static void admin_perror(buf, name)
|
|
char *buf;
|
|
char *name;
|
|
{
|
|
|
|
if (errno > sys_nerr)
|
|
sprintf(buf, "%s: Error code %d\n", name, errno);
|
|
else
|
|
sprintf(buf, "%s: %s\n", name, sys_errlist[errno]);
|
|
}
|