summaryrefslogtreecommitdiff
path: root/expreserve.c
diff options
context:
space:
mode:
Diffstat (limited to 'expreserve.c')
-rw-r--r--expreserve.c555
1 files changed, 555 insertions, 0 deletions
diff --git a/expreserve.c b/expreserve.c
new file mode 100644
index 0000000..e0e49a8
--- /dev/null
+++ b/expreserve.c
@@ -0,0 +1,555 @@
+/*
+ * 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 = "@(#)expreserve.c 1.23 (gritter) 11/27/04";
+#endif
+
+/* from expreserve.c 7.13.2 (2.11BSD GTE) 1996/10/26 */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <dirent.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <time.h>
+
+#include "config.h"
+
+#ifdef LANGMSG
+#include <nl_types.h>
+#include <locale.h>
+nl_catd catd;
+#else
+#define catgets(a, b, c, d) (d)
+#endif
+
+#ifdef BUFSIZ
+#undef BUFSIZ
+#endif
+#ifdef LINE_MAX
+#define BUFSIZ LINE_MAX /* POSIX line size */
+#else /* !LINE_MAX */
+#ifdef VMUNIX
+#define BUFSIZ 1024
+#else /* !VMUNIX */
+#ifdef u370
+#define BUFSIZ 4096
+#else /* !u370 */
+#define BUFSIZ 512
+#endif /* !u370 */
+#endif
+#endif /* !VMUNIX */
+
+#ifdef LARGEF
+typedef off_t bloc;
+#else
+typedef short bloc;
+#endif
+
+#ifdef VMUNIX
+#ifdef LARGEF
+typedef off_t bbloc;
+#else
+typedef int bbloc;
+#endif
+#else
+typedef short bbloc;
+#endif
+
+#ifdef notdef
+#define TMP "/tmp"
+#else
+#define TMP "/var/tmp"
+#endif
+
+#ifndef VMUNIX
+#define LBLKS 125
+#else
+#ifdef LARGEF
+#define LBLKS 20000
+#else
+#define LBLKS 900
+#endif
+#endif
+#ifdef _POSIX_PATH_MAX
+#define FNSIZE _POSIX_PATH_MAX
+#else
+#define FNSIZE 128
+#endif
+
+#ifdef VMUNIX
+#define HBLKS (1 + (FNSIZE + LBLKS * sizeof(bloc)) / BUFSIZ)
+#else
+#define HBLKS 1
+#endif
+
+char xstr[1]; /* make loader happy */
+
+extern void notify(uid_t, char *, int, time_t);
+extern int copyout(char *);
+extern void mkdigits(char *);
+extern void mknext(char *);
+
+/*
+ * Expreserve - preserve a file in /usr/preserve
+ * Bill Joy UCB November 13, 1977
+ *
+ * This routine is very naive - it doesn't remove anything from
+ * /usr/preserve... this may mean that we leave
+ * stuff there... the danger in doing anything with /usr/preserve
+ * is that the clock may be screwed up and we may get confused.
+ *
+ * We are called in two ways - first from the editor with no argumentss
+ * and the standard input open on the temp file. Second with an argument
+ * to preserve the entire contents of /tmp (root only).
+ *
+ * BUG: should do something about preserving Rx... (register contents)
+ * temporaries.
+ */
+
+struct header {
+ time_t Time; /* Time temp file last updated */
+ uid_t Uid;
+ bbloc Flines; /* Number of lines in file */
+ char Savedfile[FNSIZE]; /* The current file name */
+ bloc Blocks[LBLKS]; /* Blocks where line pointers stashed */
+} H;
+
+#define ignore(a) a
+#define ignorl(a) a
+
+#define eq(a, b) (strcmp(a, b) == 0)
+
+int
+main(int argc, char **argv)
+{
+ register DIR *tf;
+ struct dirent *dirent;
+ struct stat stbuf;
+
+#ifdef LANGMSG
+ setlocale(LC_MESSAGES, "");
+ catd = catopen(CATNAME, NL_CAT_LOCALE);
+#endif
+ /*
+ * If only one argument, then preserve the standard input.
+ */
+ if (argc == 1) {
+ if (copyout((char *) 0))
+ exit(1);
+ exit(0);
+ }
+
+ /*
+ * If not super user, then can only preserve standard input.
+ */
+ if (getuid()) {
+ fprintf(stderr, catgets(catd, 3, 1, "NOT super user\n"));
+ exit(1);
+ }
+
+ /*
+ * ... else preserve all the stuff in /tmp, removing
+ * it as we go.
+ */
+ if (chdir(TMP) < 0) {
+ perror(TMP);
+ exit(1);
+ }
+
+ tf = opendir(".");
+ if (tf == NULL) {
+ perror(TMP);
+ exit(1);
+ }
+ while ((dirent = readdir(tf)) != NULL) {
+ /* Ex temporaries must begin with Ex. */
+ if (dirent->d_name[0] != 'E' || dirent->d_name[1] != 'x')
+ continue;
+ if (stat(dirent->d_name, &stbuf))
+ continue;
+ if ((stbuf.st_mode & S_IFMT) != S_IFREG)
+ continue;
+ /*
+ * Save the bastard.
+ */
+ ignore(copyout(dirent->d_name));
+ }
+ closedir(tf);
+ return 0;
+}
+
+#ifdef notdef
+char pattern[] = "/usr/preserve/Exaa`XXXXX";
+#else
+char pattern[] = "/var/preserve/Exa`XXXXXXXXXX";
+#endif
+
+/*
+ * Notify user uid that his file fname has been saved.
+ */
+void
+notify(uid_t uid, char *fname, int flag, time_t time)
+{
+ struct passwd *pp = getpwuid(uid);
+ register FILE *mf;
+ char cmd[BUFSIZ];
+ struct utsname ut;
+ char *hostname;
+ char croak[128];
+ char *timestamp;
+
+ if (pp == NULL)
+ return;
+ uname(&ut);
+ hostname = ut.nodename;
+ timestamp = ctime(&time);
+ timestamp[16] = 0; /* blast from seconds on */
+ putenv("MAILRC=/dev/null");
+ sprintf(cmd, "/bin/mail %s", pp->pw_name);
+ setuid(getuid());
+ mf = popen(cmd, "w");
+ if (mf == NULL)
+ return;
+ setbuf(mf, cmd);
+ /*
+ * flag says how the editor croaked:
+ * "the editor was killed" is perhaps still not an ideal
+ * error message. Usually, either it was forcably terminated
+ * or the phone was hung up, but we don't know which.
+ */
+ sprintf(croak, flag
+ ? catgets(catd, 3, 2, "the system went down")
+ : catgets(catd, 3, 3, "the editor was killed"));
+ if (fname[0] == 0) {
+ fname = "LOST";
+ fprintf(mf, catgets(catd, 3, 4,
+ "Subject: editor saved ``LOST''\n"));
+ fprintf(mf, catgets(catd, 3, 5,
+ "You were editing a file without a name\n"));
+ fprintf(mf, catgets(catd, 3, 6,
+ "at <%s> on the machine ``%s'' when %s.\n"),
+ timestamp, hostname, croak);
+ fprintf(mf, catgets(catd, 3, 7,
+ "Since the file had no name, it has been named \"LOST\".\n"));
+ } else {
+ fprintf(mf, catgets(catd, 3, 8,
+ "Subject: editor saved ``%s''\n"), fname);
+ fprintf(mf, catgets(catd, 3, 9,
+ "You were editing the file \"%s\"\n"), fname);
+ fprintf(mf, catgets(catd, 3, 10,
+ "at <%s> on the machine ``%s''\n"),
+ timestamp, hostname);
+ fprintf(mf, catgets(catd, 3, 11, "when %s.\n"), croak);
+ }
+ fprintf(mf, catgets(catd, 3, 12,
+ "\nYou can retrieve most of your changes to this file\n"));
+ fprintf(mf, catgets(catd, 3, 13,
+ "using the \"recover\" command of the editor.\n"));
+ fprintf(mf, catgets(catd, 3, 14,
+"An easy way to do this is to give the command \"vi -r %s\".\n"), fname);
+ fprintf(mf, catgets(catd, 3, 15,
+ "This method also works using \"ex\" and \"edit\".\n"));
+ pclose(mf);
+}
+
+/*
+ * Copy file name into /usr/preserve/...
+ * If name is (char *) 0, then do the standard input.
+ * We make some checks on the input to make sure it is
+ * really an editor temporary, generate a name for the
+ * file (this is the slowest thing since we must stat
+ * to find a unique name), and finally copy the file.
+ */
+int
+copyout(char *name)
+{
+ int i;
+ char buf[BUFSIZ];
+ static int reenter;
+
+ /*
+ * The first time we put in the digits of our
+ * process number at the end of the pattern.
+ */
+ if (reenter == 0) {
+ mkdigits(pattern);
+ reenter++;
+ }
+
+ /*
+ * If a file name was given, make it the standard
+ * input if possible.
+ */
+ if (name != 0) {
+ ignore(close(0));
+ /*
+ * Need read/write access for arcane reasons
+ * (see below).
+ */
+ if (open(name, O_RDWR) < 0)
+ return (-1);
+ }
+
+ /*
+ * Get the header block.
+ */
+ ignorl(lseek(0, (off_t) 0, SEEK_SET));
+ if (read(0, (char *) &H, sizeof H) != sizeof H) {
+format:
+ if (name == 0)
+ fprintf(stderr, catgets(catd, 3, 16,
+ "Buffer format error\t"));
+ return (-1);
+ }
+
+ /*
+ * Consistency checsks so we don't copy out garbage.
+ */
+ if (H.Flines < 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Negative number of lines\n");
+#endif
+ goto format;
+ }
+ if (H.Blocks[0] != HBLKS || H.Blocks[1] != HBLKS+1) {
+#ifdef DEBUG
+ fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
+#endif
+ goto format;
+ }
+ if (name == 0 && H.Uid != getuid()) {
+#ifdef DEBUG
+ fprintf(stderr, "Wrong user-id\n");
+#endif
+ goto format;
+ }
+ if (lseek(0, (off_t) 0, SEEK_SET)) {
+#ifdef DEBUG
+ fprintf(stderr, "Negative number of lines\n");
+#endif
+ goto format;
+ }
+
+ /*
+ * If no name was assigned to the file, then give it the name
+ * LOST, by putting this in the header.
+ */
+ if (H.Savedfile[0] == 0) {
+ strcpy(H.Savedfile, "LOST");
+ ignore(write(0, (char *) &H, sizeof H));
+ H.Savedfile[0] = 0;
+ lseek(0, (off_t) 0, SEEK_SET);
+ }
+
+ /*
+ * File is good. Get a name and create a file for the copy.
+ */
+ mknext(pattern);
+ ignore(close(1));
+ if (open(pattern, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC
+#ifdef O_NOFOLLOW
+ |O_NOFOLLOW
+#endif /* O_NOFOLLOW */
+ , 0600) < 0) {
+ if (name == 0)
+ perror(pattern);
+ return (1);
+ }
+
+ /*
+ * Make the target be owned by the owner of the file.
+ */
+ ignore(chown(pattern, H.Uid, 0));
+
+ /*
+ * Copy the file.
+ */
+ for (;;) {
+ i = read(0, buf, BUFSIZ);
+ if (i < 0) {
+ if (name)
+ perror(catgets(catd, 3, 17,
+ "Buffer read error"));
+ ignore(unlink(pattern));
+ return (-1);
+ }
+ if (i == 0) {
+ if (name)
+ ignore(unlink(name));
+ notify(H.Uid, H.Savedfile, name != 0, H.Time);
+ return (0);
+ }
+ if (write(1, buf, i) != i) {
+ if (name == 0)
+ perror(pattern);
+ unlink(pattern);
+ return (-1);
+ }
+ }
+}
+
+/*
+ * Blast the last 5 characters of cp to be the process number.
+ */
+void
+mkdigits(char *cp)
+{
+ register pid_t i;
+ register int j;
+
+#ifdef notdef
+ for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
+ *--cp = i % 10 | '0';
+#else
+ for (i = getpid(), j = 10, cp += strlen(cp); j > 0; i /= 10, j--)
+ *--cp = i % 10 | '0';
+#endif
+}
+
+/*
+ * Make the name in cp be unique by clobbering up to
+ * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
+ * Mktemp gets weird names too quickly to be useful here.
+ */
+void
+mknext(char *cp)
+{
+ char *dcp;
+ struct stat stb;
+
+ dcp = cp + strlen(cp) - 1;
+ while (isdigit(*dcp & 0377))
+ dcp--;
+whoops:
+ if (dcp[0] == 'z') {
+ dcp[0] = 'a';
+ if (dcp[-1] == 'z') {
+#ifdef notdef
+ dcp[-1] = 'a';
+ if (dcp[-2] == 'z')
+#endif
+ fprintf(stderr, catgets(catd, 3, 18,
+ "Can't find a name\t"));
+#ifdef notdef
+ dcp[-2]++;
+#endif
+ } else
+ dcp[-1]++;
+ } else
+ dcp[0]++;
+ if (stat(cp, &stb) == 0)
+ goto whoops;
+}
+
+/*
+ * people making love
+ * never exactly the same
+ * just like a snowflake
+ */
+
+#ifdef lint
+void
+Ignore(int a)
+{
+
+ a = a;
+}
+
+void
+Ignorl(long a)
+{
+
+ a = a;
+}
+#endif