#ident "@(#)rserver_funcs.c 1.19 94/08/10" /* * Copyright (c) 1990,1991,1992 by Sun Microsystems, Inc. */ #include "defs.h" #define _POSIX_SOURCE /* hack to avoid redef of MAXNAMLEN */ #define _POSIX_C_SOURCE #include #undef _POSIX_C_SOURCE #undef _POSIX_SOURCE #include #include #include "rpcdefs.h" #include "dboper.h" #ifdef __STDC__ static int header_search(struct fsheader_readargs *, struct dheader *, int); static void lockdb(void); static void unlockdb(void); static void addupdatepid(int); static int getfd(const char *); #else static int header_search(); static void lockdb(); static void unlockdb(); static void addupdatepid(); static int getfd(); #endif int * start_update_1(host) char **host; { int hid; static int rc = -1; /* * XXX: must ensure that we get a unique timestamp! */ (void) sleep(1); hid = (int)time((time_t *)0); if (new_handle(hid, *host) == NULL_HANDLE) { (void) fprintf(stderr, gettext("%s error\n"), "new_handle"); return (&rc); } rc = hid; return (&rc); } int * process_update_1(p) struct process *p; { int handle; char oldname[256], newname[256]; struct file_handle *h; static int rc = -1; int pid; extern int updatecnt; handle = p->handle; if ((h = handle_lookup(handle)) == NULL_HANDLE) { (void) fprintf(stderr, "process_update/handle_lookup\n"); return (&rc); } /* * XXX: attempt to verify the file here. We'd like to ensure * that the file contains at least something resembling good * data and that we'll be able to write all the temp files * and junk for the given host before we tell the caller * that everything's OK. */ (void) sprintf(oldname, "%s/%s%s.%d", h->host, TEMP_PREFIX, UPDATE_FILE, handle); (void) sprintf(newname, "%s/%s.%d", h->host, UPDATE_FILE, handle); if (rename(oldname, newname) == -1) { perror("process_update: rename"); return (&rc); } if ((pid = fork()) == -1) { perror("fork"); return (&rc); } else if (pid == 0) { yp_unbind(mydomain); closefiles(); (void) oper_init(opserver, myname, 0); /* * lock the database. Is it important that updates * be processed in the order they're received (i.e., * must the lock be acquired in request order)? */ lockdb(); cleanup(); if (!duplicate_dump(h->host, newname)) { if (batch_update(h->host, newname)) { (void) fprintf(stderr, gettext( "%s error\n"), "batch_update"); /* XXX ??? */ } } unlockdb(); (void) unlink(newname); oper_end(); exit(0); } else { addupdatepid(pid); updatecnt++; free_handle(h); rc = 0; return (&rc); } /*NOTREACHED*/ } struct readdata * read_dir_1(p) struct blk_readargs *p; { static struct readdata r; static struct dir_block d; char dirfile[256]; int fd; extern time_t dbupdatetime; r.retdata = NULL; (void) sprintf(dirfile, "%s/%s", p->host, DIRFILE); if ((fd = getfd(dirfile)) == -1) { perror(dirfile); r.readrc = DBREAD_NOHOST; return (&r); } #if 0 /* DEBUG */ { struct stat stbuf; if (fstat(fd, &stbuf) == -1) { perror("fstat/dir"); r.readrc = DBREAD_NOHOST; return (&r); } if (p->blksize != DIR_BLKSIZE) { r.readrc = DBREAD_USERERROR; return (&r); } if (p->recnum*p->blksize > stbuf.st_size) { (void) fprintf(stderr, gettext("%s: read past EOF\n"), "read_dir"); r.readrc = DBREAD_USERERROR; return (&r); } } #endif if (dbupdatetime > p->cachetime) { /* * let caller know his cache is stale */ r.readrc = DBREAD_NEWDATA; return (&r); } if (lseek(fd, (off_t)(p->recnum*p->blksize), SEEK_SET) == -1) { perror("lseek"); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (read(fd, (char *)&d, sizeof (struct dir_block)) == -1) { perror("read"); r.readrc = DBREAD_INTERNALERROR; return (&r); } r.retdata = (char *)&d; r.readrc = DBREAD_SUCCESS; return (&r); } struct readdata * read_inst_1(p) struct blk_readargs *p; { static struct readdata r; /* large enough to hold a 50 entry instance record */ static char i[COMPUTE_INST_RECSIZE(50)]; char instfile[256]; int fd; extern time_t dbupdatetime; r.retdata = NULL; if (p->blksize > sizeof (i)) { r.readrc = DBREAD_INTERNALERROR; return (&r); } if (dbupdatetime > p->cachetime) { /* * tell caller his cache is outdated */ r.readrc = DBREAD_NEWDATA; return (&r); } (void) sprintf(instfile, "%s/%s", p->host, INSTANCEFILE); if ((fd = getfd(instfile)) == -1) { perror(instfile); r.readrc = DBREAD_NOHOST; return (&r); } #if 0 /* DEBUG */ { struct stat stbuf; struct instance_record dummy; if (fstat(fd, &stbuf) == -1) { perror("fstat/instance"); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (read(fd, &dummy, sizeof (struct instance_record)) != sizeof (struct instance_record)) { (void) fprintf(stderr, gettext("%s: cannot get blocksize\n"), "read_instance"); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (dummy.i_entry[0].ie_dnode_index != p->blksize) { if (p->blksize != sizeof (struct instance_record) || p->recnum != INSTANCE_FREEREC) { (void) fprintf(stderr, gettext( "%s: bad user block size\n"), "read_instance"); (void) fprintf(stderr, "<%d,%d>\n", dummy.i_entry[0].ie_dnode_index, p->blksize); r.readrc = DBREAD_USERERROR; return (&r); } } if (p->recnum*p->blksize > stbuf.st_size) { (void) fprintf(stderr, gettext("%s: read past EOF\n"), "read_instance"); r.readrc = DBREAD_USERERROR; return (&r); } } #endif if (lseek(fd, (off_t)(p->recnum*p->blksize), SEEK_SET) == -1) { perror("lseek"); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (read(fd, i, p->blksize) == -1) { perror("read"); r.readrc = DBREAD_INTERNALERROR; return (&r); } r.retdata = i; r.blksize = p->blksize; r.readrc = DBREAD_SUCCESS; return (&r); } int * delete_tape_1(label) char **label; { static int rc; lockdb(); rc = delete_tape(*label); unlockdb(); return (&rc); } struct readdata * read_dnode_1(p) struct dnode_readargs *p; { static struct readdata r; static struct dnode d; char dnodefile[256]; int fd; r.retdata = NULL; (void) sprintf(dnodefile, "%s/%s.%lu", p->host, DNODEFILE, p->dumpid); if ((fd = open(dnodefile, O_RDONLY)) == -1) { r.readrc = DBREAD_NODUMP; perror(dnodefile); return (&r); } #if 0 /* DEBUG */ { struct stat stbuf; if (fstat(fd, &stbuf) == -1) { perror("fstat/dir"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (p->recnum*sizeof (struct dnode) > stbuf.st_size) { (void) fprintf(stderr, gettext("%s: read past EOF\n"), "read_dnode"); (void) close(fd); r.readrc = DBREAD_USERERROR; return (&r); } } #endif if (lseek(fd, (off_t)(p->recnum*sizeof (struct dnode)), SEEK_SET) == -1) { perror("lseek"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (read(fd, (char *)&d, sizeof (struct dnode)) == -1) { perror("read"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } r.retdata = (char *)&d; r.readrc = DBREAD_SUCCESS; (void) close(fd); return (&r); } struct readdata * read_dnodeblk_1(p) struct dnode_readargs *p; { static struct readdata r; static struct dnode d[DNODE_READBLKSIZE]; char dnodefile[256]; int fd; r.retdata = NULL; (void) sprintf(dnodefile, "%s/%s.%lu", p->host, DNODEFILE, p->dumpid); if ((fd = getfd(dnodefile)) == -1) { r.readrc = DBREAD_NODUMP; perror(dnodefile); return (&r); } #if 0 /* DEBUG */ { struct stat stbuf; if (fstat(fd, &stbuf) == -1) { perror("fstat/dir"); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (p->recnum*sizeof (struct dnode) > stbuf.st_size) { (void) fprintf(stderr, gettext("%s: read past EOF\n"), "read_dnodeblk"); r.readrc = DBREAD_USERERROR; return (&r); } } #endif if (lseek(fd, (off_t)(p->recnum*sizeof (struct dnode)), SEEK_SET) == -1) { perror("lseek"); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (read(fd, (char *)d, DNODE_READBLKSIZE*sizeof (struct dnode)) == -1) { perror("read"); r.readrc = DBREAD_INTERNALERROR; return (&r); } r.readrc = DBREAD_SUCCESS; r.retdata = (char *)d; return (&r); } struct readdata * read_linkval_1(p) struct dnode_readargs *p; { static struct readdata r; char linkfile[256]; static char linkval[MAXPATHLEN]; FILE *fp; register char *s; r.retdata = NULL; (void) sprintf(linkfile, "%s/%s.%lu", p->host, LINKFILE, p->dumpid); if ((fp = fopen(linkfile, "r")) == NULL) { r.readrc = DBREAD_NODUMP; perror(linkfile); return (&r); } if (fseek(fp, (long)p->recnum, 0) == -1) { perror("fseek"); (void) fclose(fp); r.readrc = DBREAD_INTERNALERROR; return (&r); } for (s = linkval; *s = getc(fp); s++) ; r.retdata = linkval; r.readrc = DBREAD_SUCCESS; (void) fclose(fp); return (&r); } struct readdata * read_header_1(p) struct header_readargs *p; { static struct readdata r; static struct dheader dh; char filename[256]; int fd; r.retdata = NULL; (void) sprintf(filename, "%s/%s.%lu", p->host, HEADERFILE, p->dumpid); if ((fd = open(filename, O_RDONLY)) == -1) { perror(filename); r.readrc = DBREAD_NODUMP; return (&r); } if (read(fd, (char *)&dh, sizeof (struct dheader)) == -1) { perror("read"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } r.retdata = (char *)&dh; r.readrc = DBREAD_SUCCESS; (void) close(fd); return (&r); } struct readdata * read_fullheader_1(p) struct header_readargs *p; { #define MAXLABELS 20 /* dump never spans more tapes than this! */ static struct { struct dheader d; char labels[MAXLABELS][LBLSIZE]; } dh; static struct readdata r; char filename[256]; int fd; struct stat stbuf; r.retdata = NULL; (void) sprintf(filename, "%s/%s.%lu", p->host, HEADERFILE, p->dumpid); if ((fd = open(filename, O_RDONLY)) == -1) { perror(filename); r.readrc = DBREAD_NODUMP; return (&r); } if (fstat(fd, &stbuf) == -1) { perror("fstat"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (stbuf.st_size > sizeof (dh)) { (void) fprintf(stderr, gettext( "%s: buffer too small\n"), "read_fullheader"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } if (read(fd, (char *)&dh, (int)stbuf.st_size) == -1) { perror("read"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } r.retdata = (char *)&dh; r.readrc = DBREAD_SUCCESS; (void) close(fd); return (&r); } struct readdata * read_fsheader_1(p) struct fsheader_readargs *p; { static struct readdata r; static struct dheader dh; dh.dh_host[0] = '\0'; dh.dh_time = 0; r.retdata = NULL; r.readrc = header_search(p, &dh, sizeof (dh)); if (r.readrc == DBREAD_SUCCESS) { r.retdata = (char *)&dh; } return (&r); } struct readdata * read_fullfsheader_1(p) struct fsheader_readargs *p; { static struct readdata r; static struct { struct dheader d; char labels[MAXLABELS][LBLSIZE]; } dh; r.retdata = NULL; dh.d.dh_host[0] = '\0'; dh.d.dh_time = 0; r.readrc = header_search(p, (struct dheader *)&dh, sizeof (dh)); if (r.readrc == DBREAD_SUCCESS) r.retdata = (char *)&dh; return (&r); } static int header_search(p, dhp, size) struct fsheader_readargs *p; struct dheader *dhp; int size; { DIR *dirp; struct dheader *hold; struct dirent *ep; char fullname[1024]; int fd, gotone, rc; gotone = 0; rc = DBREAD_NODUMP; hold = (struct dheader *)malloc((unsigned)size); if (!hold) { (void) fprintf(stderr, gettext("%s: out of memory\n"), "header_search"); return (DBREAD_INTERNALERROR); } if ((dirp = opendir(p->host)) == NULL) { (void) fprintf(stderr, gettext( "cannot open host directory for %s\n"), p->host); free((char *)hold); return (DBREAD_NOHOST); } while (ep = readdir(dirp)) { if (strncmp(ep->d_name, HEADERFILE, strlen(HEADERFILE))) continue; (void) sprintf(fullname, "%s/%s", p->host, ep->d_name); if ((fd = open(fullname, O_RDONLY)) == -1) { perror(fullname); continue; } if (read(fd, (char *)hold, size) == -1) { perror("read"); (void) close(fd); continue; } if (strcmp(p->mntpt, hold->dh_mnt) == 0) { if (hold->dh_time <= p->time) { if (hold->dh_time > dhp->dh_time) { gotone++; bcopy((char *)hold, (char *)dhp, size); } } } (void) close(fd); } (void) closedir(dirp); free((char *)hold); if (gotone) rc = DBREAD_SUCCESS; return (rc); } struct readdata * read_tape_1(p) struct tape_readargs *p; { int fd; static struct active_tape t; static struct readdata r; r.retdata = NULL; if ((fd = open(TAPEFILE, O_RDONLY)) == -1) { perror(TAPEFILE); r.readrc = DBREAD_NOTAPE; return (&r); } if (lseek(fd, (off_t)(TAPE_FIRSTDATA*sizeof (struct active_tape)), SEEK_SET) == -1) { perror("lseek"); (void) close(fd); r.readrc = DBREAD_INTERNALERROR; return (&r); } while (read(fd, (char *)&t, sizeof (struct active_tape)) == sizeof (struct active_tape)) { if (bcmp(t.tape_label, p->label, LBLSIZE) == 0) { r.readrc = DBREAD_SUCCESS; r.retdata = (char *)&t; (void) close(fd); return (&r); } } r.readrc = DBREAD_NOTAPE; (void) close(fd); return (&r); } #include #ifndef LOCK_SH #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ #define LOCK_NB 4 /* don't block when locking */ #define LOCK_UN 8 /* unlock */ #endif #if defined(USG) && !defined(FLOCK) /* * Trump up a version of flock based on fcntl. * You don't need this if your implementation * has flock -- just compile with -DFLOCK. */ static int flock(fd, operation) int fd; int operation; { struct flock fl; int block = 0; int status; if (operation & LOCK_SH) fl.l_type = F_RDLCK; else if (operation & LOCK_EX) fl.l_type = F_WRLCK; else if (operation & LOCK_UN) fl.l_type = F_UNLCK; if ((operation & LOCK_NB) == 0) block = 1; fl.l_whence = SEEK_SET; /* XXX ? */ fl.l_start = (off_t)0; fl.l_len = (off_t)0; /* till EOF */ while ((status = fcntl(fd, F_SETLK, (char *)&fl)) < 0 && (errno == EACCES || errno == EAGAIN) && block) { (void) sleep(1); } return (status); } #endif static int lockfd = -1; static void #ifdef __STDC__ lockdb(void) #else lockdb() #endif { if (lockfd != -1) { (void) fprintf(stderr, gettext("%s: already locked?\n"), "lockdb"); } if ((lockfd = open(DBSERV_LOCKFILE, O_RDWR|O_CREAT, 0600)) == -1) { perror("lockdb/open"); exit(1); } if (flock(lockfd, LOCK_EX) == -1) { perror("lockdb/flock"); } } static void #ifdef __STDC__ unlockdb(void) #else unlockdb() #endif { if (flock(lockfd, LOCK_UN) == -1) { perror("unlockdb/flock"); exit(1); } (void) close(lockfd); lockfd = -1; } static int readlk_fd = -1; #ifdef __STDC__ getreadlock(void) #else getreadlock() #endif { if (readlk_fd != -1) { (void) fprintf(stderr, gettext( "process %ld readlock?\n"), (long)getpid()); } if ((readlk_fd = open(DBSERV_LOCKFILE, O_RDWR|O_CREAT, 0600)) == -1) { perror("getreadlock/open"); return (0); } if (flock(readlk_fd, LOCK_SH|LOCK_NB) == -1) { if (errno != EACCES && errno != EAGAIN) { perror("getreadlock/flock"); } (void) close(readlk_fd); readlk_fd = -1; return (0); } return (1); } void #ifdef __STDC__ releasereadlock(void) #else releasereadlock() #endif { if (flock(readlk_fd, LOCK_UN) == -1) { perror("releasereadlock/flock"); } (void) close(readlk_fd); readlk_fd = -1; } static struct pidlist { int pid; struct pidlist *nxt; } *pid_upd_list, *pid_free_list; isupdatepid(pid) int pid; { register struct pidlist *t, *prv; prv = (struct pidlist *)0; for (t = pid_upd_list; t; t = t->nxt) { if (t->pid == pid) { if (prv) { prv->nxt = t->nxt; } else { pid_upd_list = t->nxt; } t->nxt = pid_free_list; pid_free_list = t; return (1); } prv = t; } return (0); } static void addupdatepid(pid) int pid; { register struct pidlist *t; t = pid_free_list; if (t) { pid_free_list = t->nxt; } else { t = (struct pidlist *)malloc(sizeof (struct pidlist)); if (t == (struct pidlist *)0) { (void) fprintf(stderr, gettext("%s: out of memory\n"), "addupdatepid"); exit(0); } } t->nxt = pid_upd_list; pid_upd_list = t; t->pid = pid; } /* * keep a cache of open file descriptors. * Sub-processes call `closefiles()' as part of their startup * activity. */ #define MAXFDS 15 /* for the cache - much smaller than NOFILE */ static int nfds; static struct holdfd { char *name; int fd; struct holdfd *nxt; } *allfds; static int #ifdef __STDC__ getfd(const char *name) #else getfd(name) char *name; #endif { int newfd; register struct holdfd *p, *last, *prv; prv = last = (struct holdfd *)0; for (p = allfds; p; p = p->nxt) { if (strcmp(p->name, name) == 0) { return (p->fd); } prv = last; last = p; } if ((newfd = open(name, O_RDONLY)) == -1) return (-1); if (nfds < MAXFDS) { nfds++; p = (struct holdfd *)malloc(sizeof (struct holdfd)); if (!p) { (void) fprintf(stderr, gettext("%s: out of memory\n"), "getfd"); (void) close(newfd); return (-1); } p->name = malloc(strlen(name) + 1); if (!p->name) { (void) fprintf(stderr, gettext("%s: out of memory\n"), "getfd"); (void) close(newfd); free((char *)p); return (-1); } (void) strcpy(p->name, name); p->nxt = allfds; allfds = p; p->fd = newfd; return (p->fd); } else { /* * re-use the file that was least recently opened * (least recently used would be even better...) */ if (!(last && prv)) { (void) fprintf(stderr, gettext( "%s: %s error!\n"), "getfd", "last/prv"); (void) close(newfd); return (-1); } free(last->name); last->name = malloc(strlen(name) + 1); if (!last->name) { (void) fprintf(stderr, gettext("%s: out of memory\n"), "getfd"); (void) close(newfd); return (-1); } (void) close(last->fd); (void) strcpy(last->name, name); prv->nxt = (struct holdfd *)0; last->nxt = allfds; allfds = last; last->fd = newfd; return (last->fd); } } void #ifdef __STDC__ closefiles(void) #else closefiles() #endif { register struct holdfd *p, *t; p = allfds; while (p) { (void) close(p->fd); free(p->name); t = p; p = p->nxt; free((char *)t); } allfds = (struct holdfd *)0; nfds = 0; }