#ifndef lint static char sccsid[] = "@(#)bootparam_lib.c 1.1 94/10/31 SMI"; #endif /* * Library routines of the bootparam server. */ #include #include #include #include #include #define iseol(c) (c == '\0' || c == '\n' || c == '#') #define issep(c) (c == ' ' || c == '\t') #define BOOTPARAMS "/etc/bootparams" #define LINESIZE 512 #define NAMESIZE 256 #define DOMAINSIZE 256 static char domain[DOMAINSIZE]; /* NIS domain name */ struct stat laststat; static char *bpbuf; char * read_bootparams() { int fd; struct stat statb; if (stat(BOOTPARAMS, &statb) < 0) { fprintf(stderr, "rpc.bootparamsd: can't stat %s\n", BOOTPARAMS); return (NULL); } if (statb.st_mtime != laststat.st_mtime) { if ((fd = open(BOOTPARAMS, O_RDWR, 0)) < 0) { perror(BOOTPARAMS); return (NULL); } if (bpbuf) { free(bpbuf); } bpbuf = (char *)malloc(statb.st_size + 1); if (bpbuf == NULL) { fprintf("rpc.bootparamd: out of memory\n"); return (NULL); } if (read(fd, bpbuf, statb.st_size) < 0) { perror(BOOTPARAMS); return (NULL); } bpbuf[statb.st_size] = '\0'; laststat = statb; } return (bpbuf); } /* * getline() * Read a line from a buffer. * Fill in line buffer, and update lpp, return number of chars. */ getline(line, maxlinelen, lpp) char *line; int maxlinelen; char **lpp; { int count; char *p; char *linestart; p = *lpp; if (p == NULL || *p == '\0') { return (0); } count = 0; linestart = line; while (iseol(*p)) { p++; } while (*p) { if (*p == '\n') { if (count && p[-1] == '\\') { /* * Continuation line, back up one char * and get next line from buf. */ line--; p++; } else { break; } } count++; *line++ = *p++; } *line = '\0'; *lpp = p; return (count); } /* * getname() * Get the next entry from the line. * You tell getname() which characters to ignore before storing them * into name, and which characters separate entries in a line. * The cookie is updated appropriately. * return: * 1: one entry parsed * 0: partial entry parsed, ran out of space in name * -1: no more entries in line */ int getname(name, namelen, linep) char *name; int namelen; char **linep; { char c; char *lp; char *np; int maxnamelen; lp = *linep; do { c = *lp++; } while (issep(c) && !iseol(c)); if (iseol(c)) { *linep = lp - 1; return(0); } np = name; while (! issep(c) && ! iseol(c) && np - name < namelen - 1) { *np++ = c; c = *lp++; } *np = '\0'; lp--; *linep = lp; return (np - name); } /* * getclntent reads the line buffer and returns a string of client entry * in NIS or the "/etc/bootparams" file. Called by getclntent. */ static int getvalue(lpp, clnt_entry) register char **lpp; /* function input */ register char *clnt_entry; /* function output */ { char name[NAMESIZE]; int append = 0; while (getname(name, sizeof(name), lpp) > 0) { if (!append) { strcpy(clnt_entry, name); append++; } else { strcat(clnt_entry, " "); strcat(clnt_entry, name); } } return (0); } /* * getfileent returns the client entry in the "/etc/bootparams" * file given the client name. */ int bp_getclntent(clnt_name, clnt_entry) register char *clnt_name; /* function input */ register char *clnt_entry; /* function output */ { FILE *fp; char line[LINESIZE]; char name[NAMESIZE]; char *lp; char *linep; char *val; int vallen; int reason; reason = -1; lp = read_bootparams(); while (reason && getline(line, sizeof(line), &lp)) { linep = line; val = NULL; if (*linep == '+' && useyp()) { linep++; if (getname(name, sizeof(name), &linep)) { reason = yp_match(domain, name, clnt_name, strlen(clnt_name), &val, &vallen); } else { reason = yp_match(domain, "bootparams", clnt_name, strlen(clnt_name), &val,&vallen); } if (!reason) { linep = val; } } if (!reason || (getname(name, sizeof(name), &linep) > 0 && strcmp(name,clnt_name) == 0)) { reason = getvalue(&linep, clnt_entry); } if (val) { free(val); } } return (reason); } /* * return the value string associated with clnt_key (key=value) in * the line buffer lpp. Update lpp. */ static int getkeyval(lpp, clnt_key, clnt_entry) register char **lpp; /* function input */ register char *clnt_key; /* function input */ register char *clnt_entry; /* function output */ { char name[NAMESIZE]; char *cp; while (getname(name, sizeof(name), lpp) > 0) { if ((cp = (char *)index(name, '=')) == 0) return (-1); *cp++ = '\0'; if (strcmp(name, clnt_key) == 0) { strcpy(clnt_entry, cp); return (0); } } if (strcmp(clnt_key, "dump") == 0) { /* * This is a gross hack to handle the case where * no dump file exists in bootparams. The null * server and path names indicate this fact to the * client. */ strcpy(clnt_entry, ":"); return (0); } return (-1); } /* * getclntkey returns the client's server name and its pathname from either * the NIS or the "/etc/bootparams" file given the client name and * the key. */ int bp_getclntkey(clnt_name, clnt_key, clnt_entry) register char *clnt_name; /* function input */ register char *clnt_key; /* function input */ register char *clnt_entry; /* function output */ { char line[LINESIZE]; char name[NAMESIZE]; char *lp; char *linep; char *val; int reason; int vallen; reason = -1; lp = read_bootparams(); while (reason && getline(line, sizeof(line), &lp)) { linep = line; val = NULL; if (*linep == '+' && useyp()) { linep++; if (getname(name, sizeof(name), &linep)) { reason = yp_match(domain, name, clnt_name, strlen(clnt_name), &val, &vallen); } else { reason = yp_match(domain, "bootparams", clnt_name, strlen(clnt_name), &val,&vallen); } if (!reason) { linep = val; } } if (!reason || ( getname(name, sizeof(name), &linep) > 0 && strcmp(name,clnt_name) == 0) ) { reason = getkeyval(&linep, clnt_key, clnt_entry); } if (val) { free(val); } } return (reason); } /* * Determine whether or not to use the NIS service to do lookups. */ static int initted; static int usingyp; static int useyp() { if (!initted) { getdomainname(domain, sizeof(domain)); usingyp = !yp_bind(domain); initted = 1; } return (usingyp); } /* * Determine if a descriptor belongs to a socket or not */ issock(fd) int fd; { struct stat st; if (fstat(fd, &st) < 0) { return (0); } /* * SunOS returns S_IFIFO for sockets, while 4.3 returns 0 and * does not even have an S_IFIFO mode. Since there is confusion * about what the mode is, we check for what it is not instead of * what it is. */ switch (st.st_mode & S_IFMT) { case S_IFCHR: case S_IFREG: case S_IFLNK: case S_IFDIR: case S_IFBLK: return (0); default: return (1); } }