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
-----
- 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
we can prepare regression tests completely independent on hw and architecture.

View File

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

View File

@ -15,6 +15,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdint.h>
#ifdef HAVE_SYS_MKDEV_H
# 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);
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 */

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/crc32.c \
lib/crc32c.c \
lib/c_strtod.c \
lib/encode.c \
lib/env.c \
lib/fileutils.c \
@ -91,7 +92,8 @@ check_PROGRAMS += \
test_remove_env \
test_strutils \
test_ttyutils \
test_timeutils
test_timeutils \
test_c_strtod
if LINUX
@ -135,6 +137,9 @@ test_mangle_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_MANGLE
test_strutils_SOURCES = lib/strutils.c
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_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_COLORS
test_colors_LDADD = $(LDADD) libtcolors.la

View File

@ -15,6 +15,10 @@
#include <linux/fd.h>
#endif
#ifdef HAVE_LINUX_BLKZONED_H
#include <linux/blkzoned.h>
#endif
#ifdef HAVE_SYS_DISKLABEL_H
#include <sys/disklabel.h>
#endif
@ -412,6 +416,31 @@ int blkdev_lock(int fd, const char *devname, const char *lockmode)
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
#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
crc32.c
crc32c.c
c_strtod.c
encode.c
env.c
fileutils.c

View File

@ -150,6 +150,10 @@ struct blkid_idmag
const char *hoff; /* hint which contains byte offset to kboff */
long kboff; /* kilobyte offset of 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 */
unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */
mode_t mode; /* struct stat.sb_mode */
uint64_t zone_size; /* zone size (BLKGETZONESZ ioctl) */
int flags; /* private library flags */
int prob_flags; /* always zeroized by blkid_do_*() */

View File

@ -94,6 +94,9 @@
#ifdef HAVE_LINUX_CDROM_H
#include <linux/cdrom.h>
#endif
#ifdef HAVE_LINUX_BLKZONED_H
#include <linux/blkzoned.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
@ -177,6 +180,7 @@ blkid_probe blkid_clone_probe(blkid_probe parent)
pr->disk_devno = parent->disk_devno;
pr->blkssz = parent->blkssz;
pr->flags = parent->flags;
pr->zone_size = parent->zone_size;
pr->parent = parent;
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_size = 0;
pr->wipe_chain = NULL;
pr->zone_size = 0;
if (fd < 0)
return 1;
@ -1000,6 +1005,15 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
#endif
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"",
pr->off, pr->size));
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 */
while(mag && mag->magic) {
unsigned char *buf;
uint64_t kboff;
uint64_t hint_offset;
if (!mag->hoff || blkid_probe_get_hint(pr, mag->hoff, &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);
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)) {
DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld",
mag->sboff, mag->kboff));
mag->sboff, kboff));
if (offset)
*offset = off + (mag->sboff & 0x3ff);
if (res)
@ -1207,6 +1233,39 @@ int blkid_do_probe(blkid_probe pr)
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:
* @pr: prober
@ -1246,6 +1305,7 @@ int blkid_do_wipe(blkid_probe pr, int dryrun)
const char *off = NULL;
size_t len = 0;
uint64_t offset, magoff;
int conventional;
char buf[BUFSIZ];
int fd, rc = 0;
struct blkid_chain *chn;
@ -1281,6 +1341,11 @@ int blkid_do_wipe(blkid_probe pr, int dryrun)
if (len > sizeof(buf))
len = sizeof(buf);
rc = is_conventional(pr, offset);
if (rc < 0)
return rc;
conventional = rc == 1;
DBG(LOWPROBE, ul_debug(
"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"));
@ -1288,13 +1353,31 @@ int blkid_do_wipe(blkid_probe pr, int dryrun)
if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
return -1;
memset(buf, 0, len);
if (!dryrun && len) {
/* wipen on device */
if (write_all(fd, buf, len))
return -1;
fsync(fd);
if (conventional) {
memset(buf, 0, len);
/* wipen on device */
if (write_all(fd, buf, len))
return -1;
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 */
return blkid_probe_step_back(pr);

View File

@ -9,6 +9,12 @@
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#ifdef HAVE_LINUX_BLKZONED_H
#include <linux/blkzoned.h>
#endif
#include "superblocks.h"
@ -59,11 +65,157 @@ struct btrfs_super_block {
uint8_t label[256];
} __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)
{
struct btrfs_super_block *bfs;
bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
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);
}
if (!bfs)
return errno ? -errno : 1;
@ -88,6 +240,11 @@ const struct blkid_idinfo btrfs_idinfo =
.magics =
{
{ .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 }
}
};

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include "lscpu.h"
#include "fileutils.h"
#include "c_strtod.h"
/* 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);
if (pattern->id == PAT_BOGOMIPS_CPU && pr->curr_type && !pr->curr_type->bogomips)
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;
case CPUINFO_LINE_CPUTYPE:
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)
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))
cpu->type->has_freq = 1;
@ -583,6 +593,27 @@ float lsblk_cputype_get_minmhz(struct lscpu_cxt *cxt, struct lscpu_cputype *ct)
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)
{
size_t i;

View File

@ -105,6 +105,7 @@ enum {
COL_CPU_CONFIGURED,
COL_CPU_ONLINE,
COL_CPU_MHZ,
COL_CPU_SCALMHZ,
COL_CPU_MAXMHZ,
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_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_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_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"));
break;
case COL_CPU_MHZ:
if (cpu->mhz)
xstrncpy(buf, cpu->mhz, bufsz);
if (cpu->mhz_cur_freq)
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;
case COL_CPU_MAXMHZ:
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);
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 min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt, ct));
}

View File

@ -127,11 +127,12 @@ struct lscpu_cpu {
int logical_id;
char *bogomips; /* per-CPU bogomips */
char *mhz; /* max freq from cpuinfo */
char *mhz; /* freq from cpuinfo */
char *dynamic_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_min_freq; /* realtime freq from /sys/.../cpuinfo_min_freq */
float mhz_cur_freq;
int coreid;
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_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);
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.
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.
@ -63,6 +63,14 @@ Do not truncate text in columns.
*-W*, *--nowrap*::
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*::
Display version information and exit.

