Author: marius
Date: Tue Jul 26 14:41:54 2011
New Revision: 224447
URL: http://svn.freebsd.org/changeset/base/224447

Log:
  MFC: r214921, r219954, r219956, r221387, r221470, r221536, r222191
  
  - Sync with the latest version from NetBSD. It notably addds ISO9660 support.
  - Add support for synthesizing an APM partition map to map Mac PowerPC
    bootstrap partitions from the ISO9660 boot catalog. This preserves OS X's
    ability to mount the CD, while allowing us a way to provide HFS-ified
    bootstrap code for Open Firmware.
  - Add analogs to the -chrp-boot and -prep-boot options to mkisofs.

Added:
  stable/8/usr.sbin/makefs/cd9660/
     - copied from r214921, head/usr.sbin/makefs/cd9660/
  stable/8/usr.sbin/makefs/cd9660.c
     - copied, changed from r214921, head/usr.sbin/makefs/cd9660.c
  stable/8/usr.sbin/makefs/cd9660.h
     - copied, changed from r214921, head/usr.sbin/makefs/cd9660.h
  stable/8/usr.sbin/makefs/compat/Makefile.inc
     - copied unchanged from r214921, head/usr.sbin/makefs/compat/Makefile.inc
  stable/8/usr.sbin/makefs/ffs.h
     - copied unchanged from r214921, head/usr.sbin/makefs/ffs.h
  stable/8/usr.sbin/makefs/ffs/Makefile.inc
     - copied unchanged from r214921, head/usr.sbin/makefs/ffs/Makefile.inc
Modified:
  stable/8/usr.sbin/makefs/Makefile
  stable/8/usr.sbin/makefs/cd9660/cd9660_eltorito.c
  stable/8/usr.sbin/makefs/cd9660/cd9660_strings.c
  stable/8/usr.sbin/makefs/ffs.c
  stable/8/usr.sbin/makefs/ffs/buf.c
  stable/8/usr.sbin/makefs/ffs/ffs_alloc.c
  stable/8/usr.sbin/makefs/ffs/mkfs.c
  stable/8/usr.sbin/makefs/makefs.8
  stable/8/usr.sbin/makefs/makefs.c
  stable/8/usr.sbin/makefs/makefs.h
  stable/8/usr.sbin/makefs/walk.c
Directory Properties:
  stable/8/usr.sbin/makefs/   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_bswap.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_subr.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ufs_bswap.h   (props changed)
  stable/8/usr.sbin/makefs/getid.c   (props changed)

Modified: stable/8/usr.sbin/makefs/Makefile
==============================================================================
--- stable/8/usr.sbin/makefs/Makefile   Tue Jul 26 14:41:28 2011        
(r224446)
+++ stable/8/usr.sbin/makefs/Makefile   Tue Jul 26 14:41:54 2011        
(r224447)
@@ -1,22 +1,23 @@
 #      $FreeBSD$
 
 PROG=  makefs
+
+CFLAGS+=-I${.CURDIR}
+
+SRCS=  cd9660.c ffs.c \
+       getid.c \
+       makefs.c \
+       walk.c
 MAN=   makefs.8
 
 WARNS?=        2
 
-CFLAGS+=-I${.CURDIR}
-SRCS=  ffs.c getid.c makefs.c walk.c
+.include "${.CURDIR}/cd9660/Makefile.inc"
+.include "${.CURDIR}/ffs/Makefile.inc"
+.include "${.CURDIR}/compat/Makefile.inc"
 
-.PATH: ${.CURDIR}/ffs
-CFLAGS+=-I${.CURDIR}/ffs
 CFLAGS+=-DHAVE_STRUCT_STAT_ST_FLAGS=1
 CFLAGS+=-DHAVE_STRUCT_STAT_ST_GEN=1
-SRCS+= buf.c ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c mkfs.c ufs_bmap.c
-
-.PATH: ${.CURDIR}/compat
-CFLAGS+=-I${.CURDIR}/compat
-SRCS+= pwcache.c strsuftoll.c
 
 .PATH: ${.CURDIR}/../mtree
 CFLAGS+=-I${.CURDIR}/../mtree

Copied and modified: stable/8/usr.sbin/makefs/cd9660.c (from r214921, 
head/usr.sbin/makefs/cd9660.c)
==============================================================================
--- head/usr.sbin/makefs/cd9660.c       Sun Nov  7 16:05:04 2010        
(r214921, copy source)
+++ stable/8/usr.sbin/makefs/cd9660.c   Tue Jul 26 14:41:54 2011        
(r224447)
@@ -207,6 +207,7 @@ cd9660_set_defaults(void)
        diskStructure.rr_moved_dir = 0;
 
        diskStructure.archimedes_enabled = 0;
+       diskStructure.chrp_boot = 0;
 
        diskStructure.include_padding_areas = 1;
 
