📄 nsrec.c
字号:
/* @(#)nsrec.c 1.1 92/07/30 SMI *//* Copyright (c) 1984 AT&T *//* All Rights Reserved *//* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T *//* The copyright notice above does not evidence any *//* actual or intended publication of such source code. *//* * nsrec.c contains name server recovery functions and * other related functions. */#ident "@(#)nserve:nsrec.c 1.21.1.1"#include <stdio.h>#include <string.h>#include <signal.h>#include <sys/utsname.h>#include <sys/stropts.h>#include <errno.h>#include <fcntl.h>#include "nsdb.h"#include "nslog.h"#include <tiuser.h>#include <rfs/nsaddr.h>#include "stdns.h"#include <rfs/nserve.h>#include <sys/mount.h>#include <rfs/cirmgr.h>#include <rfs/pn.h>#include "nsports.h"#include "nsrec.h"#define NLS_Q "nlsadmin -q"#define NLS_ADDR "nlsadmin -l -"#define UNADV_CMD "/usr/bin/unadv"#define ADV_CMD "/usr/bin/adv"#define AUTH_INFO NSDIRQ/auth.info"#define MNT_CMD "/etc/mount -d"#define UMNT_CMD "/etc/umount -d"#define R_TIMEOUT 25extern int Done;extern char *Netmaster;extern char *Net_spec;extern void (*Alarmsig)();int Polltime=POLLTIME;char *Mydomains[MAXDOMAINS];int Mylastdom=0;struct ns_info { int n_state; int n_pd; char *n_dname; struct address *n_addr;};static struct ns_info Nsinfo[MAXNS];static int getprime();static int Rdone=FALSE;char *prec();char *dompart();char *aatos();struct address *getmyaddr();struct address *astoa();int r_poll();int r_checkup();struct ns_info *pdtonp();struct ns_info *nmtonp();/* * setmaster takes the information returned from * the NS_INIT call to the primary and writes * a new netmaster file. */intsetmaster(req)struct request *req;{ struct res_rec *rns; struct res_rec *rar; long nscount; int i; char dname[BUFSIZ]; char *ptr; FILE *fp; FILE *fopen(); LOG2(L_COMM,"(%5d) setmaster: enter\n",Logstamp); /* * don't rewrite rfmaster if this machine is listed as "p" * in rfmaster. */ strcpy(dname,dompart(Dname)); if (domauth(dname) == SOA) { LOG2(L_COMM,"(%5d) setmaster: don't rewrite rfmaster\n",Logstamp); return(R_NSFAIL); } if (req->rq_head->h_rcode != R_NOERR) return(R_NSFAIL); LOG2(L_COMM,"(%5d) setmaster: rcode ok\n",Logstamp); if ((nscount = req->rq_head->h_nscnt) == 0 || req->rq_head->h_arcnt == 0) return(R_NSFAIL); LOG3(L_COMM,"(%5d) setmaster: record count = %d\n",Logstamp, req->rq_head->h_nscnt); if ((fp = fopen(Netmaster,"w")) == NULL) { PLOG2("rfs: ns_init can't write master file %s\n",Netmaster); return(R_NSFAIL); } for (i=0, rns = *req->rq_ns, rar = *req->rq_ar; i < nscount; i++, rns++, rar++) { fprintf(fp,"%s\n",prec(rns)); fprintf(fp,"%s%c%s\n",dompart(rns->rr_ns),SEPARATOR,prec(rar)); } fclose(fp); return(R_NOERR);}/* * mydom returns TRUE if name is in the list of domains * that this machine has authority over, otherwise it * returns FALSE. */intmydom(name)char *name;{ register int i; for (i=0; i < Mylastdom; i++) if (strcmp(name,Mydomains[i]) == NULL) return(TRUE); return(FALSE);}/* * r_init initializes recovery. If this machine is just * a normal machine, its state is set, and the function * returns, otherwise, the recovery mechanism is set in * motion. */intr_init(){ if (getprime(dompart(Dname)) == RFS_FAILURE) return(RFS_FAILURE); if (!Myaddress && (Myaddress = getmyaddr()) == NULL) return(RFS_FAILURE); if (findmydoms() == 0) { /* this is a "regular" machine */ alarm(0); sigset(SIGALRM,SIG_IGN); getnsinfo(); Primary = FALSE; return(RFS_SUCCESS); } /* * This machine "owns" one or more domains. * Now set up recovery circuits. */ if (getnsinfo() == RFS_FAILURE) return(RFS_FAILURE); if (setrstate() == RFS_FAILURE) return(RFS_FAILURE); return(RFS_SUCCESS);}/* * find primary machine address(es) from * database. */static intgetprime(dom)char *dom;{ int count; int i,j; struct res_rec **rlist, **arlist=NULL; struct res_rec *srlist[MAXREC]; struct res_rec **srp = srlist; char abuf[BUFSIZ]; strcpy(abuf,dom); if ((rlist = findrr(abuf,NSTYPE)) == NULL || (count = copyrlist(&srp,rlist)) == 0 || getars(srlist,&arlist,count) == 0) { PLOG1("RFS name server can't find primary name server address\n"); return(RFS_FAILURE); } for (i=0; i < MAXNS; i++) Paddress[i] = NULL; for (i=0; i < count; i++) { LOG3(L_OVER,"getprime: add primary %d, name = %s\n", (srlist[i]->rr_type & ~MASKNS)-1, srlist[i]->rr_ns); Paddress[(srlist[i]->rr_type & ~MASKNS)-1] = astoa(arlist[i]->rr_a,NULL); } /* compress addresses in list to eliminate gaps */ for (i=0, j=0; j < count && i < MAXNS; i++) { if (Paddress[i] == NULL) continue; if (i != j) Paddress[j++] = Paddress[i]; else j++; } if (j == 0) { PLOG1("RFS name server can't find good primary ns address\n"); return(RFS_FAILURE); } Paddress[count] = NULL; for (i=0; Paddress[i]; i++) { LOG3(L_OVER,"getprime: using addr=%s as primary %d\n", aatos(abuf,Paddress[i],KEEP | HEX),i); } freelist(rlist); freelist(arlist); return(RFS_SUCCESS);}/* * look for this machine's listen address using nlsadmin. */struct address *getmyaddr(){ struct address *retaddr=NULL; FILE *fp; FILE *popen(); char buf[BUFSIZ]; sprintf(buf,"%s -z %d %s >/dev/null 2>&1",NLS_Q,RFSD,Net_spec); switch (system(buf)) { case 0: LOG2(L_ALL,"getmyaddr: listener correctly set up for net_spec %s\n", Net_spec); break; case -1: PLOG4("RFS name server: %s -z %d %s : request failed\n",NLS_Q,RFSD,Net_spec); return(NULL); default: PLOG2("RFS name server: listener not properly set up for RFS on network %s\n", Net_spec); return(NULL); } sprintf(buf,"%s %s >/dev/null 2>&1",NLS_Q,Net_spec); switch (system(buf)) { case 0: LOG2(L_ALL,"getmyaddr: listener is running for net_spec %s\n", Net_spec); break; case -1: PLOG3("RFS name server: %s %s : request failed\n",NLS_Q,Net_spec); return(NULL); default: PLOG2("RFS name server: listener not currently active for network %s\n", Net_spec); return(NULL); } sprintf(buf,"%s %s",NLS_ADDR,Net_spec); if ((fp = popen(buf,"r")) == NULL) { PLOG2("RFS name server: %s failed\n",buf); return(NULL); } if (fgets(buf,BUFSIZ,fp) == NULL) { PLOG1("RFS name server: can't get listen address\n"); pclose(fp); } if ((retaddr = astoa(buf,NULL)) == NULL) { PLOG2("RFS name server: got bad address from listener '%s'\n",buf); } else { LOG2(L_OVER,"getmyaddr: using addr=%s as my address\n",buf); } pclose(fp); return(retaddr);}/* * getnsinfo searches the database for the names of potential * primary name servers for the domains this machine serves. */intgetnsinfo(){ struct res_rec **rlist; struct res_rec **arlist; struct res_rec *srlist[MAXREC]; struct res_rec **srp = srlist; struct res_rec *rec; char *dom; struct ns_info *nptr; int i, j; long indx; int count; static int first=TRUE; LOG2(L_COMM,"(%5d) getnsinfo: enter\n",Logstamp); /* first clear out Nsinfo */ for (i=0, nptr = Nsinfo; i < MAXNS; i++, nptr++) { if (!first && nptr->n_pd != -1) nsrclose(nptr->n_pd); nptr->n_state = R_UNUSED; nptr->n_pd = -1; if (!first && nptr->n_dname) free(nptr->n_dname); nptr->n_dname = NULL; if (!first && nptr->n_addr) free(nptr->n_addr); nptr->n_addr = NULL; } first = FALSE; for (i=0; i < Mylastdom; i++) { dom = Mydomains[i]; if ((rlist = findrr(dom,NSTYPE)) == NULL) continue; count = copyrlist(&srp,rlist); if (getars(srlist, &arlist, count) == 0) { freelist(rlist); continue; } for (j=0, rec=srlist[0]; j < count; rec = srlist[++j]) { if ((indx = rec->rr_type & ~MASKNS) < 1 || indx > MAXNS) continue; indx--; nptr = &Nsinfo[indx]; if (nptr->n_state == R_UNUSED) { nptr->n_state = R_NOTPRIME; nptr->n_dname = copystr(rec->rr_data); if ((nptr->n_addr = astoa(arlist[j]->rr_a,NULL)) == NULL) { PLOG2("RFS name server: bad NS addr for %s\n", nptr->n_dname); freelist(rlist); return(RFS_FAILURE); } LOG4(L_COMM,"(%5d) getnsinfo: add %s to Nsinfo[%d]\n", Logstamp, nptr->n_dname,indx); continue; } if (strcmp(rec->rr_data,nptr->n_dname)) { PLOG3("RFS name server: NS setup conflict, %s & %s\n", rec->rr_data,nptr->n_dname); freelist(rlist); return(RFS_FAILURE); } } freelist(rlist); } return(RFS_SUCCESS);}/* * setrstate is called to find out who is primary, and to * set the state of this machine. */intsetrstate(){ int i; register struct ns_info *np; struct ns_info *pnp=NULL; struct ns_info *npnp=NULL; struct ns_info *Mynp=NULL; void (*usr2sig)(); char *block=NULL; int size=0; int state; long code; int timesave; void rst_alrm(); int ret; int pd = -1; struct request *req=NULL; int savetime = R_TIMEOUT; LOG4(L_ALL,"(%5d) recovery: enter setrstate, Primary=%s, Recover=%s\n", Logstamp, (Primary)?"TRUE":"FALSE", (Recover)?"TRUE":"FALSE"); if (!Recover) return(R_NOTPRIME); /* stop polling until after state is set */ usr2sig = sigset(SIGUSR2,SIG_HOLD); sigset(SIGALRM,SIG_IGN); timesave = alarm(0); Primary = FALSE; for (i=0, np=Nsinfo; i < MAXNS; i++, np++) { if (np->n_state == R_UNUSED) continue; if (strcmp(Dname,np->n_dname) == NULL) { Mynp = np; Mynp->n_state = R_NOTPRIME; continue; } LOG4(L_COMM,"(%5d) recover: polling %s, current state = %d\n", Logstamp, np->n_dname, np->n_state); if (np->n_pd == -1) { if ((np->n_pd = rconnect(np->n_addr,RECOVER)) == -1) np->n_state = R_DEAD; else np->n_state = R_PENDING; } else { if (r_sndreq(np->n_pd, np, QUERY, NS_IM_NP) == RFS_FAILURE) np->n_state = R_DEAD; else np->n_state = R_UNK; } LOG4(L_ALL,"(%5d) recovery: state of %s set to %d\n", Logstamp,np->n_dname,np->n_state); } /* now wait for replies and don't take other requests */ sigset(SIGALRM,rst_alrm); Rdone = FALSE; while (Rdone == FALSE) { /* is anything pending or unknown? if not, we are through */ for (i=0, np = Nsinfo; i < MAXNS; i++, np++) { if (np != Mynp && (np->n_state == R_PENDING || np->n_state == R_UNK)) break; } if (i == MAXNS) break; alarm(savetime); ret = nswait(&pd); if ((savetime = alarm(0)) == 0) break; np = pdtonp(pd); if (block) { free(block); block = NULL; } if (req) { freerp(req, TRUE); req = NULL; } switch (ret) { case LOC_REQ: /* fail normal request with R_INREC */ case REM_REQ: LOG3(L_COMM,"(%5d) recovery: rcvd %s, ignore\n",Logstamp, (ret==LOC_REQ)?"local request":"remote request"); nsread(pd, &block, 0); sndback(pd,R_INREC); break; case REC_IN: LOG4(L_COMM,"(%5d) recovery: rcvd REC_IN from %s on pd %d\n", Logstamp,(np)?np->n_dname:"unknown machine",pd); if ((size = nsread(pd, &block, 0)) == -1 || (req = btoreq(block,size)) == NULL || checkver(req) == RFS_FAILURE) { LOG3(L_ALL,"(%5d) recovery: REC_IN failed for %s\n", Logstamp, (np)?np->n_dname:"UNKNOWN"); break; } if (!np && (np = nmtonp(req->rq_head->h_dname)) == NULL) { LOG3(L_ALL,"(%5d) recovery: unexpected ns msg from %s\n", Logstamp, req->rq_head->h_dname); break; } if (strcmp(np->n_dname,req->rq_head->h_dname) != 0) { LOG4(L_ALL,"(%5d) recover: expect ns %s got ns %s\n", Logstamp,np->n_dname,req->rq_head->h_dname); nsrclose(pd); if (pd != np->n_pd) nsrclose(np->n_pd); if ((np->n_pd = rconnect(np->n_addr,RECOVER)) == -1) np->n_state = R_DEAD; else np->n_state = R_PENDING; LOG4(L_COMM,"(%5d) recover: set state of %s to %d\n", Logstamp,np->n_dname,np->n_state); break; } /* only deal with NS_IM_NP and NS_IM_P msg types */ code = req->rq_head->h_opcode; if (code == NS_IM_NP) state = R_NOTPRIME; else if (code == NS_IM_P) state = R_PRIME; else { if (req->rq_head->h_flags & QUERY) sndback(pd,R_INREC); break; } if (np->n_state == R_DEAD) { np->n_pd = pd; np->n_state = state; } else if (np->n_state == R_UNK) { if (pd != np->n_pd) { /* * shouldn't happen, but if it does * treat like a collision */ LOG5(L_ALL,"(%5d) recover: %s, pd %d != %d\n", Logstamp, np->n_dname, pd, np->n_pd); if (np > Mynp) { nsrclose(np->n_pd); np->n_pd = pd; } else { nsrclose(pd); break; } } np->n_state = state; } else if (np->n_state == R_PENDING) { if (pd == np->n_pd) LOG2(L_ALL,"recovery: WARNING NS %s out of state\n", np->n_dname); else { /* collision */ if (np > Mynp) { nsrclose(np->n_pd); np->n_pd = pd; } else { nsrclose(pd); break; } } np->n_state = state; } else np->n_state = state; if (req->rq_head->h_flags & QUERY) r_sndreq(pd, np, RESPONSE, NS_IM_NP); LOG4(L_COMM,"(%5d) recover: set state of %s to %d\n", Logstamp,np->n_dname,np->n_state); break; case REC_ACC: if (!np) { /* collision */ LOG3(L_ALL,"(%5d) recovery: connects collided ns=%s\n", Logstamp, np->n_dname); nsrclose(pd); break; } LOG3(L_COMM,"(%5d) recovery: rcvd REC_ACC from %s\n", Logstamp, np->n_dname); /* got connection, send poll */ if (r_sndreq(pd, np, QUERY, NS_IM_NP) == RFS_FAILURE) { nsrclose(pd); np->n_state = R_DEAD; np->n_pd = -1; } else np->n_state = R_UNK; LOG4(L_COMM,"(%5d) recover: set state of %s to %d\n", Logstamp,np->n_dname,np->n_state); break; case REC_HUP: LOG4(L_COMM,"(%5d) recovery: rcvd hangup from %s, pd=%d\n", Logstamp, (np)?np->n_dname:"unknown ns",pd); nsrclose(pd); if (np) { if ((np->n_pd = rconnect(np->n_addr,RECOVER)) == -1) np->n_state = R_DEAD; else np->n_state = R_PENDING; LOG4(L_COMM,"(%5d) recover: set state of %s to %d\n", Logstamp,np->n_dname,np->n_state); } break; case FATAL: PLOG3("(%5d) recovery: fatal return from nswait, errno=%d\n", Logstamp, errno); sigset(SIGUSR2,usr2sig); return(RFS_FAILURE); case REC_CON: /* wait for poll from connector */ case NON_FATAL: default: break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -