Merge branch 'next'

* next: (26 commits)
  build-sys: add script to compare config.h from meson and autotools
  meson: add missing header files check
  docs: update TODO
  tests: update lscpu outputs
  lscpu: read MHZ from /sys/.../cpufreq/scaling_cur_freq
  lscpu: use locale-independent strtod() when read from kernel
  lib/c_strtod; add locale independent strtod()
  tests: update lscpu output
  lscpu: use MHZ as number to be locale sensitive
  lscpu: add SCALMHZ% and "CPU scaling MHz:"
  sulogin: fix whitespace error
  sulogin: ignore none-existing console devices
  lsns: fix old error message
  lsns: fix copy & past in man page
  lsns: fill UID and USER columns for interpolated namespaces
  fixup! lsns: interpolate missing namespaces for converting forests to a tree
  lsns: interpolate missing namespaces for converting forests to a tree
  lsns: reorganize members specifying other namespaces in lsns_namespace
  lsns: make namespace having no process printable
  libblkid: support zone reset for wipefs
  ...
This commit is contained in:
Karel Zak 2021-06-02 12:33:07 +02:00
commit ac55a4130f
27 changed files with 877 additions and 54 deletions

View File

@ -53,6 +53,11 @@ cal
lscpu lscpu
----- -----
- add "Boost/Turbo: true|false" based on /sys/devices/system/cpu/intel_pstate/no_turbo and
/sys/devices/system/cpu/cpufreq/boost
- add --freq output to visualise CPU use, see https://github.com/karelzak/util-linux/issues/1314
- read cpuid and uname information from file if --sysroot is specified, then - read cpuid and uname information from file if --sysroot is specified, then
we can prepare regression tests completely independent on hw and architecture. we can prepare regression tests completely independent on hw and architecture.

View File

