diff options
Diffstat (limited to 'exrecover.c')
| -rw-r--r-- | exrecover.c | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/exrecover.c b/exrecover.c new file mode 100644 index 0000000..17ba06f --- /dev/null +++ b/exrecover.c @@ -0,0 +1,905 @@ +/* + * This code contains changes by + * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. + * + * Conditions 1, 2, and 4 and the no-warranty notice below apply + * to these changes. + * + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __GNUC__ +#define UNUSED __attribute__ ((unused)) +#else +#define UNUSED +#endif + +#ifndef lint +#ifdef DOSCCS +char *copyright = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif +static char sccsid[] UNUSED = "@(#)exrecover.c 1.23 (gritter) 12/25/06"; +#endif + +/* from exrecover.c 7.9.2 (2.11BSD) 1996/10/26 */ + +#include <stdarg.h> +#ifdef notdef /* GR */ +#include <stdio.h> /* mjm: BUFSIZ: stdio = 512, VMUNIX = 1024 */ +#undef BUFSIZ /* mjm: BUFSIZ different */ +#undef EOF /* mjm: EOF and NULL effectively the same */ +#undef NULL +#else +#define xstderr (int*)0 +typedef int xFILE; +extern void perror(const char *); +extern int vsprintf(char *, const char *, va_list); +#endif + +#define var + +#include "ex.h" +#include "ex_temp.h" +#include "ex_tty.h" +#include <dirent.h> +#include <time.h> + +#ifndef MAXNAMLEN +#ifdef FNSIZE +#define MAXNAMLEN FNSIZE +#else +#ifdef NAME_MAX +#define MAXNAMLEN NAME_MAX +#else +#define MAXNAMLEN 255 +#endif +#endif +#endif + +#define TMP "/var/tmp" + +#ifdef LANGMSG +nl_catd catd; +#endif + +char xstr[1]; /* make loader happy */ +int tfile = -1; /* ditto */ + +/* + * + * This program searches through the specified directory and then + * the directory /usr/preserve looking for an instance of the specified + * file from a crashed editor or a crashed system. + * If this file is found, it is unscrambled and written to + * the standard output. + * + * If this program terminates without a "broken pipe" diagnostic + * (i.e. the editor doesn't die right away) then the buffer we are + * writing from is removed when we finish. This is potentially a mistake + * as there is not enough handshaking to guarantee that the file has actually + * been recovered, but should suffice for most cases. + */ + +/* + * Here we save the information about files, when + * you ask us what files we have saved for you. + * We buffer file name, number of lines, and the time + * at which the file was saved. + */ +struct svfile { + char sf_name[FNSIZE + 1]; + int sf_lines; + char sf_entry[MAXNAMLEN + 1]; + time_t sf_time; +}; + +#define ignorl(a) a + +/* + * This directory definition also appears (obviously) in expreserve.c. + * Change both if you change either. + */ +#ifdef notdef +char mydir[] = "/usr/preserve"; +#else +char mydir[] = "/var/lib/ex"; +#endif + +/* + * Limit on the number of printed entries + * when an, e.g. ``ex -r'' command is given. + */ +#define NENTRY 50 + +char nb[BUFSIZ]; +int vercnt; /* Count number of versions of file found */ + +extern void error(char *, ...); +extern void listfiles(char *); +extern void enter(struct svfile *, char *, int); +extern int qucmp(struct svfile *, struct svfile *); +extern void findtmp(char *); +extern void searchdir(char *); +extern int yeah(char *); +extern int preserve(void); +extern void scrapbad(void); +extern void putfile(int); +extern void wrerror(void); +extern void clrstats(void); +extern void getline(line); +extern char *getblock(line, int); +extern void blkio(bloc, char *, ssize_t (*)(int, void *, size_t)); +extern void syserror(void); +extern void xvfprintf(xFILE *, char *, va_list); +extern void xfprintf(xFILE *, char *, ...); + +int +main(int argc, char *argv[]) +{ + register char *cp; + register int b, i; + + /* + * Initialize the built-in memory allocator. + */ +#ifdef VMUNIX + poolsbrk(0); +#endif + linebuf = calloc(LBSIZE = BUFSIZ<4096?4096:BUFSIZ, sizeof *linebuf); + genbuf = calloc(MAXBSIZE, sizeof *genbuf); +#ifdef LANGMSG + setlocale(LC_MESSAGES, ""); + catd = catopen(CATNAME, NL_CAT_LOCALE); +#endif + + /* + * Initialize as though the editor had just started. + */ + fendcore = (line *) sbrk(0); + dot = zero = dol = fendcore; + one = zero + 1; + endcore = fendcore - 2; + iblock = oblock = -1; + + /* + * If given only a -r argument, then list the saved files. + */ + if (argc == 2 && strcmp(argv[1], "-r") == 0) { + listfiles(mydir); + listfiles(TMP); + exit(0); + } + if (argc != 3) + error(catgets(catd, 2, 1, + " Wrong number of arguments to exrecover"), 0); + + strcpy(file, argv[2]); + + /* + * Search for this file. + */ + findtmp(argv[1]); + + /* + * Got (one of the versions of) it, write it back to the editor. + */ + cp = ctime(&H.Time); + cp[19] = 0; + xfprintf(xstderr, catgets(catd, 2, 2, " [Dated: %s"), cp); + xfprintf(xstderr, vercnt > 1 ? catgets(catd, 2, 3, + ", newest of %d saved]") + : catgets(catd, 2, 4, "]"), vercnt); + H.Flines++; + + /* + * Allocate space for the line pointers from the temp file. + */ + if ((char *) sbrk(H.Flines * sizeof (line)) == (char *) -1) + /* + * Good grief. + */ + error(catgets(catd, 1, 5, " Not enough core for lines"), 0); +#ifdef DEBUG + xfprintf(xstderr, "%d lines\n", H.Flines); +#endif + + /* + * Now go get the blocks of seek pointers which are scattered + * throughout the temp file, reconstructing the incore + * line pointers at point of crash. + */ + b = 0; + while (H.Flines > 0) { + ignorl(lseek(tfile, (off_t) ((blocks[b] & BLKMSK) * BUFSIZ), + SEEK_SET)); + i = H.Flines < BUFSIZ / sizeof (line) ? + H.Flines * sizeof (line) : BUFSIZ; + if (read(tfile, (char *) dot, i) != i) { + perror(nb); + exit(1); + } + dot += i / sizeof (line); + H.Flines -= i / sizeof (line); + b++; + } + dot--; dol = dot; + + /* + * Sigh... due to sandbagging some lines may really not be there. + * Find and discard such. This shouldn't happen much. + */ + scrapbad(); + + /* + * Now if there were any lines in the recovered file + * write them to the standard output. + */ + if (dol > zero) { + addr1 = one; addr2 = dol; io = 1; + putfile(0); + } + + /* + * Trash the saved buffer. + * Hopefully the system won't crash before the editor + * syncs the new recovered buffer; i.e. for an instant here + * you may lose if the system crashes because this file + * is gone, but the editor hasn't completed reading the recovered + * file from the pipe from us to it. + * + * This doesn't work if we are coming from an non-absolute path + * name since we may have chdir'ed but what the hay, noone really + * ever edits with temporaries in "." anyways. + */ + if (nb[0] == '/') + ignore(unlink(nb)); + + /* + * Adieu. + */ + exit(0); +} + +/* + * Print an error message (notably not in error + * message file). If terminal is in RAW mode, then + * we should be writing output for "vi", so don't print + * a newline which would screw up the screen. + */ +/*VARARGS2*/ +void +error(char *str, ...) +{ + va_list ap; + + va_start(ap, str); + xvfprintf(xstderr, str, ap); + va_end(ap); + tcgetattr(2, &tty); + if (tty.c_lflag & ICANON) + xfprintf(xstderr, "\n"); + exit(1); +} + +void +listfiles(char *dirname) +{ + register DIR *dir; + struct dirent *dirent; + int ecount; + register int f; + char *cp; + struct svfile *fp, svbuf[NENTRY]; + + /* + * Open /usr/preserve, and go there to make things quick. + */ + dir = opendir(dirname); + if (dir == NULL) { + perror(dirname); + return; + } + if (chdir(dirname) < 0) { + perror(dirname); + return; + } + xfprintf(xstderr, "%s:\n", dirname); + + /* + * Look at the candidate files in /usr/preserve. + */ + fp = &svbuf[0]; + ecount = 0; + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] != 'E') + continue; +#ifdef DEBUG + xfprintf(xstderr, "considering %s\n", dirent->d_name); +#endif + /* + * Name begins with E; open it and + * make sure the uid in the header is our uid. + * If not, then don't bother with this file, it can't + * be ours. + */ + f = open(dirent->d_name, O_RDONLY); + if (f < 0) { +#ifdef DEBUG + xfprintf(xstderr, "open failed\n"); +#endif + continue; + } + if (read(f, (char *) &H, sizeof H) != sizeof H) { +#ifdef DEBUG + xfprintf(xstderr, "culdnt read hedr\n"); +#endif + ignore(close(f)); + continue; + } + ignore(close(f)); + if (getuid() != H.Uid) { +#ifdef DEBUG + xfprintf(xstderr, "uid wrong\n"); +#endif + continue; + } + + /* + * Saved the day! + */ + enter(fp++, dirent->d_name, ecount); + ecount++; +#ifdef DEBUG + xfprintf(xstderr, "entered file %s\n", dirent->d_name); +#endif + } + ignore(closedir(dir)); + + /* + * If any files were saved, then sort them and print + * them out. + */ + if (ecount == 0) { + xfprintf(xstderr, catgets(catd, 2, 6, "No files saved.\n")); + return; + } + qsort(&svbuf[0], ecount, sizeof svbuf[0], (int(*)(const void *, const void *)) qucmp); + for (fp = &svbuf[0]; fp < &svbuf[ecount]; fp++) { + cp = ctime(&fp->sf_time); + cp[10] = 0; + xfprintf(xstderr, catgets(catd, 2, 7, "On %s at "), cp); + cp[16] = 0; + xfprintf(xstderr, &cp[11]); + xfprintf(xstderr, catgets(catd, 2, 8, + " saved %d lines of file \"%s\"\n"), + fp->sf_lines, fp->sf_name); + } +} + +/* + * Enter a new file into the saved file information. + */ +void +enter(struct svfile *fp, char *fname, int count) +{ + register char *cp, *cp2; + register struct svfile *f, *fl; + time_t curtime; + + f = 0; + if (count >= NENTRY) { + /* + * My god, a huge number of saved files. + * Would you work on a system that crashed this + * often? Hope not. So lets trash the oldest + * as the most useless. + * + * (I wonder if this code has ever run?) + */ + fl = fp - count + NENTRY - 1; + curtime = fl->sf_time; + for (f = fl; --f > fp-count; ) + if (f->sf_time < curtime) + curtime = f->sf_time; + for (f = fl; --f > fp-count; ) + if (f->sf_time == curtime) + break; + fp = f; + } + + /* + * Gotcha. + */ + fp->sf_time = H.Time; + fp->sf_lines = H.Flines; + cp2 = fp->sf_name, cp = savedfile; + while (*cp2++ = *cp++); + for (cp2 = fp->sf_entry, cp = fname; *cp && cp-fname < 14;) + *cp2++ = *cp++; + *cp2++ = 0; +} + +/* + * Do the qsort compare to sort the entries first by file name, + * then by modify time. + */ +int +qucmp(struct svfile *p1, struct svfile *p2) +{ + register int t; + + if (t = strcmp(p1->sf_name, p2->sf_name)) + return(t); + if (p1->sf_time > p2->sf_time) + return(-1); + return(p1->sf_time < p2->sf_time); +} + +/* + * Scratch for search. + */ +char bestnb[BUFSIZ]; /* Name of the best one */ +long besttime; /* Time at which the best file was saved */ +int bestfd; /* Keep best file open so it dont vanish */ + +/* + * Look for a file, both in the users directory option value + * (i.e. usually /tmp) and in /usr/preserve. + * Want to find the newest so we search on and on. + */ +void +findtmp(char *dir) +{ + + /* + * No name or file so far. + */ + bestnb[0] = 0; + bestfd = -1; + + /* + * Search /usr/preserve and, if we can get there, /tmp + * (actually the users "directory" option). + */ + searchdir(dir); + if (chdir(mydir) == 0) + searchdir(mydir); + if (bestfd != -1) { + /* + * Gotcha. + * Put the file (which is already open) in the file + * used by the temp file routines, and save its + * name for later unlinking. + */ + tfile = bestfd; + strcpy(nb, bestnb); + ignorl(lseek(tfile, (off_t) 0, SEEK_SET)); + + /* + * Gotta be able to read the header or fall through + * to lossage. + */ + if (read(tfile, (char *) &H, sizeof H) == sizeof H) + return; + } + + /* + * Extreme lossage... + */ + error(catgets(catd, 2, 9, " File not found"), 0); +} + +/* + * Search for the file in directory dirname. + * + * Don't chdir here, because the users directory + * may be ".", and we would move away before we searched it. + * Note that we actually chdir elsewhere (because it is too slow + * to look around in /usr/preserve without chdir'ing there) so we + * can't win, because we don't know the name of '.' and if the path + * name of the file we want to unlink is relative, rather than absolute + * we won't be able to find it again. + */ +void +searchdir(char *dirname) +{ + struct dirent *dirent; + register DIR *dir; + /* char dbuf[BUFSIZ]; */ + + dir = opendir(dirname); + if (dir == NULL) + return; + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] != 'E') + continue; + /* + * Got a file in the directory starting with E... + * Save a consed up name for the file to unlink + * later, and check that this is really a file + * we are looking for. + */ + ignore(strcat(strcat(strcpy(nb, dirname), "/"), dirent->d_name)); + if (yeah(nb)) { + /* + * Well, it is the file we are looking for. + * Is it more recent than any version we found before? + */ + if (H.Time > besttime) { + /* + * A winner. + */ + ignore(close(bestfd)); + bestfd = dup(tfile); + besttime = H.Time; + strcpy(bestnb, nb); + } + /* + * Count versions so user can be told there are + * ``yet more pages to be turned''. + */ + vercnt++; + } + ignore(close(tfile)); + } + ignore(closedir(dir)); +} + +/* + * Given a candidate file to be recovered, see + * if its really an editor temporary and of this + * user and the file specified. + */ +int +yeah(char *name) +{ + + tfile = open(name, O_RDWR); + if (tfile < 0) + return (0); + if (read(tfile, (char *) &H, sizeof H) != sizeof H) { +nope: + ignore(close(tfile)); + return (0); + } + if (strcmp(savedfile, file)) + goto nope; + if (getuid() != H.Uid) + goto nope; + /* + * This is old and stupid code, which + * puts a word LOST in the header block, so that lost lines + * can be made to point at it. + */ + ignorl(lseek(tfile, (off_t) (BUFSIZ*HBLKS-8), SEEK_SET)); + ignore(write(tfile, "LOST", 5)); + return (1); +} + +int +preserve(void) +{ + return 0; +} + +/* + * Find the true end of the scratch file, and ``LOSE'' + * lines which point into thin air. This lossage occurs + * due to the sandbagging of i/o which can cause blocks to + * be written in a non-obvious order, different from the order + * in which the editor tried to write them. + * + * Lines which are lost are replaced with the text LOST so + * they are easy to find. We work hard at pretty formatting here + * as lines tend to be lost in blocks. + * + * This only seems to happen on very heavily loaded systems, and + * not very often. + */ +void +scrapbad(void) +{ + register line *ip; + struct stat stbuf; + off_t size, maxt; + bbloc bno, cnt = 0, bad, was; + char bk[BUFSIZ]; + + ignore(fstat(tfile, &stbuf)); + size = stbuf.st_size; + maxt = (size >> SHFT) | (BNDRY-1); + bno = (maxt >> OFFBTS) & BLKMSK; +#ifdef DEBUG + xfprintf(xstderr, "size %ld, maxt %o, bno %d\n", size, maxt, bno); +#endif + + /* + * Look for a null separating two lines in the temp file; + * if last line was split across blocks, then it is lost + * if the last block is. + */ + while (bno > 0) { + ignorl(lseek(tfile, (off_t) (BUFSIZ * (bno & BLKMSK)), + SEEK_SET)); + cnt = read(tfile, (char *) bk, BUFSIZ); + while (cnt > 0) + if (bk[--cnt] == 0) + goto null; + bno--; + } +null: + + /* + * Magically calculate the largest valid pointer in the temp file, + * consing it up from the block number and the count. + */ + maxt = ((bno << OFFBTS) | (cnt >> SHFT)) & ~1; +#ifdef DEBUG + xfprintf(xstderr, "bno %d, cnt %d, maxt %o\n", bno, cnt, maxt); +#endif + + /* + * Now cycle through the line pointers, + * trashing the Lusers. + */ + was = bad = 0; + for (ip = one; ip <= dol; ip++) + if (*ip > maxt) { +#ifdef DEBUG + xfprintf(xstderr, "%d bad, %o > %o\n", ip - zero, *ip, maxt); +#endif + if (was == 0) + was = ip - zero; + *ip = ((HBLKS*BUFSIZ)-8) >> SHFT; + } else if (was) { + if (bad == 0) + xfprintf(xstderr, catgets(catd, 2, 10, + " [Lost line(s):")); + xfprintf(xstderr, catgets(catd, 2, 11, + " %d"), was); + if ((ip - 1) - zero > was) + xfprintf(xstderr, catgets(catd, 2, 12, "-%d"), + (int) ((ip - 1) - zero)); + bad++; + was = 0; + } + if (was != 0) { + if (bad == 0) + xfprintf(xstderr, catgets(catd, 2, 13, + " [Lost line(s):")); + xfprintf(xstderr, catgets(catd, 2, 14, " %d"), was); + if (dol - zero != was) + xfprintf(xstderr, catgets(catd, 2, 15, + "-%d"), (int) (dol - zero)); + bad++; + } + if (bad) + xfprintf(xstderr, catgets(catd, 2, 16, "]")); +} + +int cntch, cntln, cntodd, cntnull; + +/* + * Following routines stolen mercilessly from ex. + */ +void +putfile(int unused) +{ + line *a1; + register char *fp, *lp; + register int nib; + + a1 = addr1; + clrstats(); + cntln = addr2 - a1 + 1; + if (cntln == 0) + return; + nib = BUFSIZ; + fp = genbuf; + do { + getline(*a1++); + lp = linebuf; + for (;;) { + if (--nib < 0) { + nib = fp - genbuf; + if (write(io, genbuf, nib) != nib) + wrerror(); + cntch += nib; + nib = MAXBSIZE - 1 /* 511 */; + fp = genbuf; + } + if ((*fp++ = *lp++) == 0) { + fp[-1] = '\n'; + break; + } + } + } while (a1 <= addr2); + nib = fp - genbuf; + if (write(io, genbuf, nib) != nib) + wrerror(); + cntch += nib; +} + +void +wrerror(void) +{ + + syserror(); +} + +void +clrstats(void) +{ + + ninbuf = 0; + cntch = 0; + cntln = 0; + cntnull = 0; + cntodd = 0; +} + +#define READ 0 +#define WRITE 1 + +void +getline(line tl) +{ + register char *bp, *lp; + register int nl; + + lp = linebuf; + bp = getblock(tl, READ); + nl = nleft; + tl &= ~OFFMSK; + while (*lp++ = *bp++) + if (--nl == 0) { + bp = getblock(tl += INCRMT, READ); + nl = nleft; + } +} + +char * +getblock(line atl, int iof) +{ + register bbloc bno, off; + + bno = (atl >> OFFBTS) & BLKMSK; + off = (atl << SHFT) & LBTMSK; + if (bno >= NMBLKS) + error(catgets(catd, 2, 17, " Tmp file too large")); + nleft = BUFSIZ - off; + if (bno == iblock) { + ichanged |= iof; + return (ibuff + off); + } + if (bno == oblock) + return (obuff + off); + if (iof == READ) { + if (ichanged) + blkio(iblock, ibuff, + (ssize_t(*)(int, void *, size_t))write); + ichanged = 0; + iblock = bno; + blkio(bno, ibuff, (ssize_t(*)(int, void *, size_t))read); + return (ibuff + off); + } + if (oblock >= 0) + blkio(oblock, obuff, (ssize_t(*)(int, void *, size_t))write); + oblock = bno; + return (obuff + off); +} + +void +blkio(bloc b, char *buf, ssize_t (*iofcn)(int, void *, size_t)) +{ + + lseek(tfile, (off_t) ((b & BLKMSK) * BUFSIZ), SEEK_SET); + if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) + syserror(); +} + +void +syserror(void) +{ + + dirtcnt = 0; + write(2, " ", 1); + error("%s", strerror(errno)); + exit(1); +} + +/* + * Must avoid stdio because expreserve uses sbrk to do memory + * allocation and stdio uses malloc. + */ +/* + * I do not know whether vsprintf() uses malloc() or not. + * So this may be fail, too. + */ +void +xvfprintf(xFILE *fp, char *fmt, va_list ap) +{ + char buf[BUFSIZ]; + + if (fp != xstderr) + return; + vsprintf(buf, fmt, ap); + write(2, buf, strlen(buf)); +} + +void +xfprintf(xFILE *fp, char *fmt, ...) +{ + va_list ap; + + if (fp != xstderr) + return; + va_start(ap, fmt); + xvfprintf(fp, fmt, ap); + va_end(ap); +} |
