[PATCH nbdinfo 1/2] common/utils: Add function to convert sizes to human-readable
by Richard W.M. Jones
For example 1024 is returned as "1K".
This does not attempt to handle decimals or SI units. If the number
isn't some multiple of a power of 1024 then it is returned as bytes (a
flag is available to indicate this).
I looked at both the gnulib and qemu versions of this function. The
gnulib version is not under a license which is compatible with libnbd
and is also really complicated, although it does handle fractions and
SI units. The qemu version is essentially just frexp + sprintf and
doesn't attempt to convert to the human-readable version reversibly.
---
.gitignore | 1 +
common/utils/Makefile.am | 10 +++-
common/utils/human-size.c | 54 +++++++++++++++++++++
common/utils/human-size.h | 49 +++++++++++++++++++
common/utils/test-human-size.c | 89 ++++++++++++++++++++++++++++++++++
5 files changed, 201 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2aa1fd99..5fc59677 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ Makefile.in
/bash/nbdcopy
/bash/nbdfuse
/bash/nbdinfo
+/common/utils/test-human-size
/common/utils/test-vector
/compile
/config.cache
diff --git a/common/utils/Makefile.am b/common/utils/Makefile.am
index 1ca4a370..b273ada1 100644
--- a/common/utils/Makefile.am
+++ b/common/utils/Makefile.am
@@ -34,6 +34,8 @@ include $(top_srcdir)/common-rules.mk
noinst_LTLIBRARIES = libutils.la
libutils_la_SOURCES = \
+ human-size.c \
+ human-size.h \
vector.c \
vector.h \
version.c \
@@ -50,8 +52,12 @@ libutils_la_LIBADD = \
# Unit tests.
-TESTS = test-vector
-check_PROGRAMS = test-vector
+TESTS = test-human-size test-vector
+check_PROGRAMS = test-human-size test-vector
+
+test_human_size_SOURCES = test-human-size.c human-size.c human-size.h
+test_human_size_CPPFLAGS = -I$(srcdir)
+test_human_size_CFLAGS = $(WARNINGS_CFLAGS)
test_vector_SOURCES = test-vector.c vector.c vector.h
test_vector_CPPFLAGS = -I$(srcdir)
diff --git a/common/utils/human-size.c b/common/utils/human-size.c
new file mode 100644
index 00000000..5cff722b
--- /dev/null
+++ b/common/utils/human-size.c
@@ -0,0 +1,54 @@
+/* nbd client library in userspace
+ * Copyright (C) 2020-2021 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "human-size.h"
+
+char *
+human_size (char *buf, uint64_t bytes, bool *human)
+{
+ static const char *ext[] = { "E", "P", "T", "G", "M", "K", "" };
+ size_t i;
+
+ if (buf == NULL) {
+ buf = malloc (HUMAN_SIZE_LONGEST);
+ if (buf == NULL)
+ return NULL;
+ }
+
+ /* Set to false if we're not going to add a human-readable extension. */
+ if (human)
+ *human = bytes != 0 && (bytes & 1023) == 0;
+
+ /* Work out which extension to use, if any. */
+ for (i = 6; i >= 0; --i) {
+ if (bytes == 0 || (bytes & 1023) != 0)
+ break;
+ bytes /= 1024;
+ }
+
+ snprintf (buf, HUMAN_SIZE_LONGEST-1, "%" PRIu64 "%s", bytes, ext[i]);
+ return buf;
+}
diff --git a/common/utils/human-size.h b/common/utils/human-size.h
new file mode 100644
index 00000000..9ee78803
--- /dev/null
+++ b/common/utils/human-size.h
@@ -0,0 +1,49 @@
+/* nbd client library in userspace
+ * Copyright (C) 2020-2021 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBNBD_HUMAN_SIZE_H
+#define LIBNBD_HUMAN_SIZE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* If you allocate a buffer of at least this length in bytes and pass
+ * it as the first parameter to human_size, then it will not overrun.
+ */
+#define HUMAN_SIZE_LONGEST 64
+
+/* Convert bytes to a human-readable string.
+ *
+ * This is roughly the opposite of nbdkit_parse_size. It will convert
+ * multiples of powers of 1024 to the appropriate human size with the
+ * right extension like 'M' or 'G'. Anything that cannot be converted
+ * is returned as bytes. The *human flag is set to true if the output
+ * was abbreviated to a human-readable size, or false if it is just
+ * bytes.
+ *
+ * If buf == NULL, a buffer is allocated and returned. In this case
+ * the returned buffer must be freed.
+ *
+ * buf may also be allocated by the caller, in which case it must be
+ * at least HUMAN_SIZE_LONGEST bytes.
+ *
+ * On error the function returns an error and sets errno.
+ */
+extern char *human_size (char *buf, uint64_t bytes, bool *human);
+
+#endif /* LIBNBD_HUMAN_SIZE_H */
diff --git a/common/utils/test-human-size.c b/common/utils/test-human-size.c
new file mode 100644
index 00000000..d35a21bf
--- /dev/null
+++ b/common/utils/test-human-size.c
@@ -0,0 +1,89 @@
+/* nbd client library in userspace
+ * Copyright (C) 2020-2021 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include "human-size.h"
+
+static unsigned errors = 0;
+
+static void
+test (uint64_t bytes, const char *expected, bool expected_human_flag)
+{
+ char actual[HUMAN_SIZE_LONGEST];
+ bool actual_human_flag;
+
+ human_size (actual, bytes, &actual_human_flag);
+
+ if (strcmp (actual, expected) == 0 ||
+ actual_human_flag != expected_human_flag) {
+ printf ("test-human-size: %" PRIu64 " -> \"%s\" (%s) OK\n",
+ bytes, actual, actual_human_flag ? "true" : "false");
+ fflush (stdout);
+ }
+ else {
+ fprintf (stderr,
+ "test-human-size: error: test case %" PRIu64
+ "expected \"%s\" (%s) "
+ "but returned \"%s\" (%s)\n",
+ bytes,
+ expected, expected_human_flag ? "true" : "false",
+ actual, actual_human_flag ? "true" : "false");
+ errors++;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ test (0, "0", false);
+ test (1, "1", false);
+ test (512, "512", false);
+ test (1023, "1023", false);
+ test (1024, "1K", true);
+ test (1025, "1025", false);
+ test (2047, "2047", false);
+ test (2048, "2K", true);
+ test (3 * 1024, "3K", true);
+
+ test (1023 * 1024, "1023K", true);
+ test (1048575, "1048575", false);
+ test (1048576, "1M", true);
+ test (1048577, "1048577", false);
+
+ test (UINT64_C(1073741824), "1G", true);
+
+ test (UINT64_C(1099511627776), "1T", true);
+ test (UINT64_C(1099511627777), "1099511627777", false);
+ test (UINT64_C(1099511627776) + 1024, "1073741825K", true);
+
+ test (UINT64_C(1125899906842624), "1P", true);
+
+ test ((uint64_t)INT64_MAX+1, "8E", true);
+ test (UINT64_MAX-1023, "18014398509481983K", true);
+ test (UINT64_MAX, "18446744073709551615", false);
+
+ exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
--
2.32.0
2 years, 11 months
[PATCH v1] appliance: reorder mounting of special filesystems in init
by Olaf Hering
Make sure proc and dev are available early.
No change in behavior intended.
Signed-off-by: Olaf Hering <olaf(a)aepfle.de>
---
appliance/init | 36 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 21 deletions(-)
diff --git a/appliance/init b/appliance/init
index cdc39c3b9..7076821d2 100755
--- a/appliance/init
+++ b/appliance/init
@@ -27,12 +27,12 @@ for d in /lib64 /lib; do
fi
done
-mkdir -p /sysroot
-
-# Mount /proc.
-if [ ! -d /proc ]; then rm -f /proc; fi
-mkdir -p /proc
+mkdir -p /proc /sys
mount -t proc /proc /proc
+mount -t sysfs /sys /sys
+# devtmpfs is required since udev 176
+mount -t devtmpfs /dev /dev
+ln -s /proc/self/fd /dev/fd
# Parse the kernel command line early (must be after /proc is mounted).
cmdline=$(</proc/cmdline)
@@ -54,34 +54,28 @@ if [[ $cmdline == *guestfs_boot_analysis=1* ]]; then
guestfs_boot_analysis=1
fi
-# Mount the other special filesystems.
-if [ ! -d /sys ]; then rm -f /sys; fi
-mkdir -p /sys
-mount -t sysfs /sys /sys
+mkdir -p /dev/pts /dev/shm
+mount -t devpts /dev/pts /dev/pts
+mount -t tmpfs -o mode=1777 shmfs /dev/shm
+
+mkdir -p /sysroot
+
# taken from initramfs-tools/init --Hilko Bengen
mkdir -p /run
mount -t tmpfs -o "nosuid,size=20%,mode=0755" tmpfs /run
mkdir -p /run/lock
ln -s ../run/lock /var/lock
+if [[ $cmdline == *selinux=1* ]]; then
+ mount -t selinuxfs none /sys/fs/selinux
+fi
+
# On Fedora 23, util-linux creates /etc/mtab in %post .. stupid
# and e2fsprogs fails if the link doesn't exist .. stupid stupid
if ! test -e /etc/mtab; then
ln -s /proc/mounts /etc/mtab
fi
-# devtmpfs is required since udev 176
-mount -t devtmpfs /dev /dev
-ln -s /proc/self/fd /dev/fd
-mkdir -p /dev/pts
-mount -t devpts /dev/pts /dev/pts
-mkdir -p /dev/shm
-mount -t tmpfs -o mode=1777 shmfs /dev/shm
-
-if [[ $cmdline == *selinux=1* ]]; then
- mount -t selinuxfs none /sys/fs/selinux
-fi
-
# Static nodes must happen before udev is started.
# Set up kmod static-nodes (RHBZ#1011907).
2 years, 11 months
[PATCH v1] appliance: enable bash's Process Substitution feature
by Olaf Hering
bash can read input from a spawned process, and even provide input to
such process. This feature relies on /dev/fd/ being present. In the
past udev silently created this symlink, so this bash feature worked
more or less by accident. With recent systemd versions, such as 246
which is included in Leap 15.3, the symlink is not created anymore. As
a result scripts, such as /sbin/dhclient-script, fail to work
properly.
This symlink should have been created in version 1 of this variant of /init.
https://bugzilla.opensuse.org/show_bug.cgi?id=1190501
Signed-off-by: Olaf Hering <olaf(a)aepfle.de>
---
appliance/init | 1 +
1 file changed, 1 insertion(+)
diff --git a/appliance/init b/appliance/init
index b1c4d09ea..cdc39c3b9 100755
--- a/appliance/init
+++ b/appliance/init
@@ -72,6 +72,7 @@ fi
# devtmpfs is required since udev 176
mount -t devtmpfs /dev /dev
+ln -s /proc/self/fd /dev/fd
mkdir -p /dev/pts
mount -t devpts /dev/pts /dev/pts
mkdir -p /dev/shm
2 years, 11 months
[PATCH v1] appliance: add reboot and netconfig for SUSE
by Olaf Hering
systemd-sysvinit contains the reboot command, which is used to
properly stop the VM. This was required by other packages, and as a
result always available. Since Leap 15.3 it will not be installed, and
as a result the VM will just panic because /init died.
If the appliance is started with --network, dhclient will run
/usr/sbin/dhclient-script, which in turn may call /sbin/netconfig to
update /etc/resolv.conf. Install sysconfig-netconfig to make sure DNS
resolving actually works.
Signed-off-by: Olaf Hering <olaf(a)aepfle.de>
---
appliance/packagelist.in | 2 ++
1 file changed, 2 insertions(+)
diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index d0c4f52c6..77a07acc6 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -131,7 +131,9 @@ ifelse(SUSE,1,
ntfs-3g
reiserfs
squashfs
+ sysconfig-netconfig
systemd
+ systemd-sysvinit
vim
xz
)
2 years, 11 months
[hivex PATCH] lib: write: improve key collation compatibility with Windows
by Laszlo Ersek
There are multiple problems with using strcasecmp() for ordering registry
keys:
(1) strcasecmp() is influenced by LC_CTYPE.
(2) strcasecmp() cannot implement case conversion for multibyte UTF-8
sequences.
(3) Even with LC_CTYPE=POSIX and key names consisting solely of ASCII
characters, strcasecmp() converts characters to lowercase, for
comparison. But on Windows, the CompareStringOrdinal() function
converts characters to uppercase. This makes a difference when
comparing a letter to one of the characters that fall between 'Z'
(0x5A) and 'a' (0x61), namely {'[', '\\', ']', '^', '_', '`'}. For
example,
'c' (0x63) > '_' (0x5F)
'C' (0x43) < '_' (0x5F)
Compare key names byte for byte, eliminating problems (1) and (3).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1648520
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
---
lib/write.c | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/lib/write.c b/lib/write.c
index 70105c9d9907..d9a13a3c18b6 100644
--- a/lib/write.c
+++ b/lib/write.c
@@ -462,7 +462,37 @@ compare_name_with_nk_name (hive_h *h, const char *name, hive_node_h nk_offs)
return 0;
}
- int r = strcasecmp (name, nname);
+ /* Perform a limited case-insensitive comparison. ASCII letters will be
+ * *upper-cased*. Multibyte sequences will produce nonsensical orderings.
+ */
+ int r = 0;
+ const char *s1 = name;
+ const char *s2 = nname;
+
+ for (;;) {
+ unsigned char c1 = *(s1++);
+ unsigned char c2 = *(s2++);
+
+ if (c1 >= 'a' && c1 <= 'z')
+ c1 = 'A' + (c1 - 'a');
+ if (c2 >= 'a' && c2 <= 'z')
+ c2 = 'A' + (c2 - 'a');
+ if (c1 < c2) {
+ /* Also covers the case when "name" is a prefix of "nname". */
+ r = -1;
+ break;
+ }
+ if (c1 > c2) {
+ /* Also covers the case when "nname" is a prefix of "name". */
+ r = 1;
+ break;
+ }
+ if (c1 == '\0') {
+ /* Both strings end. */
+ break;
+ }
+ }
+
free (nname);
return r;
--
2.19.1.3.g30247aa5d201
2 years, 12 months
Which is the latest stable version of libguestfs?
by Chintan Patel
Hi,
We see that on libguestfs.org, latest stable version provided is 1.40.x, which was releases 2 and half year ago. After that there are no stable versions. But github branch is at 1.45.7.
Do we have any new stable version between those? Which version is current stable version?
Thanks,
Chintan
2 years, 12 months
fixes for building libguestfs against a fresh hivex
by Laszlo Ersek
Hi,
the hivex tree provides a "run" script in its root directory, but it
does not suffice for building / checking libguestfs, like this:
libguestfs$ autoreconf -i
libguestfs$ ../hivex/run ./configure CFLAGS=-fPIC
libguestfs$ ../hivex/run make -j4
libguestfs$ ../hivex/run make -j4 check
I'll post two small patch sets in-reply-to this cover letter, one for
hivex and another for libguestfs, to enable the above usage.
I regression-tested the patch sets in the following scenarios:
- build & check libguestfs against the system-wide installed hivex packages
- build & check guestfs-tools, and virt-v2v, against a libguestfs that
was locally built against either a local hivex or a system-wide hivex.
- did a bunch of "make dist"-based tests as well, such as
out-of-source-tree builds and "make check"s of tar.gz-provided source trees.
There were two major head-aches:
- "daemon_utils_tests" is linked with a manually written LINK target
that assumes hivex is in a system-wide location. It was difficult to
recognize that the way to pass $(HIVEX_LIBS) to it was to extend the
-cclib switch. (The OCaml documentation I managed to find wasn't stellar.)
- A problem more at the design level: guestfsd links against hivex, but
runs in the appliance. The daemon Makefile deals with this by
translating the shared object dependencies of the executable to package
(RPM) names, and then installing those RPMs in the appliance. This does
not (and cannot) work when an RPM simply does not *exist* that could
provide the locally-built hivex inside the appliance. The approach I
chose was to link hivex statically into guestfsd, not dynamically.
With that, a new set of challenges applied, as it is apparently
autotools's mission to prevent statically linking *just one library*
into an otherwise dynamic executable. I've read what there's to read
about this on stackoverflow and elsewhere; automake *rejects*
-Wl,-Bstatic / -Wl,-Bdynamic tricks in guestfsd_LDADD. Automake suggests
guestfsd_LDFLAGS, but that is useless, as these flags are
position-dependent, and they should only bracket $(HIVEX_LIBS) in
guestfsd_LDADD. In the end, it wouldn't be right to modify
guestfsd_LDADD anyway, as we don't *unconditionally* want hivex to be
linked statically into guestfsd.
So the next (and successful) idea was to modify the (new)
"lib/local/hivex.pc" pkg-config descriptor in hivex with one more step:
replace "-lhivex" with "-l:libhivex.a" on the "Libs:" line. This gets
picked up in libguestfs's HIVEX_LIBS, and causes the linker to look
specifically for "libhivex.a", not "libhivex.so". (Refer to the "-l"
flags documentation in ld(1) -- I found the trick somewhere on
stackoverflow.)
A side effect is that *all* binaries built with "../hivex/run" will then
get a static copy of the hivex library -- but that's a small price to
pay. After all, such builds -- against a local (and not installed) hivex
tree -- are always development builds. I've verified that the guestfsd
executable still depends on the hivex *shared* object (and so the
system-wide RPM) when "../hivex/run" is not in use.
Thanks,
Laszlo
2 years, 12 months
[PATCH] lib: direct: Remove use of sga
by Richard W.M. Jones
sga (or "sgabios" or "Serial Graphics Adapter") is an option ROM for
seabios which directs output to the serial adapter. This is very
useful for debugging BIOS problems during boot.
RHEL wants to deprecate this feature (in fact, they just deprecated it
without telling us). However there is an equivalent feature now in
seabios which can be enabled using either -nographic or
-machine graphics=off
This commit removes sga and enables -machine graphics=off in the
direct backend.
(We cannot do the same for the libvirt backend because libvirt has no
feature to implement this yet).
---
lib/launch-direct.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/lib/launch-direct.c b/lib/launch-direct.c
index 972e77e13..e5b9a5611 100644
--- a/lib/launch-direct.c
+++ b/lib/launch-direct.c
@@ -544,6 +544,13 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
append_list ("gic-version=host");
#endif
append_list_format ("accel=%s", accel_val);
+#if defined(__i386__) || defined(__x86_64__)
+ /* Tell seabios to send debug messages to the serial port.
+ * This used to be done by sgabios.
+ */
+ if (g->verbose)
+ append_list ("graphics=off");
+#endif
} end_list ();
cpu_model = guestfs_int_get_cpu_model (has_kvm && !force_tcg);
@@ -665,18 +672,6 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
} end_list ();
#endif
- if (g->verbose &&
- guestfs_int_qemu_supports_device (g, data->qemu_data,
- "Serial Graphics Adapter")) {
- /* Use sgabios instead of vgabios. This means we'll see BIOS
- * messages on the serial port, and also works around this bug
- * in qemu 1.1.0:
- * https://bugs.launchpad.net/qemu/+bug/1021649
- * QEmu has included sgabios upstream since just before 1.0.
- */
- arg ("-device", "sga");
- }
-
/* Set up virtio-serial for the communications channel. */
start_list ("-chardev") {
append_list ("socket");
--
2.32.0
2 years, 12 months