@ -301,6 +301,7 @@ AC_CHECK_HEADERS([ \
inttypes.h \ inttypes.h \
lastlog.h \ lastlog.h \
libutil.h \ libutil.h \
linux/blkzoned.h \
linux/btrfs.h \ linux/btrfs.h \
linux/capability.h \ linux/capability.h \
linux/cdrom.h \ linux/cdrom.h \
@ -382,8 +383,6 @@ AC_CHECK_HEADERS([security/pam_misc.h],
#endif #endif
]) ])
AC_CHECK_HEADERS([linux/blkzoned.h])
AC_CHECK_DECLS([BLK_ZONE_REP_CAPACITY], [], [], [ AC_CHECK_DECLS([BLK_ZONE_REP_CAPACITY], [], [], [
#include <linux/blkzoned.h> #include <linux/blkzoned.h>
]) ])
@ -540,6 +539,7 @@ AC_CHECK_FUNCS([ \
jrand48 \ jrand48 \
lchown \ lchown \
llseek \ llseek \
newlocale \
mempcpy \ mempcpy \
mkostemp \ mkostemp \
nanosleep \ nanosleep \
@ -565,10 +565,12 @@ AC_CHECK_FUNCS([ \
strnchr \ strnchr \
strndup \ strndup \
strnlen \ strnlen \
strtod_l \
sysconf \ sysconf \
sysinfo \ sysinfo \
timegm \ timegm \
usleep \ usleep \
uselocale \
utimensat \ utimensat \
vwarnx \ vwarnx \
warn \ warn \

View File

@ -15,6 +15,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdint.h>
#ifdef HAVE_SYS_MKDEV_H #ifdef HAVE_SYS_MKDEV_H
# include <sys/mkdev.h> /* major and minor on Solaris */ # include <sys/mkdev.h> /* major and minor on Solaris */
@ -147,5 +148,13 @@ int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s);
const char *blkdev_scsi_type_to_name(int type); const char *blkdev_scsi_type_to_name(int type);
int blkdev_lock(int fd, const char *devname, const char *lockmode); int blkdev_lock(int fd, const char *devname, const char *lockmode);
#ifdef HAVE_LINUX_BLKZONED_H
struct blk_zone_report *blkdev_get_zonereport(int fd, uint64_t sector, uint32_t nzones);
#else
static inline struct blk_zone_report *blkdev_get_zonereport(int fd, uint64_t sector, uint32_t nzones)
{
return NULL;
}
#endif
#endif /* BLKDEV_H */ #endif /* BLKDEV_H */

6
include/c_strtod.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef UTIL_LINUX_C_STRTOD_H
#define UTIL_LINUX_C_STRTOD_H
extern double c_strtod(char const *str, char **end);
#endif

View File

@ -18,6 +18,7 @@ libcommon_la_SOURCES = \
lib/color-names.c \ lib/color-names.c \
lib/crc32.c \ lib/crc32.c \
lib/crc32c.c \ lib/crc32c.c \
lib/c_strtod.c \
lib/encode.c \ lib/encode.c \
lib/env.c \ lib/env.c \
lib/fileutils.c \ lib/fileutils.c \
@ -91,7 +92,8 @@ check_PROGRAMS += \
test_remove_env \ test_remove_env \
test_strutils \ test_strutils \
test_ttyutils \ test_ttyutils \
test_timeutils test_timeutils \
test_c_strtod
if LINUX if LINUX
@ -135,6 +137,9 @@ test_mangle_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_MANGLE
test_strutils_SOURCES = lib/strutils.c test_strutils_SOURCES = lib/strutils.c
test_strutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_STRUTILS test_strutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_STRUTILS
test_c_strtod_SOURCES = lib/c_strtod.c
test_c_strtod_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
test_colors_SOURCES = lib/colors.c lib/color-names.c test_colors_SOURCES = lib/colors.c lib/color-names.c
test_colors_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_COLORS test_colors_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_COLORS
test_colors_LDADD = $(LDADD) libtcolors.la test_colors_LDADD = $(LDADD) libtcolors.la

View File

@ -15,6 +15,10 @@
#include <linux/fd.h> #include <linux/fd.h>
#endif #endif
#ifdef HAVE_LINUX_BLKZONED_H
#include <linux/blkzoned.h>
#endif
#ifdef HAVE_SYS_DISKLABEL_H #ifdef HAVE_SYS_DISKLABEL_H
#include <sys/disklabel.h> #include <sys/disklabel.h>
#endif #endif
@ -412,6 +416,31 @@ int blkdev_lock(int fd, const char *devname, const char *lockmode)
return rc; return rc;
} }
#ifdef HAVE_LINUX_BLKZONED_H
struct blk_zone_report *blkdev_get_zonereport(int fd, uint64_t sector, uint32_t nzones)
{
struct blk_zone_report *rep;
size_t rep_size;
int ret;
rep_size = sizeof(struct blk_zone_report) + sizeof(struct blk_zone) * 2;
rep = calloc(1, rep_size);
if (!rep)
return NULL;
rep->sector = sector;
rep->nr_zones = nzones;
ret = ioctl(fd, BLKREPORTZONE, rep);
if (ret || rep->nr_zones != nzones) {
free(rep);
return NULL;
}
return rep;
}
#endif
#ifdef TEST_PROGRAM_BLKDEV #ifdef TEST_PROGRAM_BLKDEV
#include <stdio.h> #include <stdio.h>

105
lib/c_strtod.c Normal file
View File

@ -0,0 +1,105 @@
/*
* Locale-independent strtod().
*
* This file may be redistributed under the terms of the
* GNU Lesser General Public License.
*
* Copyright (C) 2021 Karel Zak <kzak@redhat.com>
*/
#include "c.h"
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include "c_strtod.h"
#if defined(HAVE_NEWLOCALE) && (defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE))
# define USE_CLOCALE
#endif
#if defined(USE_CLOCALE)
static volatile locale_t c_locale;
static locale_t get_c_locale(void)
{
if (!c_locale)
c_locale = newlocale(LC_ALL_MASK, "C", (locale_t) 0);
return c_locale;
}
#endif
double c_strtod(char const *str, char **end)
{
double res;
int errsv;
#if defined(USE_CLOCALE)
locale_t cl = get_c_locale();
#if defined(HAVE_STRTOD_L)
/*
* A) try strtod_l() for "C" locale
*/
if (cl)
return strtod_l(str, end, cl);
#elif defined(HAVE_USELOCALE)
/*
* B) classic strtod(), but switch to "C" locale by uselocal()
*/
if (cl) {
locale_t org_cl = uselocale(locale);
if (!org_cl)
return 0;
res = strtod(str, end);
errsv = errno;
uselocale(org_cl);
errno = errsv;
return res;
}
#endif /* HAVE_USELOCALE */
#endif /* USE_CLOCALE */
/*
* C) classic strtod(), but switch to "C" locale by setlocale()
*/
char *org_locale = setlocale(LC_NUMERIC, NULL);
if (org_locale) {
org_locale = strdup(org_locale);
if (!org_locale)
return 0;
setlocale(LC_NUMERIC, "C");
}
res = strtod(str, end);
errsv = errno;
if (org_locale) {
setlocale(LC_NUMERIC, org_locale);
free(org_locale);
}
errno = errsv;
return res;
}
#ifdef TEST_PROGRAM
int main(int argc, char *argv[])
{
double res;
char *end;
if (argc < 2) {
fprintf(stderr, "usage: %s decimal.number\n",
program_invocation_short_name);
return EXIT_FAILURE;
}
res = c_strtod(argv[1], &end);
printf("Result: %g, errno: %d, endptr: '%s'\n", res, errno, end);
return errno ? EXIT_FAILURE : EXIT_SUCCESS;
}
#endif

View File

@ -5,6 +5,7 @@ lib_common_sources = '''
color-names.c color-names.c
crc32.c crc32.c
crc32c.c crc32c.c
c_strtod.c
encode.c encode.c
env.c env.c
fileutils.c fileutils.c

View File

@ -150,6 +150,10 @@ struct blkid_idmag
const char *hoff; /* hint which contains byte offset to kboff */ const char *hoff; /* hint which contains byte offset to kboff */
long kboff; /* kilobyte offset of superblock */ long kboff; /* kilobyte offset of superblock */
unsigned int sboff; /* byte offset within superblock */ unsigned int sboff; /* byte offset within superblock */
int is_zoned; /* indicate magic location is calcluated based on zone position */
long zonenum; /* zone number which has superblock */
long kboff_inzone; /* kilobyte offset of superblock in a zone */
}; };
/* /*
@ -206,6 +210,7 @@ struct blkid_struct_probe
dev_t disk_devno; /* devno of the whole-disk or 0 */ dev_t disk_devno; /* devno of the whole-disk or 0 */
unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */ unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */
mode_t mode; /* struct stat.sb_mode */ mode_t mode; /* struct stat.sb_mode */
uint64_t zone_size; /* zone size (BLKGETZONESZ ioctl) */
int flags; /* private library flags */ int flags; /* private library flags */
int prob_flags; /* always zeroized by blkid_do_*() */ int prob_flags; /* always zeroized by blkid_do_*() */

View File

@ -94,6 +94,9 @@
#ifdef HAVE_LINUX_CDROM_H #ifdef HAVE_LINUX_CDROM_H
#include <linux/cdrom.h> #include <linux/cdrom.h>
#endif #endif
#ifdef HAVE_LINUX_BLKZONED_H
#include <linux/blkzoned.h>
#endif
#ifdef HAVE_SYS_STAT_H #ifdef HAVE_SYS_STAT_H
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
@ -177,6 +180,7 @@ blkid_probe blkid_clone_probe(blkid_probe parent)
pr->disk_devno = parent->disk_devno; pr->disk_devno = parent->disk_devno;
pr->blkssz = parent->blkssz; pr->blkssz = parent->blkssz;
pr->flags = parent->flags; pr->flags = parent->flags;
pr->zone_size = parent->zone_size;
pr->parent = parent; pr->parent = parent;
pr->flags &= ~BLKID_FL_PRIVATE_FD; pr->flags &= ~BLKID_FL_PRIVATE_FD;
@ -901,6 +905,7 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
pr->wipe_off = 0; pr->wipe_off = 0;
pr->wipe_size = 0; pr->wipe_size = 0;
pr->wipe_chain = NULL; pr->wipe_chain = NULL;
pr->zone_size = 0;
if (fd < 0) if (fd < 0)
return 1; return 1;
@ -1000,6 +1005,15 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
#endif #endif
free(dm_uuid); free(dm_uuid);
# ifdef HAVE_LINUX_BLKZONED_H
if (S_ISBLK(sb.st_mode)) {
uint32_t zone_size_sector;
if (!ioctl(pr->fd, BLKGETZONESZ, &zone_size_sector))
pr->zone_size = zone_size_sector << 9;
}
# endif
DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%"PRIu64", size=%"PRIu64"", DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%"PRIu64", size=%"PRIu64"",
pr->off, pr->size)); pr->off, pr->size));
DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s", DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s",
@ -1068,12 +1082,24 @@ int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
/* try to detect by magic string */ /* try to detect by magic string */
while(mag && mag->magic) { while(mag && mag->magic) {
unsigned char *buf; unsigned char *buf;
uint64_t kboff;
uint64_t hint_offset; uint64_t hint_offset;
if (!mag->hoff || blkid_probe_get_hint(pr, mag->hoff, &hint_offset) < 0) if (!mag->hoff || blkid_probe_get_hint(pr, mag->hoff, &hint_offset) < 0)
hint_offset = 0; hint_offset = 0;
off = hint_offset + ((mag->kboff + (mag->sboff >> 10)) << 10); /* If the magic is for zoned device, skip non-zoned device */
if (mag->is_zoned && !pr->zone_size) {
mag++;
continue;
}
if (!mag->is_zoned)
kboff = mag->kboff;
else
kboff = ((mag->zonenum * pr->zone_size) >> 10) + mag->kboff_inzone;
off = hint_offset + ((kboff + (mag->sboff >> 10)) << 10);
buf = blkid_probe_get_buffer(pr, off, 1024); buf = blkid_probe_get_buffer(pr, off, 1024);
if (!buf && errno) if (!buf && errno)
@ -1083,7 +1109,7 @@ int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
buf + (mag->sboff & 0x3ff), mag->len)) { buf + (mag->sboff & 0x3ff), mag->len)) {
DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld", DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld",
mag->sboff, mag->kboff)); mag->sboff, kboff));
if (offset) if (offset)
*offset = off + (mag->sboff & 0x3ff); *offset = off + (mag->sboff & 0x3ff);
if (res) if (res)
@ -1207,6 +1233,39 @@ int blkid_do_probe(blkid_probe pr)
return rc; return rc;
} }
#ifdef HAVE_LINUX_BLKZONED_H
static int is_conventional(blkid_probe pr, uint64_t offset)
{
struct blk_zone_report *rep = NULL;
int ret;
uint64_t zone_mask;
if (!pr->zone_size)
return 1;
zone_mask = ~(pr->zone_size - 1);
rep = blkdev_get_zonereport(blkid_probe_get_fd(pr),
(offset & zone_mask) >> 9, 1);
if (!rep)
return -1;
if (rep->zones[0].type == BLK_ZONE_TYPE_CONVENTIONAL)
ret = 1;
else
ret = 0;
free(rep);
return ret;
}
#else
static inline int is_conventional(blkid_probe pr __attribute__((__unused__)),
uint64_t offset __attribute__((__unused__)))
{
return 1;
}
#endif
/** /**
* blkid_do_wipe: * blkid_do_wipe:
* @pr: prober * @pr: prober
@ -1246,6 +1305,7 @@ int blkid_do_wipe(blkid_probe pr, int dryrun)
const char *off = NULL; const char *off = NULL;
size_t len = 0; size_t len = 0;
uint64_t offset, magoff; uint64_t offset, magoff;
int conventional;
char buf[BUFSIZ]; char buf[BUFSIZ];
int fd, rc = 0; int fd, rc = 0;
struct blkid_chain *chn; struct blkid_chain *chn;
@ -1281,6 +1341,11 @@ int blkid_do_wipe(blkid_probe pr, int dryrun)
if (len > sizeof(buf)) if (len > sizeof(buf))
len = sizeof(buf); len = sizeof(buf);
rc = is_conventional(pr, offset);
if (rc < 0)
return rc;
conventional = rc == 1;
DBG(LOWPROBE, ul_debug( DBG(LOWPROBE, ul_debug(
"do_wipe [offset=0x%"PRIx64" (%"PRIu64"), len=%zu, chain=%s, idx=%d, dryrun=%s]\n", "do_wipe [offset=0x%"PRIx64" (%"PRIu64"), len=%zu, chain=%s, idx=%d, dryrun=%s]\n",
offset, offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not")); offset, offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not"));
@ -1288,13 +1353,31 @@ int blkid_do_wipe(blkid_probe pr, int dryrun)
if (lseek(fd, offset, SEEK_SET) == (off_t) -1) if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
return -1; return -1;
if (!dryrun && len) {
if (conventional) {
memset(buf, 0, len); memset(buf, 0, len);
if (!dryrun && len) {
/* wipen on device */ /* wipen on device */
if (write_all(fd, buf, len)) if (write_all(fd, buf, len))
return -1; return -1;
fsync(fd); fsync(fd);
} else {
#ifdef HAVE_LINUX_BLKZONED_H
uint64_t zone_mask = ~(pr->zone_size - 1);
struct blk_zone_range range = {
.sector = (offset & zone_mask) >> 9,
.nr_sectors = pr->zone_size >> 9,
};
rc = ioctl(fd, BLKRESETZONE, &range);
if (rc < 0)
return -1;
#else
/* Should not reach here */
assert(0);
#endif
}
pr->flags &= ~BLKID_FL_MODIF_BUFF; /* be paranoid */ pr->flags &= ~BLKID_FL_MODIF_BUFF; /* be paranoid */
return blkid_probe_step_back(pr); return blkid_probe_step_back(pr);

View File

@ -9,6 +9,12 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#ifdef HAVE_LINUX_BLKZONED_H
#include <linux/blkzoned.h>
#endif
#include "superblocks.h" #include "superblocks.h"
@ -59,11 +65,157 @@ struct btrfs_super_block {
uint8_t label[256]; uint8_t label[256];
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
#define BTRFS_SUPER_INFO_SIZE 4096
/* Number of superblock log zones */
#define BTRFS_NR_SB_LOG_ZONES 2
/* Introduce some macros and types to unify the code with kernel side */
#define SECTOR_SHIFT 9
typedef uint64_t sector_t;
#ifdef HAVE_LINUX_BLKZONED_H
static int sb_write_pointer(blkid_probe pr, struct blk_zone *zones, uint64_t *wp_ret)
{
bool empty[BTRFS_NR_SB_LOG_ZONES];
bool full[BTRFS_NR_SB_LOG_ZONES];
sector_t sector;
assert(zones[0].type != BLK_ZONE_TYPE_CONVENTIONAL &&
zones[1].type != BLK_ZONE_TYPE_CONVENTIONAL);
empty[0] = zones[0].cond == BLK_ZONE_COND_EMPTY;
empty[1] = zones[1].cond == BLK_ZONE_COND_EMPTY;
full[0] = zones[0].cond == BLK_ZONE_COND_FULL;
full[1] = zones[1].cond == BLK_ZONE_COND_FULL;
/*
* Possible states of log buffer zones
*
* Empty[0] In use[0] Full[0]
* Empty[1] * x 0
* In use[1] 0 x 0
* Full[1] 1 1 C
*
* Log position:
* *: Special case, no superblock is written
* 0: Use write pointer of zones[0]
* 1: Use write pointer of zones[1]
* C: Compare super blcoks from zones[0] and zones[1], use the latest
* one determined by generation
* x: Invalid state
*/
if (empty[0] && empty[1]) {
/* Special case to distinguish no superblock to read */
*wp_ret = zones[0].start << SECTOR_SHIFT;
return -ENOENT;
} else if (full[0] && full[1]) {
/* Compare two super blocks */
struct btrfs_super_block *super[BTRFS_NR_SB_LOG_ZONES];
int i;
for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) {
uint64_t bytenr;
bytenr = ((zones[i].start + zones[i].len)
<< SECTOR_SHIFT) - BTRFS_SUPER_INFO_SIZE;
super[i] = (struct btrfs_super_block *)
blkid_probe_get_buffer(pr, bytenr, BTRFS_SUPER_INFO_SIZE);
if (!super[i])
return -EIO;
}
if (super[0]->generation > super[1]->generation)
sector = zones[1].start;
else
sector = zones[0].start;
} else if (!full[0] && (empty[1] || full[1])) {
sector = zones[0].wp;
} else if (full[0]) {
sector = zones[1].wp;
} else {
return -EUCLEAN;
}
*wp_ret = sector << SECTOR_SHIFT;
return 0;
}
static int sb_log_offset(blkid_probe pr, uint64_t *bytenr_ret)
{
uint32_t zone_num = 0;
uint32_t zone_size_sector;
struct blk_zone_report *rep;
struct blk_zone *zones;
int ret;
int i;
uint64_t wp;
zone_size_sector = pr->zone_size >> SECTOR_SHIFT;
rep = blkdev_get_zonereport(pr->fd, zone_num * zone_size_sector, 2);
if (!rep) {
ret = -errno;
goto out;
}
zones = (struct blk_zone *)(rep + 1);
/*
* Use the head of the first conventional zone, if the zones
* contain one.
*/
for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) {
if (zones[i].type == BLK_ZONE_TYPE_CONVENTIONAL) {
*bytenr_ret = zones[i].start << SECTOR_SHIFT;
ret = 0;
goto out;
}
}
ret = sb_write_pointer(pr, zones, &wp);
if (ret != -ENOENT && ret) {
ret = 1;
goto out;
}
if (ret != -ENOENT) {
if (wp == zones[0].start << SECTOR_SHIFT)
wp = (zones[1].start + zones[1].len) << SECTOR_SHIFT;
wp -= BTRFS_SUPER_INFO_SIZE;
}
*bytenr_ret = wp;
ret = 0;
out:
free(rep);
return ret;
}
#endif
static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag) static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag)
{ {
struct btrfs_super_block *bfs; struct btrfs_super_block *bfs;
if (pr->zone_size) {
#ifdef HAVE_LINUX_BLKZONED_H
uint64_t offset = 0;
int ret;
ret = sb_log_offset(pr, &offset);
if (ret)
return ret;
bfs = (struct btrfs_super_block *)
blkid_probe_get_buffer(pr, offset,
sizeof(struct btrfs_super_block));
#else
/* Nothing can be done */
return 1;
#endif
} else {
bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
}
if (!bfs) if (!bfs)
return errno ? -errno : 1; return errno ? -errno : 1;
@ -88,6 +240,11 @@ const struct blkid_idinfo btrfs_idinfo =
.magics = .magics =
{ {
{ .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 }, { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 },
/* For zoned btrfs */
{ .magic = "_BHRfS_M", .len = 8, .sboff = 0x40,
.is_zoned = 1, .zonenum = 0, .kboff_inzone = 0 },
{ .magic = "_BHRfS_M", .len = 8, .sboff = 0x40,
.is_zoned = 1, .zonenum = 1, .kboff_inzone = 0 },
{ NULL } { NULL }
} }
}; };

View File

@ -40,6 +40,7 @@ struct console {
int fd, id; int fd, id;
#define CON_SERIAL 0x0001 #define CON_SERIAL 0x0001
#define CON_NOTTY 0x0002 #define CON_NOTTY 0x0002
#define CON_EIO 0x0004
pid_t pid; pid_t pid;
struct chardata cp; struct chardata cp;
struct termios tio; struct termios tio;

View File

@ -52,6 +52,7 @@
#ifdef __linux__ #ifdef __linux__
# include <sys/kd.h> # include <sys/kd.h>
# include <sys/param.h> # include <sys/param.h>
# include <linux/serial.h>
#endif #endif
#include "c.h" #include "c.h"
@ -104,6 +105,9 @@ static void tcinit(struct console *con)
int flags = 0, mode = 0; int flags = 0, mode = 0;
struct termios *tio = &con->tio; struct termios *tio = &con->tio;
const int fd = con->fd; const int fd = con->fd;
#if defined(TIOCGSERIAL)
struct serial_struct serinfo;
#endif
#ifdef USE_PLYMOUTH_SUPPORT #ifdef USE_PLYMOUTH_SUPPORT
struct termios lock; struct termios lock;
int i = (plymouth_command(MAGIC_PING)) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0; int i = (plymouth_command(MAGIC_PING)) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
@ -123,27 +127,72 @@ static void tcinit(struct console *con)
} }
memset(&lock, 0, sizeof(struct termios)); memset(&lock, 0, sizeof(struct termios));
ioctl(fd, TIOCSLCKTRMIOS, &lock); ioctl(fd, TIOCSLCKTRMIOS, &lock);
#endif
errno = 0; errno = 0;
#endif
#if defined(TIOCGSERIAL)
if (ioctl(fd, TIOCGSERIAL, &serinfo) >= 0)
con->flags |= CON_SERIAL;
errno = 0;
#else
# if defined(KDGKBMODE)
if (ioctl(fd, KDGKBMODE, &mode) < 0)
con->flags |= CON_SERIAL;
errno = 0;
# endif
#endif
if (tcgetattr(fd, tio) < 0) { if (tcgetattr(fd, tio) < 0) {
int saveno = errno;
#if defined(KDGKBMODE) || defined(TIOCGSERIAL)
if (con->flags & CON_SERIAL) { /* Try to recover this */
# if defined(TIOCGSERIAL)
serinfo.flags |= ASYNC_SKIP_TEST; /* Skip test of UART */
if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
goto tcgeterr;
if (ioctl(fd, TIOCSERCONFIG) < 0) /* Try to autoconfigure */
goto tcgeterr;
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
goto tcgeterr; /* Ouch */
# endif
if (tcgetattr(fd, tio) < 0) /* Retry to get tty attributes */
saveno = errno;
}
# if defined(TIOCGSERIAL)
tcgeterr:
# endif
if (saveno)
#endif
{
FILE *fcerr = fdopen(fd, "w");
if (fcerr) {
fprintf(fcerr, _("tcgetattr failed"));
fclose(fcerr);
}
warn(_("tcgetattr failed")); warn(_("tcgetattr failed"));
con->flags &= ~CON_SERIAL;
if (saveno != EIO)
con->flags |= CON_NOTTY; con->flags |= CON_NOTTY;
else
con->flags |= CON_EIO;
errno = 0;
return; return;
} }
}
/* Handle lines other than virtual consoles here */ /* Handle lines other than virtual consoles here */
#if defined(KDGKBMODE) #if defined(KDGKBMODE) || defined(TIOCGSERIAL)
if (ioctl(fd, KDGKBMODE, &mode) < 0) if (con->flags & CON_SERIAL)
#endif #endif
{ {
speed_t ispeed, ospeed; speed_t ispeed, ospeed;
struct winsize ws; struct winsize ws;
errno = 0; errno = 0;
/* this is a modem line */
con->flags |= CON_SERIAL;
/* Flush input and output queues on modem lines */ /* Flush input and output queues on modem lines */
tcflush(fd, TCIOFLUSH); tcflush(fd, TCIOFLUSH);
@ -220,6 +269,8 @@ static void tcfinal(struct console *con)
struct termios *tio = &con->tio; struct termios *tio = &con->tio;
const int fd = con->fd; const int fd = con->fd;
if (con->flags & CON_EIO)
return;
if ((con->flags & CON_SERIAL) == 0) { if ((con->flags & CON_SERIAL) == 0) {
xsetenv("TERM", "linux", 1); xsetenv("TERM", "linux", 1);
return; return;
@ -557,12 +608,16 @@ err:
static void setup(struct console *con) static void setup(struct console *con)
{ {
int fd = con->fd; int fd = con->fd;
const pid_t pid = getpid(), pgrp = getpgid(0), ppgrp = const pid_t pid = getpid(), pgrp = getpgid(0), ppgrp = getpgid(getppid());
getpgid(getppid()), ttypgrp = tcgetpgrp(fd); pid_t ttypgrp;
if (con->flags & CON_NOTTY) if (con->flags & CON_NOTTY)
goto notty;
if (con->flags & CON_EIO)
return; return;
ttypgrp = tcgetpgrp(fd);
/* /*
* Only go through this trouble if the new * Only go through this trouble if the new
* tty doesn't fall in this process group. * tty doesn't fall in this process group.
@ -585,6 +640,7 @@ static void setup(struct console *con)
ioctl(fd, TIOCSCTTY, (char *)1); ioctl(fd, TIOCSCTTY, (char *)1);
tcsetpgrp(fd, ppgrp); tcsetpgrp(fd, ppgrp);
} }
notty:
dup2(fd, STDIN_FILENO); dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO); dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO); dup2(fd, STDERR_FILENO);
@ -608,19 +664,24 @@ static const char *getpasswd(struct console *con)
struct termios tty; struct termios tty;
static char pass[128], *ptr; static char pass[128], *ptr;
struct chardata *cp; struct chardata *cp;
const char *ret = pass; const char *ret = NULL;
unsigned char tc; unsigned char tc;
char c, ascval; char c, ascval;
int eightbit; int eightbit;
const int fd = con->fd; const int fd = con->fd;
if (con->flags & CON_NOTTY) if (con->flags & CON_EIO)
goto out; goto out;
cp = &con->cp; cp = &con->cp;
tty = con->tio; tty = con->tio;
tc = 0;
ret = pass;
tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG); tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG);
if ((con->flags & CON_NOTTY) == 0)
tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0); tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0);
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -647,11 +708,12 @@ static const char *getpasswd(struct console *con)
} }
ret = NULL; ret = NULL;
switch (errno) { switch (errno) {
case 0:
case EIO: case EIO:
con->flags |= CON_EIO;
case ESRCH: case ESRCH:
case EINVAL: case EINVAL:
case ENOENT: case ENOENT:
case 0:
break; break;
default: default:
warn(_("cannot read %s"), con->tty); warn(_("cannot read %s"), con->tty);
@ -969,10 +1031,13 @@ int main(int argc, char **argv)
con = list_entry(ptr, struct console, entry); con = list_entry(ptr, struct console, entry);
if (con->id >= CONMAX) if (con->id >= CONMAX)
break; break;
if (con->flags & CON_EIO)
goto next;
switch ((con->pid = fork())) { switch ((con->pid = fork())) {
case 0: case 0:
mask_signal(SIGCHLD, SIG_DFL, NULL); mask_signal(SIGCHLD, SIG_DFL, NULL);
dup2(con->fd, STDERR_FILENO);
nofork: nofork:
setup(con); setup(con);
while (1) { while (1) {
@ -1027,7 +1092,7 @@ int main(int argc, char **argv)
default: default:
break; break;
} }
next:
ptr = ptr->next; ptr = ptr->next;
} while (ptr != &consoles); } while (ptr != &consoles);

View File

@ -156,8 +156,10 @@ headers = '''
linux/compiler.h linux/compiler.h
linux/falloc.h linux/falloc.h
linux/fd.h linux/fd.h
linux/fs.h linux/fiemap.h
linux/gsmmux.h
linux/net_namespace.h linux/net_namespace.h
linux/nsfs.h
linux/raw.h linux/raw.h
linux/securebits.h linux/securebits.h
linux/tiocl.h linux/tiocl.h
@ -195,6 +197,7 @@ headers = '''
sys/types.h sys/types.h
sys/ucred.h sys/ucred.h
sys/un.h sys/un.h
sys/xattr.h
'''.split() '''.split()
lib_m = cc.find_library('m') lib_m = cc.find_library('m')
@ -460,6 +463,7 @@ funcs = '''
jrand48 jrand48
lchown lchown
llseek llseek
newlocale
mempcpy mempcpy
mkostemp mkostemp
nanosleep nanosleep
@ -484,6 +488,7 @@ funcs = '''
strnchr strnchr
strndup strndup
strnlen strnlen
strtod_l
sysconf sysconf
sysinfo sysinfo
swapon swapon
@ -491,6 +496,7 @@ funcs = '''
timegm timegm
unshare unshare
usleep usleep
uselocale
utimensat utimensat
vwarnx vwarnx
warn warn

View File

@ -5,6 +5,7 @@
#include "lscpu.h" #include "lscpu.h"
#include "fileutils.h" #include "fileutils.h"
#include "c_strtod.h"
/* Lookup a pattern and get the value for format "<pattern> : <key>" /* Lookup a pattern and get the value for format "<pattern> : <key>"
*/ */
@ -510,6 +511,12 @@ int lscpu_read_cpuinfo(struct lscpu_cxt *cxt)
pr->curr_type->static_mhz = xstrdup(value); pr->curr_type->static_mhz = xstrdup(value);
if (pattern->id == PAT_BOGOMIPS_CPU && pr->curr_type && !pr->curr_type->bogomips) if (pattern->id == PAT_BOGOMIPS_CPU && pr->curr_type && !pr->curr_type->bogomips)
pr->curr_type->bogomips = xstrdup(value); pr->curr_type->bogomips = xstrdup(value);
if (pattern->id == PAT_MHZ && pr->curr_cpu && value) {
errno = 0;
pr->curr_cpu->mhz_cur_freq = (float) c_strtod(value, NULL);
if (errno)
pr->curr_cpu->mhz_cur_freq = 0;
}
break; break;
case CPUINFO_LINE_CPUTYPE: case CPUINFO_LINE_CPUTYPE:
if (pr->curr_type && is_different_cputype(pr->curr_type, pattern->offset, value)) { if (pr->curr_type && is_different_cputype(pr->curr_type, pattern->offset, value)) {

View File

@ -546,6 +546,16 @@ static int read_mhz(struct lscpu_cxt *cxt, struct lscpu_cpu *cpu)
if (ul_path_readf_s32(sys, &mhz, "cpu%d/cpufreq/cpuinfo_min_freq", num) == 0) if (ul_path_readf_s32(sys, &mhz, "cpu%d/cpufreq/cpuinfo_min_freq", num) == 0)
cpu->mhz_min_freq = (float) mhz / 1000; cpu->mhz_min_freq = (float) mhz / 1000;
/* The default current-frequency value comes is from /proc/cpuinfo (if
* available). This /proc value is usually based on MSR registers
* (APERF/APERF) and it changes pretty often. It seems better to read
* frequency from cpufreq subsystem that provides the current frequency
* for the current policy. There is also cpuinfo_cur_freq in sysfs, but
* it's not always available.
*/
if (ul_path_readf_s32(sys, &mhz, "cpu%d/cpufreq/scaling_cur_freq", num) == 0)
cpu->mhz_cur_freq = (float) mhz / 1000;
if (cpu->type && (cpu->mhz_min_freq || cpu->mhz_max_freq)) if (cpu->type && (cpu->mhz_min_freq || cpu->mhz_max_freq))
cpu->type->has_freq = 1; cpu->type->has_freq = 1;
@ -583,6 +593,27 @@ float lsblk_cputype_get_minmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct)
return res; return res;
} }
/* returns scaling (use) of CPUs freq. in percent */
float lsblk_cputype_get_scalmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct)
{
size_t i;
float fmax = 0, fcur = 0;
for (i = 0; i < cxt->npossibles; i++) {
struct lscpu_cpu *cpu = cxt->cpus[i];
if (!cpu || cpu->type != ct || !is_cpu_present(cxt, cpu))
continue;
if (cpu->mhz_max_freq <= 0.0 || cpu->mhz_cur_freq <= 0.0)
continue;
fmax += cpu->mhz_max_freq;
fcur += cpu->mhz_cur_freq;
}
if (fcur <= 0.0)
return 0.0;
return fcur / fmax * 100;
}
int lscpu_read_topology(struct lscpu_cxt *cxt) int lscpu_read_topology(struct lscpu_cxt *cxt)
{ {
size_t i; size_t i;

View File

@ -105,6 +105,7 @@ enum {
COL_CPU_CONFIGURED, COL_CPU_CONFIGURED,
COL_CPU_ONLINE, COL_CPU_ONLINE,
COL_CPU_MHZ, COL_CPU_MHZ,
COL_CPU_SCALMHZ,
COL_CPU_MAXMHZ, COL_CPU_MAXMHZ,
COL_CPU_MINMHZ, COL_CPU_MINMHZ,
}; };
@ -150,6 +151,7 @@ static struct lscpu_coldesc coldescs_cpu[] =
[COL_CPU_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") }, [COL_CPU_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") },
[COL_CPU_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT }, [COL_CPU_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT },
[COL_CPU_MHZ] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT }, [COL_CPU_MHZ] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT },
[COL_CPU_SCALMHZ] = { "SCALMHZ%", N_("shows scaling percentage of the CPU frequency"), SCOLS_FL_RIGHT },
[COL_CPU_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT }, [COL_CPU_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT },
[COL_CPU_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT } [COL_CPU_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT }
}; };
@ -422,8 +424,12 @@ static char *get_cell_data(
is_cpu_online(cxt, cpu) ? _("yes") : _("no")); is_cpu_online(cxt, cpu) ? _("yes") : _("no"));
break; break;
case COL_CPU_MHZ: case COL_CPU_MHZ:
if (cpu->mhz) if (cpu->mhz_cur_freq)
xstrncpy(buf, cpu->mhz, bufsz); snprintf(buf, bufsz, "%.4f", cpu->mhz_cur_freq);
break;
case COL_CPU_SCALMHZ:
if (cpu->mhz_cur_freq && cpu->mhz_max_freq)
snprintf(buf, bufsz, "%.0f%%", cpu->mhz_cur_freq / cpu->mhz_max_freq * 100);
break; break;
case COL_CPU_MAXMHZ: case COL_CPU_MAXMHZ:
if (cpu->mhz_max_freq) if (cpu->mhz_max_freq)
@ -890,6 +896,9 @@ print_summary_cputype(struct lscpu_cxt *cxt,
add_summary_s(tb, sec, _("CPU static MHz:"), ct->static_mhz); add_summary_s(tb, sec, _("CPU static MHz:"), ct->static_mhz);
if (ct->has_freq) { if (ct->has_freq) {
float scal = lsblk_cputype_get_scalmhz(cxt, ct);
if (scal > 0.0)
add_summary_x(tb, sec, _("CPU(s) scaling MHz:"), "%.0f%%", scal);
add_summary_x(tb, sec, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt, ct)); add_summary_x(tb, sec, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt, ct));
add_summary_x(tb, sec, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt, ct)); add_summary_x(tb, sec, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt, ct));
} }