@@ -391,6 +392,8 @@ cd9660_parse_opts(const char *option, fs
                diskStructure.rock_ridge_enabled = 1;
        else if (CD9660_IS_COMMAND_ARG_DUAL(var, "A", "archimedes"))
                diskStructure.archimedes_enabled = 1;
+       else if (CD9660_IS_COMMAND_ARG(var, "chrp-boot"))
+               diskStructure.chrp_boot = 1;
        else if (CD9660_IS_COMMAND_ARG_DUAL(var, "K", "keep-bad-images"))
                diskStructure.keep_bad_images = 1;
        else if (CD9660_IS_COMMAND_ARG(var, "allow-deep-trees"))

Copied and modified: stable/8/usr.sbin/makefs/cd9660.h (from r214921, 
head/usr.sbin/makefs/cd9660.h)
==============================================================================
--- head/usr.sbin/makefs/cd9660.h       Sun Nov  7 16:05:04 2010        
(r214921, copy source)
+++ stable/8/usr.sbin/makefs/cd9660.h   Tue Jul 26 14:41:54 2011        
(r224447)
@@ -285,6 +285,7 @@ typedef struct _iso9660_disk {
        cd9660node *rr_moved_dir;
 
        int archimedes_enabled;
+       int chrp_boot;
 
        /* Spec breaking options */
        u_char allow_deep_trees;

Modified: stable/8/usr.sbin/makefs/cd9660/cd9660_eltorito.c
==============================================================================
--- head/usr.sbin/makefs/cd9660/cd9660_eltorito.c       Sun Nov  7 16:05:04 
2010        (r214921)
+++ stable/8/usr.sbin/makefs/cd9660/cd9660_eltorito.c   Tue Jul 26 14:41:54 
2011        (r224447)
@@ -31,6 +31,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  * OF SUCH DAMAGE.
  */
+
+#include <sys/endian.h>
+
 #include "cd9660.h"
 #include "cd9660_eltorito.h"
 
@@ -497,11 +500,79 @@ cd9660_setup_boot_volume_descriptor(volu
        return 1;
 }
 
+static int
+cd9660_write_mbr_partition_entry(FILE *fd, int index, off_t sector_start,
+    off_t nsectors, int type)
+{
+       uint8_t val;
+       uint32_t lba;
+
+       fseeko(fd, (off_t)(index) * 16 + 0x1be, SEEK_SET);
+       
+       val = 0x80; /* Bootable */
+       fwrite(&val, sizeof(val), 1, fd);
+
+       val = 0xff; /* CHS begin */
+       fwrite(&val, sizeof(val), 1, fd);
+       fwrite(&val, sizeof(val), 1, fd);
+       fwrite(&val, sizeof(val), 1, fd);
+
+       val = type; /* Part type */
+       fwrite(&val, sizeof(val), 1, fd);
+
+       val = 0xff; /* CHS end */
+       fwrite(&val, sizeof(val), 1, fd);
+       fwrite(&val, sizeof(val), 1, fd);
+       fwrite(&val, sizeof(val), 1, fd);
+
+       /* LBA extent */
+       lba = htole32(sector_start);
+       fwrite(&lba, sizeof(lba), 1, fd);
+       lba = htole32(nsectors);
+       fwrite(&lba, sizeof(lba), 1, fd);
+
+       return (0);
+}
+
+static int
+cd9660_write_apm_partition_entry(FILE *fd, int index, int total_partitions,
+    off_t sector_start, off_t nsectors, off_t sector_size,
+    const char *part_name, const char *part_type)
+{
+       uint32_t apm32;
+       uint16_t apm16;
+
+       fseeko(fd, (off_t)(index + 1) * sector_size, SEEK_SET);
+
+       /* Signature */
+       apm16 = htobe16(0x504d);
+       fwrite(&apm16, sizeof(apm16), 1, fd);
+       apm16 = 0;
+       fwrite(&apm16, sizeof(apm16), 1, fd);
+
+       /* Total number of partitions */
+       apm32 = htobe32(total_partitions);
+       fwrite(&apm32, sizeof(apm32), 1, fd);
+       /* Bounds */
+       apm32 = htobe32(sector_start);
+       fwrite(&apm32, sizeof(apm32), 1, fd);
+       apm32 = htobe32(nsectors);
+       fwrite(&apm32, sizeof(apm32), 1, fd);
+
+       fwrite(part_name, strlen(part_name) + 1, 1, fd);
+       fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
+       fwrite(part_type, strlen(part_type) + 1, 1, fd);
+
+       return 0;
+}
+
 int
 cd9660_write_boot(FILE *fd)
 {
        struct boot_catalog_entry *e;
        struct cd9660_boot_image *t;
+       int apm_partitions = 0;
+       int mbr_partitions = 0;
 
        /* write boot catalog */
        if (fseeko(fd, (off_t)diskStructure.boot_catalog_sector *
@@ -533,7 +604,88 @@ cd9660_write_boot(FILE *fd)
                            t->filename, t->sector);
                }
                cd9660_copy_file(fd, t->sector, t->filename);
+
+               if (t->system == ET_SYS_MAC) 
+                       apm_partitions++;
+               if (t->system == ET_SYS_PPC) 
+                       mbr_partitions++;
+       }
+
+       /* some systems need partition tables as well */
+       if (mbr_partitions > 0 || diskStructure.chrp_boot) {
+               uint16_t sig;
+
+               fseek(fd, 0x1fe, SEEK_SET);
+               sig = htole16(0xaa55);
+               fwrite(&sig, sizeof(sig), 1, fd);
+
+               mbr_partitions = 0;
+
+               /* Write ISO9660 descriptor, enclosing the whole disk */
+               if (diskStructure.chrp_boot)
+                       cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
+                           0, diskStructure.totalSectors *
+                           (diskStructure.sectorSize / 512), 0x96);
+
+               /* Write all partition entries */
+               TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) {
+                       if (t->system != ET_SYS_PPC)
+                               continue;
+                       cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
+                           t->sector * (diskStructure.sectorSize / 512),
+                           t->num_sectors * (diskStructure.sectorSize / 512),
+                           0x41 /* PReP Boot */);
+               }
+       }
+
+       if (apm_partitions > 0) {
+               /* Write DDR and global APM info */
+               uint32_t apm32;
+               uint16_t apm16;
+               int total_parts;
+
+               fseek(fd, 0, SEEK_SET);
+               apm16 = htobe16(0x4552);
+               fwrite(&apm16, sizeof(apm16), 1, fd);
+               /* Device block size */
+               apm16 = htobe16(512);
+               fwrite(&apm16, sizeof(apm16), 1, fd);
+               /* Device block count */
+               apm32 = htobe32(diskStructure.totalSectors *
+                   (diskStructure.sectorSize / 512));
+               fwrite(&apm32, sizeof(apm32), 1, fd);
+               /* Device type/id */
+               apm16 = htobe16(1);
+               fwrite(&apm16, sizeof(apm16), 1, fd);
+               fwrite(&apm16, sizeof(apm16), 1, fd);
+
+               /* Count total needed entries */
+               total_parts = 2 + apm_partitions; /* Self + ISO9660 */
+
+               /* Write self-descriptor */
+               cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
+                   total_parts, 512, "Apple", "Apple_partition_map");
+
+               /* Write ISO9660 descriptor, enclosing the whole disk */
+               cd9660_write_apm_partition_entry(fd, 1, total_parts, 0,
+                   diskStructure.totalSectors *
+                   (diskStructure.sectorSize / 512), 512, "ISO9660",
+                   "CD_ROM_Mode_1");
+
+               /* Write all partition entries */
+               apm_partitions = 0;
+               TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) {
+                       if (t->system != ET_SYS_MAC)
+                               continue;
+
+                       cd9660_write_apm_partition_entry(fd,
+                           2 + apm_partitions++, total_parts,
+                           t->sector * (diskStructure.sectorSize / 512),
+                           t->num_sectors * (diskStructure.sectorSize / 512),
+                           512, "CD Boot", "Apple_Bootstrap");
+               }
        }
 
        return 0;
 }