View File

@ -142,16 +142,25 @@ static char *ns_names[] = {
[LSNS_ID_TIME] = "time"
};
enum {
RELA_PARENT,
RELA_OWNER,
MAX_RELA
};
struct lsns_namespace {
ino_t id;
int type; /* LSNS_* */
int nprocs;
int netnsid;
ino_t parentid;
ino_t ownerid;
ino_t related_id[MAX_RELA];
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 processes; /* head of lsns_process *siblings */
};
@ -177,6 +186,14 @@ struct lsns_process {
int netnsid;
};
enum {
LSNS_TREE_NONE,
LSNS_TREE_PROCESS,
LSNS_TREE_OWNER,
LSNS_TREE_PARENT,
};
struct lsns {
struct list_head processes;
struct list_head namespaces;
@ -188,12 +205,12 @@ struct lsns {
unsigned int raw : 1,
json : 1,
tree : 1,
list : 1,
tree : 2,
no_trunc : 1,
no_headings: 1,
no_wrap : 1;
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->id = ino;
ns->parentid = parent_ino;
ns->ownerid = owner_ino;
ns->related_id[RELA_PARENT] = parent_ino;
ns->related_id[RELA_OWNER] = owner_ino;
list_add_tail(&ns->namespaces, &ls->namespaces);
return ns;
@ -660,9 +677,126 @@ static int netnsid_xasputs(char **str, int netnsid)
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)
{
struct list_head *p;
struct lsns_namespace *orphan[2] = {NULL, NULL};
int rela;
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);
return 0;
@ -774,7 +958,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
assert(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) {
warn(_("failed to add line to output"));
return;
@ -788,10 +975,12 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
xasprintf(&str, "%ju", (uintmax_t)ns->id);
break;
case COL_PID:
xasprintf(&str, "%d", (int) proc->pid);
if (proc)
xasprintf(&str, "%d", (int) proc->pid);
break;
case COL_PPID:
xasprintf(&str, "%d", (int) proc->ppid);
if (proc)
xasprintf(&str, "%d", (int) proc->ppid);
break;
case COL_TYPE:
xasprintf(&str, "%s", ns_names[ns->type]);
@ -800,20 +989,26 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
xasprintf(&str, "%d", ns->nprocs);
break;
case COL_COMMAND:
if (!proc)
break;
str = proc_get_command(proc->pid);
if (!str)
str = proc_get_command_name(proc->pid);
break;
case COL_PATH:
if (!proc)
break;
xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]);
break;
case COL_UID:
xasprintf(&str, "%d", (int) proc->uid);
xasprintf(&str, "%d", proc? (int) proc->uid: (int) ns->uid_fallback);
break;
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;
case COL_NETNSID:
if (!proc)
break;
if (ns->type == LSNS_ID_NET)
netnsid_xasputs(&str, proc->netnsid);
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');
break;
case COL_PNS:
xasprintf(&str, "%ju", (uintmax_t)ns->parentid);
xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_PARENT]);
break;
case COL_ONS:
xasprintf(&str, "%ju", (uintmax_t)ns->ownerid);
xasprintf(&str, "%ju", (uintmax_t)ns->related_id[RELA_OWNER]);
break;
default:
break;
@ -834,7 +1029,10 @@ static void add_scols_line(struct lsns *ls, struct libscols_table *table,
err_oom();
}
proc->outline = line;
if (ls->tree == LSNS_TREE_OWNER || ls->tree == LSNS_TREE_PARENT)
ns->ns_outline = line;
else if (proc)
proc->outline = line;
}
static struct libscols_table *init_scols_table(struct lsns *ls)
@ -862,10 +1060,15 @@ static struct libscols_table *init_scols_table(struct lsns *ls)
if (ls->no_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;
if (ls->no_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);
if (cl == NULL) {
@ -890,6 +1093,28 @@ err:
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)
{
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))
continue;
add_scols_line(ls, tab, ns, ns->proc);
if (!ns->ns_outline)
show_namespace(ls, tab, ns, ns->proc);
}
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
* within the same namespace
*/
if (ls->tree
if (ls->tree == LSNS_TREE_PROCESS
&& proc->parent
&& !proc->parent->outline
&& 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(_(" -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, --tree <rel> use tree format (parent, owner, or process)\n"), out);
fputs(USAGE_SEPARATOR, out);
printf(USAGE_HELP_OPTIONS(24));
@ -994,7 +1221,7 @@ static void __attribute__((__noreturn__)) usage(void)
int main(int argc, char *argv[])
{
struct lsns ls;
int c;
int c, force_list = 0;
int r = 0;
char *outarg = NULL;
enum {
@ -1013,11 +1240,13 @@ int main(int argc, char *argv[])
{ "list", no_argument, NULL, 'l' },
{ "raw", no_argument, NULL, 'r' },
{ "type", required_argument, NULL, 't' },
{ "tree", optional_argument, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
{ 'J','r' },
{ 'l','T' },
{ 0 }
};
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);
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);
@ -1045,7 +1274,7 @@ int main(int argc, char *argv[])
ls.json = 1;
break;
case 'l':
ls.list = 1;
force_list = 1;
break;
case 'o':
outarg = optarg;
@ -1080,6 +1309,19 @@ int main(int argc, char *argv[])
case 'W':
ls.no_wrap = 1;
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':
usage();
@ -1101,7 +1343,8 @@ int main(int argc, char *argv[])
if (ls.fltr_pid)
errx(EXIT_FAILURE, _("--task is mutually exclusive with <namespace>"));
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) {
columns[ncolumns++] = COL_PID;
@ -1122,6 +1365,9 @@ int main(int argc, char *argv[])
columns[ncolumns++] = COL_NSFS;
}
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),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,7 @@ Core(s) per socket: 24
Socket(s): 2
Stepping: 2
Frequency boost: enabled
CPU(s) scaling MHz: 126%
CPU max MHz: 2300.0000
CPU min MHz: 1200.0000
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