View File

@ -127,11 +127,12 @@ struct lscpu_cpu {
int logical_id; int logical_id;
char *bogomips; /* per-CPU bogomips */ char *bogomips; /* per-CPU bogomips */
char *mhz; /* max freq from cpuinfo */ char *mhz; /* freq from cpuinfo */
char *dynamic_mhz; /* from cpuinf for s390 */ char *dynamic_mhz; /* from cpuinf for s390 */
char *static_mhz; /* from cpuinf for s390 */ char *static_mhz; /* from cpuinf for s390 */
float mhz_max_freq; /* realtime freq from /sys/.../cpuinfo_max_freq */ float mhz_max_freq; /* realtime freq from /sys/.../cpuinfo_max_freq */
float mhz_min_freq; /* realtime freq from /sys/.../cpuinfo_min_freq */ float mhz_min_freq; /* realtime freq from /sys/.../cpuinfo_min_freq */
float mhz_cur_freq;
int coreid; int coreid;
int socketid; int socketid;
@ -280,6 +281,7 @@ void lscpu_cputype_free_topology(struct lscpu_cputype *ct);
float lsblk_cputype_get_maxmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct); float lsblk_cputype_get_maxmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct);
float lsblk_cputype_get_minmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct); float lsblk_cputype_get_minmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct);
float lsblk_cputype_get_scalmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct);
struct lscpu_arch *lscpu_read_architecture(struct lscpu_cxt *cxt); struct lscpu_arch *lscpu_read_architecture(struct lscpu_cxt *cxt);
void lscpu_free_architecture(struct lscpu_arch *ar); void lscpu_free_architecture(struct lscpu_arch *ar);

