mkfs.mfs -I: insert fs at offset feature
. use it in x86_hdimage.sh: avoid copying big FS images into iso & hd images each time Change-Id: I0775f43cd1821ea7be2fec5b96d107a68afb96d6
This commit is contained in:
parent
09143af258
commit
8dbe32610b
3 changed files with 121 additions and 104 deletions
|
@ -28,12 +28,6 @@ fi
|
|||
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
#
|
||||
# Artifacts from this script are stored in the IMG_DIR
|
||||
#
|
||||
rm -rf $IMG_DIR $IMG
|
||||
mkdir -p $IMG_DIR $CDFILES
|
||||
|
||||
while getopts "i" c
|
||||
do
|
||||
case "$c" in
|
||||
|
@ -45,6 +39,12 @@ done
|
|||
|
||||
: ${IMG=minix_x86.img}
|
||||
|
||||
#
|
||||
# Artifacts from this script are stored in the IMG_DIR
|
||||
#
|
||||
rm -rf $IMG_DIR $IMG
|
||||
mkdir -p $IMG_DIR $CDFILES
|
||||
|
||||
#
|
||||
# Call build.sh using a sloppy file list so we don't need to remove the installed /etc/fstag
|
||||
#
|
||||
|
@ -56,24 +56,13 @@ then cp ${DESTDIR}/usr/mdec/boot_monitor $CDFILES/boot
|
|||
cp ${MODDIR}/* $CDFILES/
|
||||
. ./releasetools/release.functions
|
||||
cd_root_changes # uses $CDFILES and writes $CDFILES/boot.cfg
|
||||
${CROSS_TOOLS}/nbwriteisofs -s0x0 -l MINIX -B ${DESTDIR}/usr/mdec/bootxx_cd9660 -n $CDFILES ${IMG_DIR}/iso.img
|
||||
ISO_SIZE=$((`stat -c %s ${IMG_DIR}/iso.img` / 512))
|
||||
# start the image off with the iso image; reduce root size to reserve
|
||||
${CROSS_TOOLS}/nbwriteisofs -s0x0 -l MINIX -B ${DESTDIR}/usr/mdec/bootxx_cd9660 -n $CDFILES $IMG
|
||||
ISO_SIZE=$((`stat -c %s $IMG` / 512))
|
||||
else # just make an empty iso partition
|
||||
ISO_SIZE=8
|
||||
fi
|
||||
|
||||
# This script creates a bootable image and should at some point in the future
|
||||
# be replaced by makefs.
|
||||
#
|
||||
# All sized are written in 512 byte blocks
|
||||
#
|
||||
# we create a disk image of about 2 gig's
|
||||
# for alignment reasons, prefer sizes which are multiples of 4096 bytes
|
||||
#
|
||||
: ${ROOT_SIZE=$(( 64*(2**20) / 512))}
|
||||
: ${HOME_SIZE=$(( 128*(2**20) / 512))}
|
||||
: ${USR_SIZE=$((1536*(2**20) / 512))}
|
||||
|
||||
#
|
||||
# create a fstab entry in /etc this is normally done during the
|
||||
# setup phase on x86
|
||||
|
@ -87,15 +76,6 @@ rm -f ${DESTDIR}/SETS.*
|
|||
|
||||
${CROSS_TOOLS}/nbpwd_mkdb -V 0 -p -d ${DESTDIR} ${DESTDIR}/etc/master.passwd
|
||||
|
||||
#
|
||||
# Now given the sizes above use DD to create separate files representing
|
||||
# the partitions we are going to use.
|
||||
#
|
||||
dd if=/dev/zero of=${IMG_DIR}/iso.img bs=512 count=1 seek=$(($ISO_SIZE -1)) 2>/dev/null
|
||||
dd if=/dev/zero of=${IMG_DIR}/root.img bs=512 count=1 seek=$(($ROOT_SIZE -1)) 2>/dev/null
|
||||
dd if=/dev/zero of=${IMG_DIR}/home.img bs=512 count=1 seek=$(($HOME_SIZE -1)) 2>/dev/null
|
||||
dd if=/dev/zero of=${IMG_DIR}/usr.img bs=512 count=1 seek=$(($USR_SIZE -1)) 2>/dev/null
|
||||
|
||||
# make the different file system. this part is *also* hacky. We first convert
|
||||
# the METALOG.sanitised using mtree into a input METALOG containing uids and
|
||||
# gids.
|
||||
|
@ -133,54 +113,48 @@ rm ${IMG_DIR}/root.in
|
|||
cat ${IMG_DIR}/input | grep "^\./usr/\|^. " | sed "s,\./usr,\.,g" | ${CROSS_TOOLS}/nbtoproto -b ${DESTDIR}/usr -o ${IMG_DIR}/usr.proto
|
||||
cat ${IMG_DIR}/input | grep "^\./home/\|^. " | sed "s,\./home,\.,g" | ${CROSS_TOOLS}/nbtoproto -b ${DESTDIR}/home -o ${IMG_DIR}/home.proto
|
||||
|
||||
# If in ISO mode, fit the FSes
|
||||
# This script creates a bootable image and should at some point in the future
|
||||
# be replaced by makefs.
|
||||
#
|
||||
# All sized are written in 512 byte blocks
|
||||
#
|
||||
# we create a disk image of about 2 gig's
|
||||
# for alignment reasons, prefer sizes which are multiples of 4096 bytes
|
||||
#
|
||||
: ${ROOT_SIZE=$(( 64*(2**20) / 512))}
|
||||
: ${HOME_SIZE=$(( 128*(2**20) / 512))}
|
||||
: ${USR_SIZE=$(( 1536*(2**20) / 512))}
|
||||
|
||||
if [ "$ISOMODE" ]
|
||||
then ROOTSIZEARG="-x 5" # give root fs a little breathing room on the CD
|
||||
else # give args with the right sizes
|
||||
then
|
||||
# In iso mode, make all FSes fit (i.e. as small as possible), but
|
||||
# leave some space on /
|
||||
ROOTSIZEARG="-x 5"
|
||||
else
|
||||
# In hd image mode, FSes have fixed sizes
|
||||
ROOTSIZEARG="-b $((${ROOT_SIZE} / 8))"
|
||||
USRSIZEARG="-b $((${USR_SIZE} / 8))"
|
||||
HOMESIZEARG="-b $((${HOME_SIZE} / 8))"
|
||||
fi
|
||||
|
||||
#
|
||||
# Generate /root, /usr and /home partition images.
|
||||
#
|
||||
echo "Writing Minix filesystem images"
|
||||
echo " - ROOT"
|
||||
${CROSS_TOOLS}/nbmkfs.mfs $ROOTSIZEARG ${IMG_DIR}/root.img ${IMG_DIR}/root.proto
|
||||
echo " - USR"
|
||||
${CROSS_TOOLS}/nbmkfs.mfs $USRSIZEARG ${IMG_DIR}/usr.img ${IMG_DIR}/usr.proto
|
||||
echo " - HOME"
|
||||
${CROSS_TOOLS}/nbmkfs.mfs $HOMESIZEARG ${IMG_DIR}/home.img ${IMG_DIR}/home.proto
|
||||
|
||||
# Set the sizes based on what was just generated - should change nothing if sizes
|
||||
# were specified
|
||||
echo "$ROOT_SIZE $USR_SIZE $HOME_SIZE"
|
||||
ROOT_SIZE=$((`stat -c %s ${IMG_DIR}/root.img` / 512))
|
||||
USR_SIZE=$((`stat -c %s ${IMG_DIR}/usr.img` / 512))
|
||||
HOME_SIZE=$((`stat -c %s ${IMG_DIR}/home.img` / 512))
|
||||
echo "$ROOT_SIZE $USR_SIZE $HOME_SIZE"
|
||||
|
||||
# Do some math to determine the start addresses of the partitions.
|
||||
# Ensure the start of the partitions are always aligned, the end will
|
||||
# always be as we assume the sizes are multiples of 4096 bytes, which
|
||||
# is always true as soon as you have an integer multiple of 1MB.
|
||||
#
|
||||
ISO_START=0
|
||||
ROOT_START=$(($ISO_START + $ISO_SIZE))
|
||||
ROOT_START=$ISO_SIZE
|
||||
|
||||
echo " - ROOT"
|
||||
ROOT_SIZE=$((`${CROSS_TOOLS}/nbmkfs.mfs -d $ROOTSIZEARG -I $(($ROOT_START*512)) $IMG ${IMG_DIR}/root.proto`/512))
|
||||
USR_START=$(($ROOT_START + $ROOT_SIZE))
|
||||
echo " - USR"
|
||||
USR_SIZE=$((`${CROSS_TOOLS}/nbmkfs.mfs -d $USRSIZEARG -I $(($USR_START*512)) $IMG ${IMG_DIR}/usr.proto`/512))
|
||||
HOME_START=$(($USR_START + $USR_SIZE))
|
||||
echo " - HOME"
|
||||
HOME_SIZE=$((`${CROSS_TOOLS}/nbmkfs.mfs -d $HOMESIZEARG -I $(($HOME_START*512)) $IMG ${IMG_DIR}/home.proto`/512))
|
||||
|
||||
#
|
||||
# Merge the partitions into a single image.
|
||||
#
|
||||
echo "Merging file systems"
|
||||
dd if=${IMG_DIR}/iso.img of=${IMG} seek=$ISO_START conv=notrunc
|
||||
dd if=${IMG_DIR}/root.img of=${IMG} seek=$ROOT_START conv=notrunc
|
||||
dd if=${IMG_DIR}/usr.img of=${IMG} seek=$USR_START conv=notrunc
|
||||
dd if=${IMG_DIR}/home.img of=${IMG} seek=$HOME_START conv=notrunc
|
||||
|
||||
${CROSS_TOOLS}/nbpartition -m ${IMG} ${ISO_START} 81:${ISO_SIZE} 81:${ROOT_SIZE} 81:${USR_SIZE} 81:${HOME_SIZE}
|
||||
${CROSS_TOOLS}/nbpartition -m ${IMG} 0 81:${ISO_SIZE} 81:${ROOT_SIZE} 81:${USR_SIZE} 81:${HOME_SIZE}
|
||||
|
||||
mods="`( cd $MODDIR; echo mod* | tr ' ' ',' )`"
|
||||
if [ "$ISOMODE" ]
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
|
||||
#if !defined(__minix)
|
||||
#define mul64u(a,b) ((uint64_t)(a) * (b))
|
||||
#define lseek64(a,b,c,d) lseek(a,b,c)
|
||||
#endif
|
||||
|
||||
/* some Minix specific types that do not conflict with Posix */
|
||||
|
@ -88,6 +87,7 @@ int lct = 0, fd, print = 0;
|
|||
int simple = 0, dflag = 0, verbose = 0;
|
||||
int donttest; /* skip test if it fits on medium */
|
||||
char *progname;
|
||||
uint64_t fs_offset_bytes, fs_offset_blocks, written_fs_size = 0;
|
||||
|
||||
time_t current_time;
|
||||
char *zero;
|
||||
|
@ -128,11 +128,13 @@ __dead void pexit(char const *s, ...) __printflike(1,2);
|
|||
void *alloc_block(void);
|
||||
void print_fs(void);
|
||||
int read_and_set(block_t n);
|
||||
void special(char *string);
|
||||
void special(char *string, int insertmode);
|
||||
__dead void usage(void);
|
||||
void get_block(block_t n, void *buf);
|
||||
void get_super_block(void *buf);
|
||||
void put_block(block_t n, void *buf);
|
||||
static uint64_t mkfs_seek(uint64_t pos, int whence);
|
||||
static ssize_t mkfs_write(void * buf, size_t count);
|
||||
|
||||
/*================================================================
|
||||
* mkfs - make filesystem
|
||||
|
@ -145,6 +147,7 @@ main(int argc, char *argv[])
|
|||
ino_t inodes, root_inum;
|
||||
char *token[MAX_TOKENS], line[LINE_LEN], *sfx;
|
||||
struct fs_size fssize;
|
||||
int insertmode = 0;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
|
@ -157,7 +160,7 @@ main(int argc, char *argv[])
|
|||
#endif
|
||||
zone_shift = 0;
|
||||
extra_space_percent = 0;
|
||||
while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:")) != EOF)
|
||||
while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:I:")) != EOF)
|
||||
switch (ch) {
|
||||
#ifndef MFS_STATIC_BLOCK_SIZE
|
||||
case 'B':
|
||||
|
@ -179,6 +182,10 @@ main(int argc, char *argv[])
|
|||
break;
|
||||
(void)sfx; /* shut up warnings about unused variable...*/
|
||||
#endif
|
||||
case 'I':
|
||||
fs_offset_bytes = strtoul(optarg, (char **) NULL, 0);
|
||||
insertmode = 1;
|
||||
break;
|
||||
case 'b':
|
||||
blocks = bblocks = strtoul(optarg, (char **) NULL, 0);
|
||||
break;
|
||||
|
@ -253,9 +260,11 @@ main(int argc, char *argv[])
|
|||
*/
|
||||
zero = alloc_block();
|
||||
|
||||
fs_offset_blocks = roundup(fs_offset_bytes, block_size) / block_size;
|
||||
|
||||
/* Determine the size of the device if not specified as -b or proto. */
|
||||
maxblocks = sizeup(argv[optind]);
|
||||
if (bblocks != 0 && bblocks > maxblocks){
|
||||
if (bblocks != 0 && bblocks + fs_offset_blocks > maxblocks && !insertmode) {
|
||||
errx(4, "Given size -b %d exeeds device capacity(%d)\n", bblocks, maxblocks);
|
||||
}
|
||||
|
||||
|
@ -274,7 +283,7 @@ main(int argc, char *argv[])
|
|||
*/
|
||||
if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
|
||||
|
||||
if (maxblocks && blocks > maxblocks) {
|
||||
if (maxblocks && blocks > maxblocks && !insertmode) {
|
||||
errx(1, "%s: number of blocks too large for device.", argv[optind]);
|
||||
}
|
||||
|
||||
|
@ -315,7 +324,7 @@ main(int argc, char *argv[])
|
|||
blocks += blocks*extra_space_percent/100;
|
||||
inodes += inodes*extra_space_percent/100;
|
||||
/* XXX is it OK to write on stdout? Use warn() instead? Also consider using verbose */
|
||||
printf("dynamically sized filesystem: %u blocks, %u inodes\n",
|
||||
fprintf(stderr, "dynamically sized filesystem: %u blocks, %u inodes\n",
|
||||
(unsigned int) blocks, (unsigned int) inodes);
|
||||
}
|
||||
} else {
|
||||
|
@ -362,7 +371,7 @@ main(int argc, char *argv[])
|
|||
(unsigned)umap_array_elements);
|
||||
|
||||
/* Open special. */
|
||||
special(argv[--optind]);
|
||||
special(argv[--optind], insertmode);
|
||||
|
||||
if (!donttest) {
|
||||
uint16_t *testb;
|
||||
|
@ -371,19 +380,13 @@ main(int argc, char *argv[])
|
|||
testb = alloc_block();
|
||||
|
||||
/* Try writing the last block of partition or diskette. */
|
||||
if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
|
||||
err(1, "couldn't seek to last block to test size (1)");
|
||||
}
|
||||
mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET);
|
||||
testb[0] = 0x3245;
|
||||
testb[1] = 0x11FF;
|
||||
testb[block_size/2-1] = 0x1F2F;
|
||||
if ((w=write(fd, testb, block_size)) != block_size)
|
||||
err(1, "File system is too big for minor device (write1 %d/%u)",
|
||||
w, block_size);
|
||||
w=mkfs_write(testb, block_size);
|
||||
sync(); /* flush write, so if error next read fails */
|
||||
if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
|
||||
err(1, "couldn't seek to last block to test size (2)");
|
||||
}
|
||||
mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET);
|
||||
testb[0] = 0;
|
||||
testb[1] = 0;
|
||||
testb[block_size/2-1] = 0;
|
||||
|
@ -395,13 +398,12 @@ main(int argc, char *argv[])
|
|||
testb[0], testb[1], testb[block_size-1]);
|
||||
errx(1, "File system is too big for minor device (read)");
|
||||
}
|
||||
lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL);
|
||||
mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET);
|
||||
testb[0] = 0;
|
||||
testb[1] = 0;
|
||||
testb[block_size/2-1] = 0;
|
||||
if (write(fd, testb, block_size) != block_size)
|
||||
err(1, "File system is too big for minor device (write2)");
|
||||
lseek(fd, 0L, SEEK_SET);
|
||||
mkfs_write(testb, block_size);
|
||||
mkfs_seek(0L, SEEK_SET);
|
||||
free(testb);
|
||||
}
|
||||
|
||||
|
@ -426,6 +428,8 @@ main(int argc, char *argv[])
|
|||
(int)next_inode-1, next_zone);
|
||||
}
|
||||
|
||||
if(insertmode) printf("%ld\n", written_fs_size);
|
||||
|
||||
return(0);
|
||||
|
||||
/* NOTREACHED */
|
||||
|
@ -560,9 +564,7 @@ sizeup(char * device)
|
|||
progname, (unsigned long)d);
|
||||
}
|
||||
#else
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
if (size == (off_t) -1)
|
||||
err(1, "cannot get device size fd=%d: %s", fd, device);
|
||||
size = mkfs_seek(0, SEEK_END);
|
||||
/* Assume block_t is unsigned */
|
||||
if (size / block_size > (block_t)(-1ul)) {
|
||||
d = (block_t)(-1ul);
|
||||
|
@ -691,10 +693,8 @@ super(zone_t zones, ino_t inodes)
|
|||
#endif
|
||||
}
|
||||
|
||||
if (lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) == (off_t) -1)
|
||||
err(1, "super() couldn't seek");
|
||||
if (write(fd, buf, SUPER_BLOCK_BYTES) != SUPER_BLOCK_BYTES)
|
||||
err(1, "super() couldn't write");
|
||||
mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET);
|
||||
mkfs_write(buf, SUPER_BLOCK_BYTES);
|
||||
|
||||
/* Clear maps and inodes. */
|
||||
for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero);
|
||||
|
@ -1541,19 +1541,20 @@ read_and_set(block_t n)
|
|||
__dead void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-dltv] [-b blocks] [-i inodes] [-z zone_shift]\n"
|
||||
"\t[-x extra] [-B blocksize] special [proto]\n",
|
||||
fprintf(stderr, "Usage: %s [-dltv] [-b blocks] [-i inodes]\n"
|
||||
"\t[-z zone_shift] [-I offset] [-x extra] [-B blocksize] special [proto]\n",
|
||||
progname);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
void
|
||||
special(char * string)
|
||||
special(char * string, int insertmode)
|
||||
{
|
||||
fd = creat(string, 0777);
|
||||
close(fd);
|
||||
fd = open(string, O_RDWR);
|
||||
int openmode = O_RDWR;
|
||||
if(!insertmode) openmode |= O_TRUNC;
|
||||
fd = open(string, O_RDWR | O_CREAT, 0644);
|
||||
if (fd < 0) err(1, "Can't open special file %s", string);
|
||||
mkfs_seek(0, SEEK_SET);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1569,8 +1570,7 @@ get_block(block_t n, void *buf)
|
|||
memcpy(buf, zero, block_size);
|
||||
return;
|
||||
}
|
||||
if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t)(-1))
|
||||
pexit("get_block couldn't seek");
|
||||
mkfs_seek(mul64u(n, block_size), SEEK_SET);
|
||||
k = read(fd, buf, block_size);
|
||||
if (k != block_size)
|
||||
pexit("get_block couldn't read block #%u", (unsigned)n);
|
||||
|
@ -1582,8 +1582,7 @@ get_super_block(void *buf)
|
|||
{
|
||||
ssize_t k;
|
||||
|
||||
if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) == (off_t) -1)
|
||||
err(1, "seek for superblock failed");
|
||||
mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET);
|
||||
k = read(fd, buf, SUPER_BLOCK_BYTES);
|
||||
if (k != SUPER_BLOCK_BYTES)
|
||||
err(1, "get_super_block couldn't read super block");
|
||||
|
@ -1596,8 +1595,49 @@ put_block(block_t n, void *buf)
|
|||
|
||||
(void) read_and_set(n);
|
||||
|
||||
if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1)
|
||||
pexit("put_block couldn't seek");
|
||||
if (write(fd, buf, block_size)!= block_size)
|
||||
pexit("put_block couldn't write block #%u", (unsigned)n);
|
||||
mkfs_seek(mul64u(n, block_size), SEEK_SET);
|
||||
mkfs_write(buf, block_size);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
mkfs_write(void * buf, size_t count)
|
||||
{
|
||||
uint64_t fssize;
|
||||
ssize_t w;
|
||||
|
||||
/* Perform & check write */
|
||||
w = write(fd, buf, count);
|
||||
if(w < 0)
|
||||
err(1, "mkfs_write: write failed");
|
||||
if(w != count)
|
||||
errx(1, "mkfs_write: short write: %ld != %ld", w, count);
|
||||
|
||||
/* Check if this has made the FS any bigger; count bytes after offset */
|
||||
fssize = mkfs_seek(0, SEEK_CUR);
|
||||
|
||||
assert(fssize >= fs_offset_bytes);
|
||||
fssize -= fs_offset_bytes;
|
||||
fssize = roundup(fssize, block_size);
|
||||
if(fssize > written_fs_size)
|
||||
written_fs_size = fssize;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/* Seek to position in FS we're creating. */
|
||||
static uint64_t
|
||||
mkfs_seek(uint64_t pos, int whence)
|
||||
{
|
||||
if(whence == SEEK_SET) pos += fs_offset_bytes;
|
||||
#ifdef __minix
|
||||
uint64_t newpos;
|
||||
if((lseek64(fd, pos, whence, &newpos)) < 0)
|
||||
err(1, "mkfs_seek: lseek64 failed");
|
||||
return newpos;
|
||||
#else
|
||||
off_t newpos;
|
||||
if((newpos=lseek(fd, pos, whence)) == (off_t) -1)
|
||||
err(1, "mkfs_seek: lseek failed");
|
||||
return newpos;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
.Op Fl b Ar blocks
|
||||
.Op Fl z Ar zone_shift
|
||||
.Op Fl x Ar extra_space
|
||||
.Op Fl I Ar fs_offset
|
||||
.Ar special
|
||||
.Op Ar prototype
|
||||
.Sh OPTIONS
|
||||
|
@ -35,6 +36,8 @@ Number of i-nodes (files)
|
|||
Filesystem block size (in bytes)
|
||||
.It Fl b Ar blocks
|
||||
Filesystem size (in blocks)
|
||||
.It Fl I Ar fs_offset
|
||||
Write filesystem starting at offset (in bytes)
|
||||
.It Fl x Ar extra_space
|
||||
Extra space after dynamic sizing (blocks and inodes)
|
||||
.It Fl z Ar zone_shift
|
||||
|
@ -118,4 +121,4 @@ For special files, the major and minor devices are needed.
|
|||
The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
|
||||
.An Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
|
||||
|
|
Loading…
Reference in a new issue