* [9fans] Re: worm problems
@ 2001-12-13 1:27 arisawa
0 siblings, 0 replies; 3+ messages in thread
From: arisawa @ 2001-12-13 1:27 UTC (permalink / raw)
To: 9fans
Hello
>kenji,
>
>thanks, i will give this a try and let you know my results.
>
>--sam
Latest version is in:
ftp://plan9.aichi-u.ac.jp/cmd/backup/
or
ftp://ar.aichi-u.ac.jp/plan9/cmd/backup/
Some bugs are removed from posted version.
Try the latest verion.
Kenji Arisawa
E-mail: arisawa@aichi-u.ac.jp
^ permalink raw reply [flat|nested] 3+ messages in thread
* [9fans] Re: worm problems
@ 2001-12-10 0:48 arisawa
2001-12-12 12:39 ` Sam Ducksworth
0 siblings, 1 reply; 3+ messages in thread
From: arisawa @ 2001-12-10 0:48 UTC (permalink / raw)
To: 9fans
Hello,
For the safe of fs crash, I have written another backup tool.
-WARNING-
You should examine this tool carefully by yourself
before you apply to your system.
Kenji Arisawa
E-mail: arisawa@aichi-u.ac.jp
/* ---------------------- backup.c ------------------------
name: backup
backup utility for Plan9
usage: backup [-vn] -s source -d destination [-l backuplist] [path ...]
options and arguments:
-v: verbose
-n: make a new backup, i.e.,
execute backup even if destination is an empty directory
-s source: source dir from which backup is made.
-d destination: diestination dir in which backup is made.
-l backuplist: path list to be processed. path list must be a path per line.
path ... : path list to be processed.
function:
`backup' makes an effort to make mirror of source/path in destination/path
`backup' tries to preserve the following info.:
- contents (judged from modification time)
- modification time
- permissions
- owner and group info.
and `backup' discards files and directories in destination/path
that are non-existent in source/path
typical usage 1:
# Let's consider that we (host owner) want to have a backup of 9fs in kfs,
# then:
# confirm 9fs and kfs are mounted on /n/9fs and /n/kfs respectively
# and execute:
% disk/kfscmd allow
% backup -s /n/9fs -d /n/kfs /
% disk/kfscmd disallow
# note that only at first time we should execute:
% backup -n -s /n/9fs -d /n/kfs /
typical usage 2:
# backup my files to kfs
# confirm 9fs and kfs are mounted on /n/9fs and /n/kfs respectively
# and then executed
% backup -s /n/9fs -d /n/kfs $home
backuplist sample:
# each line is trimmed before evaluation
# lines starting with `#' are comments
# one path per line
386
cron
dist
rc
lib
sys
lp
acme
mail/lib
adm
wrap
usr
Coded by Kenji Arisawa (Kenar)
Bug report to: arisawa@aichi-u.ac.jp
------------------------------------------------------- */
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#define MAXPATH 4096
void usage(void);
char *mkpath2(char *path1, char *path2);
char *mkpath3(char *path1, char *path2, char *path3);
char *strtrim(char *s);
int growto(Dir **dirbuf, int ndirbuf, long n);
int compar(Dir *a, Dir *b);
void backup(char *s);
int check(char *path);
int dirinfo(Dir **dirbuf, char *path);
void cpfile(char *path);
void rmdir(char *path);
int rmfile(char *path);
char *src, *dst;
int vflag;
int nflag;
void usage(void)
{ fprint(2, "usage: backup [-nv] -s source -d destination [-l backuplist] [path ....]\n");
exits("usage");
}
char *
mkpath2(char *path1, char *path2)
{
char *p;
p = malloc(strlen(path1)+strlen(path2)+5);
if(strlen(path1))
sprint(p, "%s/%s", path1, path2);
else
sprint(p, "%s", path2);
return p;
}
char *
mkpath3(char *path1, char *path2, char *path3)
{
char *p;
p = malloc(strlen(path1)+strlen(path2)+strlen(path3)+5);
if(strlen(path2))
sprint(p, "%s/%s/%s", path1, path2, path3);
else
sprint(p, "%s/%s", path1, path3);
return p;
}
char *strtrim(char *s)
{
char *t;
while(*s && isspace(*s))
s++;
t = s + strlen(s) - 1;
if(s < t){
while(*t && isspace(*t)) t--;
t++;
*t = 0;
}
return s;
}
void main(int argc, char *argv[])
{
char *file = 0;
USED(argc);
ARGBEGIN{
case 'd': dst = ARGF(); break;
case 's': src = ARGF(); break;
case 'l': file = ARGF(); break;
case 'v': vflag = 1; break;
case 'n': nflag = 1; break;
default: usage();
}ARGEND
if(!src || !dst)
usage();
if(!file && !*argv)
usage();
/* check src whether it is not empty */
switch(check(src)){
case 1:
fprint(2, "%s is non-existent\n", src);
exits("error");
case 2:
fprint(2, "%s is not a directory\n", src);
exits("error");
case 3:
fprint(2, "%s is empty\n", src);
exits("error");
default:
break;
}
/* check dst whether it exits */
switch(check(dst)){
case 1:
fprint(2, "%s is non-existent\n", dst);
exits("error");
case 2:
fprint(2, "%s is not a directory\n", dst);
exits("error");
case 3:
if(!nflag){
fprint(2, "%s is empty\n", dst);
exits("error");
}
default:
break;
}
/* check that whether dst is one of subtree of src.
* if it is, we must abort processing */
if(strlen(dst) >= strlen(src) && strncmp(dst,src,strlen(src)) == 0){
/* then be careful */
if(dst[strlen(src)] == '/'){
fprint(2, "%s is a subtree of %s\n", dst, src);
exits("error");
}
}
if(file){
Biobuf in;
char *line;
char *path;
char buf[MAXPATH];
int fd;
int n;
fd = open(file, OREAD);
if(fd<0){
fprint(2, "balckuplist %s not open\n", file);
exits("error");
}
Binit(&in, fd, OREAD);
while(line = Brdline(&in,'\n')){/* assign = */
n = Blinelen(&in);
strncpy(buf, line, n);
buf[n] = 0;
path = strtrim(buf);
if(path[0] == '#')
continue;
if(vflag) print("looking... %s\n", path);
backup(path);
}
Bterm(&in); // note: Bterm close the file
}
while(*argv){
if(vflag) print("looking... %s\n", *argv);
backup(*argv++);
}
}
void backup(char *path)
{
int f;
int nsrcdir;
int ndstdir;
Dir *srcdirbuf, *sd, *sdend, *ddend;
Dir *dstdirbuf, *dd;
char *newpath;
char srcpath[MAXPATH];
char dstpath[MAXPATH];
if(path[0] == '/') path++;
snprint(srcpath,sizeof(srcpath),"%s/%s", src, path);
nsrcdir = dirinfo(&srcdirbuf, srcpath);
if(nsrcdir < 0){
/* skip this backup */
fprint(2, "%s unreadable\n", srcpath);
return;
}
snprint(dstpath,sizeof(dstpath),"%s/%s", dst, path);
ndstdir = dirinfo(&dstdirbuf, dstpath);
if(ndstdir < 0){
/* skip this backup */
fprint(2, "%s unreadable\n", dstpath);
free(srcdirbuf);
return;
}
sdend = srcdirbuf + nsrcdir;
ddend = dstdirbuf + ndstdir;
/* backup them */
for(sd = srcdirbuf, dd = dstdirbuf; sd < sdend && dd < ddend; ){
if(strcmp(sd->name, dd->name) < 0){
/* create destination */
newpath = mkpath2(path, sd->name);
if(vflag) print("creating: %s/%s\n", dst, newpath);
if(sd->mode & CHDIR){
char *p;
/* create the directory and go on */
p = mkpath2(dst, newpath);
f = create(dstpath, OREAD, sd->mode);
if(f < 0)
fprint(2, "mkdir: can't create %s: %r\n", p);
close(f);
free(p);
backup(newpath);
}
else
{
cpfile(newpath);
}
free(newpath);
sd++;
}
else if(strcmp(sd->name, dd->name) > 0){
/* remove destination */
char *p;
p = mkpath3(dst, path, dd->name);
if(vflag) print("removing: %s\n", p);
if(dd->mode & CHDIR)
rmdir(p);
else
rmfile(p);
free(p);
dd++;
}
else {
/* both names exist */
char *target;
newpath = mkpath2(path, sd->name);
target = mkpath3(dst, path, sd->name);
if(sd->mode & CHDIR){
int err = 0;
if((dd->mode & CHDIR) == 0){
/* file. so we remove it and create dir. */
if(rmfile(target) < 0){
err = 1;
}
f = create(target, OREAD, sd->mode);
if(f < 0){
fprint(2, "unable to create %s", target);
err = 1;
}
close(f);
}
if(!err) backup(newpath);
}
/* check the date */
if(sd->mtime > dd->mtime){
if(sd->mode & CHDIR ){
strcpy(dd->uid, sd->uid);
strcpy(dd->gid, sd->gid);
dd->mode = sd->mode;
dd->mtime = sd->mtime;
dirwstat(target, dd);
}
else{
/* file */
if(vflag) print("copying: %s\n", target);
cpfile(newpath);
}
}
else{
int cf = 0;
if(strcmp(sd->uid,dd->uid) != 0){
/* change owner */;
if(vflag) print("chown: %s\n", target);
strcpy(dd->uid, sd->uid);
cf = 1;
}
if(strcmp(sd->gid, dd->gid) != 0){
/* change group */;
if(vflag) print("chgrp: %s\n", target);
strcpy(dd->gid, sd->gid);
cf = 1;
}
if(sd->mode != dd->mode){
/* change mode */;
if(vflag) print("chmod: %s\n", target);
dd->mode = sd->mode;
cf = 1;
}
if(cf)
dirwstat(target, dd);
}
free(newpath);
free(target);
sd++;
dd++;
}
}
if(sd < sdend){
char *p;
int f;
for(; sd < sdend; sd++){
newpath = mkpath2(path, sd->name);
p = mkpath3(dst, path, sd->name);
if(vflag) print("creating: %s\n", p);
if(sd->mode & CHDIR){
f = create(p, OREAD, sd->mode);
if(f < 0)
fprint(2, "mkdir: can't create %s: %r\n", p);
close(f);
backup(newpath);
}
else
cpfile(newpath);
free(newpath);
free(p);
}
}
else if(dd < ddend){
char *p;
for(; dd < ddend; dd++){
p = mkpath3(dst, path, dd->name);
if(vflag) print("removing: %s\n", p);
if(dd->mode & CHDIR)
rmdir(p);
else
rmfile(p);
free(p);
}
}
/* free dirbuf */
free(srcdirbuf);
free(dstdirbuf);
}
int
check(char *path)
{
int fd;
Dir db[1], d;
fd = open(path, OREAD);
if(fd == -1)
return 1; // non existent
dirfstat(fd, &d);
if((d.mode & CHDIR) == 0){
close(fd);
return 2; // not a directory
}
if(dirread(fd, db, sizeof db) == 0){
close(fd);
return 3; // empty
}
close(fd);
return 0;
}
/*
* dirinfo
*
* return value
* case -1: not exit
* case 0: empty
* others: the numbers of files/directory
*
* note:
* free(dirbuf) if return value is not -1
*
* ref: /sys/src/cmd/ls.c
*/
int dirinfo(Dir **dirbufp, char *path)
{
int fd;
int ndirbuf = 0;
int ndir = 0;
Dir *dirbuf = 0;
Dir db[50],d;
int i,n;
fd = open(path, OREAD);
if(fd == -1)
return -1;
dirfstat(fd, &d);
while((n=dirread(fd, db, sizeof db)) > 0){
n /= sizeof(Dir);
ndirbuf = growto(&dirbuf, ndirbuf, ndir+n);
for(i=0; i<n; i++)
memmove(dirbuf+ndir+i, db+i, sizeof(Dir));
ndir += n;
}
close(fd);
/* sort by name */
qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(void*, void*))compar);
*dirbufp = dirbuf;
return ndir;
}
/*
* stolen from /sys/src/cmd/ls.c
*/
int
growto(Dir **dirbuf, int ndirbuf, long n)
{
if(n <= ndirbuf)
return ndirbuf;
ndirbuf = n;
*dirbuf=(Dir *)realloc(*dirbuf, ndirbuf*sizeof(Dir));
if(*dirbuf == 0){
fprint(2, "ls: malloc fail\n");
exits("malloc fail");
}
return ndirbuf;
}
int
compar(Dir *a, Dir *b)
{
return strcmp(a->name, b->name);
}
void cpfile(char *path)
{
char srcpath[MAXPATH];
char dstpath[MAXPATH];
Dir d, d1;
char buf[4096];
int n;
int sfd, dfd;
if(path[0] == '/') path++;
snprint(srcpath,sizeof(srcpath),"%s/%s", src, path);
snprint(dstpath,sizeof(dstpath),"%s/%s", dst, path);
sfd = open(srcpath, OREAD);
if(sfd < 0){
fprint(2, "open error: %s\n", srcpath);
return;
}
dirfstat(sfd, &d);
remove(dstpath);
dfd = create(dstpath, OWRITE | OTRUNC, 0777);
if(dfd < 0){
fprint(2, "unable to create: %s\n", dstpath);
close(sfd);
return;
}
for(;;){
n = read(sfd, buf, sizeof buf);
if(n <= 0) break;
if(write(dfd, buf, n) != n){
fprint(2, "write error: %s\n", dstpath);
break;
}
}
dirfstat(dfd, &d1);
close(sfd);
close(dfd);
/* and we copy dirstat info */
d1.mode = d.mode;
d1.mtime = d.mtime;
strcpy(d1.uid, d.uid);
strcpy(d1.gid, d.gid);
dirwstat(dstpath, &d1);
}
int
rmfile(char *path){
int status;
status = remove(path);
if(status == -1)
fprint(2,"%s not removed", path);
return status;
}
void
rmdir(char *path)
{
char *name;
int i, ndir;
Dir *dirbuf;
ndir = dirinfo(&dirbuf, path);
if(ndir < 0){
fprint(2, "cannot get dir info %s\n", path);
return;
}
for(i=0; i<ndir; i++){
name = mkpath2(path, dirbuf[i].name);
if(dirbuf[i].mode & CHDIR)
rmdir(name);
else
rmfile(name);
free(name);
}
rmfile(path);
free(dirbuf);
}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [9fans] Re: worm problems
2001-12-10 0:48 arisawa
@ 2001-12-12 12:39 ` Sam Ducksworth
0 siblings, 0 replies; 3+ messages in thread
From: Sam Ducksworth @ 2001-12-12 12:39 UTC (permalink / raw)
To: 9fans
kenji,
thanks, i will give this a try and let you know my results.
--sam
On Mon, 10 Dec 2001 arisawa@ar.aichi-u.ac.jp wrote:
> Hello,
>
> For the safe of fs crash, I have written another backup tool.
>
> -WARNING-
> You should examine this tool carefully by yourself
> before you apply to your system.
>
--sam
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2001-12-13 1:27 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-12-13 1:27 [9fans] Re: worm problems arisawa
-- strict thread matches above, loose matches on Subject: below --
2001-12-10 0:48 arisawa
2001-12-12 12:39 ` Sam Ducksworth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).