View File

@ -23,7 +23,7 @@ lsns - list namespaces
*lsns* lists information about all the currently accessible namespaces or about the given _namespace_. The _namespace_ identifier is an inode number. *lsns* lists information about all the currently accessible namespaces or about the given _namespace_. The _namespace_ identifier is an inode number.
The default output is subject to change. So whenever possible, you should avoid using default outputs in your scripts. Always explicitly define expected columns by using the *--output* option together with a columns list in environments where a stable output is required. The default output is subject to change. So whenever possible, you should avoid using default outputs in your scripts. Always explicitly define expected output mode (*--tree* or *--list*) and columns by using the *--output* option together with a columns list in environments where a stable output is required.
The *NSFS* column, printed when *net* is specified for the *--type* option, is special; it uses multi-line cells. Use the option *--nowrap* to switch to ","-separated single-line representation. The *NSFS* column, printed when *net* is specified for the *--type* option, is special; it uses multi-line cells. Use the option *--nowrap* to switch to ","-separated single-line representation.
@ -63,6 +63,14 @@ Do not truncate text in columns.
*-W*, *--nowrap*:: *-W*, *--nowrap*::
Do not use multi-line text in columns. Do not use multi-line text in columns.
*-T*, *--tree* _rel_::
Use tree-like output format.
If *process* is given as _rel_, print proecss tree(s) in each name space. This is default when *--tree* is not specified.
If *parent* is given, print tree(s) constructed by the parent/child relationship.
If *owner* is given, print tree(s) constructed by the owner/owned relationship.
*owner* is used as default when _rel_ is omitted.
*-V*, *--version*:: *-V*, *--version*::
Display version information and exit. Display version information and exit.