+

Modified: stable/8/usr.sbin/makefs/cd9660/cd9660_strings.c
==============================================================================
--- head/usr.sbin/makefs/cd9660/cd9660_strings.c        Sun Nov  7 16:05:04 
2010        (r214921)
+++ stable/8/usr.sbin/makefs/cd9660/cd9660_strings.c    Tue Jul 26 14:41:54 
2011        (r224447)
@@ -55,19 +55,19 @@ cd9660_uppercase_characters(char *str, i
 }
 
 static inline int
-cd9660_is_a_char(char c)
+cd9660_is_d_char(char c)
 {
        return (isupper((unsigned char)c)
                || c == '_'
-               || (c >= '0' && c <= '?'));
+               || (c >= '0' && c <= '9'));
 }
 
 static inline int
-cd9660_is_d_char(char c)
+cd9660_is_a_char(char c)
 {
        return (isupper((unsigned char)c)
                        || c == '_'
-                       || (c >= '%' && c <= '9')
+                       || (c >= '%' && c <= '?')
                        || (c >= ' ' && c <= '\"'));
 }
 

Copied: stable/8/usr.sbin/makefs/compat/Makefile.inc (from r214921, 
head/usr.sbin/makefs/compat/Makefile.inc)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/8/usr.sbin/makefs/compat/Makefile.inc        Tue Jul 26 14:41:54 
2011        (r224447, copy of r214921, head/usr.sbin/makefs/compat/Makefile.inc)
@@ -0,0 +1,8 @@
+#      $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/compat
+
+CFLAGS+=       -I${.CURDIR}/compat
+
+SRCS+= pwcache.c strsuftoll.c

Modified: stable/8/usr.sbin/makefs/ffs.c
==============================================================================
--- stable/8/usr.sbin/makefs/ffs.c      Tue Jul 26 14:41:28 2011        
(r224446)
+++ stable/8/usr.sbin/makefs/ffs.c      Tue Jul 26 14:41:54 2011        
(r224447)
@@ -1,4 +1,4 @@
-/*     $NetBSD: ffs.c,v 1.30 2004/06/24 22:30:13 lukem Exp $   */
+/*     $NetBSD: ffs.c,v 1.44 2009/04/28 22:49:26 joerg Exp $   */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -76,17 +76,24 @@ __FBSDID("$FreeBSD$");
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "makefs.h"
+#include "ffs.h"
+
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
+#include <sys/statvfs.h>
+#endif
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ffs/fs.h>
 
+
 #include "ffs/ufs_bswap.h"
 #include "ffs/ufs_inode.h"
 #include "ffs/newfs_extern.h"
@@ -94,7 +101,7 @@ __FBSDID("$FreeBSD$");
 
 #undef DIP
 #define DIP(dp, field) \
