summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2009-10-10 11:48:46 +0300
committerLars Wirzenius <liw@liw.fi>2009-10-10 11:48:46 +0300
commit311b87e84b602a422e8845e329629c5ed33d82bd (patch)
tree04aeda10c306f011fbf90c40fc54ae213c00a567
parente213000d37b418c4b4703bb9465e9c2d09050edf (diff)
parentc9ecc35c1556cadc943d9a6482b692c697eaa505 (diff)
downloadextrautils-311b87e84b602a422e8845e329629c5ed33d82bd.tar.gz
Merged from upstream.
-rw-r--r--Makefile4
-rw-r--r--corrupt.132
-rw-r--r--corrupt.c177
-rwxr-xr-xcreate-file89
-rw-r--r--create-file.145
-rwxr-xr-xerrno20
-rw-r--r--errno.151
-rwxr-xr-xminimify71
-rw-r--r--minimify.133
-rwxr-xr-xonerror12
-rw-r--r--trunc126
11 files changed, 659 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 20a7bc9..45087a0 100644
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,11 @@ sharedir = $(prefix)/share
mandir = $(sharedir)/man
man1dir = $(mandir)/man1
-progs = isascii
+progs = isascii corrupt
scripts = total
+CFLAGS = -Wall -O2 --std=gnu99
+
all: $(progs)
install: all
diff --git a/corrupt.1 b/corrupt.1
new file mode 100644
index 0000000..593a0e3
--- /dev/null
+++ b/corrupt.1
@@ -0,0 +1,32 @@
+.\" corrupt.1 - manual page for the corrupt command
+.\" Copyright (C) 2009 Lars Wirzenius
+.\"
+.\" This program is free software: you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+.\"
+.TH CORRUPT 1
+.SH NAME
+corrupt \- modify files by randomly changing bits
+.SH SYNOPSIS
+.BR corrupt
+[\fB-n\fR \fIBITS\fR]
+[\fB--bits\fR \fIBITS\fR]
+.IR file ...
+.SH DESCRIPTION
+.B corrupt
+modifies files by toggling a randomly chosen bit.
+.SH OPTIONS
+.TP
+.BR -n " \fIBITS\fR, " --bits " \fIBITS\fR"
+Set the number of bits to modify.
+Default is one bit.
diff --git a/corrupt.c b/corrupt.c
new file mode 100644
index 0000000..0d29453
--- /dev/null
+++ b/corrupt.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009 Lars Wirzenius
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+
+/* Number of bits to corrupt. */
+static int num_bits = 1;
+
+
+/* Choose a random integer in [0..n-1]. */
+static long choose(long n)
+{
+ if (n == 0)
+ return 0;
+
+ long buckets = (RAND_MAX + 1L) / n;
+ long max = buckets * n;
+ long r;
+
+ do {
+ r = random();
+ } while (r >= max);
+ return r / buckets;
+}
+
+
+static int seek(const char *filename, int fd, off_t offset)
+{
+ if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
+ fprintf(stderr, "Can't seek in %s: %s", filename, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+
+static int corrupt_one_bit(const char *filename, int fd, struct stat st)
+{
+ long offset;
+ long bit;
+ unsigned char byte;
+
+ offset = choose(st.st_size);
+ bit = choose(CHAR_BIT);
+
+ if (seek(filename, fd, offset) == -1)
+ return -1;
+ if (read(fd, &byte, 1) == -1) {
+ fprintf(stderr, "Can't read %s: %s", filename, strerror(errno));
+ return -1;
+ }
+
+ /* This is where we toggle the bit. */
+ unsigned mask = 1 << bit; // All zeroes, except for the interesting bit.
+ unsigned interesting = byte & mask; // Only the interesting bit can be 1.
+ unsigned toggled = interesting ^ mask; // Interesting bit has been toggled.
+ unsigned others = byte & (~mask); // Interesting bit is 0.
+ byte = others | toggled;
+
+ /* Now write it back. */
+ if (seek(filename, fd, offset) == -1)
+ return -1;
+ if (write(fd, &byte, 1) != 1) {
+ fprintf(stderr, "Can't write %s: %s", filename, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int corrupt(const char *filename)
+{
+ int fd;
+ struct stat st;
+
+ fd = open(filename, O_RDWR | O_LARGEFILE);
+ if (fd == -1) {
+ fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno));
+ return -1;
+ }
+
+ if (fstat(fd, &st) == -1) {
+ fprintf(stderr, "Can't find length of %s: %s", filename,
+ strerror(errno));
+ return -1;
+ }
+
+ for (int i = 0; i < num_bits; ++i)
+ if (corrupt_one_bit(filename, fd, st) == -1)
+ return -1;
+
+ if (close(fd) == -1) {
+ fprintf(stderr, "Can't close %s: %s", filename, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int parse_args(int argc, char **argv)
+{
+ const char optstring[] = "n:";
+ const struct option longopts[] = {
+ { "bits", required_argument, NULL, 'n' },
+ { 0 },
+ };
+ char *endptr;
+
+ for (;;) {
+ int opt = getopt_long(argc, argv, optstring, longopts, NULL);
+ switch (opt) {
+ case -1:
+ return optind;
+
+ case 'n':
+ num_bits = strtol(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Invalid number of bits: %s\n", optarg);
+ exit(1);
+ }
+ break;
+
+ default:
+ case '?':
+ exit(1);
+ }
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ int exit_code;
+ int i;
+
+ i = parse_args(argc, argv);
+ if (i == -1)
+ return 1;
+
+ srandom(time(NULL) + getpid());
+ exit_code = 0;
+ for (; i < argc; ++i)
+ if (corrupt(argv[i]) == -1)
+ exit_code = 1;
+ return exit_code;
+}
diff --git a/create-file b/create-file
new file mode 100755
index 0000000..dd41073
--- /dev/null
+++ b/create-file
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+#
+# create-file -- create a file full of zeroes
+# Copyright (C) 2009 Lars Wirzenius
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+import optparse
+import os
+
+
+def parse_size(size):
+ sizes = (
+ ("k", 1000),
+ ("m", 1000**2),
+ ("g", 1000**3),
+
+ ("kb", 1000),
+ ("mb", 1000**2),
+ ("gb", 1000**3),
+
+ ("kib", 1024),
+ ("mib", 1024**2),
+ ("gib", 1024**3),
+ )
+ size = size.lower()
+ for suffix, x in sizes:
+ if size.endswith(suffix):
+ amount = int(size[:-len(suffix)].strip())
+ return amount * x
+ return int(size.strip())
+
+
+def parse_args():
+ parser = optparse.OptionParser()
+
+ parser.epilog = ("SIZE is a size. Default is in bytes, use suffixes "
+ "kB/MB/GB for multiples of 1000, KiB/MiB/GiB for "
+ "multiples of 1024. Only integers supported.")
+
+ parser.add_option("--sparse", action="store_true",
+ help="create a sparse file")
+
+ parser.add_option("--size", metavar="SIZE", default="0",
+ help="create a file of size SIZE")
+
+ options, filenames = parser.parse_args()
+ options.size = parse_size(options.size)
+
+ return options, filenames
+
+
+def create_file(filename, options):
+ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0666)
+ if options.sparse:
+ if options.size > 0:
+ os.lseek(fd, options.size - 1, os.SEEK_SET)
+ os.write(fd, "\0")
+ else:
+ bytes = options.size
+ data = "\0" * 1024**2
+ while bytes >= len(data):
+ os.write(fd, data)
+ bytes -= len(data)
+ if bytes > 0:
+ os.write(fd, data[:bytes])
+ os.close(fd)
+
+
+def main():
+ options, filenames = parse_args()
+ for filename in filenames:
+ create_file(filename, options)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/create-file.1 b/create-file.1
new file mode 100644
index 0000000..4bdfea7
--- /dev/null
+++ b/create-file.1
@@ -0,0 +1,45 @@
+.\" create-file.1 - manual page for the create-file command
+.\" Copyright (C) 2009 Lars Wirzenius
+.\"
+.\" This program is free software: you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+.\"
+.TH CREATE-FILE 1
+.SH NAME
+create-file \- create a file full of zero bytes
+.SH SYNOPSIS
+.B create-file
+.RB [ -h ]
+.RB [ --help ]
+.RB [ --sparse ]
+.RB [ --size =\fISIZE ]
+.RI [ filename ]...
+.SH DESCRIPTION
+.B create-file
+creates a file full of zero bytes (0x00, NUL).
+.SH OPTIONS
+.TP
+.BR -h ", " --help
+Show a short help message.
+.TP
+.B --sparse
+Create a sparse file, which does not allocate disk blocks.
+.TP
+.BR --size =\fISIZE
+Create a file of
+.I SIZE
+bytes.
+The size may be have a suffix to indicate kilobyte (K, KB), megabyte (M, MB),
+or gigabyte (G, GB), or power-of-two multipliers for kibibyte (KiB),
+mebibyte (MiB), or gibibyte (GiB).
+All suffixes are case-insensitive.
diff --git a/errno b/errno
new file mode 100755
index 0000000..d801faa
--- /dev/null
+++ b/errno
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+import errno
+import os
+import sys
+
+toname = dict((str(getattr(errno, x)), x)
+ for x in dir(errno)
+ if x.startswith("E"))
+tocode = dict((x, getattr(errno, x))
+ for x in dir(errno)
+ if x.startswith("E"))
+
+for arg in sys.argv[1:]:
+ if arg in tocode:
+ print arg, tocode[arg], os.strerror(tocode[arg])
+ elif arg in toname:
+ print toname[arg], arg, os.strerror(int(arg))
+ else:
+ print "Unknown:", arg
diff --git a/errno.1 b/errno.1
new file mode 100644
index 0000000..aefb0ff
--- /dev/null
+++ b/errno.1
@@ -0,0 +1,51 @@
+.\" errno.1 - manual page for the errno command
+.\" Copyright (C) 2009 Lars Wirzenius
+.\"
+.\" This program is free software: you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+.\"
+.TH ERRNO 1
+.SH NAME
+errno \- look up errno codes or names
+.SH SYNOPSIS
+.B errno
+.RI [ code | name ]...
+.SH DESCRIPTION
+.B errno
+prints the description of
+.BR errno (3)
+values, from the command line.
+It can look descriptions based on the numeric code or names like
+.BR EEXIST .
+.PP
+For example, to look up what the code 2 means:
+.sp 1
+.nf
+.RS
+$ errno 2
+ENOENT 2 No such file or directory
+.RE
+.fi
+.sp 1
+Similarly, to look up what the code EEXIST means:
+.sp 1
+.nf
+.RS
+$ errno EEXIST
+EEXIST 17 File exists
+.RE
+.fi
+.sp 1
+Note that the output always lists both the name and the code.
+.SH "SEE ALSO"
+.BR errno (3).
diff --git a/minimify b/minimify
new file mode 100755
index 0000000..c4985cf
--- /dev/null
+++ b/minimify
@@ -0,0 +1,71 @@
+#!/usr/bin/python
+#
+# minimify -- compress file to smallest size
+# Copyright (C) 2009 Lars Wirzenius
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+import multiprocessing
+import optparse
+import os
+import subprocess
+import tempfile
+
+
+COMPRESSORS = (
+ ('gzip', '.gz'),
+ ('bzip2', '.bz2'),
+ ('lzma', '.lzma'),
+)
+
+
+def parse_args():
+ parser = optparse.OptionParser()
+ options, filenames = parser.parse_args()
+ return options, filenames
+
+
+def run_compressor(t):
+ compressor, filename, suffix, options = t
+ input_f = file(filename)
+ fd, name = tempfile.mkstemp(dir=os.path.dirname(filename))
+ p = subprocess.Popen([compressor], stdin=input_f, stdout=fd)
+ p.communicate('')
+ os.close(fd)
+ if p.returncode:
+ raise Exception('Compression program %s failed' % p.returncode)
+ os.rename(name, filename + suffix)
+ return os.path.getsize(filename + suffix), filename + suffix
+
+
+def compress(filename, options):
+ args = [(compressor, filename, suffix, options)
+ for compressor, suffix in COMPRESSORS]
+ pool = multiprocessing.Pool()
+ sizes = sorted(pool.map(run_compressor, args))
+ for size, pathname in sizes[1:]:
+ os.remove(pathname)
+ return sizes[0]
+
+
+def main():
+ options, filenames = parse_args()
+ for filename in filenames:
+ size, name = compress(filename, options)
+ print size, name
+
+
+if __name__ == "__main__":
+ main()
diff --git a/minimify.1 b/minimify.1
new file mode 100644
index 0000000..0e9a4b3
--- /dev/null
+++ b/minimify.1
@@ -0,0 +1,33 @@
+.\" minimify.1 - manual page for the minimify command
+.\" Copyright (C) 2009 Lars Wirzenius
+.\"
+.\" This program is free software: you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+.\"
+.TH MINIMIFY 1
+.SH NAME
+minimify \- compress file to minimal size
+.SH SYNOPSIS
+.BR minimify
+.IR file ...
+.SH DESCRIPTION
+.B minimify
+compresses a file using different compression programs and picks the
+smallest output.
+Note that this can be extremely slow.
+.PP
+The following compression programs are supported:
+.BR gzip ,
+.BR bzip2 ,
+and
+.BR lzma .
diff --git a/onerror b/onerror
new file mode 100755
index 0000000..3e5a927
--- /dev/null
+++ b/onerror
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+temp=$(mktemp)
+"$@" > "$temp" 2>&1
+ret=$?
+if [ $ret != 0 ]
+then
+ cat "$temp" 1>&2
+fi
+rm -f "$temp"
+exit $ret
+
diff --git a/trunc b/trunc
new file mode 100644
index 0000000..51b62c4
--- /dev/null
+++ b/trunc
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+# trunc v.1.0 - Truncate a file to a given length
+#
+# Copyright Mikko Rauhala <mjr@iki.fi>, 2009
+#
+# This program is free software. It comes without any warranty, to
+# the extent permitted by applicable law. You can redistribute it
+# and/or modify it under the terms of the Do What The Fuck You Want
+# To Public License, Version 2, as published by Sam Hocevar at
+# http://sam.zoy.org/wtfpl/COPYING and reproduced here:
+#
+# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+# Version 2, December 2004
+#
+# Copyright (C) 2004 Sam Hocevar
+# 14 rue de Plaisance, 75014 Paris, France
+# Everyone is permitted to copy and distribute verbatim or modified
+# copies of this license document, and changing it is allowed as long
+# as the name is changed.
+#
+# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+#
+# 0. You just DO WHAT THE FUCK YOU WANT TO.
+
+# README:
+
+usage()
+{
+cat 1>&2 << EOF
+Usage: trunc [-b blocksize] size file(s)
+ trunc [--help|-h|--version|-v]
+
+Files will be truncated to the given size. Size is given in bytes
+by default, but another block size may also be spesified. If a
+file was originally larger than the given size, the rest of it
+is lost. If it was smaller, the newly created part of the file
+will be filled with zeroes (sparse if supported by the system).
+If a file doesn't exist, an empty (sparse) file is created with
+the given size and name.
+
+Size is given directly to dd as a count and the optional blocksize
+as bs; refer to your system's dd documentation for possible special
+formatting options.
+
+EOF
+exit 0
+}
+
+# In practice, trunc is a small convenience wrapper for dd, which
+# does the entire actual job. The dd recipe isn't all that complicated
+# either, but hey, this is still more convenient and some of us find
+# ourselves wanting to do this from time to time.
+
+# Technically, we rely on the fact that dd per default (without
+# conv=notrunc) truncates the output file after completing its other
+# tasks. We merely tell dd to seek the output file to the given
+# position and write nothing.
+
+# There are some idiosyncracies in this script; most of them can be
+# explained by me having started scripting first in the mid-90s and
+# not bothering to properly find out which of the nicer constructs
+# are bashims (which I want to avoid). Yeah, I'm a lazy bastard.
+
+# History:
+
+# 1.0 Initial release. Slightly cleaned up from rc1 though
+# no actual bugs were found. While cleaning, added also
+# -v and -h.
+# 1.0rc1 Initial release candidate. Will be named 1.0 later if
+# no bugs are found.
+
+
+# Make sure locale settings don't interfere. Might need to rethink and
+# isolate this setting to smaller parts of the script if this ever gets
+# localized, but for now, it's okay. (Probably unnecessary in this
+# script anyway, I don't _think_ we're doing anything locale-spesific,
+# but I've taken this habit to be sure. Doesn't hurt.)
+LC_ALL=C
+export LC_ALL
+
+ohnoes()
+{
+ echo "trunc: $1" 1>&2
+ exit "$2"
+}
+
+if ! which dd > /dev/null; then
+ ohnoes "dd not found (why, oh why?)" 3
+fi
+
+if [ "a$1" = "a-h" -o "a$1" = "a--help" ]; then
+ usage
+fi
+
+if [ "a$1" = "a-v" -o "a$1" = "a--version" ]; then
+ echo "trunc 1.0 by Mikko Rauhala <mjr@iki.fi>" 1>&2
+ exit 0
+fi
+
+BS=1
+if [ "a$1" = "a-b" ]; then
+ if [ "a$2" = "a" ]; then
+ usage
+ else
+ BS="$2"
+ shift
+ shift
+ fi
+fi
+
+if [ "a$1" = a -o "a$2" = a ]; then
+ usage
+fi
+
+SIZE="$1"
+shift
+
+for FILE in "$@"; do
+ if ! ERROR="`dd if=/dev/null of="$FILE" bs="$BS" count=0 seek="$SIZE" 2>&1`"; then
+ ohnoes "$ERROR" 1
+ fi
+done
+
+exit 0