View File

@ -142,16 +142,25 @@ static char *ns_names[] = {
[LSNS_ID_TIME] = "time" [LSNS_ID_TIME] = "time"
}; };
enum {
RELA_PARENT,
RELA_OWNER,
MAX_RELA
};
struct lsns_namespace { struct lsns_namespace {
ino_t id; ino_t id;
int type; /* LSNS_* */ int type; /* LSNS_* */
int nprocs; int nprocs;
int netnsid; int netnsid;
ino_t parentid; ino_t related_id[MAX_RELA];
ino_t ownerid;
struct lsns_process *proc; struct lsns_process *proc;
struct lsns_namespace *related_ns[MAX_RELA];
struct libscols_line *ns_outline;
uid_t uid_fallback; /* refer this member if `proc' is NULL. */
struct list_head namespaces; /* lsns->processes member */ struct list_head namespaces; /* lsns->processes member */
struct list_head processes; /* head of lsns_process *siblings */ struct list_head processes; /* head of lsns_process *siblings */
}; };
@ -177,6 +186,14 @@ struct lsns_process {
int netnsid; int netnsid;
}; };
enum {
LSNS_TREE_NONE,
LSNS_TREE_PROCESS,
LSNS_TREE_OWNER,
LSNS_TREE_PARENT,
};
struct lsns { struct lsns {
struct list_head processes; struct list_head processes;
struct list_head namespaces; struct list_head namespaces;
@ -188,12 +205,12 @@ struct lsns {
unsigned int raw : 1, unsigned int raw : 1,
json : 1, json : 1,
tree : 1, tree : 2,
list : 1,
no_trunc : 1, no_trunc : 1,
no_headings: 1, no_headings: 1,
no_wrap : 1; no_wrap : 1;
struct libmnt_table *tab; struct libmnt_table *tab;
}; };
@ -608,8 +625,8 @@ static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino
ns->type = type; ns->type = type;
ns->id = ino; ns->id = ino;
ns->parentid = parent_ino; ns->related_id[RELA_PARENT] = parent_ino;
ns->ownerid = owner_ino; ns->related_id[RELA_OWNER] = owner_ino;
list_add_tail(&ns->namespaces, &ls->namespaces); list_add_tail(&ns->namespaces, &ls->namespaces);
return ns; return ns;
@ -660,9 +677,126 @@ static int netnsid_xasputs(char **str, int netnsid)
return 0; return 0;
} }
static int clone_type_to_lsns_type(int clone_type)
{
switch (clone_type) {
case CLONE_NEWNS:
return LSNS_ID_MNT;
case CLONE_NEWCGROUP:
return LSNS_ID_CGROUP;
case CLONE_NEWUTS:
return LSNS_ID_UTS;
case CLONE_NEWIPC:
return LSNS_ID_IPC;
case CLONE_NEWUSER:
return LSNS_ID_USER;
case CLONE_NEWPID:
return LSNS_ID_PID;
case CLONE_NEWNET:
return LSNS_ID_NET;
default:
return -1;
}
}
static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, ino_t ino)
{
int fd_owner = -1, fd_parent = -1;
struct stat st_owner, st_parent;
ino_t ino_owner = 0, ino_parent = 0;
struct lsns_namespace *ns;
int clone_type, lsns_type;
clone_type = ioctl(fd, NS_GET_NSTYPE);
if (clone_type < 0)
return NULL;
lsns_type = clone_type_to_lsns_type(clone_type);
if (lsns_type < 0)
return NULL;
fd_owner = ioctl(fd, NS_GET_USERNS);
if (fd_owner < 0)
goto parent;
if (fstat(fd_owner, &st_owner) < 0)
goto parent;
ino_owner = st_owner.st_ino;
parent:
fd_parent = ioctl(fd, NS_GET_PARENT);
if (fd_parent < 0)
goto add_ns;
if (fstat(fd_parent, &st_parent) < 0)
goto add_ns;
ino_parent = st_parent.st_ino;
add_ns:
ns = add_namespace(ls, lsns_type, ino, ino_parent, ino_owner);
ioctl(fd, NS_GET_OWNER_UID, &ns->uid_fallback);
add_uid(uid_cache, ns->uid_fallback);
if ((lsns_type == LSNS_ID_USER || lsns_type == LSNS_ID_PID)
&& ino_parent != ino && ino_parent != 0) {
ns->related_ns[RELA_PARENT] = get_namespace(ls, ino_parent);
if (!ns->related_ns[RELA_PARENT]) {
ns->related_ns[RELA_PARENT] = add_namespace_for_nsfd(ls, fd_parent, ino_parent);
if (ino_parent == ino_owner)
ns->related_ns[RELA_OWNER] = ns->related_ns[RELA_PARENT];
}
}
if (ns->related_ns[RELA_OWNER] == NULL && ino_owner != 0) {
ns->related_ns[RELA_OWNER] = get_namespace(ls, ino_owner);
if (!ns->related_ns[RELA_OWNER])
ns->related_ns[RELA_OWNER] = add_namespace_for_nsfd(ls, fd_owner, ino_owner);
}
if (fd_owner >= 0)
close(fd_owner);
if (fd_parent >= 0)
close(fd_parent);
return ns;
}
static void interpolate_missing_namespaces(struct lsns *ls, struct lsns_namespace *orphan, int rela)
{
const int cmd[MAX_RELA] = {
[RELA_PARENT] = NS_GET_PARENT,
[RELA_OWNER] = NS_GET_USERNS
};
char buf[BUFSIZ];
int fd_orphan, fd_missing;
struct stat st;
orphan->related_ns[rela] = get_namespace(ls, orphan->related_id[rela]);
if (orphan->related_ns[rela])
return;
snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", orphan->proc->pid, ns_names[orphan->type]);
fd_orphan = open(buf, O_RDONLY);
if (fd_orphan < 0)
return;
fd_missing = ioctl(fd_orphan, cmd[rela]);
close(fd_orphan);
if (fd_missing < 0)
return;
if (fstat(fd_missing, &st) < 0
|| st.st_ino != orphan->related_id[rela]) {
close(fd_missing);
return;
}
orphan->related_ns[rela] = add_namespace_for_nsfd(ls, fd_missing, orphan->related_id[rela]);
close(fd_missing);
}
static int read_namespaces(struct lsns *ls) static int read_namespaces(struct lsns *ls)
{ {
struct list_head *p; struct list_head *p;
struct lsns_namespace *orphan[2] = {NULL, NULL};
int rela;
DBG(NS, ul_debug("reading namespace")); DBG(NS, ul_debug("reading namespace"));
@ -684,6 +818,56 @@ static int read_namespaces(struct lsns *ls)
} }
} }
if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT) {
list_for_each(p, &ls->namespaces) {
struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces);
struct list_head *pp;
list_for_each(pp, &ls->namespaces) {
struct lsns_namespace *pns = list_entry(pp, struct lsns_namespace, namespaces);
if (ns->type == LSNS_ID_USER
|| ns->type == LSNS_ID_PID) {
if (ns->related_id[RELA_PARENT] == pns->id)
ns->related_ns[RELA_PARENT] = pns;
if (ns->related_id[RELA_OWNER] == pns->id)
ns->related_ns[RELA_OWNER] = pns;
if (ns->related_ns[RELA_PARENT] && ns->related_ns[RELA_OWNER])
break;
} else {
if (ns->related_id[RELA_OWNER] == pns->id) {
ns->related_ns[RELA_OWNER] = pns;
break;
}
}
}
/* lsns scans /proc/[0-9]+ for finding namespaces.
* So if a namespace has no process, lsns cannot
* find it. Here we call it a missing namespace.
*
* If the id for a related namesspce is known but
* namespace for the id is not found, there must
* be orphan namespaces. A missing namespace is an
* owner or a parent of the orphan namespace.
*/
for (rela = 0; rela < MAX_RELA; rela++) {
if (ns->related_id[rela] != 0
&& ns->related_ns[rela] == NULL) {
ns->related_ns[rela] = orphan[rela];
orphan[rela] = ns;
}
}
}
}
for (rela = 0; rela < MAX_RELA; rela++) {
while (orphan[rela]) {
struct lsns_namespace *current = orphan[rela];
orphan[rela] = orphan[rela]->related_ns[rela];
current->related_ns[rela] = NULL;
interpolate_missing_namespaces(ls, current, rela);
}
}
list_sort(&ls->namespaces, cmp_namespaces, NULL); list_sort(&ls->namespaces, cmp_namespaces, NULL);
return 0; return 0;
@ -774,7 +958,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
assert(table); assert(table);
line = scols_table_new_line(table, line = scols_table_new_line(table,
ls->tree && proc->parent ? proc->parent->outline : NULL); (ls->tree == LSNS_TREE_PROCESS && proc) && proc->parent ? proc->parent->outline:
(ls->tree == LSNS_TREE_PARENT) && ns->related_ns[RELA_PARENT] ? ns->related_ns[RELA_PARENT]->ns_outline:
(ls->tree == LSNS_TREE_OWNER) && ns->related_ns[RELA_OWNER] ? ns->related_ns[RELA_OWNER]->ns_outline:
NULL);
if (!line) { if (!line) {
warn(_("failed to add line to output")); warn(_("failed to add line to output"));
return; return;
@ -788,9 +975,11 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
xasprintf(&str, "%ju", (uintmax_t)ns->id); xasprintf(&str, "%ju", (uintmax_t)ns->id);
break; break;
case COL_PID: case COL_PID:
if (proc)
xasprintf(&str, "%d", (int) proc->pid); xasprintf(&str, "%d", (int) proc->pid);
break; break;
case COL_PPID: case COL_PPID:
if (proc)
xasprintf(&str, "%d", (int) proc->ppid); xasprintf(&str, "%d", (int) proc->ppid);
break; break;
case COL_TYPE: case COL_TYPE:
@ -800,20 +989,26 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
xasprintf(&str, "%d", ns->nprocs); xasprintf(&str, "%d", ns->nprocs);
break; break;
case COL_COMMAND: case COL_COMMAND:
if (!proc)
break;
str = proc_get_command(proc->pid); str = proc_get_command(proc->pid);
if (!str) if (!str)
str = proc_get_command_name(proc->pid); str = proc_get_command_name(proc->pid);
break; break;
case COL_PATH: case COL_PATH:
if (!proc)
break;
xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]); xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]);
break; break;
case COL_UID: case COL_UID:
xasprintf(&str, "%d", (int) proc->uid); xasprintf(&str, "%d", proc? (int) proc->uid: (int) ns->uid_fallback);
break; break;
case COL_USER: case COL_USER:
xasprintf(&str, "%s", get_id(uid_cache, proc->uid)->name); xasprintf(&str, "%s", get_id(uid_cache, proc? proc->uid: ns->uid_fallback)->name);
break; break;
case COL_NETNSID: case COL_NETNSID:
if (!proc)
break;
if (ns->type == LSNS_ID_NET) if (ns->type == LSNS_ID_NET)
netnsid_xasputs(&str, proc->netnsid); netnsid_xasputs(&str, proc->netnsid);
break; break;
@ -821,10 +1016,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
nsfs_xasputs(&str, ns, ls->tab, ls->no_wrap ? ',' : '\n'); nsfs_xasputs(&str, ns, ls->tab, ls->no_wrap ? ',' : '\n');
break; break;
case COL_PNS: case COL_PNS:
xasprintf(&str, "%ju", (uintmax_t)ns->parentid); xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_PARENT]);
break; break;
case COL_ONS: case COL_ONS:
xasprintf(&str, "%ju", (uintmax_t)ns->ownerid); xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_OWNER]);
break; break;
default: default:
break; break;
@ -834,6 +1029,9 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
err_oom(); err_oom();
} }
if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
ns->ns_outline = line;
else if (proc)
proc->outline = line; proc->outline = line;
} }
@ -862,10 +1060,15 @@ static struct libscols_table *init_scols_table(struct lsns *ls)
if (ls->no_trunc) if (ls->no_trunc)
flags &= ~SCOLS_FL_TRUNC; flags &= ~SCOLS_FL_TRUNC;
if (ls->tree && get_column_id(i) == COL_COMMAND) if (ls->tree == LSNS_TREE_PROCESS && get_column_id(i) == COL_COMMAND)
flags |= SCOLS_FL_TREE; flags |= SCOLS_FL_TREE;
if (ls->no_wrap) if (ls->no_wrap)
flags &= ~SCOLS_FL_WRAP; flags &= ~SCOLS_FL_WRAP;
if ((ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
&& get_column_id(i) == COL_NS) {
flags |= SCOLS_FL_TREE;
flags &= ~SCOLS_FL_RIGHT;
}
cl = scols_table_new_column(tab, col->name, col->whint, flags); cl = scols_table_new_column(tab, col->name, col->whint, flags);
if (cl == NULL) { if (cl == NULL) {
@ -890,6 +1093,28 @@ err:
return NULL; return NULL;
} }
static void show_namespace(struct lsns *ls, struct libscols_table *tab,
struct lsns_namespace *ns, struct lsns_process *proc)
{
/*
* create a tree from owner->owned and/or parent->child relation
*/
if (ls->tree == LSNS_TREE_OWNER
&& ns->related_ns[RELA_OWNER]
&& !ns->related_ns[RELA_OWNER]->ns_outline)
show_namespace(ls, tab, ns->related_ns[RELA_OWNER], ns->related_ns[RELA_OWNER]->proc);
else if (ls->tree == LSNS_TREE_PARENT) {
if (ns->related_ns[RELA_PARENT]) {
if (!ns->related_ns[RELA_PARENT]->ns_outline)
show_namespace(ls, tab, ns->related_ns[RELA_PARENT], ns->related_ns[RELA_PARENT]->proc);
}
else if (ns->related_ns[RELA_OWNER] && !ns->related_ns[RELA_OWNER]->ns_outline)
show_namespace(ls, tab, ns->related_ns[RELA_OWNER], ns->related_ns[RELA_OWNER]->proc);
}
add_scols_line(ls, tab, ns, proc);
}
static int show_namespaces(struct lsns *ls) static int show_namespaces(struct lsns *ls)
{ {
struct libscols_table *tab; struct libscols_table *tab;
@ -906,7 +1131,8 @@ static int show_namespaces(struct lsns *ls)
if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid)) if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid))
continue; continue;
add_scols_line(ls, tab, ns, ns->proc); if (!ns->ns_outline)
show_namespace(ls, tab, ns, ns->proc);
} }
scols_print_table(tab); scols_print_table(tab);
@ -921,7 +1147,7 @@ static void show_process(struct lsns *ls, struct libscols_table *tab,
* create a tree from parent->child relation, but only if the parent is * create a tree from parent->child relation, but only if the parent is
* within the same namespace * within the same namespace
*/ */
if (ls->tree if (ls->tree == LSNS_TREE_PROCESS
&& proc->parent && proc->parent
&& !proc->parent->outline && !proc->parent->outline
&& proc->parent->ns_ids[ns->type] == proc->ns_ids[ns->type]) && proc->parent->ns_ids[ns->type] == proc->ns_ids[ns->type])
@ -977,6 +1203,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -u, --notruncate don't truncate text in columns\n"), out); fputs(_(" -u, --notruncate don't truncate text in columns\n"), out);
fputs(_(" -W, --nowrap don't use multi-line representation\n"), out); fputs(_(" -W, --nowrap don't use multi-line representation\n"), out);
fputs(_(" -t, --type <name> namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out); fputs(_(" -t, --type <name> namespace type (mnt, net, ipc, user, pid, uts, cgroup, time)\n"), out);
fputs(_(" -T, --tree <rel> use tree format (parent, owner, or process)\n"), out);
fputs(USAGE_SEPARATOR, out); fputs(USAGE_SEPARATOR, out);
printf(USAGE_HELP_OPTIONS(24)); printf(USAGE_HELP_OPTIONS(24));
@ -994,7 +1221,7 @@ static void __attribute__((__noreturn__)) usage(void)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct lsns ls; struct lsns ls;
int c; int c, force_list = 0;
int r = 0; int r = 0;
char *outarg = NULL; char *outarg = NULL;
enum { enum {
@ -1013,11 +1240,13 @@ int main(int argc, char *argv[])
{ "list", no_argument, NULL, 'l' }, { "list", no_argument, NULL, 'l' },
{ "raw", no_argument, NULL, 'r' }, { "raw", no_argument, NULL, 'r' },
{ "type", required_argument, NULL, 't' }, { "type", required_argument, NULL, 't' },
{ "tree", optional_argument, NULL, 'T' },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
{ 'J','r' }, { 'J','r' },
{ 'l','T' },
{ 0 } { 0 }
}; };
int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
@ -1036,7 +1265,7 @@ int main(int argc, char *argv[])
INIT_LIST_HEAD(&netnsids_cache); INIT_LIST_HEAD(&netnsids_cache);
while ((c = getopt_long(argc, argv, while ((c = getopt_long(argc, argv,
"Jlp:o:nruhVt:W", long_opts, NULL)) != -1) { "Jlp:o:nruhVt:T::W", long_opts, NULL)) != -1) {
err_exclusive_options(c, long_opts, excl, excl_st); err_exclusive_options(c, long_opts, excl, excl_st);
@ -1045,7 +1274,7 @@ int main(int argc, char *argv[])
ls.json = 1; ls.json = 1;
break; break;
case 'l': case 'l':
ls.list = 1; force_list = 1;
break; break;
case 'o': case 'o':
outarg = optarg; outarg = optarg;
@ -1080,6 +1309,19 @@ int main(int argc, char *argv[])
case 'W': case 'W':
ls.no_wrap = 1; ls.no_wrap = 1;
break; break;
case 'T':
ls.tree = LSNS_TREE_OWNER;
if (optarg) {
if (*optarg == '=')
optarg++;
if (strcmp (optarg, "parent") == 0)
ls.tree = LSNS_TREE_PARENT;
else if (strcmp (optarg, "process") == 0)
ls.tree = LSNS_TREE_PROCESS;
else if (strcmp (optarg, "owner") != 0)
errx(EXIT_FAILURE, _("unknown tree type: %s"), optarg);
}
break;
case 'h': case 'h':
usage(); usage();
@ -1101,7 +1343,8 @@ int main(int argc, char *argv[])
if (ls.fltr_pid) if (ls.fltr_pid)
errx(EXIT_FAILURE, _("--task is mutually exclusive with <namespace>")); errx(EXIT_FAILURE, _("--task is mutually exclusive with <namespace>"));
ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument")); ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument"));
ls.tree = ls.list ? 0 : 1; if (!ls.tree && !force_list)
ls.tree = LSNS_TREE_PROCESS;
if (!ncolumns) { if (!ncolumns) {
columns[ncolumns++] = COL_PID; columns[ncolumns++] = COL_PID;
@ -1122,6 +1365,9 @@ int main(int argc, char *argv[])
columns[ncolumns++] = COL_NSFS; columns[ncolumns++] = COL_NSFS;
} }
columns[ncolumns++] = COL_COMMAND; columns[ncolumns++] = COL_COMMAND;
if (!ls.tree && !force_list)
ls.tree = LSNS_TREE_PROCESS;
} }
if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),

