2011-03-30 12:46:40 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2011-04-29 09:15:28 +00:00
|
|
|
#include <disk.h>
|
2011-03-30 12:46:40 +00:00
|
|
|
#include <auth.h>
|
|
|
|
#include <bio.h>
|
|
|
|
|
|
|
|
enum{
|
2011-04-29 09:15:28 +00:00
|
|
|
LEN = 4096,
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* types of destination file sytems
|
|
|
|
*/
|
2015-08-21 17:32:48 +00:00
|
|
|
Fs = 0,
|
2011-03-30 12:46:40 +00:00
|
|
|
Archive,
|
|
|
|
};
|
|
|
|
|
2011-04-29 09:15:28 +00:00
|
|
|
void protowarn(char *msg, void *);
|
|
|
|
void protoenum(char *new, char *old, Dir *d, void *);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
void arch(Dir*);
|
|
|
|
void copy(Dir*);
|
|
|
|
void error(char *, ...);
|
|
|
|
void mkdir(Dir*);
|
|
|
|
int uptodate(Dir*, char*);
|
|
|
|
void usage(void);
|
|
|
|
void warn(char *, ...);
|
|
|
|
|
|
|
|
Biobufhdr bout; /* stdout when writing archive */
|
|
|
|
uchar boutbuf[2*LEN];
|
|
|
|
char newfile[LEN];
|
|
|
|
char oldfile[LEN];
|
|
|
|
char *proto;
|
|
|
|
char *oldroot;
|
|
|
|
char *newroot;
|
|
|
|
char *prog = "mkfs";
|
|
|
|
char *buf;
|
|
|
|
char *zbuf;
|
|
|
|
int buflen = 1024-8;
|
|
|
|
int verb;
|
|
|
|
int modes;
|
|
|
|
int ream;
|
|
|
|
int debug;
|
|
|
|
int xflag;
|
2014-12-14 23:52:22 +00:00
|
|
|
int oflag;
|
2011-03-30 12:46:40 +00:00
|
|
|
int sfd;
|
2015-08-21 17:32:48 +00:00
|
|
|
int fskind; /* Fs, Archive */
|
2011-03-30 12:46:40 +00:00
|
|
|
int setuid; /* on Fs: set uid and gid? */
|
|
|
|
char *user;
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int i, errs;
|
|
|
|
|
|
|
|
quotefmtinstall();
|
|
|
|
user = getuser();
|
|
|
|
oldroot = "";
|
2015-08-21 17:32:48 +00:00
|
|
|
newroot = "/n/newfs";
|
|
|
|
fskind = Fs;
|
2011-03-30 12:46:40 +00:00
|
|
|
ARGBEGIN{
|
|
|
|
case 'a':
|
|
|
|
fskind = Archive;
|
|
|
|
newroot = "";
|
|
|
|
Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf);
|
|
|
|
break;
|
|
|
|
case 'd':
|
2015-08-21 17:32:48 +00:00
|
|
|
if(fskind != Fs) {
|
2011-03-30 12:46:40 +00:00
|
|
|
fprint(2, "cannot use -d with -a\n");
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
fskind = Fs;
|
2015-08-21 17:32:48 +00:00
|
|
|
newroot = EARGF(usage());
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
debug = 1;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
modes = 1;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
ream = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
2015-08-21 17:32:48 +00:00
|
|
|
oldroot = EARGF(usage());
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
setuid = 1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verb = 1;
|
|
|
|
break;
|
2014-12-14 23:52:22 +00:00
|
|
|
case 'o':
|
|
|
|
oflag = 1;
|
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
case 'x':
|
|
|
|
xflag = 1;
|
|
|
|
break;
|
|
|
|
case 'z':
|
2015-08-21 17:32:48 +00:00
|
|
|
buflen = atoi(EARGF(usage()))-8;
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}ARGEND
|
|
|
|
|
2014-12-14 23:52:22 +00:00
|
|
|
if(!argc)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
if((xflag || oflag) && fskind != Archive){
|
|
|
|
fprint(2, "cannot use -x and -o without -a\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
usage();
|
2014-12-14 23:52:22 +00:00
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-04-29 09:15:28 +00:00
|
|
|
buf = malloc(buflen);
|
|
|
|
zbuf = malloc(buflen);
|
2011-03-30 12:46:40 +00:00
|
|
|
memset(zbuf, 0, buflen);
|
|
|
|
|
|
|
|
errs = 0;
|
|
|
|
for(i = 0; i < argc; i++){
|
|
|
|
proto = argv[i];
|
|
|
|
fprint(2, "processing %q\n", proto);
|
2011-04-29 09:15:28 +00:00
|
|
|
if(rdproto(proto, oldroot, protoenum, protowarn, nil) < 0){
|
2011-03-30 12:46:40 +00:00
|
|
|
fprint(2, "%q: can't open %q: skipping\n", prog, proto);
|
|
|
|
errs++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fprint(2, "file system made\n");
|
|
|
|
if(errs)
|
|
|
|
exits("skipped protos");
|
|
|
|
if(fskind == Archive){
|
2014-12-14 23:52:22 +00:00
|
|
|
if(!xflag && !oflag)
|
|
|
|
Bprint(&bout, "end of archive\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
Bterm(&bout);
|
|
|
|
}
|
|
|
|
exits(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check if file to is up to date with
|
|
|
|
* respect to the file represented by df
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
uptodate(Dir *df, char *to)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
Dir *dt;
|
|
|
|
|
|
|
|
if(fskind == Archive || ream || (dt = dirstat(to)) == nil)
|
|
|
|
return 0;
|
|
|
|
ret = dt->mtime >= df->mtime;
|
|
|
|
free(dt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
copy(Dir *d)
|
|
|
|
{
|
|
|
|
char cptmp[LEN], *p;
|
|
|
|
int f, t, n, needwrite, nowarnyet = 1;
|
|
|
|
vlong tot, len;
|
|
|
|
Dir nd;
|
|
|
|
|
|
|
|
f = open(oldfile, OREAD);
|
|
|
|
if(f < 0){
|
|
|
|
warn("can't open %q: %r", oldfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
t = -1;
|
|
|
|
if(fskind == Archive)
|
|
|
|
arch(d);
|
|
|
|
else{
|
|
|
|
strcpy(cptmp, newfile);
|
|
|
|
p = utfrrune(cptmp, L'/');
|
|
|
|
if(!p)
|
|
|
|
error("internal temporary file error");
|
|
|
|
strcpy(p+1, "__mkfstmp");
|
|
|
|
t = create(cptmp, OWRITE, 0666);
|
|
|
|
if(t < 0){
|
|
|
|
warn("can't create %q: %r", newfile);
|
|
|
|
close(f);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
needwrite = 0;
|
|
|
|
for(tot = 0; tot < d->length; tot += n){
|
|
|
|
len = d->length - tot;
|
|
|
|
/* don't read beyond d->length */
|
|
|
|
if (len > buflen)
|
|
|
|
len = buflen;
|
|
|
|
n = read(f, buf, len);
|
|
|
|
if(n <= 0) {
|
|
|
|
if(n < 0 && nowarnyet) {
|
|
|
|
warn("can't read %q: %r", oldfile);
|
|
|
|
nowarnyet = 0;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* don't quit: pad to d->length (in pieces) to agree
|
|
|
|
* with the length in the header, already emitted.
|
|
|
|
*/
|
|
|
|
memset(buf, 0, len);
|
|
|
|
n = len;
|
|
|
|
}
|
|
|
|
if(fskind == Archive){
|
|
|
|
if(Bwrite(&bout, buf, n) != n)
|
|
|
|
error("write error: %r");
|
|
|
|
}else if(memcmp(buf, zbuf, n) == 0){
|
|
|
|
if(seek(t, n, 1) < 0)
|
|
|
|
error("can't write zeros to %q: %r", newfile);
|
|
|
|
needwrite = 1;
|
|
|
|
}else{
|
|
|
|
if(write(t, buf, n) < n)
|
|
|
|
error("can't write %q: %r", newfile);
|
|
|
|
needwrite = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(f);
|
|
|
|
if(needwrite){
|
|
|
|
if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1)
|
|
|
|
error("can't write zero at end of %q: %r", newfile);
|
|
|
|
}
|
|
|
|
if(tot != d->length){
|
|
|
|
/* this should no longer happen */
|
|
|
|
warn("wrong number of bytes written to %q (was %lld should be %lld)\n",
|
|
|
|
newfile, tot, d->length);
|
|
|
|
if(fskind == Archive){
|
|
|
|
warn("seeking to proper position\n");
|
|
|
|
/* does no good if stdout is a pipe */
|
|
|
|
Bseek(&bout, d->length - tot, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(fskind == Archive)
|
|
|
|
return;
|
|
|
|
remove(newfile);
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.mode = d->mode;
|
|
|
|
nd.gid = d->gid;
|
|
|
|
nd.mtime = d->mtime;
|
|
|
|
nd.name = d->name;
|
|
|
|
if(dirfwstat(t, &nd) < 0)
|
|
|
|
error("can't move tmp file to %q: %r", newfile);
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.uid = d->uid;
|
|
|
|
dirfwstat(t, &nd);
|
|
|
|
close(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mkdir(Dir *d)
|
|
|
|
{
|
|
|
|
Dir *d1;
|
|
|
|
Dir nd;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if(fskind == Archive){
|
|
|
|
arch(d);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fd = create(newfile, OREAD, d->mode);
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.mode = d->mode;
|
|
|
|
nd.gid = d->gid;
|
|
|
|
nd.mtime = d->mtime;
|
|
|
|
if(fd < 0){
|
|
|
|
if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){
|
|
|
|
free(d1);
|
|
|
|
error("can't create %q", newfile);
|
|
|
|
}
|
|
|
|
free(d1);
|
|
|
|
if(dirwstat(newfile, &nd) < 0)
|
|
|
|
warn("can't set modes for %q: %r", newfile);
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.uid = d->uid;
|
|
|
|
dirwstat(newfile, &nd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(dirfwstat(fd, &nd) < 0)
|
|
|
|
warn("can't set modes for %q: %r", newfile);
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.uid = d->uid;
|
|
|
|
dirfwstat(fd, &nd);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
arch(Dir *d)
|
|
|
|
{
|
|
|
|
Bprint(&bout, "%q %luo %q %q %lud %lld\n",
|
|
|
|
newfile, d->mode, d->uid, d->gid, d->mtime, d->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-04-29 09:15:28 +00:00
|
|
|
protowarn(char *msg, void *)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-04-29 09:15:28 +00:00
|
|
|
warn("%s", msg);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-04-29 09:15:28 +00:00
|
|
|
protoenum(char *new, char *old, Dir *d, void *)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-04-29 09:15:28 +00:00
|
|
|
Dir nd;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-04-29 09:15:28 +00:00
|
|
|
sprint(newfile, "%s%s", newroot, new);
|
|
|
|
sprint(oldfile, "%s", old);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-12-14 23:52:22 +00:00
|
|
|
if(oflag){
|
|
|
|
if(!(d->mode & DMDIR))
|
|
|
|
Bprint(&bout, "%q\n", cleanname(oldfile));
|
|
|
|
return;
|
|
|
|
}
|
2011-04-29 09:15:28 +00:00
|
|
|
if(xflag){
|
|
|
|
Bprint(&bout, "%q\t%ld\t%lld\n", new, d->mtime, d->length);
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-04-29 09:15:28 +00:00
|
|
|
if(verb && (fskind == Archive || ream))
|
|
|
|
fprint(2, "%q\n", new);
|
|
|
|
if(fskind == Fs && !setuid){
|
|
|
|
d->uid = "";
|
|
|
|
d->gid = "";
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-04-29 09:15:28 +00:00
|
|
|
if(!uptodate(d, newfile)){
|
|
|
|
if(verb && (fskind != Archive && ream == 0))
|
|
|
|
fprint(2, "%q\n", new);
|
|
|
|
if(d->mode & DMDIR)
|
|
|
|
mkdir(d);
|
2011-03-30 12:46:40 +00:00
|
|
|
else
|
2011-04-29 09:15:28 +00:00
|
|
|
copy(d);
|
|
|
|
}else if(modes){
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.mode = d->mode;
|
|
|
|
nd.gid = d->gid;
|
|
|
|
nd.mtime = d->mtime;
|
|
|
|
if(verb && (fskind != Archive && ream == 0))
|
|
|
|
fprint(2, "%q\n", new);
|
|
|
|
if(dirwstat(newfile, &nd) < 0)
|
|
|
|
warn("can't set modes for %q: %r", new);
|
|
|
|
nulldir(&nd);
|
|
|
|
nd.uid = d->uid;
|
|
|
|
dirwstat(newfile, &nd);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
error(char *fmt, ...)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
va_list arg;
|
|
|
|
|
2011-04-29 09:15:28 +00:00
|
|
|
sprint(buf, "%q: %q: ", prog, proto);
|
2011-03-30 12:46:40 +00:00
|
|
|
va_start(arg, fmt);
|
|
|
|
vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
|
|
|
|
va_end(arg);
|
|
|
|
fprint(2, "%s\n", buf);
|
|
|
|
exits(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
warn(char *fmt, ...)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
va_list arg;
|
|
|
|
|
2011-04-29 09:15:28 +00:00
|
|
|
sprint(buf, "%q: %q: ", prog, proto);
|
2011-03-30 12:46:40 +00:00
|
|
|
va_start(arg, fmt);
|
|
|
|
vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
|
|
|
|
va_end(arg);
|
|
|
|
fprint(2, "%s\n", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
2015-08-21 17:32:48 +00:00
|
|
|
fprint(2, "usage: %q [-adprvoxUD] [-d root] [-s source] [-z n] proto ...\n", prog);
|
2011-03-30 12:46:40 +00:00
|
|
|
exits("usage");
|
|
|
|
}
|