-       ((fsopts->version == 1) ? \
+       ((ffs_opts->version == 1) ? \
        (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
 
 /*
@@ -139,39 +146,71 @@ int       sectorsize;             /* XXX: for buf.c::getb
 
        /* publically visible functions */
 
+void
+ffs_prep_opts(fsinfo_t *fsopts)
+{
+       ffs_opt_t *ffs_opts;
+
+       if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL)
+               err(1, "Allocating memory for ffs_options");
+
+       fsopts->fs_specific = ffs_opts;
+
+       ffs_opts->bsize= -1;
+       ffs_opts->fsize= -1;
+       ffs_opts->cpg= -1;
+       ffs_opts->density= -1;
+       ffs_opts->minfree= -1;
+       ffs_opts->optimization= -1;
+       ffs_opts->maxcontig= -1;
+       ffs_opts->maxbpg= -1;
+       ffs_opts->avgfilesize= -1;
+       ffs_opts->avgfpdir= -1;
+       ffs_opts->version = 1;
+}
+
+void
+ffs_cleanup_opts(fsinfo_t *fsopts)
+{
+       if (fsopts->fs_specific)
+               free(fsopts->fs_specific);
+}
+
 int
 ffs_parse_opts(const char *option, fsinfo_t *fsopts)
 {
+       ffs_opt_t       *ffs_opts = fsopts->fs_specific;
+
        option_t ffs_options[] = {
-               { "bsize",      &fsopts->bsize,         1,      INT_MAX,
+               { "bsize",      &ffs_opts->bsize,       1,      INT_MAX,
                                        "block size" },
-               { "fsize",      &fsopts->fsize,         1,      INT_MAX,
+               { "fsize",      &ffs_opts->fsize,       1,      INT_MAX,
                                        "fragment size" },
-               { "density",    &fsopts->density,       1,      INT_MAX,
+               { "density",    &ffs_opts->density,     1,      INT_MAX,
                                        "bytes per inode" },
-               { "minfree",    &fsopts->minfree,       0,      99,
+               { "minfree",    &ffs_opts->minfree,     0,      99,
                                        "minfree" },
-               { "maxbpf",     &fsopts->maxbpg,        1,      INT_MAX,
+               { "maxbpf",     &ffs_opts->maxbpg,      1,      INT_MAX,
                                        "max blocks per file in a cg" },
-               { "avgfilesize", &fsopts->avgfilesize,  1,      INT_MAX,
+               { "avgfilesize", &ffs_opts->avgfilesize,1,      INT_MAX,
                                        "expected average file size" },
-               { "avgfpdir",   &fsopts->avgfpdir,      1,      INT_MAX,
+               { "avgfpdir",   &ffs_opts->avgfpdir,    1,      INT_MAX,
                                        "expected # of files per directory" },
-               { "extent",     &fsopts->maxbsize,      1,      INT_MAX,
+               { "extent",     &ffs_opts->maxbsize,    1,      INT_MAX,
                                        "maximum # extent size" },
-               { "maxbpcg",    &fsopts->maxblkspercg,  1,      INT_MAX,
+               { "maxbpcg",    &ffs_opts->maxblkspercg,1,      INT_MAX,
                                        "max # of blocks per group" },
-               { "version",    &fsopts->version,       1,      2,
+               { "version",    &ffs_opts->version,     1,      2,
                                        "UFS version" },
-               { NULL }
+               { .name = NULL }
        };
 
        char    *var, *val;
        int     rv;
 
-       (void)&ffs_options;
        assert(option != NULL);
        assert(fsopts != NULL);
+       assert(ffs_opts != NULL);
 
        if (debug & DEBUG_FS_PARSE_OPTS)
                printf("ffs_parse_opts: got `%s'\n", option);
@@ -188,9 +227,9 @@ ffs_parse_opts(const char *option, fsinf
 
        if (strcmp(var, "optimization") == 0) {
                if (strcmp(val, "time") == 0) {
-                       fsopts->optimization = FS_OPTTIME;
+                       ffs_opts->optimization = FS_OPTTIME;
                } else if (strcmp(val, "space") == 0) {
-                       fsopts->optimization = FS_OPTSPACE;
+                       ffs_opts->optimization = FS_OPTSPACE;
                } else {
                        warnx("Invalid optimization `%s'", val);
                        goto leave_ffs_parse_opts;
@@ -277,11 +316,12 @@ ffs_validate(const char *dir, fsnode *ro
 #if notyet
        int32_t spc, nspf, ncyl, fssize;
 #endif
-       off_t size;
+       ffs_opt_t       *ffs_opts = fsopts->fs_specific;
 
        assert(dir != NULL);
        assert(root != NULL);
        assert(fsopts != NULL);
+       assert(ffs_opts != NULL);
 
        if (debug & DEBUG_FS_VALIDATE) {
                printf("ffs_validate: before defaults set:\n");
@@ -291,31 +331,31 @@ ffs_validate(const char *dir, fsnode *ro
                /* set FFS defaults */
        if (fsopts->sectorsize == -1)
                fsopts->sectorsize = DFL_SECSIZE;
-       if (fsopts->fsize == -1)
-               fsopts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
-       if (fsopts->bsize == -1)
-               fsopts->bsize = MIN(DFL_BLKSIZE, 8 * fsopts->fsize);
-       if (fsopts->cpg == -1)
-               fsopts->cpg = DFL_CYLSPERGROUP;
+       if (ffs_opts->fsize == -1)
+               ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
+       if (ffs_opts->bsize == -1)
+               ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize);
+       if (ffs_opts->cpg == -1)
+               ffs_opts->cpg = DFL_CYLSPERGROUP;
        else
-               fsopts->cpgflg = 1;
+               ffs_opts->cpgflg = 1;
                                /* fsopts->density is set below */
-       if (fsopts->nsectors == -1)
-               fsopts->nsectors = DFL_NSECTORS;
-       if (fsopts->minfree == -1)
-               fsopts->minfree = MINFREE;
-       if (fsopts->optimization == -1)
-               fsopts->optimization = DEFAULTOPT;
-       if (fsopts->maxcontig == -1)
-               fsopts->maxcontig =
-                   MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / fsopts->bsize);
+       if (ffs_opts->nsectors == -1)
+               ffs_opts->nsectors = DFL_NSECTORS;
+       if (ffs_opts->minfree == -1)
+               ffs_opts->minfree = MINFREE;
+       if (ffs_opts->optimization == -1)
+               ffs_opts->optimization = DEFAULTOPT;
+       if (ffs_opts->maxcontig == -1)
+               ffs_opts->maxcontig =
+                   MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize);
        /* XXX ondisk32 */
-       if (fsopts->maxbpg == -1)
-               fsopts->maxbpg = fsopts->bsize / sizeof(int32_t);
-       if (fsopts->avgfilesize == -1)
-               fsopts->avgfilesize = AVFILESIZ;
-       if (fsopts->avgfpdir == -1)
-               fsopts->avgfpdir = AFPDIR;
+       if (ffs_opts->maxbpg == -1)
+               ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
+       if (ffs_opts->avgfilesize == -1)
+               ffs_opts->avgfilesize = AVFILESIZ;
+       if (ffs_opts->avgfpdir == -1)
+               ffs_opts->avgfpdir = AFPDIR;
 
                /* calculate size of tree */
        ffs_size_dir(root, fsopts);
@@ -343,17 +383,19 @@ ffs_validate(const char *dir, fsnode *ro
         */
        fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
                /* add space needed to store inodes, x3 for blockmaps, etc */
-       if (fsopts->version == 1)
+       if (ffs_opts->version == 1)
                fsopts->size += ncg * DINODE1_SIZE *
-                   roundup(fsopts->inodes / ncg, fsopts->bsize / DINODE1_SIZE);
+                   roundup(fsopts->inodes / ncg, 
+                       ffs_opts->bsize / DINODE1_SIZE);
        else
                fsopts->size += ncg * DINODE2_SIZE *
-                   roundup(fsopts->inodes / ncg, fsopts->bsize / DINODE2_SIZE);
+                   roundup(fsopts->inodes / ncg, 
+                       ffs_opts->bsize / DINODE2_SIZE);
 
                /* add minfree */
-       if (fsopts->minfree > 0)
+       if (ffs_opts->minfree > 0)
                fsopts->size =
-                   fsopts->size * (100 + fsopts->minfree) / 100;
+                   fsopts->size * (100 + ffs_opts->minfree) / 100;
        /*
         * XXX  any other fs slop to add, such as csum's, bitmaps, etc ??
         */
@@ -362,24 +404,11 @@ ffs_validate(const char *dir, fsnode *ro
                fsopts->size = fsopts->minsize;
 
                /* round up to the next block */
-       size = roundup(fsopts->size, fsopts->bsize);
-
-               /* now check calculated sizes vs requested sizes */
-       if (fsopts->maxsize > 0 && size > fsopts->maxsize) {
-               if (debug & DEBUG_FS_VALIDATE) {
-                       printf("%s: `%s' size of %lld is larger than the "
-                           "maxsize of %lld; rounding down to %lld.",
-                           __func__, dir, (long long)size,
-                           (long long)fsopts->maxsize,
-                           (long long) rounddown(fsopts->size, fsopts->bsize));
-               }
-               size = rounddown(fsopts->size, fsopts->bsize);
-       }
-       fsopts->size = size;
+       fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
 
                /* calculate density if necessary */
-       if (fsopts->density == -1)
-               fsopts->density = fsopts->size / fsopts->inodes + 1;
+       if (ffs_opts->density == -1)
+               ffs_opts->density = fsopts->size / fsopts->inodes + 1;
 
        if (debug & DEBUG_FS_VALIDATE) {
                printf("ffs_validate: after defaults set:\n");
@@ -388,6 +417,12 @@ ffs_validate(const char *dir, fsnode *ro
                    dir, (long long)fsopts->size, (long long)fsopts->inodes);
        }
        sectorsize = fsopts->sectorsize;        /* XXX - see earlier */
+
+               /* now check calculated sizes vs requested sizes */
+       if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
+               errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
+                   dir, (long long)fsopts->size, (long long)fsopts->maxsize);
+       }
 }
 
 
@@ -395,6 +430,8 @@ static void
 ffs_dump_fsinfo(fsinfo_t *f)
 {
 
+       ffs_opt_t       *fs = f->fs_specific;
+
        printf("fsopts at %p\n", f);
 
        printf("\tsize %lld, inodes %lld, curinode %u\n",
@@ -409,20 +446,20 @@ ffs_dump_fsinfo(fsinfo_t *f)
        printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
 
        printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
-           f->bsize, f->fsize, f->cpg, f->density);
+           fs->bsize, fs->fsize, fs->cpg, fs->density);
        printf("\tnsectors %d, rpm %d, minfree %d\n",
-           f->nsectors, f->rpm, f->minfree);
+           fs->nsectors, fs->rpm, fs->minfree);
        printf("\tmaxcontig %d, maxbpg %d\n",
-           f->maxcontig, f->maxbpg);
+           fs->maxcontig, fs->maxbpg);
        printf("\toptimization %s\n",
-           f->optimization == FS_OPTSPACE ? "space" : "time");
+           fs->optimization == FS_OPTSPACE ? "space" : "time");
 }
 
 
 static int
 ffs_create_image(const char *image, fsinfo_t *fsopts)
 {
-#if HAVE_STRUCT_STATVFS_F_IOSIZE
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
        struct statvfs  sfs;
 #endif
        struct fs       *fs;
@@ -434,18 +471,18 @@ ffs_create_image(const char *image, fsin
        assert (fsopts != NULL);
 
                /* create image */
-       if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0777))
+       if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666))
            == -1) {
                warn("Can't open `%s' for writing", image);
                return (-1);
        }
 
                /* zero image */
-#if HAVE_STRUCT_STATVFS_F_IOSIZE
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
        if (fstatvfs(fsopts->fd, &sfs) == -1) {
 #endif
                bufsize = 8192;
-#if HAVE_STRUCT_STATVFS_F_IOSIZE
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
                warn("can't fstatvfs `%s', using default %d byte chunk",
                    image, bufsize);
        } else
@@ -465,10 +502,12 @@ ffs_create_image(const char *image, fsin
                if (i == -1) {
                        warn("zeroing image, %lld bytes to go",
                            (long long)bufrem);
+                       free(buf);
                        return (-1);
                }
                bufrem -= i;
        }
+       free(buf);
 
                /* make the file system */
        if (debug & DEBUG_FS_CREATE_IMAGE)
@@ -492,7 +531,7 @@ ffs_create_image(const char *image, fsin
                warnx(
                "Image file `%s' has %lld free inodes; %lld are required.",
                    image,
-                   (long long)fs->fs_cstotal.cs_nifree + ROOTINO,
+                   (long long)(fs->fs_cstotal.cs_nifree + ROOTINO),
                    (long long)fsopts->inodes);
                return (-1);
        }
@@ -506,9 +545,11 @@ ffs_size_dir(fsnode *root, fsinfo_t *fso
        struct direct   tmpdir;
        fsnode *        node;
        int             curdirsize, this;
+       ffs_opt_t       *ffs_opts = fsopts->fs_specific;
 
        /* node may be NULL (empty directory) */
        assert(fsopts != NULL);
+       assert(ffs_opts != NULL);
 
        if (debug & DEBUG_FS_SIZE_DIR)
                printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
@@ -516,7 +557,7 @@ ffs_size_dir(fsnode *root, fsinfo_t *fso
 
 #define        ADDDIRENT(e) do {                                               
\
        tmpdir.d_namlen = strlen((e));                                  \
-       this = DIRSIZ_SWAP(0, &tmpdir, 0);                              \
+       this = DIRSIZ_SWAP(0, &tmpdir, 0);                                      
\
        if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)                       \
                printf("ADDDIRENT: was: %s (%d) this %d cur %d\n",      \
                    e, tmpdir.d_namlen, this, curdirsize);              \
@@ -533,14 +574,12 @@ ffs_size_dir(fsnode *root, fsinfo_t *fso
         *      by indirect blocks, etc.
         */
 #define        ADDSIZE(x) do {                                                 
\
-       fsopts->size += roundup((x), fsopts->fsize);                    \
+       fsopts->size += roundup((x), ffs_opts->fsize);                  \
 } while (0);
 
        curdirsize = 0;
        for (node = root; node != NULL; node = node->next) {
                ADDDIRENT(node->name);
-               if (FSNODE_EXCLUDE_P(fsopts, node))
-                       continue;
                if (node == root) {                     /* we're at "." */
                        assert(strcmp(node->name, ".") == 0);
                        ADDDIRENT("..");
@@ -558,7 +597,7 @@ ffs_size_dir(fsnode *root, fsinfo_t *fso
                                int     slen;
 
                                slen = strlen(node->symlink) + 1;
-                               if (slen >= (fsopts->version == 1 ?
+                               if (slen >= (ffs_opts->version == 1 ?
                                                MAXSYMLINKLEN_UFS1 :
                                                MAXSYMLINKLEN_UFS2))
                                        ADDSIZE(slen);
@@ -682,10 +721,12 @@ ffs_populate_dir(const char *dir, fsnode
        union dinode    din;
        void            *membuf;
        char            path[MAXPATHLEN + 1];
+       ffs_opt_t       *ffs_opts = fsopts->fs_specific;
 
        assert(dir != NULL);
        assert(root != NULL);
        assert(fsopts != NULL);
+       assert(ffs_opts != NULL);
 
        (void)memset(&dirbuf, 0, sizeof(dirbuf));
 
@@ -696,8 +737,6 @@ ffs_populate_dir(const char *dir, fsnode
                 * pass 1: allocate inode numbers, build directory `file'
                 */
        for (cur = root; cur != NULL; cur = cur->next) {
-               if (FSNODE_EXCLUDE_P(fsopts, cur))
-                       continue;
                if ((cur->inode->flags & FI_ALLOCATED) == 0) {
                        cur->inode->flags |= FI_ALLOCATED;
                        if (cur == root && cur->parent != NULL)
@@ -732,8 +771,6 @@ ffs_populate_dir(const char *dir, fsnode
        if (debug & DEBUG_FS_POPULATE)
                printf("ffs_populate_dir: PASS 2  dir %s\n", dir);
        for (cur = root; cur != NULL; cur = cur->next) {
-               if (FSNODE_EXCLUDE_P(fsopts, cur))
-                       continue;
                if (cur->inode->flags & FI_WRITTEN)
                        continue;               /* skip hard-linked entries */
                cur->inode->flags |= FI_WRITTEN;
@@ -746,7 +783,7 @@ ffs_populate_dir(const char *dir, fsnode
                        continue;               /* child creates own inode */
 
                                /* build on-disk inode */
-               if (fsopts->version == 1)
+               if (ffs_opts->version == 1)
                        membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
                            root, fsopts);
                else
@@ -777,8 +814,6 @@ ffs_populate_dir(const char *dir, fsnode
        if (debug & DEBUG_FS_POPULATE)
                printf("ffs_populate_dir: PASS 3  dir %s\n", dir);
        for (cur = root; cur != NULL; cur = cur->next) {
-               if (FSNODE_EXCLUDE_P(fsopts, cur))
-                       continue;
                if (cur->child == NULL)
                        continue;
                if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
@@ -804,16 +839,20 @@ ffs_write_file(union dinode *din, uint32
        int     isfile, ffd;
        char    *fbuf, *p;
        off_t   bufleft, chunk, offset;
+       ssize_t nread;
        struct inode    in;
        struct buf *    bp;
+       ffs_opt_t       *ffs_opts = fsopts->fs_specific;
 
        assert (din != NULL);
        assert (buf != NULL);
        assert (fsopts != NULL);
+       assert (ffs_opts != NULL);
 
        isfile = S_ISREG(DIP(din, mode));
        fbuf = NULL;
        ffd = -1;
+       p = NULL;
 
        in.i_fs = (struct fs *)fsopts->superblock;
 
@@ -830,7 +869,7 @@ ffs_write_file(union dinode *din, uint32
 
        in.i_number = ino;
        in.i_size = DIP(din, size);
-       if (fsopts->version == 1)
+       if (ffs_opts->version == 1)
                memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
                    sizeof(in.i_din.ffs1_din));
        else
@@ -842,7 +881,7 @@ ffs_write_file(union dinode *din, uint32
                goto write_inode_and_leave;             /* mmm, cheating */
 
        if (isfile) {
-               if ((fbuf = malloc(fsopts->bsize)) == NULL)
+               if ((fbuf = malloc(ffs_opts->bsize)) == NULL)
                        err(1, "Allocating memory for write buffer");
                if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
                        warn("Can't open `%s' for reading", (char *)buf);
@@ -854,13 +893,20 @@ ffs_write_file(union dinode *din, uint32
 
        chunk = 0;
        for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
-               chunk = MIN(bufleft, fsopts->bsize);
-               if (isfile) {
-                       if (read(ffd, fbuf, chunk) != chunk)
-                               err(1, "Reading `%s', %lld bytes to go",
-                                   (char *)buf, (long long)bufleft);
+               chunk = MIN(bufleft, ffs_opts->bsize);
+               if (!isfile)
+                       ;
+               else if ((nread = read(ffd, fbuf, chunk)) == -1)
+                       err(EXIT_FAILURE, "Reading `%s', %lld bytes to go",
+                           (char *)buf, (long long)bufleft);
+               else if (nread != chunk)
+                       errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, "
+                           "read %zd bytes, expected %ju bytes, does "
+                           "metalog size= attribute mismatch source size?",
+                           (char *)buf, (long long)bufleft, nread,
+                           (uintmax_t)chunk);
+               else
                        p = fbuf;
-               }
                offset = DIP(din, size) - bufleft;
                if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
                        printf(
@@ -932,7 +978,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const ch
 {
        struct direct   de, *dp;
        uint16_t        llen, reclen;
-       char            *newbuf;
+       u_char          *newbuf;
 
        assert (dbuf != NULL);
        assert (name != NULL);
@@ -969,7 +1015,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const ch
                dbuf->size += DIRBLKSIZ;
                memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
                dbuf->cur = dbuf->size - DIRBLKSIZ;
-       } else {                                /* shrink end of previous */
+       } else if (dp) {                        /* shrink end of previous */
                dp->d_reclen = ufs_rw16(llen,needswap);
                dbuf->cur += llen;
        }
@@ -993,10 +1039,12 @@ ffs_write_inode(union dinode *dp, uint32
        daddr_t         d;
        char            sbbuf[FFS_MAXBSIZE];
        int32_t         initediblk;
+       ffs_opt_t       *ffs_opts = fsopts->fs_specific;
 
        assert (dp != NULL);
        assert (ino > 0);
        assert (fsopts != NULL);
+       assert (ffs_opts != NULL);
 
        fs = (struct fs *)fsopts->superblock;
        cg = ino_to_cg(fs, ino);
@@ -1041,7 +1089,7 @@ ffs_write_inode(union dinode *dp, uint32
         * Initialize inode blocks on the fly for UFS2.
         */
        initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap);
-       if (fsopts->version == 2 && cgino + INOPB(fs) > initediblk &&
+       if (ffs_opts->version == 2 && cgino + INOPB(fs) > initediblk &&
            initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) {
                memset(buf, 0, fs->fs_bsize);
                dip = (struct ufs2_dinode *)buf;
@@ -1065,14 +1113,14 @@ ffs_write_inode(union dinode *dp, uint32
        d = fsbtodb(fs, ino_to_fsba(fs, ino));
        ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
        if (fsopts->needswap) {
-               if (fsopts->version == 1)
+               if (ffs_opts->version == 1)
                        ffs_dinode1_swap(&dp->ffs1_din,
                            &dp1[ino_to_fsbo(fs, ino)]);
                else
                        ffs_dinode2_swap(&dp->ffs2_din,
                            &dp2[ino_to_fsbo(fs, ino)]);
        } else {
-               if (fsopts->version == 1)
+               if (ffs_opts->version == 1)
                        dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
                else
                        dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;

Copied: stable/8/usr.sbin/makefs/ffs.h (from r214921, 
head/usr.sbin/makefs/ffs.h)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/8/usr.sbin/makefs/ffs.h      Tue Jul 26 14:41:54 2011        
(r224447, copy of r214921, head/usr.sbin/makefs/ffs.h)
@@ -0,0 +1,66 @@
+/*     $NetBSD: ffs.h,v 1.1 2004/12/20 20:51:42 jmc Exp $      */
+
+/*
+ * Copyright (c) 2001-2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Luke Mewburn for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ *      Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FFS_H
+#define _FFS_H
+
+typedef struct {
+       int     bsize;          /* block size */
+       int     fsize;          /* fragment size */
+       int     cpg;            /* cylinders per group */
+       int     cpgflg;         /* cpg was specified by user */
+       int     density;        /* bytes per inode */
+       int     ntracks;        /* number of tracks */
+       int     nsectors;       /* number of sectors */
+       int     rpm;            /* rpm */
+       int     minfree;        /* free space threshold */
+       int     optimization;   /* optimization (space or time) */
+       int     maxcontig;      /* max contiguous blocks to allocate */
+       int     rotdelay;       /* rotational delay between blocks */
+       int     maxbpg;         /* maximum blocks per file in a cyl group */
+       int     nrpos;          /* # of distinguished rotational positions */
+       int     avgfilesize;    /* expected average file size */
+       int     avgfpdir;       /* expected # of files per directory */
+       int     version;        /* filesystem version (1 = FFS, 2 = UFS2) */
+       int     maxbsize;       /* maximum extent size */
+       int     maxblkspercg;   /* max # of blocks per cylinder group */
+               /* XXX: support `old' file systems ? */
+} ffs_opt_t;
+
+#endif /* _FFS_H */

Copied: stable/8/usr.sbin/makefs/ffs/Makefile.inc (from r214921, 
head/usr.sbin/makefs/ffs/Makefile.inc)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/8/usr.sbin/makefs/ffs/Makefile.inc   Tue Jul 26 14:41:54 2011        
(r224447, copy of r214921, head/usr.sbin/makefs/ffs/Makefile.inc)
@@ -0,0 +1,9 @@
+#      $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/ffs ${.CURDIR}/../../sys/ufs/ffs
+
+CFLAGS+=       -I${.CURDIR}/../../sys/ufs/ffs
+
+SRCS+= ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c ufs_bmap.c
+SRCS+= buf.c mkfs.c

Modified: stable/8/usr.sbin/makefs/ffs/buf.c
==============================================================================
--- stable/8/usr.sbin/makefs/ffs/buf.c  Tue Jul 26 14:41:28 2011        
(r224446)
+++ stable/8/usr.sbin/makefs/ffs/buf.c  Tue Jul 26 14:41:54 2011        
(r224447)
@@ -118,7 +118,7 @@ brelse(struct buf *bp)
                bp->b_bcount = 0;
                return;
        }
-               
+
        TAILQ_REMOVE(&buftail, bp, b_tailq);
        free(bp->b_data);
        free(bp);
@@ -160,7 +160,7 @@ bcleanup(void)
         *      know why there's still some buffers lying around that
         *      aren't brelse()d
         */
-       
+
        if (TAILQ_EMPTY(&buftail))
                return;
 
@@ -201,7 +201,7 @@ getblk(int fd, struct fs *fs, daddr_t bl
        if (bp == NULL) {
                if ((bp = calloc(1, sizeof(struct buf))) == NULL)
                        err(1, "getblk: calloc");
-                       
+
                bp->b_bufsize = 0;
                bp->b_blkno = bp->b_lblkno = blkno;
                bp->b_fd = fd;

Modified: stable/8/usr.sbin/makefs/ffs/ffs_alloc.c
==============================================================================
--- stable/8/usr.sbin/makefs/ffs/ffs_alloc.c    Tue Jul 26 14:41:28 2011        
(r224446)
+++ stable/8/usr.sbin/makefs/ffs/ffs_alloc.c    Tue Jul 26 14:41:54 2011        
(r224447)
@@ -87,7 +87,7 @@ static int32_t ffs_mapsearch(struct fs *
  *      available block is located.
  */
 int
-ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size,
+ffs_alloc(struct inode *ip, daddr_t lbn __unused, daddr_t bpref, int size,
     daddr_t *bnp)
 {
        struct fs *fs = ip->i_fs;
@@ -95,7 +95,7 @@ ffs_alloc(struct inode *ip, daddr_t lbn,
        int cg;
        
        *bnp = 0;
-       if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) {
+       if (size > fs->fs_bsize || fragoff(fs, size) != 0) {
                errx(1, "ffs_alloc: bad size: bsize %d size %d",
                    fs->fs_bsize, size);
        }
@@ -187,11 +187,7 @@ ffs_blkpref_ufs1(struct inode *ip, daddr
 }
 
 daddr_t
-ffs_blkpref_ufs2(ip, lbn, indx, bap)
-       struct inode *ip;
-       daddr_t lbn;
-       int indx;
-       int64_t *bap;
+ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int64_t *bap)
 {
        struct fs *fs;
        int cg;
@@ -385,11 +381,11 @@ ffs_alloccgblk(struct inode *ip, struct 
        int32_t bno;
        struct fs *fs = ip->i_fs;
        const int needswap = UFS_FSNEEDSWAP(fs);
-       u_int8_t *blksfree;
+       u_int8_t *blksfree_swap;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to