View File

@ -7,6 +7,7 @@ Thread(s) per core: 1
Core(s) per socket: 2 Core(s) per socket: 2
Socket(s): 1 Socket(s): 1
Stepping: r0p4 Stepping: r0p4
CPU(s) scaling MHz: 12%
CPU max MHz: 1700.0000 CPU max MHz: 1700.0000
CPU min MHz: 200.0000 CPU min MHz: 200.0000
BogoMIPS: 1694.10 BogoMIPS: 1694.10

View File

@ -10,6 +10,7 @@ Thread(s) per core: 1
Core(s) per socket: 2 Core(s) per socket: 2
Socket(s): 1 Socket(s): 1
Stepping: 9 Stepping: 9
CPU(s) scaling MHz: 42%
CPU max MHz: 3800.0000 CPU max MHz: 3800.0000
CPU min MHz: 1600.0000 CPU min MHz: 1600.0000
BogoMIPS: 3355.62 BogoMIPS: 3355.62

View File

@ -11,6 +11,7 @@ Core(s) per socket: 4
Socket(s): 2 Socket(s): 2
Stepping: 0 Stepping: 0
Frequency boost: enabled Frequency boost: enabled
CPU(s) scaling MHz: 52%
CPU max MHz: 3200.0000 CPU max MHz: 3200.0000
CPU min MHz: 1400.0000 CPU min MHz: 1400.0000
BogoMIPS: 6399.69 BogoMIPS: 6399.69

