Files
Arquivotheca.Solaris-2.5/cmd/backup/database/dbserv/rserver_funcs.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

890 lines
18 KiB
C
Executable File

#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 <dirent.h>
#undef _POSIX_C_SOURCE
#undef _POSIX_SOURCE
#include <sys/stat.h>
#include <database/handles.h>
#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 <sys/file.h>
#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;
}