/****************************-*-C-*-***********************************
* $Id: bksh.c,v 1.50 2004/03/05 02:40:18 anarcat Exp $
**********************************************************************
* Backup wrapper shell for ssh
**********************************************************************
* Copyright (C) 2001-2003 The Anarcat <anarcat@anarcat.ath.cx>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* See also http://www.fsf.org
*********************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 2
#include <osreldate.h>
# if __FreeBSD_version >= 430000
#include <libgen.h>
# else
#include "basename.h"
# endif
#else
/* compatibility with FreeBSD extensions */
# if defined(__NetBSD__)
int optreset = 0;
#include "basename.h"
# else
char optreset = 0;
#include "basename.h"
# endif
#endif
#include "bksh.h"
/* recursively create missing directories */
int mkdirp(const char* path, mode_t mode) {
int ret;
char* wpath;
/* strip any trailing slash, since POSIX mkdir() doesn't accept it */
ret = strlen(path);
if (path[ret] == '/') {
wpath = strdup(path);
wpath[ret] = '\0';
path = wpath;
}
if ( (ret = mkdir(path, mode)) < 0) {
if (errno == ENOENT) {
wpath = dirname(path);
if (strcmp(wpath, path) == 0)
return -1;
fprintf(stderr, "directory %s missing, trying to create %s\n",
path, wpath);
wpath = strdup(wpath); /* dirname returns static storage */
mkdirp(wpath, mode);
free(wpath);
return mkdir(path, mode);
} else
return -1;
} else
return ret;
}
int main (int argc, char** argv) {
char buffer[BUFSIZ], datadir[MAXPATHLEN],
filename[MAXPATHLEN];
char *n; /* temporary handle for arg parsing */
int i, fd, ch;
int max_baks = MAX_BAKS;
/* command line parsing */
while ((ch = getopt(argc, argv,
"chV?"
)) != -1) {
switch (ch) {
case 'c': /* we ignore the -c arg */
break;
case 'V':
printf("bksh $Name: BKSH_REL_1_7 $\n");
printf("Compiled with:\n");
printf("Static %d backups maximum\n", max_baks);
#ifdef FILE_BACKUP
printf("Regular to-file backups\n");
#else
printf("Tape-only backups\n");
#endif
printf("Default backup dir: %s, default filename: %s\n",
DEF_DATADIR, DEF_FILENAME);
printf("Copyright (c) 2002-2003 The Anarcat <anarcat@anarcat.ath.cx>\n");
exit(1);
break;
default:
fprintf(stderr, "wrong argument: %c\n", ch);
break;
}
}
argc -= optind;
argv += optind;
/* manually parse the remaining options
*
* we tokenize each remaining argument into a args array that will
* be acceptable input to getopt(3)
*/
if (argc >= 1) {
char *args[MAX_ARGS], *arg;
int i, argcount = 0;
for (i = 0; i < argc; i++) {
/* tokenize the string */
for (arg = argv[i]; *arg; arg++) {
/* eat whitespace */
while (*arg && isspace(*arg)) arg++;
if (!*arg)
break;
if (argcount < MAX_ARGS) {
args[argcount++] = arg;
/* eat non whitespace */
while (*arg && !isspace(*arg)) arg++;
if (!*arg)
break;
*arg = 0; /* terminate string here */
} else {
fprintf(stderr, "maximum argument count (%d) exceeded\n", MAX_ARGS);
break;
}
}
}
optind = 1;
optreset = 1;
/* at this point we should have an array of args properly constructed */
while ((ch = getopt(argcount, args,
"t:"
)) != -1) {
if (ch == 't') {
char* m;
max_baks = strtol(optarg, &m, 0);
if (*m) { /* oups, did not stop at the end */
fprintf(stderr, "invalid numeric value: %s, ignoring\n", optarg);
max_baks = MAX_BAKS;
}
} else {
fprintf(stderr, "wrong argument: %c\n", ch);
}
}
}
#ifdef FILE_BACKUP
if ( (argc >= 1) &&
((strcmp(argv[0], "/dev/sa0") == 0) ||
(strcmp(argv[0], "/dev/nsa0") == 0) ||
(strcmp(argv[0], "/dev/esa0") == 0)) ) {
strcpy(filename, argv[0]);
} else {
char backup_file[MAXPATHLEN];
char *back_name = DEF_FILENAME;
char *home = getenv("HOME");
char *client_hn = getenv("SSH_CLIENT");
/* mandatory environment */
if (home == NULL) {
fprintf(stderr, "HOME not set, aborting\n");
exit(1);
}
if (client_hn == NULL) {
fprintf(stderr, "SSH_CLIENT not set, aborting\n");
exit(1);
}
/* first space in the SSH_CLIENT string delimits hostname */
for (n = client_hn; *n && *n != ' '; n++) {
}
*n = '\0'; /* end the string after the hostname */
snprintf(datadir, MAXPATHLEN, "%s/%s/%s",
home, DEF_DATADIR, client_hn);
/* make hierarchy leading to the drop dir */
mkdirp(datadir, 0700);
/* we take the backup name from the first argument */
if (argc >= 1)
back_name = basename(argv[0]);
snprintf(filename, MAXPATHLEN, "%s/%s",
datadir, back_name);
if (max_baks > 1) {
/* rotate the files */
/* 1- find last archive */
for (i = 1; i < (max_baks-1) &&
(access(filename, F_OK) == 0); i++) {
snprintf(filename, MAXPATHLEN, "%s/%s.%d",
datadir, back_name, i);
}
if (i < (max_baks-1)) i--; /* filename i didn't exist */
/* 2- rotate numerically named files */
while (i > 1) {
snprintf(backup_file, MAXPATHLEN, "%s/%s.%d",
datadir, back_name, i);
snprintf(filename, MAXPATHLEN, "%s/%s.%d",
datadir, back_name, (--i));
rename(filename, backup_file);
}
/* 3- rotate last file left */
if (i == 1) {
snprintf(backup_file, MAXPATHLEN, "%s/%s.%d",
datadir, back_name, i);
snprintf(filename, MAXPATHLEN, "%s/%s",
datadir, back_name);
rename(filename, backup_file);
}
} else { /* only one backup file allowed, remove prior art */
unlink(filename);
}
}
#else
strcpy(filename, "/dev/nsa0");
#endif
/* write the file */
fd = open(filename, O_WRONLY | O_CREAT, 0400);
if (fd < 0) {
fprintf(stderr, "can't open file %s: %s\n",
filename, strerror(errno));
exit(1);
}
while ( (i = read(STDIN_FILENO, buffer, BUFSIZ)) > 0) {
if (write(fd, buffer, i) < 0) {
fprintf(stderr, "can't write to file %s: %s",
filename, strerror(errno));
exit(1);
}
}
close (fd);
printf("written to %s\n", filename);
if (i < 0) {
fprintf(stderr, "cant't read from stdin: %s", strerror(errno));
exit(1);
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1