View File

@ -10,6 +10,7 @@ Thread(s) per core: 2
Core(s) per socket: 8 Core(s) per socket: 8
Socket(s): 4 Socket(s): 4
Stepping: 6 Stepping: 6
CPU(s) scaling MHz: 54%
CPU max MHz: 1996.0000 CPU max MHz: 1996.0000
CPU min MHz: 1064.0000 CPU min MHz: 1064.0000
BogoMIPS: 3990.31 BogoMIPS: 3990.31

View File

@ -10,6 +10,7 @@ Thread(s) per core: 2
Core(s) per socket: 2 Core(s) per socket: 2
Socket(s): 1 Socket(s): 1
Stepping: 5 Stepping: 5
CPU(s) scaling MHz: 59%
CPU max MHz: 2667.0000 CPU max MHz: 2667.0000
CPU min MHz: 1199.0000 CPU min MHz: 1199.0000
BogoMIPS: 5319.92 BogoMIPS: 5319.92

View File

@ -11,6 +11,7 @@ Core(s) per socket: 24
Socket(s): 2 Socket(s): 2
Stepping: 2 Stepping: 2
Frequency boost: enabled Frequency boost: enabled
CPU(s) scaling MHz: 126%
CPU max MHz: 2300.0000 CPU max MHz: 2300.0000
CPU min MHz: 1200.0000 CPU min MHz: 1200.0000
BogoMIPS: 4590.83 BogoMIPS: 4590.83

