From 76f3e8b395b53ac93b12ee4876a306d3b90d22c7 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 1 Dec 2003 04:35:39 +0000 Subject: [PATCH] Add the -C option to mount_mfs. This option will automatically copy the underlying filesystem into the MFS mount being created over it. It does this by loading the directory and file structure into memory, creating the MFS mount, then storing the directory and file structure back into the MFS mount. This will be used when booting from read-only media to generate an 'easy' read-write template. For example: mount_mfs -s 16384 -C swap /var Softlinks, devices, regular files, directories, and hardlinks are maintained. Fifos and sockets are not copied. --- sbin/newfs/Makefile | 4 +- sbin/newfs/defs.h | 57 +++++++ sbin/newfs/fscopy.c | 354 ++++++++++++++++++++++++++++++++++++++++++++ sbin/newfs/mkfs.c | 54 ++++--- sbin/newfs/newfs.c | 14 +- 5 files changed, 455 insertions(+), 28 deletions(-) create mode 100644 sbin/newfs/defs.h create mode 100644 sbin/newfs/fscopy.c diff --git a/sbin/newfs/Makefile b/sbin/newfs/Makefile index e3ca5deede..73cf47437c 100644 --- a/sbin/newfs/Makefile +++ b/sbin/newfs/Makefile @@ -1,9 +1,9 @@ # @(#)Makefile 8.2 (Berkeley) 3/27/94 # $FreeBSD: src/sbin/newfs/Makefile,v 1.6.6.2 2001/04/25 10:58:41 ru Exp $ -# $DragonFly: src/sbin/newfs/Makefile,v 1.2 2003/06/17 04:27:34 dillon Exp $ +# $DragonFly: src/sbin/newfs/Makefile,v 1.3 2003/12/01 04:35:39 dillon Exp $ PROG= newfs -SRCS= getmntopts.c newfs.c mkfs.c +SRCS= getmntopts.c newfs.c mkfs.c fscopy.c MAN= newfs.8 MOUNT= ${.CURDIR}/../mount diff --git a/sbin/newfs/defs.h b/sbin/newfs/defs.h new file mode 100644 index 0000000000..2463af38e9 --- /dev/null +++ b/sbin/newfs/defs.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003 Matthew Dillon + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $DragonFly: src/sbin/newfs/defs.h,v 1.1 2003/12/01 04:35:39 dillon Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void mkfs(struct partition *, char *, int, int, const char *); + +struct FSNode; +typedef struct FSNode *fsnode_t; + +fsnode_t FSCopy(fsnode_t *phlinks, const char *path); +void FSPaste(const char *path, fsnode_t dirnode, fsnode_t hlinks); + diff --git a/sbin/newfs/fscopy.c b/sbin/newfs/fscopy.c new file mode 100644 index 0000000000..d1d9c1d579 --- /dev/null +++ b/sbin/newfs/fscopy.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2003 Matthew Dillon + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $DragonFly: src/sbin/newfs/fscopy.c,v 1.1 2003/12/01 04:35:39 dillon Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DIRBLKSIZ +#undef DIRBLKSIZ +#endif +#include "defs.h" + +struct FSNode { + struct FSNode *fs_Next; + struct FSNode *fs_HNext; + struct FSNode *fs_Base; + struct FSNode *fs_Parent; + struct stat fs_St; + char *fs_Data; + int fs_Bytes; + int fs_Marker; + char fs_Name[4]; +}; + +static +fsnode_t +fsmknode(const char *path) +{ + int pathlen = strlen(path); + fsnode_t node = malloc(offsetof(struct FSNode, fs_Name[pathlen+1])); + + if (node == NULL) { + fprintf(stderr, "ran out of memory copying filesystem\n"); + return(NULL); + } + bzero(node, sizeof(*node)); + bcopy(path, node->fs_Name, pathlen + 1); + if (lstat(path, &node->fs_St) < 0) { + fprintf(stderr, "Unable to lstat(\"%s\")\n", path); + free(node); + return(NULL); + } + return(node); +} + +fsnode_t +fsgethlink(fsnode_t hlinks, fsnode_t node) +{ + fsnode_t scan; + + for (scan = hlinks; scan; scan = scan->fs_HNext) { + if (scan->fs_St.st_dev == node->fs_St.st_dev && + scan->fs_St.st_ino == node->fs_St.st_ino + ) { + return(scan); + } + } + return(NULL); +} + +char * +fshardpath(fsnode_t hlink, fsnode_t node) +{ + fsnode_t scan; + char *path; + char *tmp; + + for (scan = hlink; scan; scan = scan->fs_Parent) + scan->fs_Marker = 1; + for (scan = node; scan; scan = scan->fs_Parent) { + if (scan->fs_Marker == 1) { + scan->fs_Marker = 2; + break; + } + } + if (scan == NULL) + return(NULL); + + /* + * Build the path backwards + */ + asprintf(&path, "%s", hlink->fs_Name); + for (scan = hlink->fs_Parent; scan->fs_Marker == 1; scan = scan->fs_Parent) { + tmp = path; + asprintf(&path, "%s/%s", scan->fs_Name, tmp); + free(tmp); + } + for (scan = node->fs_Parent; scan; scan = scan->fs_Parent) { + if (scan->fs_Marker == 2) + break; + tmp = path; + asprintf(&path, "../%s", tmp); + free(tmp); + } + + for (scan = hlink; scan; scan = scan->fs_Parent) + scan->fs_Marker = 0; + for (scan = node; scan; scan = scan->fs_Parent) + scan->fs_Marker = 0; + return(path); +} + +fsnode_t +FSCopy(fsnode_t *phlinks, const char *path) +{ + int n; + DIR *dir; + fsnode_t node; + char buf[1024]; + + node = fsmknode(path); + if (node) { + switch(node->fs_St.st_mode & S_IFMT) { + case S_IFIFO: + break; + case S_IFCHR: + break; + case S_IFDIR: + if ((dir = opendir(path)) != NULL) { + struct dirent *den; + fsnode_t scan; + fsnode_t *pscan; + + if (chdir(path) < 0) { + fprintf(stderr, "Unable to chdir into %s\n", path); + break; + } + pscan = &node->fs_Base; + while ((den = readdir(dir)) != NULL) { + if (den->d_namlen == 1 && den->d_name[0] == '.') + continue; + if (den->d_namlen == 2 && den->d_name[0] == '.' && + den->d_name[1] == '.' + ) { + continue; + } + scan = FSCopy(phlinks, den->d_name); + if (scan) { + *pscan = scan; + scan->fs_Parent = node; + pscan = &scan->fs_Next; + } + } + if (chdir("..") < 0) { + fprintf(stderr, "Unable to chdir .. after scanning %s\n", path); + exit(1); + } + closedir(dir); + } + break; + case S_IFBLK: + break; + case S_IFREG: + if (node->fs_St.st_nlink > 1 && fsgethlink(*phlinks, node)) { + node->fs_Bytes = -1; /* hardlink indicator */ + } else if (node->fs_St.st_size >= 0x80000000LL) { + fprintf(stderr, "File %s too large to copy\n", path); + free(node); + node = NULL; + } else if ((node->fs_Data = malloc(node->fs_St.st_size)) == NULL) { + fprintf(stderr, "Ran out of memory copying %s\n", path); + free(node); + node = NULL; + } else if ((n = open(path, O_RDONLY)) < 0) { + fprintf(stderr, "Unable to open %s for reading %s\n", path); + free(node->fs_Data); + free(node); + node = NULL; + } else if (read(n, node->fs_Data, node->fs_St.st_size) != node->fs_St.st_size) { + fprintf(stderr, "Unable to read %s\n", path); + free(node->fs_Data); + free(node); + node = NULL; + + } else { + node->fs_Bytes = node->fs_St.st_size; + if (node->fs_St.st_nlink > 1) { + node->fs_HNext = *phlinks; + *phlinks = node; + } + } + break; + case S_IFLNK: + if ((n = readlink(path, buf, sizeof(buf))) > 0) { + if ((node->fs_Data = malloc(n + 1)) == NULL) { + fprintf(stderr, "Ran out of memory\n"); + free(node); + node = NULL; + } else { + node->fs_Bytes = n; + bcopy(buf, node->fs_Data, n); + node->fs_Data[n] = 0; + } + } else if (n == 0) { + node->fs_Data = ""; + node->fs_Bytes = 0; + } else { + fprintf(stderr, "Unable to read link: %s\n", path); + free(node); + node = NULL; + } + break; + case S_IFSOCK: + break; + case S_IFWHT: + break; + default: + break; + } + } + return(node); +} + +void +FSPaste(const char *path, fsnode_t node, fsnode_t hlinks) +{ + struct timeval times[2]; + fsnode_t scan; + int fd; + int ok = 0; + + switch(node->fs_St.st_mode & S_IFMT) { + case S_IFIFO: + break; + case S_IFCHR: + case S_IFBLK: + if (mknod(path, node->fs_St.st_mode, node->fs_St.st_rdev) < 0) { + fprintf(stderr, "Paste: mknod failed on %s\n", path); + break; + } + ok = 1; + break; + case S_IFDIR: + fd = open(".", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Paste: cannot open current directory\n"); + exit(1); + } + if (mkdir(path, 0700) < 0 && errno != EEXIST) { + printf("Paste: unable to create directory %s\n", path); + close(fd); + break; + } + if (chdir(path) < 0) { + printf("Paste: unable to chdir into %s\n", path); + exit(1); + } + for (scan = node->fs_Base; scan; scan = scan->fs_Next) { + FSPaste(scan->fs_Name, scan, hlinks); + } + if (fchdir(fd) < 0) { + fprintf(stderr, "Paste: cannot fchdir current dir\n"); + close(fd); + exit(1); + } + close(fd); + ok = 1; + break; + case S_IFREG: + if (node->fs_St.st_nlink > 1 && node->fs_Bytes < 0) { + if ((scan = fsgethlink(hlinks, node)) == NULL) { + fprintf(stderr, "Cannot find hardlink for %s\n", path); + } else { + char *hpath = fshardpath(scan, node); + if (hpath == NULL || link(hpath, path) < 0) { + fprintf(stderr, "Cannot create hardlink: %s->%s\n", path, hpath ? hpath : "?"); + if (hpath) + free(hpath); + break; + } + ok = 1; + free(hpath); + } + break; + } + if ((fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) { + fprintf(stderr, "Cannot create file: %s\n", path); + break; + } + if (write(fd, node->fs_Data, node->fs_Bytes) != node->fs_Bytes) { + fprintf(stderr, "Cannot write file: %s\n", path); + remove(path); + close(fd); + break; + } + close(fd); + ok = 1; + break; + case S_IFLNK: + if (symlink(node->fs_Data, path) < 0) { + fprintf(stderr, "Unable to create symbolic link: %s\n", path); + break; + } + ok = 1; + break; + case S_IFSOCK: + break; + case S_IFWHT: + break; + default: + break; + } + + /* + * Set perms + */ + if (ok) { + struct stat *st = &node->fs_St; + + times[0].tv_sec = st->st_atime; + times[0].tv_usec = 0; + times[1].tv_sec = st->st_mtime; + times[1].tv_usec = 0; + + if (lchown(path, st->st_uid, st->st_gid) < 0) + fprintf(stderr, "lchown failed on %s\n", path); + if (lutimes(path, times) < 0) + fprintf(stderr, "lutimes failed on %s\n", path); + if (lchmod(path, st->st_mode & ALLPERMS) < 0) + fprintf(stderr, "lchmod failed on %s\n", path); + if (chflags(path, st->st_flags) < 0) + fprintf(stderr, "lchflags failed on %s\n", path); + } +} + diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c index ed583d9f62..8f5f40a7a8 100644 --- a/sbin/newfs/mkfs.c +++ b/sbin/newfs/mkfs.c @@ -32,31 +32,15 @@ * * @(#)mkfs.c 8.11 (Berkeley) 5/3/95 * $FreeBSD: src/sbin/newfs/mkfs.c,v 1.29.2.6 2001/09/21 19:15:21 dillon Exp $ - * $DragonFly: src/sbin/newfs/mkfs.c,v 1.5 2003/11/01 17:16:01 drhodus Exp $ + * $DragonFly: src/sbin/newfs/mkfs.c,v 1.6 2003/12/01 04:35:39 dillon Exp $ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "defs.h" #ifndef STANDALONE #include #else + extern int atoi(char *); extern char * getenv(char *); #endif @@ -137,6 +121,8 @@ union { struct dinode zino[MAXBSIZE / sizeof(struct dinode)]; int fsi, fso; +static fsnode_t copyroot; +static fsnode_t copyhlinks; #ifdef FSIRAND int randinit; #endif @@ -165,9 +151,10 @@ caddr_t realloc(char *, u_long); #endif int mfs_ppid = 0; +int parentready_signalled; void -mkfs(struct partition *pp, char *fsys, int fi, int fo) +mkfs(struct partition *pp, char *fsys, int fi, int fo, const char *mfscopy) { register long i, mincpc, mincpg, inospercg; long cylno, rpos, blk, j, warn = 0; @@ -179,6 +166,7 @@ mkfs(struct partition *pp, char *fsys, int fi, int fo) time_t utime; quad_t sizepb; void started(); + void parentready(); int width; char tmpbuf[100]; /* XXX this will break in about 2,500 years */ @@ -192,16 +180,26 @@ mkfs(struct partition *pp, char *fsys, int fi, int fo) } #endif if (mfs) { + int omask; + mfs_ppid = getpid(); - (void) signal(SIGUSR1, started); + (void) signal(SIGUSR1, parentready); if ((i = fork())) { if (i == -1) err(10, "mfs"); + if (mfscopy) + copyroot = FSCopy(©hlinks, mfscopy); + (void) signal(SIGUSR1, started); + kill(i, SIGUSR1); if (waitpid(i, &status, 0) != -1 && WIFEXITED(status)) exit(WEXITSTATUS(status)); exit(11); /* NOTREACHED */ } + omask = sigblock(1 << SIGUSR1); + while (parentready_signalled == 0) + sigpause(1 << SIGUSR1); + sigblock(omask); #ifdef STANDALONE (void)malloc(0); #else @@ -1158,6 +1156,18 @@ iput(register struct dinode *ip, register ino_t ino) wtfs(d, sblock.fs_bsize, (char *)buf); } +/* + * Parent notifies child that it can proceed with the newfs and mount + * operation (occurs after parent has copied the underlying filesystem + * if the -C option was specified (for MFS), or immediately after the + * parent forked the child otherwise). + */ +void +parentready(void) +{ + parentready_signalled = 1; +} + /* * Notify parent process that the filesystem has created itself successfully. * @@ -1182,6 +1192,8 @@ started(void) } if (retry == 0) { fatal("mfs mount failed waiting for mount to go active"); + } else if (copyroot) { + FSPaste(mfs_mtpt, copyroot, copyhlinks); } exit(0); } diff --git a/sbin/newfs/newfs.c b/sbin/newfs/newfs.c index 562b87ab20..e5c53a3ee6 100644 --- a/sbin/newfs/newfs.c +++ b/sbin/newfs/newfs.c @@ -33,7 +33,7 @@ * @(#) Copyright (c) 1983, 1989, 1993, 1994 The Regents of the University of California. All rights reserved. * @(#)newfs.c 8.13 (Berkeley) 5/1/95 * $FreeBSD: src/sbin/newfs/newfs.c,v 1.30.2.9 2003/05/13 12:03:55 joerg Exp $ - * $DragonFly: src/sbin/newfs/newfs.c,v 1.5 2003/11/01 17:16:01 drhodus Exp $ + * $DragonFly: src/sbin/newfs/newfs.c,v 1.6 2003/12/01 04:35:39 dillon Exp $ */ /* @@ -72,6 +72,7 @@ #endif #include "mntopts.h" +#include "defs.h" struct mntopt mopts[] = { MOPT_STDOPTS, @@ -157,6 +158,7 @@ char *mfs_mtpt; /* mount point for mfs */ struct stat mfs_mtstat; /* stat prior to mount */ int Nflag; /* run without writing file system */ int Oflag; /* format as an 4.3BSD file system */ +int Cflag; /* copy underlying filesystem (mfs only) */ int Uflag; /* enable soft updates for file system */ int fssize; /* file system size */ int ntracks = NTRACKS; /* # tracks/cylinder */ @@ -200,7 +202,6 @@ int unlabeled; char device[MAXPATHLEN]; char *progname; -extern void mkfs(struct partition *, char *, int, int); static void usage(void); int @@ -234,7 +235,7 @@ main(int argc, char **argv) } opstring = mfs ? - "NF:T:Ua:b:c:d:e:f:g:h:i:m:o:s:v" : + "NCF:T:Ua:b:c:d:e:f:g:h:i:m:o:s:v" : "NOS:T:Ua:b:c:d:e:f:g:h:i:k:l:m:n:o:p:r:s:t:u:vx:"; while ((ch = getopt(argc, argv, opstring)) != -1) switch (ch) { @@ -244,6 +245,9 @@ main(int argc, char **argv) case 'O': Oflag = 1; break; + case 'C': + Cflag = 1; /* MFS only */ + break; case 'S': if ((sectorsize = atoi(optarg)) <= 0) fatal("%s: bad sector size", optarg); @@ -599,7 +603,7 @@ havelabel: fatal("mount point not dir: %s", mfs_mtpt); } } - mkfs(pp, special, fsi, fso); + mkfs(pp, special, fsi, fso, (Cflag && mfs) ? argv[1] : NULL); #ifdef tahoe if (realsectorsize != DEV_BSIZE) pp->p_size *= DEV_BSIZE / realsectorsize; @@ -638,7 +642,7 @@ havelabel: if (mount(vfc.vfc_name, argv[1], mntflags, &args) < 0) fatal("%s: %s", argv[1], strerror(errno)); - if(filename) { + if (filename) { munmap(membase,fssize * sectorsize); } } -- 2.41.0