35
tools/compare-buildsys.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/sh
FILTER="$1"
MESON_CONFIG_H="build/config.h"
AUTOCONF_CONFIG_H="./config.h"
if [ ! -f $MESON_CONFIG_H ]; then
echo 'Meson is not ready in the build/ directory (try "meson build")'
exit 1
fi
if [ ! -f $AUTOCONF_CONFIG_H ]; then
echo 'Autotools are not ready (try "./autogen.sh; ./configure")'
exit 1
fi
TMPFILE_MESON="/tmp/util-linux-meson"
TMPFILE_AUTOCONF="/tmp/util-linux-autoconf"
GREP_PATTERN="#define "
if [ "$FILTER" = "headers" ]; then
GREP_PATTERN="#define .*_H[[:blank:]]"
fi
echo "===MESON===" > $TMPFILE_MESON
grep "$GREP_PATTERN" $MESON_CONFIG_H | sort >> $TMPFILE_MESON
echo "===AUTOCONF===" > $TMPFILE_AUTOCONF
grep "$GREP_PATTERN" $AUTOCONF_CONFIG_H | sort >> $TMPFILE_AUTOCONF
diff --side-by-side $TMPFILE_AUTOCONF $TMPFILE_MESON
rm -rf $TMPFILE_MESON $TMPFILE_AUTOCONF