diff --git a/SOURCES/2.17-kill-strtol.patch b/SOURCES/2.17-kill-strtol.patch new file mode 100644 index 00000000..d7f8db01 --- /dev/null +++ b/SOURCES/2.17-kill-strtol.patch @@ -0,0 +1,22 @@ +diff -up util-linux-2.23.2/misc-utils/kill.c.kzak util-linux-2.23.2/misc-utils/kill.c +--- util-linux-2.23.2/misc-utils/kill.c.kzak 2013-06-13 09:46:10.448650861 +0200 ++++ util-linux-2.23.2/misc-utils/kill.c 2014-09-25 10:08:27.879359310 +0200 +@@ -48,6 +48,7 @@ + #include /* for isdigit() */ + #include + #include ++#include + + #include "c.h" + #include "nls.h" +@@ -279,8 +280,9 @@ int main (int argc, char *argv[]) + the rest of the arguments should be process ids and names. + kill them. */ + for (errors = 0; (arg = *argv) != NULL; argv++) { ++ errno = 0; + pid = strtol (arg, &ep, 10); +- if (! *ep) ++ if (errno == 0 && ep && *ep == '\0' && arg < ep) + errors += kill_verbose (arg, pid, numsig); + else { + struct proc_processes *ps = proc_open_processes(); diff --git a/SOURCES/2.23-login-lastlog-create.patch b/SOURCES/2.23-login-lastlog-create.patch new file mode 100644 index 00000000..6db26e2a --- /dev/null +++ b/SOURCES/2.23-login-lastlog-create.patch @@ -0,0 +1,11 @@ +diff -up util-linux-2.23.2/login-utils/login.c.kzak util-linux-2.23.2/login-utils/login.c +--- util-linux-2.23.2/login-utils/login.c.kzak 2013-07-30 10:39:26.222738397 +0200 ++++ util-linux-2.23.2/login-utils/login.c 2013-09-09 09:01:39.923225757 +0200 +@@ -502,7 +502,7 @@ static void log_lastlog(struct login_con + if (!cxt->pwd) + return; + +- fd = open(_PATH_LASTLOG, O_RDWR, 0); ++ fd = open(_PATH_LASTLOG, O_RDWR | O_CREAT, 0); + if (fd < 0) + return; diff --git a/SOURCES/2.24-agetty-clocal.patch b/SOURCES/2.24-agetty-clocal.patch new file mode 100644 index 00000000..c7e6f661 --- /dev/null +++ b/SOURCES/2.24-agetty-clocal.patch @@ -0,0 +1,149 @@ +diff -up util-linux-2.23.2/term-utils/agetty.c.kzak util-linux-2.23.2/term-utils/agetty.c +--- util-linux-2.23.2/term-utils/agetty.c.kzak 2013-07-30 11:14:18.124912322 +0200 ++++ util-linux-2.23.2/term-utils/agetty.c 2013-09-09 09:07:46.406689270 +0200 +@@ -132,13 +132,20 @@ struct options { + int delay; /* Sleep seconds before prompt */ + int nice; /* Run login with this priority */ + int numspeed; /* number of baud rates to try */ ++ int clocal; /* CLOCAL_MODE_* */ + speed_t speeds[MAX_SPEED]; /* baud rates to be tried */ + }; + ++enum { ++ CLOCAL_MODE_AUTO = 0, ++ CLOCAL_MODE_ALWAYS, ++ CLOCAL_MODE_NEVER ++}; ++ + #define F_PARSE (1<<0) /* process modem status messages */ + #define F_ISSUE (1<<1) /* display /etc/issue */ + #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */ +-#define F_LOCAL (1<<3) /* force local */ ++ + #define F_INITSTRING (1<<4) /* initstring is set */ + #define F_WAITCRLF (1<<5) /* wait for CR or LF */ + #define F_CUSTISSUE (1<<6) /* give alternative issue file */ +@@ -235,10 +242,13 @@ static void login_options_to_argv(char * + static char *fakehost; + + #ifdef DEBUGGING +-#define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0) ++# ifndef DEBUG_OUTPUT ++# define DEBUG_OUTPUT "/dev/ttyp0" ++# endif ++# define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0) + FILE *dbf; + #else +-#define debug(s) do { ; } while (0) ++# define debug(s) do { ; } while (0) + #endif + + int main(int argc, char **argv) +@@ -270,7 +280,7 @@ int main(int argc, char **argv) + sigaction(SIGINT, &sa, &sa_int); + + #ifdef DEBUGGING +- dbf = fopen("/dev/ttyp0", "w"); ++ dbf = fopen(DEBUG_OUTPUT, "w"); + for (int i = 1; i < argc; i++) + debug(argv[i]); + #endif /* DEBUGGING */ +@@ -311,8 +321,10 @@ int main(int argc, char **argv) + strlen(options.initstring)); + } + +- if (!serial_tty_option(&options, F_LOCAL)) +- /* Go to blocking write mode unless -L is specified. */ ++ if (options.flags & F_VCONSOLE || options.clocal != CLOCAL_MODE_ALWAYS) ++ /* Go to blocking mode unless -L is specified, this change ++ * affects stdout, stdin and stderr as all the file descriptors ++ * are created by dup(). */ + fcntl(STDOUT_FILENO, F_SETFL, + fcntl(STDOUT_FILENO, F_GETFL, 0) & ~O_NONBLOCK); + +@@ -420,6 +432,12 @@ int main(int argc, char **argv) + options.tty); + } + ++#ifdef DEBUGGING ++ fprintf(dbf, "read %c\n", ch); ++ if (close_stream(dbf) != 0) ++ log_err("write failed: %s", DEBUG_OUTPUT); ++#endif ++ + /* Let the login program take care of password validation. */ + execv(options.login, login_argv); + log_err(_("%s: can't exec %s: %m"), options.tty, login_argv[0]); +@@ -534,7 +552,7 @@ static void parse_args(int argc, char ** + { "init-string", required_argument, 0, 'I' }, + { "noclear", no_argument, 0, 'J' }, + { "login-program", required_argument, 0, 'l' }, +- { "local-line", no_argument, 0, 'L' }, ++ { "local-line", optional_argument, 0, 'L' }, + { "extract-baud", no_argument, 0, 'm' }, + { "skip-login", no_argument, 0, 'n' }, + { "nonewline", no_argument, 0, 'N' }, +@@ -603,7 +621,18 @@ static void parse_args(int argc, char ** + op->login = optarg; + break; + case 'L': +- op->flags |= F_LOCAL; ++ /* -L and -L=always have the same meaning */ ++ op->clocal = CLOCAL_MODE_ALWAYS; ++ if (optarg) { ++ if (strcmp(optarg, "=always") == 0) ++ op->clocal = CLOCAL_MODE_ALWAYS; ++ else if (strcmp(optarg, "=never") == 0) ++ op->clocal = CLOCAL_MODE_NEVER; ++ else if (strcmp(optarg, "=auto") == 0) ++ op->clocal = CLOCAL_MODE_AUTO; ++ else ++ log_err(_("unssuported --local-line mode argument")); ++ } + break; + case 'm': + op->flags |= F_PARSE; +@@ -1090,8 +1119,19 @@ static void termio_init(struct options * + cfsetispeed(tp, ispeed); + cfsetospeed(tp, ospeed); + +- if (op->flags & F_LOCAL) +- tp->c_cflag |= CLOCAL; ++ /* The default is to follow setting from kernel, but it's possible ++ * to explicitly remove/add CLOCAL flag by -L[=]*/ ++ switch (op->clocal) { ++ case CLOCAL_MODE_ALWAYS: ++ tp->c_cflag |= CLOCAL; /* -L or -L=always */ ++ break; ++ case CLOCAL_MODE_NEVER: ++ tp->c_cflag &= ~CLOCAL; /* -L=never */ ++ break; ++ case CLOCAL_MODE_AUTO: /* -L=auto */ ++ break; ++ } ++ + #ifdef HAVE_STRUCT_TERMIOS_C_LINE + tp->c_line = 0; + #endif +@@ -1412,9 +1452,10 @@ static char *get_logname(struct options + + if (read(STDIN_FILENO, &c, 1) < 1) { + +- /* Do not report trivial like EINTR/EIO errors. */ ++ /* The terminal could be open with O_NONBLOCK when ++ * -L (force CLOCAL) is specified... */ + if (errno == EINTR || errno == EAGAIN) { +- usleep(1000); ++ usleep(250000); + continue; + } + switch (errno) { +@@ -1648,7 +1689,7 @@ static void __attribute__ ((__noreturn__ + fputs(_(" -i, --noissue do not display issue file\n"), out); + fputs(_(" -I, --init-string set init string\n"), out); + fputs(_(" -l, --login-program specify login program\n"), out); +- fputs(_(" -L, --local-line force local line\n"), out); ++ fputs(_(" -L, --local-line[=] cotrol local line flag\n"), out); + fputs(_(" -m, --extract-baud extract baud rate during connect\n"), out); + fputs(_(" -n, --skip-login do not prompt for login\n"), out); + fputs(_(" -o, --login-options options that are passed to login\n"), out); diff --git a/SOURCES/2.24-agetty-etc-os-release.patch b/SOURCES/2.24-agetty-etc-os-release.patch new file mode 100644 index 00000000..aa747e11 --- /dev/null +++ b/SOURCES/2.24-agetty-etc-os-release.patch @@ -0,0 +1,176 @@ +diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h +--- util-linux-2.23.2/include/pathnames.h.kzak 2013-07-30 10:39:26.201738190 +0200 ++++ util-linux-2.23.2/include/pathnames.h 2013-09-12 13:05:35.928359383 +0200 +@@ -63,6 +63,7 @@ + + /* used in term-utils/agetty.c */ + #define _PATH_ISSUE "/etc/issue" ++#define _PATH_OS_RELEASE "/etc/os-release" + #define _PATH_NUMLOCK_ON _PATH_LOCALSTATEDIR "/numlock-on" + + #define _PATH_LOGINDEFS "/etc/login.defs" +diff -up util-linux-2.23.2/term-utils/agetty.8.kzak util-linux-2.23.2/term-utils/agetty.8 +--- util-linux-2.23.2/term-utils/agetty.8.kzak 2013-07-30 10:58:20.889261333 +0200 ++++ util-linux-2.23.2/term-utils/agetty.8 2013-09-12 13:05:35.928359383 +0200 +@@ -310,6 +310,14 @@ Insert the current date. + .TP + s + Insert the system name, the name of the operating system. Same as `uname \-s'. ++See also \\S escape code. ++.TP ++S or S{VARIABLE} ++Insert the VARIABLE data from \fI/etc/os-release\fP. If the VARIABLE argument ++is not specified then use PRETTY_NAME from the file or the system name (see \\s). ++This escape code allows to keep \fI/etc/issue\fP distribution and release ++independent. Note that \\S{ANSI_COLOR} is converted to the real terminal ++escape sequence. + .TP + l + Insert the name of the current tty line. +@@ -368,11 +376,14 @@ the system status file. + .B /etc/issue + printed before the login prompt. + .TP ++.B /etc/os-release ++operating system identification data. ++.TP + .B /dev/console + problem reports (if syslog(3) is not used). + .TP + .B /etc/inittab +-\fIinit\fP(8) configuration file. ++\fIinit\fP(8) configuration file for SysV-style init daemon. + .SH BUGS + .ad + .fi +diff -up util-linux-2.23.2/term-utils/agetty.c.kzak util-linux-2.23.2/term-utils/agetty.c +--- util-linux-2.23.2/term-utils/agetty.c.kzak 2013-09-12 13:05:35.927359379 +0200 ++++ util-linux-2.23.2/term-utils/agetty.c 2013-09-12 13:05:35.929359388 +0200 +@@ -129,6 +129,7 @@ struct options { + char *issue; /* alternative issue file */ + char *erasechars; /* string with erase chars */ + char *killchars; /* string with kill chars */ ++ char *osrelease; /* /etc/os-release data */ + int delay; /* Sleep seconds before prompt */ + int nice; /* Run login with this priority */ + int numspeed; /* number of baud rates to try */ +@@ -431,7 +432,8 @@ int main(int argc, char **argv) + log_warn(_("%s: can't change process priority: %m"), + options.tty); + } +- ++ if (options.osrelease) ++ free(options.osrelease); + #ifdef DEBUGGING + fprintf(dbf, "read %c\n", ch); + if (close_stream(dbf) != 0) +@@ -1279,6 +1281,84 @@ static char *xgetdomainname(void) + return NULL; + } + ++static char *read_os_release(struct options *op, const char *varname) ++{ ++ int fd = -1; ++ struct stat st; ++ size_t varsz = strlen(varname); ++ char *p, *buf = NULL, *ret = NULL; ++ ++ /* read the file only once */ ++ if (!op->osrelease) { ++ fd = open(_PATH_OS_RELEASE, O_RDONLY); ++ if (fd == -1) { ++ log_warn(_("cannot open: %s: %m"), _PATH_OS_RELEASE); ++ return NULL; ++ } ++ ++ if (fstat(fd, &st) < 0 || st.st_size > 4 * 1024 * 1024) ++ goto done; ++ ++ op->osrelease = malloc(st.st_size + 1); ++ if (!op->osrelease) ++ log_err(_("failed to allocate memory: %m")); ++ if (read_all(fd, op->osrelease, st.st_size) != (ssize_t) st.st_size) { ++ free(op->osrelease); ++ op->osrelease = NULL; ++ goto done; ++ } ++ op->osrelease[st.st_size] = 0; ++ } ++ buf = strdup(op->osrelease); ++ if (!buf) ++ log_err(_("failed to allocate memory: %m")); ++ p = buf; ++ ++ for (;;) { ++ char *eol, *eon; ++ ++ p += strspn(p, "\n\r"); ++ p += strspn(p, " \t\n\r"); ++ if (!*p) ++ break; ++ if (strspn(p, "#;\n") != 0) { ++ p += strcspn(p, "\n\r"); ++ continue; ++ } ++ if (strncmp(p, varname, varsz) != 0) { ++ p += strcspn(p, "\n\r"); ++ continue; ++ } ++ p += varsz; ++ p += strspn(p, " \t\n\r=\""); ++ eol = p + strcspn(p, "\n\r"); ++ *eol = '\0'; ++ eon = eol-1; ++ while (eon > p) { ++ if (*eon == '\t' || *eon == ' ') { ++ eon--; ++ continue; ++ } ++ if (*eon == '"') { ++ *eon = '\0'; ++ break; ++ } ++ break; ++ } ++ if (ret) ++ free(ret); ++ ret = strdup(p); ++ if (!ret) ++ log_err(_("failed to allocate memory: %m")); ++ p = eol + 1; ++ } ++done: ++ free(buf); ++ if (fd >= 0) ++ close(fd); ++ return ret; ++} ++ + /* Show login prompt, optionally preceded by /etc/issue contents. */ + static void do_prompt(struct options *op, struct termios *tp) + { +@@ -1968,6 +2048,24 @@ static void output_special_char(unsigned + } + break; + } ++ case 'S': ++ { ++ char *var = NULL, varname[64]; ++ ++ if (get_escape_argument(fp, varname, sizeof(varname))) ++ var = read_os_release(op, varname); ++ else if (!(var = read_os_release(op, "PRETTY_NAME"))) ++ var = uts.sysname; ++ if (var) { ++ if (strcmp(varname, "ANSI_COLOR") == 0) ++ printf("\033[%sm", var); ++ else ++ printf("%s", var); ++ if (var != uts.sysname) ++ free(var); ++ } ++ break; ++ } + case 'u': + case 'U': + { diff --git a/SOURCES/2.24-blockdev-setbsz-hint.patch b/SOURCES/2.24-blockdev-setbsz-hint.patch new file mode 100644 index 00000000..fe47dbaa --- /dev/null +++ b/SOURCES/2.24-blockdev-setbsz-hint.patch @@ -0,0 +1,41 @@ +From 7ab32ae64d05f018c171ba1525bc337805d84391 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 11 Oct 2013 11:16:23 +0200 +Subject: [PATCH] blockdev: add note about --setbsz usability + +Signed-off-by: Karel Zak +--- + disk-utils/blockdev.8 | 4 +++- + disk-utils/blockdev.c | 2 +- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/disk-utils/blockdev.8 b/disk-utils/blockdev.8 +index 2b3d64c..f4282da 100644 +--- a/disk-utils/blockdev.8 ++++ b/disk-utils/blockdev.8 +@@ -68,7 +68,9 @@ Get size in 512-byte sectors. + .IP "\fB\-\-rereadpt\fP" + Reread partition table + .IP "\fB\-\-setbsz\fP \fIbytes\fP" +-Set blocksize. ++Set blocksize. Note that the block size is specific to the current file ++descriptor opening the block device, so the change of block size only persists ++for as long as blockdev has the device open, and is lost once blockdev exits. + .IP "\fB\-\-setfra\fP \fIsectors\fP" + Set filesystem readahead (same like --setra on 2.6 kernels). + .IP "\fB\-\-setra\fP \fIsectors\fP" +diff --git a/disk-utils/blockdev.c b/disk-utils/blockdev.c +index 4543818..d030217 100644 +--- a/disk-utils/blockdev.c ++++ b/disk-utils/blockdev.c +@@ -127,7 +127,7 @@ static const struct bdc bdcms[] = + .argname = "", + .argtype = ARG_INT, + .flags = FL_NORESULT, +- .help = N_("set blocksize") ++ .help = N_("set blocksize on file descriptor opening the block device") + },{ + IOCTL_ENTRY(BLKGETSIZE), + .name = "--getsize", +-- +1.8.3.1 diff --git a/SOURCES/2.24-fsck-fstab.patch b/SOURCES/2.24-fsck-fstab.patch new file mode 100644 index 00000000..b48172e3 --- /dev/null +++ b/SOURCES/2.24-fsck-fstab.patch @@ -0,0 +1,21 @@ +diff -up util-linux-2.23.2/disk-utils/fsck.c.kzak util-linux-2.23.2/disk-utils/fsck.c +--- util-linux-2.23.2/disk-utils/fsck.c.kzak 2013-06-13 09:46:10.377650254 +0200 ++++ util-linux-2.23.2/disk-utils/fsck.c 2014-03-25 12:46:59.525939425 +0100 +@@ -437,10 +437,14 @@ static void load_fs_info(void) + if (mnt_table_parse_fstab(fstab, path)) { + if (!path) + path = mnt_get_fstab_path(); +- if (errno) +- warn(_("%s: failed to parse fstab"), path); +- else +- warnx(_("%s: failed to parse fstab"), path); ++ ++ /* don't print error when there is no fstab at all */ ++ if (access(path, F_OK) == 0) { ++ if (errno) ++ warn(_("%s: failed to parse fstab"), path); ++ else ++ warnx(_("%s: failed to parse fstab"), path); ++ } + } + } diff --git a/SOURCES/2.24-libfdisk-fix-SIGFPE.patch b/SOURCES/2.24-libfdisk-fix-SIGFPE.patch new file mode 100644 index 00000000..7ed13cc5 --- /dev/null +++ b/SOURCES/2.24-libfdisk-fix-SIGFPE.patch @@ -0,0 +1,39 @@ +From 44baaedaffee029dca76796b933412d97a19dff6 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 9 Sep 2013 10:57:50 +0200 +Subject: [PATCH] libfdisk: fix SIGFPE + + #0 recount_geometry at libfdisk/src/alignment.c:143 + #1 fdisk_discover_geometry at libfdisk/src/alignment.c:205 + #2 fdisk_context_assign_device at libfdisk/src/context.c:173 + #3 print_partition_table_from_option at fdisks/fdisk.c:924 + +References: https://bugzilla.redhat.com/show_bug.cgi?id=1005566 +Signed-off-by: Karel Zak +--- + libfdisk/src/alignment.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c +index ac44e73..4d4ab48 100644 +--- a/libfdisk/src/alignment.c ++++ b/libfdisk/src/alignment.c +@@ -193,11 +193,12 @@ int fdisk_discover_geometry(struct fdisk_context *cxt) + + /* what the kernel/bios thinks the geometry is */ + blkdev_get_geometry(cxt->dev_fd, &h, &s); +- if (!h && !s) { +- /* unable to discover geometry, use default values */ +- s = 63; ++ ++ /* defaults */ ++ if (!h) + h = 255; +- } ++ if (!s) ++ s = 63; + + /* obtained heads and sectors */ + cxt->geom.heads = h; +-- +1.8.1.4 diff --git a/SOURCES/2.24-libmount-3.14.patch b/SOURCES/2.24-libmount-3.14.patch new file mode 100644 index 00000000..e519d7a2 --- /dev/null +++ b/SOURCES/2.24-libmount-3.14.patch @@ -0,0 +1,80 @@ +diff -up util-linux-2.23.2/libmount/src/tab.c.kzak util-linux-2.23.2/libmount/src/tab.c +--- util-linux-2.23.2/libmount/src/tab.c.kzak 2013-07-30 10:39:26.218738358 +0200 ++++ util-linux-2.23.2/libmount/src/tab.c 2014-09-25 10:53:43.525269554 +0200 +@@ -47,6 +47,8 @@ + #include "strutils.h" + #include "loopdev.h" + ++static int is_mountinfo(struct libmnt_table *tb); ++ + /** + * mnt_new_table: + * +@@ -233,7 +235,7 @@ int mnt_table_get_root_fs(struct libmnt_ + assert(tb); + assert(root); + +- if (!tb || !root) ++ if (!tb || !root || !is_mountinfo(tb)) + return -EINVAL; + + DBG(TAB, mnt_debug_h(tb, "lookup root fs")); +@@ -241,8 +243,6 @@ int mnt_table_get_root_fs(struct libmnt_ + mnt_reset_iter(&itr, MNT_ITER_FORWARD); + while(mnt_table_next_fs(tb, &itr, &fs) == 0) { + int id = mnt_fs_get_parent_id(fs); +- if (!id) +- break; /* @tab is not mountinfo file? */ + + if (!*root || id < root_id) { + *root = fs; +@@ -250,7 +250,7 @@ int mnt_table_get_root_fs(struct libmnt_ + } + } + +- return root_id ? 0 : -EINVAL; ++ return *root ? 0 : -EINVAL; + } + + /** +@@ -271,15 +271,13 @@ int mnt_table_next_child_fs(struct libmn + struct libmnt_fs *fs; + int parent_id, lastchld_id = 0, chld_id = 0; + +- if (!tb || !itr || !parent) ++ if (!tb || !itr || !parent || !is_mountinfo(tb)) + return -EINVAL; + + DBG(TAB, mnt_debug_h(tb, "lookup next child of '%s'", + mnt_fs_get_target(parent))); + + parent_id = mnt_fs_get_id(parent); +- if (!parent_id) +- return -EINVAL; + + /* get ID of the previously returned child */ + if (itr->head && itr->p != itr->head) { +@@ -310,7 +308,7 @@ int mnt_table_next_child_fs(struct libmn + } + } + +- if (!chld_id) ++ if (!*chld) + return 1; /* end of iterator */ + + /* set the iterator to the @chld for the next call */ +diff -up util-linux-2.23.2/misc-utils/findmnt.c.kzak util-linux-2.23.2/misc-utils/findmnt.c +--- util-linux-2.23.2/misc-utils/findmnt.c.kzak 2013-07-30 11:07:35.138395654 +0200 ++++ util-linux-2.23.2/misc-utils/findmnt.c 2014-09-25 10:49:50.953050560 +0200 +@@ -826,8 +826,9 @@ static int tab_is_tree(struct libmnt_tab + if (!itr) + return 0; + +- if (mnt_table_next_fs(tb, itr, &fs) == 0) +- rc = mnt_fs_get_id(fs) > 0 && mnt_fs_get_parent_id(fs) > 0; ++ rc = (mnt_table_next_fs(tb, itr, &fs) == 0 && ++ mnt_fs_is_kernel(fs) && ++ mnt_fs_get_root(fs)); + + mnt_free_iter(itr); + return rc; diff --git a/SOURCES/2.24-libmount-canonicalize-for-conversion-from-loopdev.patch b/SOURCES/2.24-libmount-canonicalize-for-conversion-from-loopdev.patch new file mode 100644 index 00000000..9778ec5b --- /dev/null +++ b/SOURCES/2.24-libmount-canonicalize-for-conversion-from-loopdev.patch @@ -0,0 +1,39 @@ +From 3f420a49dd4d0c413b635dd621aa34eebce2d3d2 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 5 Aug 2013 13:58:01 +0200 +Subject: [PATCH] libmount: canonicalize for conversion from loopdev backing + file + + # mount foo.img /mnt + # umount foo.img + umount: foo.img: not mounted + +The loopdev code (and sysfs backing_file) uses absolute paths, but +libmount does not canonicalize the path before lookup for the backing file. + +References: https://bugzilla.redhat.com/show_bug.cgi?id=950497 +Signed-off-by: Karel Zak +--- + libmount/src/context_umount.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c +index 2b791c4..b02902c 100644 +--- a/libmount/src/context_umount.c ++++ b/libmount/src/context_umount.c +@@ -161,7 +161,12 @@ try_loopdev: + struct stat st; + + if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) { +- int count = loopdev_count_by_backing_file(tgt, &loopdev); ++ int count; ++ ++ cn_tgt = mnt_resolve_path(tgt, cache); ++ count = loopdev_count_by_backing_file(cn_tgt, &loopdev); ++ if (!cache) ++ free(cn_tgt); + if (count == 1) { + DBG(CXT, mnt_debug_h(cxt, + "umount: %s --> %s (retry)", tgt, loopdev)); +-- +1.8.1.4 diff --git a/SOURCES/2.24-libmount-mem.patch b/SOURCES/2.24-libmount-mem.patch new file mode 100644 index 00000000..9a471069 --- /dev/null +++ b/SOURCES/2.24-libmount-mem.patch @@ -0,0 +1,24 @@ +diff -up util-linux-2.23.2/libmount/src/context_umount.c.kzak util-linux-2.23.2/libmount/src/context_umount.c +--- util-linux-2.23.2/libmount/src/context_umount.c.kzak 2013-10-07 11:43:10.990598629 +0200 ++++ util-linux-2.23.2/libmount/src/context_umount.c 2013-10-07 11:46:01.051031431 +0200 +@@ -423,6 +423,8 @@ static int evaluate_permissions(struct l + if (optstr && !mnt_optstr_get_option(optstr, + "user", &mtab_user, &sz) && sz) + ok = !strncmp(curr_user, mtab_user, sz); ++ ++ free(curr_user); + } + + if (ok) { +diff -up util-linux-2.23.2/libmount/src/utils.c.kzak util-linux-2.23.2/libmount/src/utils.c +--- util-linux-2.23.2/libmount/src/utils.c.kzak 2013-07-30 11:15:27.391515623 +0200 ++++ util-linux-2.23.2/libmount/src/utils.c 2013-10-07 11:43:27.209924834 +0200 +@@ -159,7 +159,7 @@ int mnt_chdir_to_parent(const char *targ + if (!last || !*last) + memcpy(*filename, ".", 2); + else +- memcpy(*filename, last, strlen(last) + 1); ++ memmove(*filename, last, strlen(last) + 1); + } else + free(buf); + return 0; diff --git a/SOURCES/2.24-losetup-add-device.patch b/SOURCES/2.24-losetup-add-device.patch new file mode 100644 index 00000000..a9d646cc --- /dev/null +++ b/SOURCES/2.24-losetup-add-device.patch @@ -0,0 +1,62 @@ +diff -up util-linux-2.23.2/include/loopdev.h.kzak util-linux-2.23.2/include/loopdev.h +--- util-linux-2.23.2/include/loopdev.h.kzak 2013-06-13 09:46:10.397650425 +0200 ++++ util-linux-2.23.2/include/loopdev.h 2014-01-14 11:11:48.427643690 +0100 +@@ -149,6 +149,7 @@ extern void loopcxt_enable_debug(struct + extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) + __attribute__ ((warn_unused_result)); + extern int loopcxt_has_device(struct loopdev_cxt *lc); ++extern int loopcxt_add_device(struct loopdev_cxt *lc); + extern char *loopcxt_strdup_device(struct loopdev_cxt *lc); + extern const char *loopcxt_get_device(struct loopdev_cxt *lc); + extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc); +diff -up util-linux-2.23.2/lib/loopdev.c.kzak util-linux-2.23.2/lib/loopdev.c +--- util-linux-2.23.2/lib/loopdev.c.kzak 2013-07-30 11:19:20.143600300 +0200 ++++ util-linux-2.23.2/lib/loopdev.c 2014-01-14 11:11:48.428643700 +0100 +@@ -1298,6 +1298,36 @@ int loopcxt_delete_device(struct loopdev + return 0; + } + ++int loopcxt_add_device(struct loopdev_cxt *lc) ++{ ++ int rc = -EINVAL; ++ int ctl, nr = -1; ++ const char *p, *dev = loopcxt_get_device(lc); ++ ++ if (!dev) ++ goto done; ++ ++ if (!(lc->flags & LOOPDEV_FL_CONTROL)) { ++ rc = -ENOSYS; ++ goto done; ++ } ++ ++ p = strrchr(dev, '/'); ++ if (!p || (sscanf(p, "/loop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1) ++ || nr < 0) ++ goto done; ++ ++ ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC); ++ if (ctl >= 0) { ++ DBG(lc, loopdev_debug("add_device %d", nr)); ++ rc = ioctl(ctl, LOOP_CTL_ADD, nr); ++ close(ctl); ++ } ++done: ++ DBG(lc, loopdev_debug("add_device done [rc=%d]", rc)); ++ return rc; ++} ++ + /* + * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older + * kernels we have to check all loop devices to found unused one. +diff -up util-linux-2.23.2/sys-utils/losetup.c.kzak util-linux-2.23.2/sys-utils/losetup.c +--- util-linux-2.23.2/sys-utils/losetup.c.kzak 2013-07-30 11:20:16.987117853 +0200 ++++ util-linux-2.23.2/sys-utils/losetup.c 2014-01-14 11:11:48.428643700 +0100 +@@ -600,6 +600,8 @@ int main(int argc, char **argv) + { + int hasdev = loopcxt_has_device(&lc); + ++ if (hasdev && !is_loopdev(loopcxt_get_device(&lc))) ++ loopcxt_add_device(&lc); + do { + const char *errpre; diff --git a/SOURCES/2.24-losetup-offset.patch b/SOURCES/2.24-losetup-offset.patch new file mode 100644 index 00000000..936263c0 --- /dev/null +++ b/SOURCES/2.24-losetup-offset.patch @@ -0,0 +1,31 @@ +diff -up util-linux-2.23.2/lib/loopdev.c.kzak util-linux-2.23.2/lib/loopdev.c +--- util-linux-2.23.2/lib/loopdev.c.kzak 2014-09-25 10:16:23.521897462 +0200 ++++ util-linux-2.23.2/lib/loopdev.c 2014-09-25 10:23:38.852050990 +0200 +@@ -1129,6 +1129,12 @@ static int loopcxt_check_size(struct loo + return -errno; + } + ++ /* It's block device, so, align to 512-byte sectors */ ++ if (expected_size % 512) { ++ DBG(lc, loopdev_debug("expected size misaligned to 512-byte sectors")); ++ expected_size = (expected_size >> 9) << 9; ++ } ++ + if (expected_size != size) { + DBG(lc, loopdev_debug("warning: loopdev and expected " + "size dismatch (%ju/%ju)", +diff -up util-linux-2.23.2/sys-utils/losetup.c.kzak util-linux-2.23.2/sys-utils/losetup.c +--- util-linux-2.23.2/sys-utils/losetup.c.kzak 2014-09-25 10:16:23.521897462 +0200 ++++ util-linux-2.23.2/sys-utils/losetup.c 2014-09-25 10:23:38.852050990 +0200 +@@ -632,11 +632,7 @@ int main(int argc, char **argv) + /* errors */ + errpre = hasdev && loopcxt_get_fd(&lc) < 0 ? + loopcxt_get_device(&lc) : file; +- if (errno == ERANGE && offset && offset % 512) +- warnx(_("%s: failed to set up loop device, " +- "offset is not 512-byte aligned."), errpre); +- else +- warn(_("%s: failed to set up loop device"), errpre); ++ warn(_("%s: failed to set up loop device"), errpre); + break; + } while (hasdev == 0); diff --git a/SOURCES/2.24-partx-update.patch b/SOURCES/2.24-partx-update.patch new file mode 100644 index 00000000..16371307 --- /dev/null +++ b/SOURCES/2.24-partx-update.patch @@ -0,0 +1,130 @@ +From 5cc378e4cdeb957b405e0264a09295eda7d75ff7 Mon Sep 17 00:00:00 2001 +From: Scott Moser +Date: Mon, 13 Jan 2014 15:32:49 -0500 +Subject: [PATCH] partx: fix --update ranges and out of order tables + +partx --update DEVICE NUMBER +was broken in 2 cases: + * if NUMBER != 1 + * if the partition table was "out of order". + Ie, where sda2 came after sda3. + +References: https://bugs.launchpad.net/ubuntu/+source/cloud-utils/+bug/1244662 +Signed-off-by: Scott Moser +Signed-off-by: Karel Zak +--- + disk-utils/partx.c | 75 ++++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 50 insertions(+), 25 deletions(-) + +diff --git a/disk-utils/partx.c b/disk-utils/partx.c +index 880d779..df03e59 100644 +--- a/disk-utils/partx.c ++++ b/disk-utils/partx.c +@@ -412,10 +412,41 @@ static void upd_parts_warnx(const char *device, int first, int last) + device, first, last); + } + ++/** ++ * get_partition_by_partno: ++ * @ls: partitions list ++ * @n: the partition number (e.g. 'N' from sda'N') ++ * ++ * This does not assume any order of the input blkid_partlist. ++ * And correctly handles "out of order" partition tables. ++ * partition N is located after partition N+1 on the disk. ++ * ++ * Returns: partition object or NULL in case or error. ++ */ ++blkid_partition get_partition_by_partno(blkid_partlist ls, int n) ++{ ++ int i, nparts; ++ blkid_partition par; ++ if (!ls) ++ return NULL; ++ ++ nparts = blkid_partlist_numof_partitions(ls); ++ if (nparts < 0) ++ return NULL; ++ ++ for (i = 0; i < nparts; i++) { ++ par = blkid_partlist_get_partition(ls, i); ++ if (n == blkid_partition_get_partno(par)) { ++ return par; ++ } ++ } ++ return NULL; ++} ++ + static int upd_parts(int fd, const char *device, dev_t devno, + blkid_partlist ls, int lower, int upper) + { +- int i, n, an, nparts, rc = 0, errfirst = 0, errlast = 0, err; ++ int n, nparts, rc = 0, errfirst = 0, errlast = 0, err; + blkid_partition par; + uintmax_t start, size; + +@@ -441,18 +472,16 @@ static int upd_parts(int fd, const char *device, dev_t devno, + return -1; + } + +- for (i = 0, n = lower; n <= upper; n++) { +- par = blkid_partlist_get_partition(ls, i); +- an = blkid_partition_get_partno(par); +- +- if (lower && n < lower) +- continue; +- if (upper && n > upper) ++ for (n = lower; n <= upper; n++) { ++ par = get_partition_by_partno(ls, n); ++ if (!par) { ++ if (verbose) ++ warn(_("%s: no partition #%d"), device, n); + continue; ++ } + + start = blkid_partition_get_start(par); + size = blkid_partition_get_size(par); +- + if (blkid_partition_is_extended(par)) + /* + * Let's follow the Linux kernel and reduce +@@ -463,25 +492,21 @@ static int upd_parts(int fd, const char *device, dev_t devno, + err = partx_del_partition(fd, n); + if (err == -1 && errno == ENXIO) + err = 0; /* good, it already doesn't exist */ +- if (an == n) ++ if (err == -1 && errno == EBUSY) + { +- if (i < nparts) +- i++; +- if (err == -1 && errno == EBUSY) +- { +- /* try to resize */ +- err = partx_resize_partition(fd, n, start, size); +- if (verbose) +- printf(_("%s: partition #%d resized\n"), device, n); +- if (err == 0) +- continue; +- } +- if (err == 0 && partx_add_partition(fd, n, start, size) == 0) { +- if (verbose) +- printf(_("%s: partition #%d added\n"), device, n); ++ /* try to resize */ ++ err = partx_resize_partition(fd, n, start, size); ++ if (verbose) ++ printf(_("%s: partition #%d resized\n"), device, n); ++ if (err == 0) + continue; +- } + } ++ if (err == 0 && partx_add_partition(fd, n, start, size) == 0) { ++ if (verbose) ++ printf(_("%s: partition #%d added\n"), device, n); ++ continue; ++ } ++ + if (err == 0) + continue; + rc = -1; +-- +1.9.3 diff --git a/SOURCES/2.24-sfdisk-y-n-miscmatch.patch b/SOURCES/2.24-sfdisk-y-n-miscmatch.patch new file mode 100644 index 00000000..6df4db73 --- /dev/null +++ b/SOURCES/2.24-sfdisk-y-n-miscmatch.patch @@ -0,0 +1,15 @@ +diff -up util-linux-2.23.2/fdisks/sfdisk.c.kzak util-linux-2.23.2/fdisks/sfdisk.c +--- util-linux-2.23.2/fdisks/sfdisk.c.kzak 2013-07-30 10:39:26.200738180 +0200 ++++ util-linux-2.23.2/fdisks/sfdisk.c 2013-10-07 11:52:10.701445115 +0200 +@@ -3201,9 +3201,9 @@ do_fdisk(char *dev) { + ignore_result( fgets(answer, sizeof(answer), stdin) ); + if (answer[0] == 'q' || answer[0] == 'Q') { + errx(EXIT_FAILURE, _("Quitting - nothing changed")); +- } else if (rpmatch(answer) == 1) { +- continue; + } else if (rpmatch(answer) == 0) { ++ continue; ++ } else if (rpmatch(answer) == 1) { + break; + } else { + printf(_("Please answer one of y,n,q\n")); diff --git a/SOURCES/2.24-su-fix-lastlog-and-btmp-logging.patch b/SOURCES/2.24-su-fix-lastlog-and-btmp-logging.patch new file mode 100644 index 00000000..db423e1e --- /dev/null +++ b/SOURCES/2.24-su-fix-lastlog-and-btmp-logging.patch @@ -0,0 +1,47 @@ +From 9b5dc4cb8d5d82c31c0cda898832998c21afc303 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 9 Sep 2013 12:24:01 +0200 +Subject: [PATCH] su: fix lastlog and btmp logging + +The su(1) logging code mix ups "old" and "new" passwd structs. The +result is things like + + Sep 9 11:50:45 x2 su: (to kzak) kzak on none + +in /var/log/messages. The right log entry is + + Sep 9 11:50:45 x2 su: (to root) kzak on pts/3 + +The bug has been introduced by commit c74a7af17c7a176c358dfaa8e1814786c89ebc14. + +References: https://bugzilla.redhat.com/show_bug.cgi?id=1005194 +Signed-off-by: Karel Zak +--- + login-utils/su-common.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/login-utils/su-common.c b/login-utils/su-common.c +index ade5c92..858af01 100644 +--- a/login-utils/su-common.c ++++ b/login-utils/su-common.c +@@ -161,7 +161,7 @@ log_syslog(struct passwd const *pw, bool successful) + old_user = pwd ? pwd->pw_name : ""; + } + +- if (get_terminal_name(STDERR_FILENO, NULL, &tty, NULL) == 0 && tty) ++ if (get_terminal_name(STDERR_FILENO, NULL, &tty, NULL) != 0 || !tty) + tty = "none"; + + openlog (program_invocation_short_name, 0 , LOG_AUTH); +@@ -483,9 +483,6 @@ authenticate (const struct passwd *pw) + + done: + +- if (lpw && lpw->pw_name) +- pw = lpw; +- + log_syslog(pw, !is_pam_failure(retval)); + + if (is_pam_failure(retval)) +-- +1.8.1.4 diff --git a/SOURCES/2.24-su-suppress-PAM-info-messages.patch b/SOURCES/2.24-su-suppress-PAM-info-messages.patch new file mode 100644 index 00000000..3b54521e --- /dev/null +++ b/SOURCES/2.24-su-suppress-PAM-info-messages.patch @@ -0,0 +1,48 @@ +diff -up util-linux-2.23.2/login-utils/su-common.c.kzak util-linux-2.23.2/login-utils/su-common.c +--- util-linux-2.23.2/login-utils/su-common.c.kzak 2013-07-30 10:39:26.223738407 +0200 ++++ util-linux-2.23.2/login-utils/su-common.c 2013-09-09 09:32:05.497238691 +0200 +@@ -111,6 +111,9 @@ static int same_session = 0; + /* SU_MODE_{RUNUSER,SU} */ + static int su_mode; + ++/* Don't print PAM info messages (Last login, etc.). */ ++static int suppress_pam_info; ++ + static bool _pam_session_opened; + static bool _pam_cred_established; + static sig_atomic_t volatile caught_signal = false; +@@ -208,10 +211,23 @@ static void log_btmp(struct passwd const + updwtmp(_PATH_BTMP, &ut); + } + ++ ++static int su_pam_conv(int num_msg, const struct pam_message **msg, ++ struct pam_response **resp, void *appdata_ptr) ++{ ++ if (suppress_pam_info ++ && num_msg == 1 ++ && msg ++ && msg[0]->msg_style == PAM_TEXT_INFO) ++ return PAM_SUCCESS; ++ ++ return misc_conv(num_msg, msg, resp, appdata_ptr); ++} ++ + static struct pam_conv conv = + { +- misc_conv, +- NULL ++ su_pam_conv, ++ NULL + }; + + static void +@@ -902,6 +918,9 @@ su_main (int argc, char **argv, int mode + + init_groups (pw, groups, num_supp_groups); + ++ if (!simulate_login || command) ++ suppress_pam_info = 1; /* don't print PAM info messages */ ++ + create_watching_parent (); + /* Now we're in the child. */ diff --git a/SOURCES/2.24-tests-portability.patch b/SOURCES/2.24-tests-portability.patch new file mode 100644 index 00000000..d16d0207 --- /dev/null +++ b/SOURCES/2.24-tests-portability.patch @@ -0,0 +1,37 @@ +diff -up util-linux-2.23.2/tests/functions.sh.kzak util-linux-2.23.2/tests/functions.sh +--- util-linux-2.23.2/tests/functions.sh.kzak 2013-06-13 09:46:10.554651768 +0200 ++++ util-linux-2.23.2/tests/functions.sh 2013-09-09 10:01:23.355469268 +0200 +@@ -483,7 +483,7 @@ function ts_scsi_debug_init { + modprobe scsi_debug $* + [ "$?" == 0 ] || ts_die "Cannot init device" + +- DEVNAME=$(grep scsi_debug /sys/block/*/device/model | awk -F '/' '{print $4}') ++ DEVNAME=$(grep --with-filename scsi_debug /sys/block/*/device/model | awk -F '/' '{print $4}') + [ "x${DEVNAME}" == "x" ] && ts_die "Cannot find device" + + DEVICE="/dev/${DEVNAME}" +diff -up util-linux-2.23.2/tests/ts/cramfs/mkfs.kzak util-linux-2.23.2/tests/ts/cramfs/mkfs +--- util-linux-2.23.2/tests/ts/cramfs/mkfs.kzak 2013-06-13 09:46:10.557651793 +0200 ++++ util-linux-2.23.2/tests/ts/cramfs/mkfs 2013-09-09 10:01:23.355469268 +0200 +@@ -80,7 +80,7 @@ cd $TS_MOUNTPOINT + + ts_log "list the image" + export TZ='GMT-1' +-ls -laR --time-style=long-iso . >> $TS_OUTPUT ++ls -laR --time-style=long-iso . | sed 's:\. : :g' >> $TS_OUTPUT + echo >> $TS_OUTPUT + + ts_log "list checksums from new data" +diff -up util-linux-2.23.2/tests/ts/libmount/context-utab.kzak util-linux-2.23.2/tests/ts/libmount/context-utab +--- util-linux-2.23.2/tests/ts/libmount/context-utab.kzak 2013-06-13 09:46:10.561651827 +0200 ++++ util-linux-2.23.2/tests/ts/libmount/context-utab 2013-09-09 10:01:23.355469268 +0200 +@@ -85,7 +85,9 @@ grep -q $DEVICE $LIBMOUNT_UTAB && \ + echo "umount (mountpoint) failed: found $DEVICE in $LIBMOUNT_UTAB" >> $TS_OUTPUT 2>&1 + ts_finalize_subtest + ++ + if [ -x "/sbin/mkfs.btrfs" ]; then ++ $TS_CMD_WIPEFS -a $DEVICE &> /dev/null + ts_log "Create filesystem [btrfs]" + /sbin/mkfs.btrfs -L "$LABEL" $DEVICE &> /dev/null + udevadm settle diff --git a/SOURCES/2.24-unshare-mount-fork.patch b/SOURCES/2.24-unshare-mount-fork.patch new file mode 100644 index 00000000..a3c8f64a --- /dev/null +++ b/SOURCES/2.24-unshare-mount-fork.patch @@ -0,0 +1,248 @@ +diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am +--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak 2014-09-25 14:16:33.526384729 +0200 ++++ util-linux-2.23.2/sys-utils/Makemodule.am 2014-09-25 14:15:34.861825005 +0200 +@@ -290,6 +290,7 @@ usrbin_exec_PROGRAMS += unshare + dist_man_MANS += sys-utils/unshare.1 + unshare_SOURCES = sys-utils/unshare.c + unshare_LDADD = $(LDADD) libcommon.la ++unshare_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir) + endif + + if BUILD_NSENTER +diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1 +--- util-linux-2.23.2/sys-utils/unshare.1.kzak 2014-09-25 14:14:30.194208005 +0200 ++++ util-linux-2.23.2/sys-utils/unshare.1 2014-09-25 14:15:17.617660476 +0200 +@@ -1,63 +1,82 @@ + .\" Process this file with + .\" groff -man -Tascii lscpu.1 + .\" +-.TH UNSHARE 1 "January 2013" "util-linux" "User Commands" ++.TH UNSHARE 1 "July 2013" "util-linux" "User Commands" + .SH NAME + unshare \- run program with some namespaces unshared from parent + .SH SYNOPSIS + .B unshare + .RI [ options ] +-program ++.I program + .RI [ arguments ] + .SH DESCRIPTION +-Unshares specified namespaces from parent process and then executes specified +-program. Unshareable namespaces are: ++Unshares the indicated namespaces from the parent process and then executes ++the specified program. The namespaces to be unshared are indicated via ++options. Unshareable namespaces are: + .TP + .BR "mount namespace" +-mounting and unmounting filesystems will not affect rest of the system ++Mounting and unmounting filesystems will not affect the rest of the system + (\fBCLONE_NEWNS\fP flag), except for filesystems which are explicitly marked as +-shared (by mount --make-shared). See /proc/self/mountinfo for the shared flags. ++shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP for the ++\fBshared\fP flags). ++ ++It's recommended to use \fBmount --make-rprivate\fP or \fBmount --make-rslave\fP ++after \fBunshare --mount\fP to make sure that mountpoints in the new namespace ++are really unshared from parental namespace. + .TP + .BR "UTS namespace" +-setting hostname, domainname will not affect rest of the system +-(\fBCLONE_NEWUTS\fP flag). ++Setting hostname or domainname will not affect the rest of the system. ++(\fBCLONE_NEWUTS\fP flag) + .TP + .BR "IPC namespace" +-process will have independent namespace for System V message queues, semaphore +-sets and shared memory segments (\fBCLONE_NEWIPC\fP flag). ++The process will have an independent namespace for System V message queues, ++semaphore sets and shared memory segments. (\fBCLONE_NEWIPC\fP flag) + .TP + .BR "network namespace" +-process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall +-rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, sockets +-etc. (\fBCLONE_NEWNET\fP flag). ++The process will have independent IPv4 and IPv6 stacks, IP routing tables, ++firewall rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, ++sockets, etc. (\fBCLONE_NEWNET\fP flag) + .TP + .BR "pid namespace" +-children will have a distinct set of pid to process mappings than their parent. +-(\fBCLONE_NEWPID\fP flag). ++Children will have a distinct set of PID to process mappings from their parent. ++(\fBCLONE_NEWPID\fP flag) + .PP +-See the \fBclone\fR(2) for exact semantics of the flags. ++See \fBclone\fR(2) for the exact semantics of the flags. + .SH OPTIONS + .TP + .BR \-h , " \-\-help" +-Print a help message, +-.TP +-.BR \-m , " \-\-mount" +-Unshare the mount namespace, +-.TP +-.BR \-u , " \-\-uts" +-Unshare the UTS namespace, ++Display help text and exit. + .TP + .BR \-i , " \-\-ipc" +-Unshare the IPC namespace, ++Unshare the IPC namespace. ++.TP ++.BR \-m , " \-\-mount" ++Unshare the mount namespace. + .TP + .BR \-n , " \-\-net" + Unshare the network namespace. + .TP + .BR \-p , " \-\-pid" + Unshare the pid namespace. ++See also the \fB--fork\fP and \fB--mount-proc\fP options. ++.TP ++.BR \-u , " \-\-uts" ++Unshare the UTS namespace. ++.TP ++.BR \-f , " \-\-fork" ++Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than ++running it directly. This is useful when creating a new pid namespace. ++.TP ++.BR \-\-mount-proc "[=\fImountpoint\fP]" ++Just before running the program, mount the proc filesystem at the \fImountpoint\fP ++(default is /proc). This is useful when creating a new pid namespace. It also ++implies creating a new mount namespace since the /proc mount would otherwise ++mess up existing programs on the system. The new proc filesystem is explicitly ++mounted as private (by MS_PRIVATE|MS_REC). + .SH SEE ALSO + .BR unshare (2), +-.BR clone (2) ++.BR clone (2), ++.BR mount (8) + .SH BUGS + None known so far. + .SH AUTHOR +diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c +--- util-linux-2.23.2/sys-utils/unshare.c.kzak 2014-09-25 14:14:30.194208005 +0200 ++++ util-linux-2.23.2/sys-utils/unshare.c 2014-09-25 14:15:34.861825005 +0200 +@@ -24,12 +24,19 @@ + #include + #include + #include ++#include ++#include ++ ++/* we only need some defines missing in sys/mount.h, no libmount linkage */ ++#include + + #include "nls.h" + #include "c.h" +-#include "closestream.h" + #include "namespace.h" + #include "exec_shell.h" ++#include "xalloc.h" ++#include "pathnames.h" ++ + + static void usage(int status) + { +@@ -40,11 +47,13 @@ static void usage(int status) + _(" %s [options] [args...]\n"), program_invocation_short_name); + + fputs(USAGE_OPTIONS, out); +- fputs(_(" -m, --mount unshare mounts namespace\n"), out); +- fputs(_(" -u, --uts unshare UTS namespace (hostname etc)\n"), out); +- fputs(_(" -i, --ipc unshare System V IPC namespace\n"), out); +- fputs(_(" -n, --net unshare network namespace\n"), out); +- fputs(_(" -p, --pid unshare pid namespace\n"), out); ++ fputs(_(" -m, --mount unshare mounts namespace\n"), out); ++ fputs(_(" -u, --uts unshare UTS namespace (hostname etc)\n"), out); ++ fputs(_(" -i, --ipc unshare System V IPC namespace\n"), out); ++ fputs(_(" -n, --net unshare network namespace\n"), out); ++ fputs(_(" -p, --pid unshare pid namespace\n"), out); ++ fputs(_(" -f, --fork fork before launching \n"), out); ++ fputs(_(" --mount-proc[=] mount proc filesystem first (implies --mount)\n"), out); + + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); +@@ -56,6 +65,9 @@ static void usage(int status) + + int main(int argc, char *argv[]) + { ++ enum { ++ OPT_MOUNTPROC = CHAR_MAX + 1 ++ }; + static const struct option longopts[] = { + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'V'}, +@@ -64,20 +76,24 @@ int main(int argc, char *argv[]) + { "ipc", no_argument, 0, 'i' }, + { "net", no_argument, 0, 'n' }, + { "pid", no_argument, 0, 'p' }, ++ { "fork", no_argument, 0, 'f' }, ++ { "mount-proc", optional_argument, 0, OPT_MOUNTPROC }, + { NULL, 0, 0, 0 } + }; + + int unshare_flags = 0; ++ int c, forkit = 0; ++ const char *procmnt = NULL; + +- int c; +- +- setlocale(LC_MESSAGES, ""); ++ setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +- atexit(close_stdout); + +- while ((c = getopt_long(argc, argv, "hVmuinp", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "+fhVmuinp", longopts, NULL)) != -1) { + switch (c) { ++ case 'f': ++ forkit = 1; ++ break; + case 'h': + usage(EXIT_SUCCESS); + case 'V': +@@ -98,6 +114,10 @@ int main(int argc, char *argv[]) + case 'p': + unshare_flags |= CLONE_NEWPID; + break; ++ case OPT_MOUNTPROC: ++ unshare_flags |= CLONE_NEWNS; ++ procmnt = optarg ? optarg : "/proc"; ++ break; + default: + usage(EXIT_FAILURE); + } +@@ -106,6 +126,31 @@ int main(int argc, char *argv[]) + if (-1 == unshare(unshare_flags)) + err(EXIT_FAILURE, _("unshare failed")); + ++ if (forkit) { ++ int status; ++ pid_t pid = fork(); ++ ++ switch(pid) { ++ case -1: ++ err(EXIT_FAILURE, _("fork failed")); ++ case 0: /* child */ ++ break; ++ default: /* parent */ ++ if (waitpid(pid, &status, 0) == -1) ++ err(EXIT_FAILURE, _("waitpid failed")); ++ if (WIFEXITED(status)) ++ return WEXITSTATUS(status); ++ else if (WIFSIGNALED(status)) ++ kill(getpid(), WTERMSIG(status)); ++ err(EXIT_FAILURE, _("child exit failed")); ++ } ++ } ++ ++ if (procmnt && ++ (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 || ++ mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0)) ++ err(EXIT_FAILURE, _("mount %s failed"), procmnt); ++ + if (optind < argc) { + execvp(argv[optind], argv + optind); + err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]); diff --git a/SOURCES/2.24-utmpdump-ipv6.patch b/SOURCES/2.24-utmpdump-ipv6.patch new file mode 100644 index 00000000..5055d997 --- /dev/null +++ b/SOURCES/2.24-utmpdump-ipv6.patch @@ -0,0 +1,56 @@ +diff -up util-linux-2.23.2/login-utils/utmpdump.c.kzak util-linux-2.23.2/login-utils/utmpdump.c +--- util-linux-2.23.2/login-utils/utmpdump.c.kzak 2013-10-07 11:56:02.030191040 +0200 ++++ util-linux-2.23.2/login-utils/utmpdump.c 2013-10-07 12:05:08.671171091 +0200 +@@ -85,11 +85,14 @@ static void xcleanse(char *s, int len) + + static void print_utline(struct utmp ut) + { +- char *addr_string, *time_string; +- struct in_addr in; ++ const char *addr_string, *time_string; ++ char buffer[INET6_ADDRSTRLEN]; ++ ++ if (ut.ut_addr_v6[1] || ut.ut_addr_v6[2] || ut.ut_addr_v6[3]) ++ addr_string = inet_ntop(AF_INET6, &(ut.ut_addr_v6), buffer, sizeof(buffer)); ++ else ++ addr_string = inet_ntop(AF_INET, &(ut.ut_addr_v6), buffer, sizeof(buffer)); + +- in.s_addr = ut.ut_addr; +- addr_string = inet_ntoa(in); + time_string = timetostr(ut.ut_time); + cleanse(ut.ut_id); + cleanse(ut.ut_user); +@@ -97,7 +100,7 @@ static void print_utline(struct utmp ut) + cleanse(ut.ut_host); + + /* pid id user line host addr time */ +- printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15.15s] [%-28.28s]\n", ++ printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15s] [%-28.28s]\n", + ut.ut_type, ut.ut_pid, ut.ut_id, 8, UT_NAMESIZE, ut.ut_user, + 12, UT_LINESIZE, ut.ut_line, 20, UT_HOSTSIZE, ut.ut_host, + addr_string, time_string); +@@ -248,11 +251,10 @@ static int gettok(char *line, char *dest + static void undump(FILE *fp) + { + struct utmp ut; +- char s_addr[16], s_time[29], *linestart, *line; ++ char s_addr[INET6_ADDRSTRLEN + 1], s_time[29], *linestart, *line; + int count = 0; + + line = linestart = xmalloc(1024 * sizeof(*linestart)); +- s_addr[15] = 0; + s_time[28] = 0; + + while (fgets(linestart, 1023, fp)) { +@@ -267,7 +269,10 @@ static void undump(FILE *fp) + line += gettok(line, s_addr, sizeof(s_addr) - 1, 1); + line += gettok(line, s_time, sizeof(s_time) - 1, 0); + +- ut.ut_addr = inet_addr(s_addr); ++ if (strchr(s_addr, '.')) ++ inet_pton(AF_INET, s_addr, &(ut.ut_addr_v6)); ++ else ++ inet_pton(AF_INET6, s_addr, &(ut.ut_addr_v6)); + ut.ut_time = strtotime(s_time); + + ignore_result( fwrite(&ut, sizeof(ut), 1, stdout) ); diff --git a/SOURCES/2.25-blockdev-geom.patch b/SOURCES/2.25-blockdev-geom.patch new file mode 100644 index 00000000..026f1fee --- /dev/null +++ b/SOURCES/2.25-blockdev-geom.patch @@ -0,0 +1,95 @@ +diff -up util-linux-2.23.2/disk-utils/blockdev.c.kzak util-linux-2.23.2/disk-utils/blockdev.c +--- util-linux-2.23.2/disk-utils/blockdev.c.kzak 2015-06-23 11:29:27.818001654 +0200 ++++ util-linux-2.23.2/disk-utils/blockdev.c 2015-06-23 11:29:43.752884860 +0200 +@@ -16,6 +16,7 @@ + #include "blkdev.h" + #include "pathnames.h" + #include "closestream.h" ++#include "sysfs.h" + + struct bdc { + long ioc; /* ioctl code */ +@@ -364,7 +365,7 @@ static void do_commands(int fd, char **a + } + + if (res == -1) { +- perror(bdcms[j].iocname); ++ warn(_("ioctl error on %s"), bdcms[j].iocname); + if (verbose) + printf(_("%s failed.\n"), _(bdcms[j].help)); + exit(EXIT_FAILURE); +@@ -436,7 +437,8 @@ static void report_device(char *device, + int ro, ssz, bsz; + long ra; + unsigned long long bytes; +- struct hd_geometry g; ++ uint64_t start = 0; ++ struct stat st; + + fd = open(device, O_RDONLY | O_NONBLOCK); + if (fd < 0) { +@@ -446,15 +448,27 @@ static void report_device(char *device, + } + + ro = ssz = bsz = 0; +- g.start = ra = 0; ++ ra = 0; ++ if (fstat(fd, &st) == 0 && !sysfs_devno_is_wholedisk(st.st_rdev)) { ++ struct sysfs_cxt cxt; ++ ++ if (sysfs_init(&cxt, st.st_rdev, NULL)) ++ err(EXIT_FAILURE, ++ _("%s: failed to initialize sysfs handler"), ++ device); ++ if (sysfs_read_u64(&cxt, "start", &start)) ++ err(EXIT_FAILURE, ++ _("%s: failed to read partition start from sysfs"), ++ device); ++ sysfs_deinit(&cxt); ++ } + if (ioctl(fd, BLKROGET, &ro) == 0 && + ioctl(fd, BLKRAGET, &ra) == 0 && + ioctl(fd, BLKSSZGET, &ssz) == 0 && + ioctl(fd, BLKBSZGET, &bsz) == 0 && +- ioctl(fd, HDIO_GETGEO, &g) == 0 && + blkdev_get_size(fd, &bytes) == 0) { +- printf("%s %5ld %5d %5d %10ld %15lld %s\n", +- ro ? "ro" : "rw", ra, ssz, bsz, g.start, bytes, device); ++ printf("%s %5ld %5d %5d %10ju %15lld %s\n", ++ ro ? "ro" : "rw", ra, ssz, bsz, start, bytes, device); + } else { + if (!quiet) + warnx(_("ioctl error on %s"), device); +diff -up util-linux-2.23.2/include/sysfs.h.kzak util-linux-2.23.2/include/sysfs.h +--- util-linux-2.23.2/include/sysfs.h.kzak 2015-06-23 11:32:12.709793086 +0200 ++++ util-linux-2.23.2/include/sysfs.h 2015-06-23 11:32:31.909652361 +0200 +@@ -72,6 +72,7 @@ extern int sysfs_is_partition_dirent(DIR + + extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno); ++extern int sysfs_devno_is_wholedisk(dev_t devno); + + extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, + int *c, int *t, int *l); +diff -up util-linux-2.23.2/lib/sysfs.c.kzak util-linux-2.23.2/lib/sysfs.c +--- util-linux-2.23.2/lib/sysfs.c.kzak 2015-06-23 11:31:32.166090250 +0200 ++++ util-linux-2.23.2/lib/sysfs.c 2015-06-23 11:31:59.684888551 +0200 +@@ -638,6 +638,18 @@ err: + return -1; + } + ++/* ++ * Return 0 or 1, or < 0 in case of error ++ */ ++int sysfs_devno_is_wholedisk(dev_t devno) ++{ ++ dev_t disk; ++ ++ if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0) ++ return -1; ++ ++ return devno == disk; ++} + + int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l) + { diff --git a/SOURCES/2.25-dmesg-w.patch b/SOURCES/2.25-dmesg-w.patch new file mode 100644 index 00000000..0735ec89 --- /dev/null +++ b/SOURCES/2.25-dmesg-w.patch @@ -0,0 +1,12 @@ +diff -up util-linux-2.23.2/sys-utils/dmesg.c.kzak util-linux-2.23.2/sys-utils/dmesg.c +--- util-linux-2.23.2/sys-utils/dmesg.c.kzak 2013-07-30 11:22:47.213494455 +0200 ++++ util-linux-2.23.2/sys-utils/dmesg.c 2014-09-24 10:24:49.179371108 +0200 +@@ -991,6 +991,8 @@ static int init_kmsg(struct dmesg_contro + + if (!ctl->follow) + mode |= O_NONBLOCK; ++ else ++ setlinebuf(stdout); + + ctl->kmsg = open("/dev/kmsg", mode); + if (ctl->kmsg < 0) diff --git a/SOURCES/2.25-flock-nfs4.patch b/SOURCES/2.25-flock-nfs4.patch new file mode 100644 index 00000000..8cf92f7f --- /dev/null +++ b/SOURCES/2.25-flock-nfs4.patch @@ -0,0 +1,11 @@ +diff -up util-linux-2.23.2/sys-utils/flock.c.kzak util-linux-2.23.2/sys-utils/flock.c +--- util-linux-2.23.2/sys-utils/flock.c.kzak 2014-03-25 12:00:53.735361387 +0100 ++++ util-linux-2.23.2/sys-utils/flock.c 2014-03-25 12:01:44.534886083 +0100 +@@ -250,6 +250,7 @@ int main(int argc, char *argv[]) + /* otherwise try again */ + continue; + case EIO: ++ case EBADF: /* since Linux 3.4 (commit 55725513) */ + /* Probably NFSv4 where flock() is emulated by fcntl(). + * Let's try to reopen in read-write mode. + */ diff --git a/SOURCES/2.25-fsck-nohelper.patch b/SOURCES/2.25-fsck-nohelper.patch new file mode 100644 index 00000000..5e19c37b --- /dev/null +++ b/SOURCES/2.25-fsck-nohelper.patch @@ -0,0 +1,173 @@ +diff -up util-linux-2.23.2/disk-utils/fsck.c.kzak util-linux-2.23.2/disk-utils/fsck.c +--- util-linux-2.23.2/disk-utils/fsck.c.kzak 2014-03-25 12:52:33.429389852 +0100 ++++ util-linux-2.23.2/disk-utils/fsck.c 2014-03-25 12:56:27.126804792 +0100 +@@ -79,9 +79,7 @@ static const char *really_wanted[] = { + "ext4dev", + "jfs", + "reiserfs", +- "xiafs", +- "xfs", +- NULL ++ "xiafs" + }; + + /* +@@ -167,6 +165,19 @@ static int string_to_int(const char *s) + return (int) l; + } + ++/* Do we really really want to check this fs? */ ++static int fs_check_required(const char *type) ++{ ++ size_t i; ++ ++ for(i = 0; i < ARRAY_SIZE(really_wanted); i++) { ++ if (strcmp(type, really_wanted[i]) == 0) ++ return 1; ++ } ++ ++ return 0; ++} ++ + static int is_mounted(struct libmnt_fs *fs) + { + int rc; +@@ -546,17 +557,17 @@ static void print_stats(struct fsck_inst + * Execute a particular fsck program, and link it into the list of + * child processes we are waiting for. + */ +-static int execute(const char *type, struct libmnt_fs *fs, int interactive) ++static int execute(const char *progname, const char *progpath, ++ const char *type, struct libmnt_fs *fs, int interactive) + { +- char *s, *argv[80], prog[80]; ++ char *argv[80]; + int argc, i; + struct fsck_instance *inst, *p; + pid_t pid; + + inst = xcalloc(1, sizeof(*inst)); + +- sprintf(prog, "fsck.%s", type); +- argv[0] = xstrdup(prog); ++ argv[0] = xstrdup(progname); + argc = 1; + + for (i=0; i pid = pid; +- inst->prog = xstrdup(prog); ++ inst->prog = xstrdup(progname); + inst->type = xstrdup(type); + gettimeofday(&inst->start_time, NULL); + inst->next = NULL; +@@ -822,6 +826,7 @@ static int wait_many(int flags) + */ + static int fsck_device(struct libmnt_fs *fs, int interactive) + { ++ char progname[80], *progpath; + const char *type; + int retval; + +@@ -838,15 +843,27 @@ static int fsck_device(struct libmnt_fs + else + type = DEFAULT_FSTYPE; + ++ sprintf(progname, "fsck.%s", type); ++ progpath = find_fsck(progname); ++ if (progpath == NULL) { ++ if (fs_check_required(type)) { ++ retval = ENOENT; ++ goto err; ++ } ++ return 0; ++ } ++ + num_running++; +- retval = execute(type, fs, interactive); ++ retval = execute(progname, progpath, type, fs, interactive); + if (retval) { +- warnx(_("error %d while executing fsck.%s for %s"), +- retval, type, fs_get_device(fs)); + num_running--; +- return FSCK_EX_ERROR; ++ goto err; + } + return 0; ++err: ++ warnx(_("error %d (%m) while executing fsck.%s for %s"), ++ retval, type, fs_get_device(fs)); ++ return FSCK_EX_ERROR; + } + + +@@ -1014,8 +1031,7 @@ static int fs_ignored_type(struct libmnt + /* Check if we should ignore this filesystem. */ + static int ignore(struct libmnt_fs *fs) + { +- const char **ip, *type; +- int wanted = 0; ++ const char *type; + + /* + * If the pass number is 0, ignore it. +@@ -1070,16 +1086,11 @@ static int ignore(struct libmnt_fs *fs) + if (fs_ignored_type(fs)) + return 1; + +- /* Do we really really want to check this fs? */ +- for(ip = really_wanted; *ip; ip++) +- if (strcmp(type, *ip) == 0) { +- wanted = 1; +- break; +- } ++ + + /* See if the program is available. */ + if (find_fsck(type) == NULL) { +- if (wanted) ++ if (fs_check_required(type)) + warnx(_("cannot check %s: fsck.%s not found"), + fs_get_device(fs), type); + return 1; +@@ -1557,7 +1568,6 @@ int main(int argc, char *argv[]) + fs = add_dummy_fs(devices[i]); + else if (fs_ignored_type(fs)) + continue; +- + if (ignore_mounted && is_mounted(fs)) + continue; + status |= fsck_device(fs, interactive); diff --git a/SOURCES/2.25-fstrim-all.patch b/SOURCES/2.25-fstrim-all.patch new file mode 100644 index 00000000..ea6be509 --- /dev/null +++ b/SOURCES/2.25-fstrim-all.patch @@ -0,0 +1,496 @@ +diff -up util-linux-2.23.2/libmount/src/libmount.h.in.kzak util-linux-2.23.2/libmount/src/libmount.h.in +--- util-linux-2.23.2/libmount/src/libmount.h.in.kzak 2015-06-23 11:54:00.510210784 +0200 ++++ util-linux-2.23.2/libmount/src/libmount.h.in 2015-06-23 11:54:58.592785482 +0200 +@@ -420,6 +420,15 @@ extern int mnt_table_get_root_fs(struct + extern int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, + struct libmnt_fs *fs); + ++enum { ++ MNT_UNIQ_FORWARD = (1 << 1), /* default is backward */ ++ MNT_UNIQ_KEEPTREE = (1 << 2) ++}; ++extern int mnt_table_uniq_fs(struct libmnt_table *tb, int flags, ++ int (*cmp)(struct libmnt_table *, ++ struct libmnt_fs *, ++ struct libmnt_fs *)); ++ + extern struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb, + const char *path, int direction); + extern struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, +diff -up util-linux-2.23.2/libmount/src/libmount.sym.kzak util-linux-2.23.2/libmount/src/libmount.sym +--- util-linux-2.23.2/libmount/src/libmount.sym.kzak 2015-06-23 11:56:47.259989779 +0200 ++++ util-linux-2.23.2/libmount/src/libmount.sym 2015-06-23 11:56:17.681206366 +0200 +@@ -256,3 +256,9 @@ global: + mnt_context_find_umount_fs; + mnt_table_find_mountpoint; + } MOUNT_2.22; ++ ++/* backport from v2.25 to RHEL7 */ ++MOUNT_2.25 { ++ mnt_table_uniq_fs; ++} MOUNT_2.23; ++ +diff -up util-linux-2.23.2/libmount/src/tab.c.kzak util-linux-2.23.2/libmount/src/tab.c +--- util-linux-2.23.2/libmount/src/tab.c.kzak 2015-06-23 11:52:04.750058424 +0200 ++++ util-linux-2.23.2/libmount/src/tab.c 2015-06-23 11:53:26.109462680 +0200 +@@ -398,6 +398,93 @@ int mnt_table_find_next_fs(struct libmnt + return 1; + } + ++static int mnt_table_move_parent(struct libmnt_table *tb, int oldid, int newid) ++{ ++ struct libmnt_iter itr; ++ struct libmnt_fs *fs; ++ ++ if (!tb) ++ return -EINVAL; ++ if (list_empty(&tb->ents)) ++ return 0; ++ ++ ++ mnt_reset_iter(&itr, MNT_ITER_FORWARD); ++ ++ while (mnt_table_next_fs(tb, &itr, &fs) == 0) { ++ if (fs->parent == oldid) ++ fs->parent = newid; ++ } ++ return 0; ++} ++ ++/** ++ * mnt_table_uniq_fs: ++ * @tb: table ++ * @flags: MNT_UNIQ_* ++ * @cmp: function to compare filesystems ++ * ++ * This function de-duplicate the @tb, but does not change order of the ++ * filesystems. The @cmp function has to return 0 if the filesystems are ++ * equal, otherwise non-zero. ++ * ++ * The default is to keep in the table later mounted filesystems (function uses ++ * backward mode iterator). ++ * ++ * @MNT_UNIQ_FORWARD: remove later mounted filesystems ++ * @MNT_UNIQ_KEEPTREE: keep parent->id relation ship stil valid ++ * ++ * Returns: negative number in case of error, or 0 o success. ++ */ ++int mnt_table_uniq_fs(struct libmnt_table *tb, int flags, ++ int (*cmp)(struct libmnt_table *, ++ struct libmnt_fs *, ++ struct libmnt_fs *)) ++{ ++ struct libmnt_iter itr; ++ struct libmnt_fs *fs; ++ int direction = MNT_ITER_BACKWARD; ++ ++ if (!tb || !cmp) ++ return -EINVAL; ++ if (list_empty(&tb->ents)) ++ return 0; ++ ++ if (flags & MNT_UNIQ_FORWARD) ++ direction = MNT_ITER_FORWARD; ++ ++ ++ mnt_reset_iter(&itr, direction); ++ ++ if ((flags & MNT_UNIQ_KEEPTREE) && !is_mountinfo(tb)) ++ flags &= ~MNT_UNIQ_KEEPTREE; ++ ++ while (mnt_table_next_fs(tb, &itr, &fs) == 0) { ++ int want = 1; ++ struct libmnt_iter xtr; ++ struct libmnt_fs *x; ++ ++ mnt_reset_iter(&xtr, direction); ++ while (want && mnt_table_next_fs(tb, &xtr, &x) == 0) { ++ if (fs == x) ++ break; ++ want = cmp(tb, x, fs) != 0; ++ } ++ ++ if (!want) { ++ if (flags & MNT_UNIQ_KEEPTREE) ++ mnt_table_move_parent(tb, mnt_fs_get_id(fs), ++ mnt_fs_get_parent_id(fs)); ++ ++ ++ ++ mnt_table_remove_fs(tb, fs); ++ } ++ } ++ ++ return 0; ++} ++ + /** + * mnt_table_set_iter: + * @tb: tab pointer +diff -up util-linux-2.23.2/sys-utils/fstrim.c.kzak util-linux-2.23.2/sys-utils/fstrim.c +--- util-linux-2.23.2/sys-utils/fstrim.c.kzak 2013-06-13 09:46:10.535651605 +0200 ++++ util-linux-2.23.2/sys-utils/fstrim.c 2015-06-23 11:57:59.435461283 +0200 +@@ -41,6 +41,11 @@ + #include "strutils.h" + #include "c.h" + #include "closestream.h" ++#include "pathnames.h" ++#include "sysfs.h" ++#include "exitcodes.h" ++ ++#include + + #ifndef FITRIM + struct fstrim_range { +@@ -51,16 +56,216 @@ struct fstrim_range { + #define FITRIM _IOWR('X', 121, struct fstrim_range) + #endif + ++/* returns: 0 = success, 1 = unsupported, < 0 = error */ ++static int fstrim_filesystem(const char *path, struct fstrim_range *rangetpl, ++ int verbose) ++{ ++ int fd; ++ struct stat sb; ++ struct fstrim_range range; ++ ++ /* kernel modifies the range */ ++ memcpy(&range, rangetpl, sizeof(range)); ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) { ++ warn(_("cannot open %s"), path); ++ return -1; ++ } ++ if (fstat(fd, &sb) == -1) { ++ warn(_("stat of %s failed"), path); ++ return -1; ++ } ++ if (!S_ISDIR(sb.st_mode)) { ++ warnx(_("%s: not a directory"), path); ++ return -1; ++ } ++ errno = 0; ++ if (ioctl(fd, FITRIM, &range)) { ++ int rc = errno == EOPNOTSUPP || errno == ENOTTY ? 1 : -1; ++ ++ if (rc != 1) ++ warn(_("%s: FITRIM ioctl failed"), path); ++ close(fd); ++ return rc; ++ } ++ ++ if (verbose) { ++ char *str = size_to_human_string( ++ SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE, ++ (uint64_t) range.len); ++ /* TRANSLATORS: The standard value here is a very large number. */ ++ printf(_("%s: %s (%" PRIu64 " bytes) trimmed\n"), ++ path, str, (uint64_t) range.len); ++ free(str); ++ } ++ close(fd); ++ return 0; ++} ++ ++static int has_discard(const char *devname, struct sysfs_cxt *wholedisk) ++{ ++ struct sysfs_cxt cxt, *parent = NULL; ++ uint64_t dg = 0; ++ dev_t disk = 0, dev; ++ int rc; ++ ++ dev = sysfs_devname_to_devno(devname, NULL); ++ if (!dev) ++ return 1; ++ /* ++ * This is tricky to read the info from sys/, because the queue ++ * atrributes are provided for whole devices (disk) only. We're trying ++ * to reuse the whole-disk sysfs context to optimize this stuff (as ++ * system usually have just one disk only). ++ */ ++ if (sysfs_devno_to_wholedisk(dev, NULL, 0, &disk) || !disk) ++ return 1; ++ if (dev != disk) { ++ if (wholedisk->devno != disk) { ++ sysfs_deinit(wholedisk); ++ if (sysfs_init(wholedisk, disk, NULL)) ++ return 1; ++ } ++ parent = wholedisk; ++ } ++ ++ rc = sysfs_init(&cxt, dev, parent); ++ if (!rc) ++ rc = sysfs_read_u64(&cxt, "queue/discard_granularity", &dg); ++ ++ sysfs_deinit(&cxt); ++ return rc == 0 && dg > 0; ++} ++ ++ ++static int uniq_fs_target_cmp( ++ struct libmnt_table *tb __attribute__((__unused__)), ++ struct libmnt_fs *a, ++ struct libmnt_fs *b) ++{ ++ return !mnt_fs_streq_target(a, mnt_fs_get_target(b)); ++} ++ ++static int uniq_fs_source_cmp( ++ struct libmnt_table *tb __attribute__((__unused__)), ++ struct libmnt_fs *a, ++ struct libmnt_fs *b) ++{ ++ int eq; ++ ++ if (mnt_fs_is_pseudofs(a) || mnt_fs_is_netfs(a) || ++ mnt_fs_is_pseudofs(b) || mnt_fs_is_netfs(b)) ++ return 1; ++ ++ eq = mnt_fs_streq_srcpath(a, mnt_fs_get_srcpath(b)); ++ if (eq) { ++ const char *aroot = mnt_fs_get_root(a), ++ *broot = mnt_fs_get_root(b); ++ if (!aroot || !broot) ++ eq = 0; ++ else if (strcmp(aroot, broot) != 0) ++ eq = 0; ++ } ++ ++ return !eq; ++} ++ ++/* ++ * fstrim --all follows "mount -a" return codes: ++ * ++ * 0 = all success ++ * 32 = all failed ++ * 64 = some failed, some success ++ */ ++static int fstrim_all(struct fstrim_range *rangetpl, int verbose) ++{ ++ struct libmnt_fs *fs; ++ struct libmnt_iter *itr; ++ struct libmnt_table *tab; ++ struct sysfs_cxt wholedisk = UL_SYSFSCXT_EMPTY; ++ int cnt = 0, cnt_err = 0; ++ ++ mnt_init_debug(0); ++ ++ itr = mnt_new_iter(MNT_ITER_BACKWARD); ++ if (!itr) ++ err(MOUNT_EX_FAIL, _("failed to initialize libmount iterator")); ++ ++ tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO); ++ if (!tab) ++ err(MOUNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO); ++ ++ /* de-duplicate by mountpoints */ ++ mnt_table_uniq_fs(tab, 0, uniq_fs_target_cmp); ++ ++ /* de-duplicate by source and root */ ++ mnt_table_uniq_fs(tab, 0, uniq_fs_source_cmp); ++ ++ while (mnt_table_next_fs(tab, itr, &fs) == 0) { ++ const char *src = mnt_fs_get_srcpath(fs), ++ *tgt = mnt_fs_get_target(fs); ++ char *path; ++ int rc = 1; ++ ++ if (!src || !tgt || *src != '/' || ++ mnt_fs_is_pseudofs(fs) || ++ mnt_fs_is_netfs(fs)) ++ continue; ++ ++ /* Is it really accessible mountpoint? Not all mountpoints are ++ * accessible (maybe over mounted by another fylesystem) */ ++ path = mnt_get_mountpoint(tgt); ++ if (path && strcmp(path, tgt) == 0) ++ rc = 0; ++ free(path); ++ if (rc) ++ continue; /* overlaying mount */ ++ ++ if (!has_discard(src, &wholedisk)) ++ continue; ++ cnt++; ++ ++ /* ++ * We're able to detect that the device supports discard, but ++ * things also depend on filesystem or device mapping, for ++ * example vfat or LUKS (by default) does not support FSTRIM. ++ * ++ * This is reason why we ignore EOPNOTSUPP and ENOTTY errors ++ * from discard ioctl. ++ */ ++ if (fstrim_filesystem(tgt, rangetpl, verbose) < 0) ++ cnt_err++; ++ } ++ ++ sysfs_deinit(&wholedisk); ++ mnt_free_table(tab); ++ mnt_free_iter(itr); ++ ++ if (cnt && cnt == cnt_err) ++ return MOUNT_EX_FAIL; /* all failed */ ++ if (cnt && cnt_err) ++ return MOUNT_EX_SOMEOK; /* some ok */ ++ ++ return EXIT_SUCCESS; ++} ++ + static void __attribute__((__noreturn__)) usage(FILE *out) + { + fputs(USAGE_HEADER, out); + fprintf(out, + _(" %s [options] \n"), program_invocation_short_name); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Discard unused blocks on a mounted filesystem.\n"), out); ++ + fputs(USAGE_OPTIONS, out); +- fputs(_(" -o, --offset offset in bytes to discard from\n" +- " -l, --length length of bytes to discard from the offset\n" +- " -m, --minimum minimum extent length to discard\n" +- " -v, --verbose print number of discarded bytes\n"), out); ++ fputs(_(" -a, --all trim all mounted filesystems that are supported\n"), out); ++ fputs(_(" -o, --offset the offset in bytes to start discarding from\n"), out); ++ fputs(_(" -l, --length the number of bytes to discard\n"), out); ++ fputs(_(" -m, --minimum the minimum extent length to discard\n"), out); ++ fputs(_(" -v, --verbose print number of discarded bytes\n"), out); ++ + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); +@@ -70,12 +275,12 @@ static void __attribute__((__noreturn__) + + int main(int argc, char **argv) + { +- char *path; +- int c, fd, verbose = 0; ++ char *path = NULL; ++ int c, rc, verbose = 0, all = 0; + struct fstrim_range range; +- struct stat sb; + + static const struct option longopts[] = { ++ { "all", 0, 0, 'a' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "offset", 1, 0, 'o' }, +@@ -93,8 +298,11 @@ int main(int argc, char **argv) + memset(&range, 0, sizeof(range)); + range.len = ULLONG_MAX; + +- while ((c = getopt_long(argc, argv, "hVo:l:m:v", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "ahVo:l:m:v", longopts, NULL)) != -1) { + switch(c) { ++ case 'a': ++ all = 1; ++ break; + case 'h': + usage(stdout); + break; +@@ -122,38 +330,26 @@ int main(int argc, char **argv) + } + } + +- if (optind == argc) +- errx(EXIT_FAILURE, _("no mountpoint specified")); +- +- path = argv[optind++]; ++ if (!all) { ++ if (optind == argc) ++ errx(EXIT_FAILURE, _("no mountpoint specified")); ++ path = argv[optind++]; ++ } + + if (optind != argc) { + warnx(_("unexpected number of arguments")); + usage(stderr); + } + +- if (stat(path, &sb) == -1) +- err(EXIT_FAILURE, _("stat failed %s"), path); +- if (!S_ISDIR(sb.st_mode)) +- errx(EXIT_FAILURE, _("%s: not a directory"), path); +- +- fd = open(path, O_RDONLY); +- if (fd < 0) +- err(EXIT_FAILURE, _("cannot open %s"), path); +- +- if (ioctl(fd, FITRIM, &range)) +- err(EXIT_FAILURE, _("%s: FITRIM ioctl failed"), path); +- +- if (verbose) { +- char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | +- SIZE_SUFFIX_SPACE, +- (uint64_t) range.len); +- /* TRANSLATORS: The standard value here is a very large number. */ +- printf(_("%s: %s (%" PRIu64 " bytes) trimmed\n"), +- path, str, +- (uint64_t) range.len); +- free(str); ++ if (all) ++ rc = fstrim_all(&range, verbose); ++ else { ++ rc = fstrim_filesystem(path, &range, verbose); ++ if (rc == 1) { ++ warnx(_("%s: the discard operation is not supported"), path); ++ rc = EXIT_FAILURE; ++ } + } +- close(fd); +- return EXIT_SUCCESS; ++ ++ return rc; + } +diff -up util-linux-2.23.2/sys-utils/fstrim.service.in.kzak util-linux-2.23.2/sys-utils/fstrim.service +--- util-linux-2.23.2/sys-utils/fstrim.service.in.kzak 2015-06-23 12:02:18.505564273 +0200 ++++ util-linux-2.23.2/sys-utils/fstrim.service.in 2015-06-23 12:02:05.049662802 +0200 +@@ -0,0 +1,6 @@ ++[Unit] ++Description=Discard unused blocks ++ ++[Service] ++Type=oneshot ++ExecStart=@sbindir@/fstrim -a +diff -up util-linux-2.23.2/sys-utils/fstrim.timer.kzak util-linux-2.23.2/sys-utils/fstrim.timer +--- util-linux-2.23.2/sys-utils/fstrim.timer.kzak 2015-06-23 12:02:18.505564273 +0200 ++++ util-linux-2.23.2/sys-utils/fstrim.timer 2015-06-23 12:02:05.049662802 +0200 +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Discard unused blocks once a week ++Documentation=man:fstrim ++ ++[Timer] ++OnCalendar=weekly ++AccuracySec=1h ++Persistent=true ++ ++[Install] ++WantedBy=multi-user.target +diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am +--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak 2015-06-23 11:59:05.803975307 +0200 ++++ util-linux-2.23.2/sys-utils/Makemodule.am 2015-06-23 12:01:18.682002323 +0200 +@@ -68,7 +68,18 @@ fsfreeze_SOURCES = sys-utils/fsfreeze.c + sbin_PROGRAMS += fstrim + dist_man_MANS += sys-utils/fstrim.8 + fstrim_SOURCES = sys-utils/fstrim.c +-fstrim_LDADD = $(LDADD) libcommon.la ++fstrim_LDADD = $(LDADD) libcommon.la libmount.la ++fstrim_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir) ++ ++if HAVE_SYSTEMD ++systemdsystemunit_DATA += \ ++ sys-utils/fstrim.service \ ++ sys-utils/fstrim.timer ++endif ++ ++PATHFILES += sys-utils/fstrim.service ++EXTRA_DIST += sys-utils/fstrim.timer ++ + + sbin_PROGRAMS += blkdiscard + dist_man_MANS += sys-utils/blkdiscard.8 diff --git a/SOURCES/2.25-hwclock-hang.patch b/SOURCES/2.25-hwclock-hang.patch new file mode 100644 index 00000000..76ee6816 --- /dev/null +++ b/SOURCES/2.25-hwclock-hang.patch @@ -0,0 +1,254 @@ +From 4a44a54b3caf77923f0e3f1d5bdf5eda6ef07f62 Mon Sep 17 00:00:00 2001 +From: Chris MacGregor +Date: Thu, 27 Feb 2014 10:40:59 -0800 +Subject: [PATCH] hwclock: fix possible hang and other + set_hardware_clock_exact() issues + +In sys-utils/hwclock.c, set_hardware_clock_exact() has some problems when the +process gets pre-empted (for more than 100ms) before reaching the time for +which it waits: + +1. The "continue" statement causes execution to skip the final tdiff +assignment at the end of the do...while loop, leading to the while condition +using the wrong value of tdiff, and thus always exiting the loop once +newhwtime != sethwtime (e.g., after 1 second). This masks bug # 2, below. + +2. The previously-existing bug is that because it starts over waiting for the +desired time whenever two successive calls to gettimeofday() return values > +100ms apart, the loop will never terminate unless the process holds the CPU +(without losing it for more than 100ms) for at least 500ms. This can happen +on a heavily loaded machine or on a virtual machine (or on a heavily loaded +virtual machine). This has been observed to occur, preventing a machine from +completing the shutdown or reboot process due to a "hwclock --systohc" call in +a shutdown script. + +The new implementation presented in this patch takes a somewhat different +approach, intended to accomplish the same goals: + +It computes the desired target system time (at which the requested hardware +clock time will be applied to the hardware clock), and waits for that time to +arrive. If it misses the time (such as due to being pre-empted for too long), +it recalculates the target time, and increases the tolerance (how late it can +be relative to the target time, and still be "close enough". Thus, if all is +well, the time will be set *very* precisely. On a machine where the hwclock +process is repeatedly pre-empted, it will set the time as precisely as is +possible under the conditions present on that particular machine. In any +case, it will always terminate eventually (and pretty quickly); it will never +hang forever. + +[kzak@redhat.com: - tiny coding style changes] + +Signed-off-by: Chris MacGregor +Signed-off-by: Karel Zak +--- + sys-utils/hwclock.c | 170 ++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 131 insertions(+), 39 deletions(-) + +diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c +index 30660d4..395b5c3 100644 +--- a/sys-utils/hwclock.c ++++ b/sys-utils/hwclock.c +@@ -125,7 +125,7 @@ struct adjtime { + * We are running in debug mode, wherein we put a lot of information about + * what we're doing to standard output. + */ +-bool debug; ++int debug; + + /* Workaround for Award 4.50g BIOS bug: keep the year in a file. */ + bool badyear; +@@ -526,43 +526,141 @@ set_hardware_clock_exact(const time_t sethwtime, + const struct timeval refsystime, + const bool universal, const bool testing) + { +- time_t newhwtime = sethwtime; +- struct timeval beginsystime, nowsystime; +- double tdiff; +- int time_resync = 1; +- + /* +- * Now delay some more until Hardware Clock time newhwtime arrives. +- * The 0.5 s is because the Hardware Clock always sets to your set +- * time plus 500 ms (because it is designed to update to the next +- * second precisely 500 ms after you finish the setting). ++ * The Hardware Clock can only be set to any integer time plus one ++ * half second. The integer time is required because there is no ++ * interface to set or get a fractional second. The additional half ++ * second is because the Hardware Clock updates to the following ++ * second precisely 500 ms (not 1 second!) after you release the ++ * divider reset (after setting the new time) - see description of ++ * DV2, DV1, DV0 in Register A in the MC146818A data sheet (and note ++ * that although that document doesn't say so, real-world code seems ++ * to expect that the SET bit in Register B functions the same way). ++ * That means that, e.g., when you set the clock to 1:02:03, it ++ * effectively really sets it to 1:02:03.5, because it will update to ++ * 1:02:04 only half a second later. Our caller passes the desired ++ * integer Hardware Clock time in sethwtime, and the corresponding ++ * system time (which may have a fractional part, and which may or may ++ * not be the same!) in refsystime. In an ideal situation, we would ++ * then apply sethwtime to the Hardware Clock at refsystime+500ms, so ++ * that when the Hardware Clock ticks forward to sethwtime+1s half a ++ * second later at refsystime+1000ms, everything is in sync. So we ++ * spin, waiting for gettimeofday() to return a time at or after that ++ * time (refsystime+500ms) up to a tolerance value, initially 1ms. If ++ * we miss that time due to being preempted for some other process, ++ * then we increase the margin a little bit (initially 1ms, doubling ++ * each time), add 1 second (or more, if needed to get a time that is ++ * in the future) to both the time for which we are waiting and the ++ * time that we will apply to the Hardware Clock, and start waiting ++ * again. ++ * ++ * For example, the caller requests that we set the Hardware Clock to ++ * 1:02:03, with reference time (current system time) = 6:07:08.250. ++ * We want the Hardware Clock to update to 1:02:04 at 6:07:09.250 on ++ * the system clock, and the first such update will occur 0.500 ++ * seconds after we write to the Hardware Clock, so we spin until the ++ * system clock reads 6:07:08.750. If we get there, great, but let's ++ * imagine the system is so heavily loaded that our process is ++ * preempted and by the time we get to run again, the system clock ++ * reads 6:07:11.990. We now want to wait until the next xx:xx:xx.750 ++ * time, which is 6:07:12.750 (4.5 seconds after the reference time), ++ * at which point we will set the Hardware Clock to 1:02:07 (4 seconds ++ * after the originally requested time). If we do that successfully, ++ * then at 6:07:13.250 (5 seconds after the reference time), the ++ * Hardware Clock will update to 1:02:08 (5 seconds after the ++ * originally requested time), and all is well thereafter. + */ +- do { +- if (time_resync) { +- gettimeofday(&beginsystime, NULL); +- tdiff = time_diff(beginsystime, refsystime); +- newhwtime = sethwtime + (int)(tdiff + 0.5); +- if (debug) +- printf(_ +- ("Time elapsed since reference time has been %.6f seconds.\n" +- "Delaying further to reach the new time.\n"), +- tdiff); +- time_resync = 0; ++ ++ time_t newhwtime = sethwtime; ++ double target_time_tolerance_secs = 0.001; /* initial value */ ++ double tolerance_incr_secs = 0.001; /* initial value */ ++ const double RTC_SET_DELAY_SECS = 0.5; /* 500 ms */ ++ const struct timeval RTC_SET_DELAY_TV = { 0, RTC_SET_DELAY_SECS * 1E6 }; ++ ++ struct timeval targetsystime; ++ struct timeval nowsystime; ++ struct timeval prevsystime = refsystime; ++ double deltavstarget; ++ ++ timeradd(&refsystime, &RTC_SET_DELAY_TV, &targetsystime); ++ ++ while (1) { ++ double ticksize; ++ ++ /* FOR TESTING ONLY: inject random delays of up to 1000ms */ ++ if (debug >= 10) { ++ int usec = random() % 1000000; ++ printf(_("sleeping ~%d usec\n"), usec); ++ usleep(usec); + } + + gettimeofday(&nowsystime, NULL); +- tdiff = time_diff(nowsystime, beginsystime); +- if (tdiff < 0) { +- time_resync = 1; /* probably backward time reset */ +- continue; +- } +- if (tdiff > 0.1) { +- time_resync = 1; /* probably forward time reset */ +- continue; ++ deltavstarget = time_diff(nowsystime, targetsystime); ++ ticksize = time_diff(nowsystime, prevsystime); ++ prevsystime = nowsystime; ++ ++ if (ticksize < 0) { ++ if (debug) ++ printf(_("time jumped backward %.6f seconds " ++ "to %ld.%06d - retargeting\n"), ++ ticksize, (long)nowsystime.tv_sec, ++ (int)nowsystime.tv_usec); ++ /* The retarget is handled at the end of the loop. */ ++ } else if (deltavstarget < 0) { ++ /* deltavstarget < 0 if current time < target time */ ++ if (debug >= 2) ++ printf(_("%ld.%06d < %ld.%06d (%.6f)\n"), ++ (long)nowsystime.tv_sec, ++ (int)nowsystime.tv_usec, ++ (long)targetsystime.tv_sec, ++ (int)targetsystime.tv_usec, ++ deltavstarget); ++ continue; /* not there yet - keep spinning */ ++ } else if (deltavstarget <= target_time_tolerance_secs) { ++ /* Close enough to the target time; done waiting. */ ++ break; ++ } else /* (deltavstarget > target_time_tolerance_secs) */ { ++ /* ++ * We missed our window. Increase the tolerance and ++ * aim for the next opportunity. ++ */ ++ if (debug) ++ printf(_("missed it - %ld.%06d is too far " ++ "past %ld.%06d (%.6f > %.6f)\n"), ++ (long)nowsystime.tv_sec, ++ (int)nowsystime.tv_usec, ++ (long)targetsystime.tv_sec, ++ (int)targetsystime.tv_usec, ++ deltavstarget, ++ target_time_tolerance_secs); ++ target_time_tolerance_secs += tolerance_incr_secs; ++ tolerance_incr_secs *= 2; + } +- beginsystime = nowsystime; +- tdiff = time_diff(nowsystime, refsystime); +- } while (newhwtime == sethwtime + (int)(tdiff + 0.5)); ++ ++ /* ++ * Aim for the same offset (tv_usec) within the second in ++ * either the current second (if that offset hasn't arrived ++ * yet), or the next second. ++ */ ++ if (nowsystime.tv_usec < targetsystime.tv_usec) ++ targetsystime.tv_sec = nowsystime.tv_sec; ++ else ++ targetsystime.tv_sec = nowsystime.tv_sec + 1; ++ } ++ ++ newhwtime = sethwtime ++ + (int)(time_diff(nowsystime, refsystime) ++ - RTC_SET_DELAY_SECS /* don't count this */ ++ + 0.5 /* for rounding */); ++ if (debug) ++ printf(_("%ld.%06d is close enough to %ld.%06d (%.6f < %.6f)\n" ++ "Set RTC to %ld (%ld + %d; refsystime = %ld.%06d)\n"), ++ (long)nowsystime.tv_sec, (int)nowsystime.tv_usec, ++ (long)targetsystime.tv_sec, (int)targetsystime.tv_usec, ++ deltavstarget, target_time_tolerance_secs, ++ (long)newhwtime, (long)sethwtime, ++ (int)(newhwtime - sethwtime), ++ (long)refsystime.tv_sec, (int)refsystime.tv_usec); + + set_hardware_clock(newhwtime, universal, testing); + } +@@ -1636,7 +1734,7 @@ int main(int argc, char **argv) + + switch (c) { + case 'D': +- debug = TRUE; ++ ++debug; + break; + case 'a': + adjust = TRUE; +@@ -1953,10 +2051,4 @@ void __attribute__((__noreturn__)) hwaudit_exit(int status) + * + * hwclock uses this method, and considers the Hardware Clock to have + * infinite precision. +- * +- * TODO: Enhancements needed: +- * +- * - When waiting for whole second boundary in set_hardware_clock_exact, +- * fail if we miss the goal by more than .1 second, as could happen if we +- * get pre-empted (by the kernel dispatcher). + */ +-- +1.9.3 diff --git a/SOURCES/2.25-lib-add-path_strdup.patch b/SOURCES/2.25-lib-add-path_strdup.patch new file mode 100644 index 00000000..c4490db9 --- /dev/null +++ b/SOURCES/2.25-lib-add-path_strdup.patch @@ -0,0 +1,50 @@ +From dd3bc51a539ffdd5c6c6b7d0b20acd1f61bdd337 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 6 Jan 2014 16:48:13 +0100 +Subject: [PATCH] lib/path: add path_strdup() + +Signed-off-by: Karel Zak +--- + include/path.h | 2 ++ + lib/path.c | 13 +++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/include/path.h b/include/path.h +index 615d284..45da692 100644 +--- a/include/path.h ++++ b/include/path.h +@@ -4,6 +4,8 @@ + #include + #include + ++extern char *path_strdup(const char *path, ...) ++ __attribute__ ((__format__ (__printf__, 1, 2))); + extern FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + extern void path_read_str(char *result, size_t len, const char *path, ...) +diff --git a/lib/path.c b/lib/path.c +index 1f7e258..42d321c 100644 +--- a/lib/path.c ++++ b/lib/path.c +@@ -49,6 +49,19 @@ path_vcreate(const char *path, va_list ap) + return pathbuf; + } + ++char * ++path_strdup(const char *path, ...) ++{ ++ const char *p; ++ va_list ap; ++ ++ va_start(ap, path); ++ p = path_vcreate(path, ap); ++ va_end(ap); ++ ++ return p ? strdup(p) : NULL; ++} ++ + static FILE * + path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap) + { +-- +1.8.4.2 diff --git a/SOURCES/2.25-libblkid-Identify-extN-file-system-properly.patch b/SOURCES/2.25-libblkid-Identify-extN-file-system-properly.patch new file mode 100644 index 00000000..317a8ea9 --- /dev/null +++ b/SOURCES/2.25-libblkid-Identify-extN-file-system-properly.patch @@ -0,0 +1,240 @@ +diff -up util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ext.c +--- util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak 2013-06-13 09:46:10.422650639 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/ext.c 2014-01-23 10:28:51.175358545 +0100 +@@ -18,7 +18,6 @@ + #endif + #include + +-#include "linux_version.h" + #include "superblocks.h" + + struct ext2_super_block { +@@ -132,140 +131,11 @@ struct ext2_super_block { + #define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP + + /* +- * Check to see if a filesystem is in /proc/filesystems. +- * Returns 1 if found, 0 if not +- */ +-static int fs_proc_check(const char *fs_name) +-{ +- FILE *f; +- char buf[80], *cp, *t; +- +- f = fopen("/proc/filesystems", "r" UL_CLOEXECSTR); +- if (!f) +- return 0; +- while (!feof(f)) { +- if (!fgets(buf, sizeof(buf), f)) +- break; +- cp = buf; +- if (!isspace(*cp)) { +- while (*cp && !isspace(*cp)) +- cp++; +- } +- while (*cp && isspace(*cp)) +- cp++; +- if ((t = strchr(cp, '\n')) != NULL) +- *t = 0; +- if ((t = strchr(cp, '\t')) != NULL) +- *t = 0; +- if ((t = strchr(cp, ' ')) != NULL) +- *t = 0; +- if (!strcmp(fs_name, cp)) { +- fclose(f); +- return 1; +- } +- } +- fclose(f); +- return (0); +-} +- +-/* +- * Check to see if a filesystem is available as a module +- * Returns 1 if found, 0 if not +- */ +-static int check_for_modules(const char *fs_name) +-{ +-#ifdef __linux__ +- struct utsname uts; +- FILE *f; +- char buf[1024], *cp; +- int namesz; +- +- if (uname(&uts)) +- return 0; +- snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); +- +- f = fopen(buf, "r" UL_CLOEXECSTR); +- if (!f) +- return 0; +- +- namesz = strlen(fs_name); +- +- while (!feof(f)) { +- if (!fgets(buf, sizeof(buf), f)) +- break; +- if ((cp = strchr(buf, ':')) != NULL) +- *cp = 0; +- else +- continue; +- if ((cp = strrchr(buf, '/')) == NULL) +- continue; +- cp++; +- +- if (!strncmp(cp, fs_name, namesz) && +- (!strcmp(cp + namesz, ".ko") || +- !strcmp(cp + namesz, ".ko.gz"))) { +- fclose(f); +- return 1; +- } +- } +- fclose(f); +-#endif /* __linux__ */ +- return 0; +-} +- +-/* + * Starting in 2.6.29, ext4 can be used to support filesystems + * without a journal. + */ + #define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29) + +-static int system_supports_ext2(void) +-{ +- static time_t last_check = 0; +- static int ret = -1; +- time_t now = time(0); +- +- if (ret != -1 || (now - last_check) < 5) +- return ret; +- last_check = now; +- ret = (fs_proc_check("ext2") || check_for_modules("ext2")); +- return ret; +-} +- +-static int system_supports_ext4(void) +-{ +- static time_t last_check = 0; +- static int ret = -1; +- time_t now = time(0); +- +- if (ret != -1 || (now - last_check) < 5) +- return ret; +- last_check = now; +- ret = (fs_proc_check("ext4") || check_for_modules("ext4")); +- return ret; +-} +- +-static int system_supports_ext4dev(void) +-{ +- static time_t last_check = 0; +- static int ret = -1; +- time_t now = time(0); +- +- if (ret != -1 || (now - last_check) < 5) +- return ret; +- last_check = now; +- ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev")); +- return ret; +-} +- +-static int system_supports_ext4_ext2(void) +-{ +-#ifdef __linux__ +- return get_linux_version() >= EXT4_SUPPORTS_EXT2; +-#else +- return 0; +-#endif +-} + /* + * reads superblock and returns: + * fc = feature_compat +@@ -355,15 +225,6 @@ static int probe_ext2(blkid_probe pr, + (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + +- /* +- * If ext2 is not present, but ext4 or ext4dev are, then +- * disclaim we are ext2 +- */ +- if (!system_supports_ext2() && +- (system_supports_ext4() || system_supports_ext4dev()) && +- system_supports_ext4_ext2()) +- return -BLKID_ERR_PARAM; +- + ext_get_info(pr, 2, es); + return 0; + } +@@ -406,34 +267,9 @@ static int probe_ext4dev(blkid_probe pr, + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return -BLKID_ERR_PARAM; + +- /* +- * If the filesystem does not have a journal and ext2 and ext4 +- * is not present, then force this to be detected as an +- * ext4dev filesystem. +- */ +- if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && +- !system_supports_ext2() && !system_supports_ext4() && +- system_supports_ext4dev() && +- system_supports_ext4_ext2()) +- goto force_ext4dev; +- +- /* +- * If the filesystem is marked as OK for use by in-development +- * filesystem code, but ext4dev is not supported, and ext4 is, +- * then don't call ourselves ext4dev, since we should be +- * detected as ext4 in that case. +- * +- * If the filesystem is marked as in use by production +- * filesystem, then it can only be used by ext4 and NOT by +- * ext4dev, so always disclaim we are ext4dev in that case. +- */ +- if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { +- if (!system_supports_ext4dev() && system_supports_ext4()) +- return -BLKID_ERR_PARAM; +- } else ++ if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)) + return -BLKID_ERR_PARAM; + +-force_ext4dev: + ext_get_info(pr, 4, es); + return 0; + } +@@ -452,22 +288,11 @@ static int probe_ext4(blkid_probe pr, + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return -BLKID_ERR_PARAM; + +- /* +- * If the filesystem does not have a journal and ext2 is not +- * present, then force this to be detected as an ext2 +- * filesystem. +- */ +- if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && +- !system_supports_ext2() && system_supports_ext4() && +- system_supports_ext4_ext2()) +- goto force_ext4; +- + /* Ext4 has at least one feature which ext3 doesn't understand */ + if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && + !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + +-force_ext4: + /* + * If the filesystem is a OK for use by in-development + * filesystem code, and ext4dev is supported or ext4 is not +@@ -478,10 +303,8 @@ force_ext4: + * filesystem, then it can only be used by ext4 and NOT by + * ext4dev. + */ +- if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { +- if (system_supports_ext4dev() || !system_supports_ext4()) +- return -BLKID_ERR_PARAM; +- } ++ if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) ++ return -BLKID_ERR_PARAM; + + ext_get_info(pr, 4, es); + return 0; diff --git a/SOURCES/2.25-libblkid-detect-alone-PMBR.patch b/SOURCES/2.25-libblkid-detect-alone-PMBR.patch new file mode 100644 index 00000000..d3e20d8f --- /dev/null +++ b/SOURCES/2.25-libblkid-detect-alone-PMBR.patch @@ -0,0 +1,100 @@ +diff -up util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak util-linux-2.23.2/libblkid/src/partitions/gpt.c +--- util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak 2013-07-30 10:39:26.206738239 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/gpt.c 2014-01-23 11:06:17.364011293 +0100 +@@ -156,13 +156,15 @@ static int last_lba(blkid_probe pr, uint + * Note that the PMBR detection is optional (enabled by default) and could be + * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()). + */ +-static int is_pmbr_valid(blkid_probe pr) ++static int is_pmbr_valid(blkid_probe pr, int *has) + { + int flags = blkid_partitions_get_flags(pr); + unsigned char *data; + struct dos_partition *p; + int i; + ++ if (has) ++ *has = 0; + if (flags & BLKID_PARTS_FORCE_GPT) + goto ok; /* skip PMBR check */ + +@@ -182,6 +184,8 @@ static int is_pmbr_valid(blkid_probe pr) + failed: + return 0; + ok: ++ if (has) ++ *has = 1; + return 1; + } + +@@ -305,7 +309,7 @@ static int probe_gpt_pt(blkid_probe pr, + if (last_lba(pr, &lastlba)) + goto nothing; + +- if (!is_pmbr_valid(pr)) ++ if (!is_pmbr_valid(pr, NULL)) + goto nothing; + + h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba); +@@ -410,3 +414,39 @@ const struct blkid_idinfo gpt_pt_idinfo + .magics = BLKID_NONE_MAGIC + }; + ++ ++ ++/* probe for *alone* protective MBR */ ++static int probe_pmbr_pt(blkid_probe pr, ++ const struct blkid_idmag *mag __attribute__((__unused__))) ++{ ++ int has = 0; ++ struct gpt_entry *e; ++ uint64_t lastlba = 0; ++ struct gpt_header hdr; ++ ++ if (last_lba(pr, &lastlba)) ++ goto nothing; ++ ++ is_pmbr_valid(pr, &has); ++ if (!has) ++ goto nothing; ++ ++ if (!get_gpt_header(pr, &hdr, &e, GPT_PRIMARY_LBA, lastlba) && ++ !get_gpt_header(pr, &hdr, &e, lastlba, lastlba)) ++ return 0; ++nothing: ++ return 1; ++} ++ ++const struct blkid_idinfo pmbr_pt_idinfo = ++{ ++ .name = "PMBR", ++ .probefunc = probe_pmbr_pt, ++ .magics = ++ { ++ { .magic = "\x55\xAA", .len = 2, .sboff = 510 }, ++ { NULL } ++ } ++}; ++ +diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c +--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak 2013-07-30 10:39:26.207738249 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c 2014-01-23 11:06:17.364011293 +0100 +@@ -125,6 +125,7 @@ static const struct blkid_idinfo *idinfo + &sun_pt_idinfo, + &dos_pt_idinfo, + &gpt_pt_idinfo, ++ &pmbr_pt_idinfo, /* always after GPT */ + &mac_pt_idinfo, + &ultrix_pt_idinfo, + &bsd_pt_idinfo, +diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.h.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.h +--- util-linux-2.23.2/libblkid/src/partitions/partitions.h.kzak 2013-07-30 10:39:26.208738259 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/partitions.h 2014-01-23 11:06:17.364011293 +0100 +@@ -59,6 +59,7 @@ extern const struct blkid_idinfo mac_pt_ + extern const struct blkid_idinfo dos_pt_idinfo; + extern const struct blkid_idinfo minix_pt_idinfo; + extern const struct blkid_idinfo gpt_pt_idinfo; ++extern const struct blkid_idinfo pmbr_pt_idinfo; + extern const struct blkid_idinfo ultrix_pt_idinfo; + + #endif /* BLKID_PARTITIONS_H */ diff --git a/SOURCES/2.25-libblkid-gpt-512.patch b/SOURCES/2.25-libblkid-gpt-512.patch new file mode 100644 index 00000000..b89945d8 --- /dev/null +++ b/SOURCES/2.25-libblkid-gpt-512.patch @@ -0,0 +1,21 @@ +diff -up util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak util-linux-2.23.2/libblkid/src/partitions/gpt.c +--- util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak 2014-09-25 10:36:26.761377688 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/gpt.c 2014-09-25 10:36:56.912665364 +0200 +@@ -332,7 +332,7 @@ static int probe_gpt_pt(blkid_probe pr, + + blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8); + +- if (blkid_probe_set_magic(pr, lba << 9, ++ if (blkid_probe_set_magic(pr, blkid_probe_get_sectorsize(pr) * lba, + sizeof(GPT_HEADER_SIGNATURE_STR) - 1, + (unsigned char *) GPT_HEADER_SIGNATURE_STR)) + goto err; +@@ -345,7 +345,8 @@ static int probe_gpt_pt(blkid_probe pr, + if (!ls) + goto err; + +- tab = blkid_partlist_new_parttable(ls, "gpt", lba << 9); ++ tab = blkid_partlist_new_parttable(ls, "gpt", ++ blkid_probe_get_sectorsize(pr) * lba); + if (!tab) + goto err; diff --git a/SOURCES/2.25-libblkid-io-errors.patch b/SOURCES/2.25-libblkid-io-errors.patch new file mode 100644 index 00000000..d15c0071 --- /dev/null +++ b/SOURCES/2.25-libblkid-io-errors.patch @@ -0,0 +1,2590 @@ +diff -up util-linux-2.23.2/libblkid/src/blkidP.h.kzak util-linux-2.23.2/libblkid/src/blkidP.h +--- util-linux-2.23.2/libblkid/src/blkidP.h.kzak 2014-03-28 15:11:18.334283704 +0100 ++++ util-linux-2.23.2/libblkid/src/blkidP.h 2014-03-28 15:11:44.676551975 +0100 +@@ -297,6 +297,9 @@ struct blkid_struct_cache + /* old systems */ + #define BLKID_CACHE_FILE_OLD "/etc/blkid.tab" + ++#define BLKID_PROBE_OK 0 ++#define BLKID_PROBE_NONE 1 ++ + #define BLKID_ERR_IO 5 + #define BLKID_ERR_PROC 9 + #define BLKID_ERR_MEM 12 +diff -up util-linux-2.23.2/libblkid/src/partitions/aix.c.kzak util-linux-2.23.2/libblkid/src/partitions/aix.c +--- util-linux-2.23.2/libblkid/src/partitions/aix.c.kzak 2013-05-30 15:21:43.120591308 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/aix.c 2014-03-28 15:11:44.676551975 +0100 +@@ -22,19 +22,17 @@ static int probe_aix_pt(blkid_probe pr, + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ return BLKID_PROBE_NONE; + + tab = blkid_partlist_new_parttable(ls, "aix", 0); + if (!tab) +- goto err; ++ return -ENOMEM; + +- return 0; +-err: +- return -1; ++ return BLKID_PROBE_OK; + } + + /* +diff -up util-linux-2.23.2/libblkid/src/partitions/bsd.c.kzak util-linux-2.23.2/libblkid/src/partitions/bsd.c +--- util-linux-2.23.2/libblkid/src/partitions/bsd.c.kzak 2013-07-15 10:25:46.283049056 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/bsd.c 2014-03-28 15:11:44.677551986 +0100 +@@ -113,20 +113,24 @@ static int probe_bsd_pt(blkid_probe pr, + blkid_partlist ls; + int i, nparts = BSD_MAXPARTITIONS; + unsigned char *data; ++ int rc = BLKID_PROBE_NONE; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return rc; + + data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag)); +- if (!data) ++ if (!data) { ++ if (errno) ++ rc = -errno; + goto nothing; ++ } + + l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag); + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + /* try to determine the real type of BSD system according to + * (parental) primary partition */ +@@ -152,8 +156,10 @@ static int probe_bsd_pt(blkid_probe pr, + } + + tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag)); +- if (!tab) +- goto err; ++ if (!tab) { ++ rc = -ENOMEM; ++ goto nothing; ++ } + + if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS) + nparts = le16_to_cpu(l->d_npartitions); +@@ -189,18 +195,18 @@ static int probe_bsd_pt(blkid_probe pr, + } + + par = blkid_partlist_add_partition(ls, tab, start, size); +- if (!par) +- goto err; ++ if (!par) { ++ rc = -ENOMEM; ++ goto nothing; ++ } + + blkid_partition_set_type(par, p->p_fstype); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; +-err: +- return -1; ++ return rc; + } + + +diff -up util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak util-linux-2.23.2/libblkid/src/partitions/dos.c +--- util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak 2013-07-30 10:39:26.205738229 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/dos.c 2014-03-28 15:13:23.220555797 +0100 +@@ -53,10 +53,13 @@ static int parse_dos_extended(blkid_prob + uint32_t start, size; + + if (++ct_nodata > 100) +- return 0; ++ return BLKID_PROBE_OK; + data = blkid_probe_get_sector(pr, cur_start); +- if (!data) ++ if (!data) { ++ if (errno) ++ return -errno; + goto leave; /* malformed partition? */ ++ } + + if (!is_valid_mbr_signature(data)) + goto leave; +@@ -99,7 +102,7 @@ static int parse_dos_extended(blkid_prob + + par = blkid_partlist_add_partition(ls, tab, abs_start, size); + if (!par) +- goto err; ++ return -ENOMEM; + + blkid_partition_set_type(par, p->sys_type); + blkid_partition_set_flags(par, p->boot_ind); +@@ -123,9 +126,7 @@ static int parse_dos_extended(blkid_prob + cur_size = size; + } + leave: +- return 0; +-err: +- return -1; ++ return BLKID_PROBE_OK; + } + + static int probe_dos_pt(blkid_probe pr, +@@ -140,8 +141,11 @@ static int probe_dos_pt(blkid_probe pr, + uint32_t start, size, id; + + data = blkid_probe_get_sector(pr, 0); +- if (!data) ++ if (!data) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + /* ignore disks with AIX magic number -- for more details see aix.c */ + if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0) +@@ -152,7 +156,7 @@ static int probe_dos_pt(blkid_probe pr, + * either the boot sector of a FAT filesystem or a DOS-type + * partition table. + */ +- if (blkid_probe_is_vfat(pr)) { ++ if (blkid_probe_is_vfat(pr) == 1) { + DBG(LOWPROBE, blkid_debug("probably FAT -- ignore")); + goto nothing; + } +@@ -189,6 +193,8 @@ static int probe_dos_pt(blkid_probe pr, + return 0; + + ls = blkid_probe_get_partlist(pr); ++ if (!ls) ++ goto nothing; + + /* sector size factor (the start and size are in the real sectors, but + * we need to convert all sizes to 512 logical sectors +@@ -198,7 +204,7 @@ static int probe_dos_pt(blkid_probe pr, + /* allocate a new partition table */ + tab = blkid_partlist_new_parttable(ls, "dos", BLKID_MSDOS_PT_OFFSET); + if (!tab) +- goto err; ++ return -ENOMEM; + + id = dos_parttable_id(data); + if (id) { +@@ -224,7 +230,7 @@ static int probe_dos_pt(blkid_probe pr, + } + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) +- goto err; ++ return -ENOMEM; + + blkid_partition_set_type(par, p->sys_type); + blkid_partition_set_flags(par, p->boot_ind); +@@ -244,13 +250,14 @@ static int probe_dos_pt(blkid_probe pr, + continue; + if (is_extended(p) && + parse_dos_extended(pr, tab, start, size, ssf) == -1) +- goto err; ++ goto nothing; + } + + /* Parse subtypes (nested partitions) on large disks */ + if (!blkid_probe_is_tiny(pr)) { + for (p = p0, i = 0; i < 4; i++, p++) { + size_t n; ++ int rc; + + if (!dos_partition_size(p) || is_extended(p)) + continue; +@@ -259,20 +266,19 @@ static int probe_dos_pt(blkid_probe pr, + if (dos_nested[n].type != p->sys_type) + continue; + +- if (blkid_partitions_do_subprobe(pr, ++ rc = blkid_partitions_do_subprobe(pr, + blkid_partlist_get_partition(ls, i), +- dos_nested[n].id) == -1) +- goto err; ++ dos_nested[n].id); ++ if (rc < 0) ++ return rc; + break; + } + } + } +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; +-err: +- return -1; ++ return BLKID_PROBE_NONE; + } + + +diff -up util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak util-linux-2.23.2/libblkid/src/partitions/gpt.c +--- util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak 2014-03-28 15:11:18.336283724 +0100 ++++ util-linux-2.23.2/libblkid/src/partitions/gpt.c 2014-03-28 15:11:44.677551986 +0100 +@@ -169,8 +169,11 @@ static int is_pmbr_valid(blkid_probe pr, + goto ok; /* skip PMBR check */ + + data = blkid_probe_get_sector(pr, 0); +- if (!data) ++ if (!data) { ++ if (errno) ++ return -errno; + goto failed; ++ } + + if (!is_valid_mbr_signature(data)) + goto failed; +@@ -305,19 +308,27 @@ static int probe_gpt_pt(blkid_probe pr, + uint64_t fu, lu; + uint32_t ssf, i; + efi_guid_t guid; ++ int ret; + + if (last_lba(pr, &lastlba)) + goto nothing; + +- if (!is_pmbr_valid(pr, NULL)) ++ ret = is_pmbr_valid(pr, NULL); ++ if (ret < 0) ++ return ret; ++ else if (ret == 0) + goto nothing; + ++ errno = 0; + h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba); +- if (!h) ++ if (!h && !errno) + h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba); + +- if (!h) ++ if (!h) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8); + +@@ -388,12 +399,13 @@ static int probe_gpt_pt(blkid_probe pr, + blkid_partition_set_flags(par, e->attributes); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; ++ + err: +- return -1; ++ return -ENOMEM; + } + + +diff -up util-linux-2.23.2/libblkid/src/partitions/mac.c.kzak util-linux-2.23.2/libblkid/src/partitions/mac.c +--- util-linux-2.23.2/libblkid/src/partitions/mac.c.kzak 2013-06-13 09:46:10.418650605 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/mac.c 2014-03-28 15:11:44.677551986 +0100 +@@ -87,8 +87,11 @@ static int probe_mac_pt(blkid_probe pr, + * the first block on the disk. + */ + md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0); +- if (!md) ++ if (!md) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + block_size = be16_to_cpu(md->block_size); + +@@ -96,8 +99,11 @@ static int probe_mac_pt(blkid_probe pr, + * the second block on the disk. + */ + p = (struct mac_partition *) get_mac_block(pr, block_size, 1); +- if (!p) ++ if (!p) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + /* check the first partition signature */ + if (!has_part_signature(p)) +@@ -109,7 +115,7 @@ static int probe_mac_pt(blkid_probe pr, + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + tab = blkid_partlist_new_parttable(ls, "mac", 0); + if (!tab) +@@ -124,15 +130,18 @@ static int probe_mac_pt(blkid_probe pr, + uint32_t size; + + p = (struct mac_partition *) get_mac_block(pr, block_size, i); +- if (!p) ++ if (!p) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + if (!has_part_signature(p)) + goto nothing; + + if (be32_to_cpu(p->map_count) != nblks) { + DBG(LOWPROBE, blkid_debug( + "mac: inconsisten map_count in partition map, " +- "entry[0]: %d, entry[%d]: %d", ++ "entry[0]: %d, entry[%d]: %d", + nblks, i - 1, + be32_to_cpu(p->map_count))); + } +@@ -157,12 +166,12 @@ static int probe_mac_pt(blkid_probe pr, + sizeof(p->type)); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + /* +diff -up util-linux-2.23.2/libblkid/src/partitions/minix.c.kzak util-linux-2.23.2/libblkid/src/partitions/minix.c +--- util-linux-2.23.2/libblkid/src/partitions/minix.c.kzak 2013-07-15 10:25:46.284049064 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/minix.c 2014-03-28 15:36:23.866715100 +0100 +@@ -26,12 +26,15 @@ static int probe_minix_pt(blkid_probe pr + int i; + + data = blkid_probe_get_sector(pr, 0); +- if (!data) ++ if (!data) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + /* Parent is required, because Minix uses the same PT as DOS and + * difference is only in primary partition (parent) type. +@@ -78,12 +81,12 @@ static int probe_minix_pt(blkid_probe pr + blkid_partition_set_flags(par, p->boot_ind); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + /* same as DOS */ +diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c +--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak 2014-03-28 15:11:18.336283724 +0100 ++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c 2014-03-28 15:12:28.036993622 +0100 +@@ -533,12 +533,13 @@ static int idinfo_probe(blkid_probe pr, + { + const struct blkid_idmag *mag = NULL; + blkid_loff_t off; +- int rc = 1; /* = nothing detected */ ++ int rc = BLKID_PROBE_NONE; /* = nothing detected */ + + if (pr->size <= 0 || (id->minsz && id->minsz > pr->size)) + goto nothing; /* the device is too small */ + +- if (blkid_probe_get_idmag(pr, id, &off, &mag)) ++ rc = blkid_probe_get_idmag(pr, id, &off, &mag); ++ if (rc != BLKID_PROBE_OK) + goto nothing; + + /* final check by probing function */ +@@ -546,14 +547,15 @@ static int idinfo_probe(blkid_probe pr, + DBG(LOWPROBE, blkid_debug( + "%s: ---> call probefunc()", id->name)); + rc = id->probefunc(pr, mag); +- if (rc == -1) { ++ if (rc < 0) { + /* reset after error */ + reset_partlist(blkid_probe_get_partlist(pr)); + if (chn && !chn->binary) + blkid_probe_chain_reset_vals(pr, chn); +- DBG(LOWPROBE, blkid_debug("%s probefunc failed", id->name)); ++ DBG(LOWPROBE, blkid_debug("%s probefunc failed, rc %d", ++ id->name, rc)); + } +- if (rc == 0 && mag && chn && !chn->binary) ++ if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary) + rc = blkid_probe_set_magic(pr, off, mag->len, + (unsigned char *) mag->magic); + +@@ -569,11 +571,11 @@ nothing: + */ + static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) + { +- int rc = 1; ++ int rc = BLKID_PROBE_NONE; + size_t i; + + if (!pr || chn->idx < -1) +- return -1; ++ return -EINVAL; + blkid_probe_chain_reset_vals(pr, chn); + + if (chn->binary) +@@ -597,7 +599,10 @@ static int partitions_probe(blkid_probe + continue; + + /* apply checks from idinfo */ +- if (idinfo_probe(pr, idinfos[i], chn) != 0) ++ rc = idinfo_probe(pr, idinfos[i], chn); ++ if (rc < 0) ++ break; ++ if (rc != BLKID_PROBE_OK) + continue; + + name = idinfos[i]->name; +@@ -613,20 +618,21 @@ static int partitions_probe(blkid_probe + break; + } + +- if (rc == 1) { +- DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed) [PARTS idx=%d]", +- chn->idx)); ++ if (rc != BLKID_PROBE_OK) { ++ DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]", ++ rc, chn->idx)); + } + + details_only: + /* + * Gather PART_ENTRY_* values if the current device is a partition. + */ +- if (!chn->binary && ++ if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary && + (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) { + +- if (!blkid_partitions_probe_partition(pr)) +- rc = 0; ++ int xrc = blkid_partitions_probe_partition(pr); ++ if (xrc < 0) ++ rc = xrc; /* optional, care about errors only */ + } + + return rc; +@@ -637,7 +643,7 @@ int blkid_partitions_do_subprobe(blkid_p + const struct blkid_idinfo *id) + { + blkid_probe prc; +- int rc = 1; ++ int rc; + blkid_partlist ls; + blkid_loff_t sz, off; + +@@ -646,7 +652,7 @@ int blkid_partitions_do_subprobe(blkid_p + id->name, parent)); + + if (!pr || !parent || !parent->size) +- return -1; ++ return -EINVAL; + + /* range defined by parent */ + sz = ((blkid_loff_t) parent->size) << 9; +@@ -656,13 +662,13 @@ int blkid_partitions_do_subprobe(blkid_p + DBG(LOWPROBE, blkid_debug( + "ERROR: parts: <---- '%s' subprobe: overflow detected.", + id->name)); +- return -1; ++ return -ENOSPC; + } + + /* create private prober */ + prc = blkid_clone_probe(pr); + if (!prc) +- return -1; ++ return -ENOMEM; + + blkid_probe_set_dimension(prc, off, sz); + +@@ -695,7 +701,7 @@ int blkid_partitions_do_subprobe(blkid_p + + static int blkid_partitions_probe_partition(blkid_probe pr) + { +- int rc = 1; ++ int rc = BLKID_PROBE_NONE; + blkid_probe disk_pr = NULL; + blkid_partlist ls; + blkid_partition par; +@@ -761,7 +767,7 @@ static int blkid_partitions_probe_partit + blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u", + major(disk), minor(disk)); + } +- rc = 0; ++ rc = BLKID_PROBE_OK; + nothing: + return rc; + } +diff -up util-linux-2.23.2/libblkid/src/partitions/sgi.c.kzak util-linux-2.23.2/libblkid/src/partitions/sgi.c +--- util-linux-2.23.2/libblkid/src/partitions/sgi.c.kzak 2013-07-15 10:25:46.285049072 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/sgi.c 2014-03-28 15:11:44.677551986 +0100 +@@ -99,8 +99,11 @@ static int probe_sgi_pt(blkid_probe pr, + int i; + + l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0); +- if (!l) ++ if (!l) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + if (count_checksum(l)) { + DBG(LOWPROBE, blkid_debug( +@@ -110,11 +113,11 @@ static int probe_sgi_pt(blkid_probe pr, + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + tab = blkid_partlist_new_parttable(ls, "sgi", 0); + if (!tab) +@@ -138,12 +141,12 @@ static int probe_sgi_pt(blkid_probe pr, + blkid_partition_set_type(par, type); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + const struct blkid_idinfo sgi_pt_idinfo = +diff -up util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c.kzak util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c +--- util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c.kzak 2013-06-13 09:46:10.418650605 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c 2014-03-28 15:11:44.677551986 +0100 +@@ -69,8 +69,11 @@ static int probe_solaris_pt(blkid_probe + uint16_t nparts; + + l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR); +- if (!l) ++ if (!l) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + if (le32_to_cpu(l->v_version) != 1) { + DBG(LOWPROBE, blkid_debug( +@@ -81,11 +84,11 @@ static int probe_solaris_pt(blkid_probe + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + parent = blkid_partlist_get_parent(ls); + +@@ -126,12 +129,12 @@ static int probe_solaris_pt(blkid_probe + blkid_partition_set_flags(par, le16_to_cpu(p->s_flag)); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + const struct blkid_idinfo solaris_x86_pt_idinfo = +diff -up util-linux-2.23.2/libblkid/src/partitions/sun.c.kzak util-linux-2.23.2/libblkid/src/partitions/sun.c +--- util-linux-2.23.2/libblkid/src/partitions/sun.c.kzak 2013-06-13 09:46:10.419650613 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/sun.c 2014-03-28 15:11:44.678551996 +0100 +@@ -27,8 +27,11 @@ static int probe_sun_pt(blkid_probe pr, + int i, use_vtoc; + + l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0); +- if (!l) ++ if (!l) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + if (sun_pt_checksum(l)) { + DBG(LOWPROBE, blkid_debug( +@@ -38,11 +41,11 @@ static int probe_sun_pt(blkid_probe pr, + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + tab = blkid_partlist_new_parttable(ls, "sun", 0); + if (!tab) +@@ -76,7 +79,7 @@ static int probe_sun_pt(blkid_probe pr, + uint16_t type = 0, flags = 0; + blkid_partition par; + +- start = be32_to_cpu(p->start_cylinder) * spc; ++ start = be32_to_cpu(p->start_cylinder) * spc; + size = be32_to_cpu(p->num_sectors); + if (use_vtoc) { + type = be16_to_cpu(l->vtoc.infos[i].id); +@@ -96,12 +99,12 @@ static int probe_sun_pt(blkid_probe pr, + if (flags) + blkid_partition_set_flags(par, flags); + } +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + +diff -up util-linux-2.23.2/libblkid/src/partitions/ultrix.c.kzak util-linux-2.23.2/libblkid/src/partitions/ultrix.c +--- util-linux-2.23.2/libblkid/src/partitions/ultrix.c.kzak 2013-05-30 15:21:43.127591380 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/ultrix.c 2014-03-28 15:11:44.678551996 +0100 +@@ -44,8 +44,11 @@ static int probe_ultrix_pt(blkid_probe p + int i; + + data = blkid_probe_get_sector(pr, ULTRIX_SECTOR); +- if (!data) ++ if (!data) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET); + +@@ -59,11 +62,11 @@ static int probe_ultrix_pt(blkid_probe p + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + tab = blkid_partlist_new_parttable(ls, "ultrix", 0); + if (!tab) +@@ -80,11 +83,11 @@ static int probe_ultrix_pt(blkid_probe p + } + } + +- return 0; ++ return BLKID_PROBE_OK; + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + const struct blkid_idinfo ultrix_pt_idinfo = +diff -up util-linux-2.23.2/libblkid/src/partitions/unixware.c.kzak util-linux-2.23.2/libblkid/src/partitions/unixware.c +--- util-linux-2.23.2/libblkid/src/partitions/unixware.c.kzak 2013-06-13 09:46:10.419650613 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/unixware.c 2014-03-28 15:11:44.678551996 +0100 +@@ -106,19 +106,22 @@ static int probe_unixware_pt(blkid_probe + + l = (struct unixware_disklabel *) + blkid_probe_get_sector(pr, UNIXWARE_SECTOR); +- if (!l) ++ if (!l) { ++ if (errno) ++ return -errno; + goto nothing; ++ } + + if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC) + goto nothing; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ +- return 0; ++ return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) +- goto err; ++ goto nothing; + + parent = blkid_partlist_get_parent(ls); + +@@ -161,12 +164,12 @@ static int probe_unixware_pt(blkid_probe + blkid_partition_set_flags(par, flg); + } + +- return 0; ++ return BLKID_PROBE_OK; + + nothing: +- return 1; ++ return BLKID_PROBE_NONE; + err: +- return -1; ++ return -ENOMEM; + } + + +diff -up util-linux-2.23.2/libblkid/src/probe.c.kzak util-linux-2.23.2/libblkid/src/probe.c +--- util-linux-2.23.2/libblkid/src/probe.c.kzak 2014-03-28 15:11:18.334283704 +0100 ++++ util-linux-2.23.2/libblkid/src/probe.c 2014-03-28 15:11:44.678551996 +0100 +@@ -559,13 +559,17 @@ unsigned char *blkid_probe_get_buffer(bl + if (!bf) { + ssize_t ret; + +- if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) ++ if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) { ++ errno = 0; + return NULL; ++ } + + /* allocate info and space for data by why call */ + bf = calloc(1, sizeof(struct blkid_bufinfo) + len); +- if (!bf) ++ if (!bf) { ++ errno = ENOMEM; + return NULL; ++ } + + bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo); + bf->len = len; +@@ -577,7 +581,10 @@ unsigned char *blkid_probe_get_buffer(bl + + ret = read(pr->fd, bf->data, len); + if (ret != (ssize_t) len) { ++ DBG(LOWPROBE, blkid_debug("\tbuffer read: return %zd error %m", ret)); + free(bf); ++ if (ret >= 0) ++ errno = 0; + return NULL; + } + list_add_tail(&bf->bufs, &pr->buffers); +@@ -766,6 +773,17 @@ int blkid_probe_set_dimension(blkid_prob + return 0; + } + ++/** ++ * blkid_probe_get_idmag: ++ * @pr: probe ++ * @id: id information ++ * @offset: begin of probing area ++ * @res: found id information ++ * ++ * Check for matching magic value. ++ * Returns BLKID_PROBE_OK if found, BLKID_PROBE_NONE if not found ++ * or no magic present, or negative value on error. ++ */ + int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, + blkid_loff_t *offset, const struct blkid_idmag **res) + { +@@ -784,6 +802,8 @@ int blkid_probe_get_idmag(blkid_probe pr + off = (mag->kboff + (mag->sboff >> 10)) << 10; + buf = blkid_probe_get_buffer(pr, off, 1024); + ++ if (!buf && errno) ++ return -errno; + if (buf && !memcmp(mag->magic, + buf + (mag->sboff & 0x3ff), mag->len)) { + DBG(LOWPROBE, blkid_debug("\tmagic sboff=%u, kboff=%ld", +@@ -792,16 +812,16 @@ int blkid_probe_get_idmag(blkid_probe pr + *offset = off + (mag->sboff & 0x3ff); + if (res) + *res = mag; +- return 0; ++ return BLKID_PROBE_OK; + } + mag++; + } + + if (id && id->magics[0].magic) + /* magic string(s) defined, but not found */ +- return 1; ++ return BLKID_PROBE_NONE; + +- return 0; ++ return BLKID_PROBE_OK; + } + + static inline void blkid_probe_start(blkid_probe pr) +diff -up util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c.kzak 2013-04-08 17:55:40.232855970 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c 2014-03-28 15:11:44.678551996 +0100 +@@ -80,10 +80,10 @@ static int probe_adraid(blkid_probe pr, + struct adaptec_metadata *ad; + + if (pr->size < 0x10000) +- return -1; ++ return BLKID_PROBE_NONE; + + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return BLKID_PROBE_NONE; + + off = ((pr->size / 0x200)-1) * 0x200; + ad = (struct adaptec_metadata *) +@@ -91,17 +91,19 @@ static int probe_adraid(blkid_probe pr, + off, + sizeof(struct adaptec_metadata)); + if (!ad) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE;; ++ + if (ad->smagic != be32_to_cpu(AD_SIGNATURE)) +- return -1; ++ return BLKID_PROBE_NONE; + if (ad->b0idcode != be32_to_cpu(AD_MAGIC)) +- return -1; ++ return BLKID_PROBE_NONE; + if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0) +- return -1; ++ return BLKID_PROBE_NONE; + if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode), + (unsigned char *) &ad->b0idcode)) +- return -1; +- return 0; ++ return BLKID_PROBE_NONE; ++ ++ return BLKID_PROBE_OK; + } + + const struct blkid_idinfo adraid_idinfo = { +diff -up util-linux-2.23.2/libblkid/src/superblocks/befs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/befs.c +--- util-linux-2.23.2/libblkid/src/superblocks/befs.c.kzak 2013-04-08 17:55:40.237856017 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/befs.c 2014-03-28 15:11:44.679552006 +0100 +@@ -261,21 +261,23 @@ static int64_t get_key_value(blkid_probe + int64_t node_pointer; + int32_t first, last, mid, cmp; + ++ errno = 0; + bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0, + sizeof(struct bplustree_header), fs_le); + if (!bh) +- return -1; ++ return errno ? -errno : -ENOENT; + + if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC) +- return -1; ++ return -ENOENT; + + node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le); + + do { ++ errno = 0; + bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data, + node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le); + if (!bn) +- return -1; ++ return errno ? -errno : -ENOENT; + + keylengths = (uint16_t *) ((uint8_t *) bn + + ((sizeof(struct bplustree_node) +@@ -336,10 +338,10 @@ static int get_uuid(blkid_probe pr, cons + + bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le); + if (!bi) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) +- return -1; ++ return BLKID_PROBE_NONE; + + sd = (struct small_data *) bi->small_data; + +@@ -376,24 +378,24 @@ static int get_uuid(blkid_probe pr, cons + bi = (struct befs_inode *) get_block_run(pr, bs, + &bi->attributes, fs_le); + if (!bi) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) +- return -1; ++ return BLKID_PROBE_NONE; + + value = get_key_value(pr, bs, bi, KEY_NAME, fs_le); +- + if (value < 0) +- return value; ++ return value == -ENOENT ? BLKID_PROBE_NONE : value; ++ + else if (value > 0) { + bi = (struct befs_inode *) blkid_probe_get_buffer(pr, + value << FS32_TO_CPU(bs->block_shift, fs_le), + FS32_TO_CPU(bs->block_size, fs_le)); + if (!bi) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) +- return -1; ++ return 1; + + if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE + && FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE +@@ -404,7 +406,7 @@ static int get_uuid(blkid_probe pr, cons + attr_data = (uint64_t *) get_block_run(pr, bs, + &bi->data.direct[0], fs_le); + if (!attr_data) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE; + + *uuid = *attr_data; + } +@@ -424,7 +426,7 @@ static int probe_befs(blkid_probe pr, co + mag->sboff - B_OS_NAME_LENGTH, + sizeof(struct befs_super_block)); + if (!bs) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE; + + if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 + && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 +@@ -439,11 +441,11 @@ static int probe_befs(blkid_probe pr, co + fs_le = 0; + version = "big-endian"; + } else +- return -1; ++ return BLKID_PROBE_NONE; + + ret = get_uuid(pr, bs, &volume_id, fs_le); + +- if (ret < 0) ++ if (ret != 0) + return ret; + + /* +@@ -459,7 +461,7 @@ static int probe_befs(blkid_probe pr, co + blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id, + sizeof(volume_id), "%016" PRIx64, + FS64_TO_CPU(volume_id, fs_le)); +- return 0; ++ return BLKID_PROBE_OK; + } + + const struct blkid_idinfo befs_idinfo = +diff -up util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/btrfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak 2014-03-28 15:11:18.335283714 +0100 ++++ util-linux-2.23.2/libblkid/src/superblocks/btrfs.c 2014-03-28 15:11:44.679552006 +0100 +@@ -65,7 +65,7 @@ static int probe_btrfs(blkid_probe pr, c + + bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); + if (!bfs) +- return -1; ++ return errno ? -errno : 1; + + if (*bfs->label) + blkid_probe_set_label(pr, +diff -up util-linux-2.23.2/libblkid/src/superblocks/cramfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/cramfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/cramfs.c.kzak 2013-04-08 17:55:40.240856046 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/cramfs.c 2014-03-28 15:11:44.679552006 +0100 +@@ -40,7 +40,7 @@ static int probe_cramfs(blkid_probe pr, + + cs = blkid_probe_get_sb(pr, mag, struct cramfs_super); + if (!cs) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_label(pr, cs->name, sizeof(cs->name)); + return 0; +diff -up util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c.kzak 2013-04-08 17:55:40.241856056 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c 2014-03-28 15:11:44.679552006 +0100 +@@ -81,7 +81,7 @@ static int probe_ddf(blkid_probe pr, + uint64_t off, lba; + + if (pr->size < 0x30000) +- return -1; ++ return 1; + + for (i = 0; i < ARRAY_SIZE(hdrs); i++) { + off = ((pr->size / 0x200) - hdrs[i]) * 0x200; +@@ -90,8 +90,7 @@ static int probe_ddf(blkid_probe pr, + off, + sizeof(struct ddf_header)); + if (!ddf) +- return -1; +- ++ return errno ? -errno : 1; + if (ddf->signature == cpu_to_be32(DDF_MAGIC) || + ddf->signature == cpu_to_le32(DDF_MAGIC)) + break; +@@ -99,7 +98,7 @@ static int probe_ddf(blkid_probe pr, + } + + if (!ddf) +- return -1; ++ return 1; + + lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ? + be64_to_cpu(ddf->primary_lba) : +@@ -111,8 +110,12 @@ static int probe_ddf(blkid_probe pr, + + buf = blkid_probe_get_buffer(pr, + lba << 9, sizeof(ddf->signature)); +- if (!buf || memcmp(buf, &ddf->signature, 4)) +- return -1; ++ if (!buf) { ++ if (errno) ++ return -errno; ++ if (memcmp(buf, &ddf->signature, 4)) ++ return 1; ++ } + } + + blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid)); +@@ -121,11 +124,11 @@ static int probe_ddf(blkid_probe pr, + *(version + sizeof(ddf->ddf_rev)) = '\0'; + + if (blkid_probe_set_version(pr, version) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, + sizeof(ddf->signature), + (unsigned char *) &ddf->signature)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/drbd.c.kzak util-linux-2.23.2/libblkid/src/superblocks/drbd.c +--- util-linux-2.23.2/libblkid/src/superblocks/drbd.c.kzak 2013-04-08 17:55:40.243856074 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/drbd.c 2014-03-28 15:11:44.679552006 +0100 +@@ -75,18 +75,18 @@ static int probe_drbd(blkid_probe pr, + + /* Small devices cannot be drbd (?) */ + if (pr->size < 0x10000) +- return -1; ++ return 1; + + md = (struct md_on_disk_08 *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct md_on_disk_08)); + if (!md) +- return -1; ++ return errno ? -errno : 1; + + if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 && + be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN) +- return -1; ++ return 1; + + /* + * DRBD does not have "real" uuids; the following resembles DRBD's +@@ -102,7 +102,7 @@ static int probe_drbd(blkid_probe pr, + off + offsetof(struct md_on_disk_08, magic), + sizeof(md->magic), + (unsigned char *) &md->magic)) +- return -1; ++ return 1; + + return 0; + } +diff -up util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c.kzak util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c +--- util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c.kzak 2013-04-08 17:55:40.244856084 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c 2014-03-28 15:11:44.679552006 +0100 +@@ -33,7 +33,7 @@ static int probe_drbdproxy_datalog(blkid + + lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh)); + if (!lh) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_uuid(pr, lh->uuid); + blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version)); +diff -up util-linux-2.23.2/libblkid/src/superblocks/exfat.c.kzak util-linux-2.23.2/libblkid/src/superblocks/exfat.c +--- util-linux-2.23.2/libblkid/src/superblocks/exfat.c.kzak 2013-04-08 17:55:40.245856093 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/exfat.c 2014-03-28 15:11:44.680552016 +0100 +@@ -115,12 +115,14 @@ static int probe_exfat(blkid_probe pr, c + + sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block); + if (!sb) +- return -1; ++ return errno ? -errno : BLKID_PROBE_NONE; + + label = find_label(pr, sb); + if (label) + blkid_probe_set_utf8label(pr, label->name, + min(label->length * 2, 30), BLKID_ENC_UTF16LE); ++ else if (errno) ++ return -errno; + + blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4, + "%02hhX%02hhX-%02hhX%02hhX", +@@ -130,7 +132,7 @@ static int probe_exfat(blkid_probe pr, c + blkid_probe_sprintf_version(pr, "%u.%u", + sb->version.major, sb->version.minor); + +- return 0; ++ return BLKID_PROBE_OK; + } + + const struct blkid_idinfo exfat_idinfo = +diff -up util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ext.c +--- util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak 2014-03-28 15:11:18.333283694 +0100 ++++ util-linux-2.23.2/libblkid/src/superblocks/ext.c 2014-03-28 15:11:44.680552016 +0100 +@@ -198,9 +198,9 @@ static int probe_jbd(blkid_probe pr, + + es = ext_get_super(pr, NULL, &fi, NULL); + if (!es) +- return -BLKID_ERR_PARAM; ++ return errno ? -errno : 1; + if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) +- return -BLKID_ERR_PARAM; ++ return 1; + + ext_get_info(pr, 2, es); + return 0; +@@ -214,16 +214,16 @@ static int probe_ext2(blkid_probe pr, + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) +- return -BLKID_ERR_PARAM; ++ return errno ? -errno : 1; + + /* Distinguish between ext3 and ext2 */ + if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) +- return -BLKID_ERR_PARAM; ++ return 1; + + /* Any features which ext2 doesn't understand */ + if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || + (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) +- return -BLKID_ERR_PARAM; ++ return 1; + + ext_get_info(pr, 2, es); + return 0; +@@ -237,16 +237,16 @@ static int probe_ext3(blkid_probe pr, + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) +- return -BLKID_ERR_PARAM; ++ return errno ? -errno : 1; + + /* ext3 requires journal */ + if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) +- return -BLKID_ERR_PARAM; ++ return 1; + + /* Any features which ext3 doesn't understand */ + if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || + (fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) +- return -BLKID_ERR_PARAM; ++ return 1; + + ext_get_info(pr, 3, es); + return 0; +@@ -261,14 +261,14 @@ static int probe_ext4dev(blkid_probe pr, + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) +- return -BLKID_ERR_PARAM; ++ return errno ? -errno : 1; + + /* Distinguish from jbd */ + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) +- return -BLKID_ERR_PARAM; ++ return 1; + + if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)) +- return -BLKID_ERR_PARAM; ++ return 1; + + ext_get_info(pr, 4, es); + return 0; +@@ -282,16 +282,16 @@ static int probe_ext4(blkid_probe pr, + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) +- return -1; ++ return errno ? -errno : 1; + + /* Distinguish from jbd */ + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) +- return -BLKID_ERR_PARAM; ++ return 1; + + /* Ext4 has at least one feature which ext3 doesn't understand */ + if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && + !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) +- return -BLKID_ERR_PARAM; ++ return 1; + + /* + * If the filesystem is a OK for use by in-development +@@ -304,7 +304,7 @@ static int probe_ext4(blkid_probe pr, + * ext4dev. + */ + if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) +- return -BLKID_ERR_PARAM; ++ return 1; + + ext_get_info(pr, 4, es); + return 0; +diff -up util-linux-2.23.2/libblkid/src/superblocks/f2fs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/f2fs.c +--- util-linux-2.23.2/libblkid/src/superblocks/f2fs.c.kzak 2013-06-13 09:46:10.422650639 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/f2fs.c 2014-03-28 15:11:44.680552016 +0100 +@@ -62,7 +62,7 @@ static int probe_f2fs(blkid_probe pr, co + + sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block); + if (!sb) +- return -1; ++ return errno ? -errno : 1; + + major = le16_to_cpu(sb->major_ver); + minor = le16_to_cpu(sb->minor_ver); +diff -up util-linux-2.23.2/libblkid/src/superblocks/gfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/gfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/gfs.c.kzak 2013-04-08 17:55:40.250856141 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/gfs.c 2014-03-28 15:11:44.680552016 +0100 +@@ -64,7 +64,7 @@ static int probe_gfs(blkid_probe pr, con + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) +- return -1; ++ return errno ? -errno : 1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) +@@ -78,7 +78,7 @@ static int probe_gfs(blkid_probe pr, con + return 0; + } + +- return -1; ++ return 1; + } + + static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag) +@@ -87,7 +87,7 @@ static int probe_gfs2(blkid_probe pr, co + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) +- return -1; ++ return errno ? -errno : 1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) +@@ -100,7 +100,7 @@ static int probe_gfs2(blkid_probe pr, co + blkid_probe_set_version(pr, "1"); + return 0; + } +- return -1; ++ return 1; + } + + const struct blkid_idinfo gfs_idinfo = +diff -up util-linux-2.23.2/libblkid/src/superblocks/hfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/hfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/hfs.c.kzak 2013-04-08 17:55:40.251856150 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/hfs.c 2014-03-28 15:11:44.680552016 +0100 +@@ -154,7 +154,7 @@ static int probe_hfs(blkid_probe pr, con + + hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb); + if (!hfs) +- return -1; ++ return errno ? -errno : 1; + + if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || + (memcmp(hfs->embed_sig, "HX", 2) == 0)) +@@ -193,7 +193,7 @@ static int probe_hfsplus(blkid_probe pr, + + sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb); + if (!sbd) +- return -1; ++ return errno ? -errno : 1; + + /* Check for a HFS+ volume embedded in a HFS volume */ + if (memcmp(sbd->signature, "BD", 2) == 0) { +@@ -218,7 +218,7 @@ static int probe_hfsplus(blkid_probe pr, + struct hfsplus_vol_header); + + if (!hfsplus) +- return -1; ++ return errno ? -errno : 1; + + if ((memcmp(hfsplus->signature, "H+", 2) != 0) && + (memcmp(hfsplus->signature, "HX", 2) != 0)) +@@ -228,7 +228,7 @@ static int probe_hfsplus(blkid_probe pr, + + blocksize = be32_to_cpu(hfsplus->blocksize); + if (blocksize < HFSPLUS_SECTOR_SIZE) +- return -1; ++ return 1; + + memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); + cat_block = be32_to_cpu(extents[0].start_block); +@@ -236,7 +236,7 @@ static int probe_hfsplus(blkid_probe pr, + buf = blkid_probe_get_buffer(pr, + off + ((blkid_loff_t) cat_block * blocksize), 0x2000); + if (!buf) +- return 0; ++ return errno ? -errno : 0; + + bnode = (struct hfsplus_bheader_record *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; +@@ -271,7 +271,7 @@ static int probe_hfsplus(blkid_probe pr, + (blkid_loff_t) off + leaf_off, + leaf_node_size); + if (!buf) +- return 0; ++ return errno ? -errno : 0; + + descr = (struct hfsplus_bnode_descriptor *) buf; + record_count = be16_to_cpu(descr->num_recs); +diff -up util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c.kzak 2013-04-08 17:55:40.251856150 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c 2014-03-28 15:11:44.680552016 +0100 +@@ -30,9 +30,9 @@ static int probe_highpoint45x(blkid_prob + uint32_t magic; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200) - 11) * 0x200; + hpt = (struct hpt45x_metadata *) +@@ -40,13 +40,13 @@ static int probe_highpoint45x(blkid_prob + off, + sizeof(struct hpt45x_metadata)); + if (!hpt) +- return -1; ++ return errno ? -errno : 1; + magic = le32_to_cpu(hpt->magic); + if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic), + (unsigned char *) &hpt->magic)) +- return -1; ++ return 1; + return 0; + } + +@@ -54,7 +54,7 @@ static int probe_highpoint37x(blkid_prob + const struct blkid_idmag *mag __attribute__((__unused__))) + { + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/hpfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/hpfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/hpfs.c.kzak 2013-04-08 17:55:40.252856159 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/hpfs.c 2014-03-28 15:11:44.680552016 +0100 +@@ -68,7 +68,7 @@ static int probe_hpfs(blkid_probe pr, co + /* super block */ + hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block); + if (!hs) +- return -1; ++ return errno ? -errno : 1; + version = hs->version; + + /* spare super block */ +@@ -77,9 +77,9 @@ static int probe_hpfs(blkid_probe pr, co + HPFS_SBSPARE_OFFSET, + sizeof(struct hpfs_spare_super)); + if (!hss) +- return -1; ++ return errno ? -errno : 1; + if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0) +- return -1; ++ return 1; + + /* boot block (with UUID and LABEL) */ + hbb = (struct hpfs_boot_block *) +@@ -87,7 +87,7 @@ static int probe_hpfs(blkid_probe pr, co + 0, + sizeof(struct hpfs_boot_block)); + if (!hbb) +- return -1; ++ return errno ? -errno : 1; + if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 && + memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 && + hbb->sig_28h == 0x28) { +diff -up util-linux-2.23.2/libblkid/src/superblocks/iso9660.c.kzak util-linux-2.23.2/libblkid/src/superblocks/iso9660.c +--- util-linux-2.23.2/libblkid/src/superblocks/iso9660.c.kzak 2013-06-13 09:46:10.422650639 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/iso9660.c 2014-03-28 15:11:44.680552016 +0100 +@@ -100,7 +100,7 @@ static int probe_iso9660_hsfs(blkid_prob + + iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor); + if (!iso) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_version(pr, "High Sierra"); + blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id)); +@@ -178,7 +178,7 @@ int probe_iso9660(blkid_probe pr, const + + iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor); + if (!iso) +- return -1; ++ return errno ? -errno : 1; + + memcpy(label, iso->volume_id, sizeof(label)); + +diff -up util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c.kzak 2013-04-08 17:55:40.252856159 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c 2014-03-28 15:11:44.680552016 +0100 +@@ -33,9 +33,9 @@ static int probe_iswraid(blkid_probe pr, + struct isw_metadata *isw; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200) - 2) * 0x200; + isw = (struct isw_metadata *) +@@ -43,15 +43,16 @@ static int probe_iswraid(blkid_probe pr, + off, + sizeof(struct isw_metadata)); + if (!isw) +- return -1; ++ return errno ? -errno : 1; ++ + if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) +- return -1; ++ return 1; + if (blkid_probe_sprintf_version(pr, "%6s", + &isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(isw->sig), + (unsigned char *) isw->sig)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/jfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/jfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/jfs.c.kzak 2013-04-08 17:55:40.253856169 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/jfs.c 2014-03-28 15:11:44.681552026 +0100 +@@ -40,7 +40,7 @@ static int probe_jfs(blkid_probe pr, con + + js = blkid_probe_get_sb(pr, mag, struct jfs_super_block); + if (!js) +- return -1; ++ return errno ? -errno : 1; + if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize))) + return 1; + if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize))) +diff -up util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c.kzak 2013-04-08 17:55:40.253856169 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c 2014-03-28 15:11:44.681552026 +0100 +@@ -32,9 +32,9 @@ static int probe_jmraid(blkid_probe pr, + struct jm_metadata *jm; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200) - 1) * 0x200; + jm = (struct jm_metadata *) +@@ -42,15 +42,16 @@ static int probe_jmraid(blkid_probe pr, + off, + sizeof(struct jm_metadata)); + if (!jm) +- return -1; ++ return errno ? -errno : 1; ++ + if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0) +- return -1; ++ return 1; + if (blkid_probe_sprintf_version(pr, "%u.%u", + jm->major_version, jm->minor_version) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(jm->signature), + (unsigned char *) jm->signature)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c.kzak 2013-04-08 17:55:40.253856169 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c 2014-03-28 15:11:44.681552026 +0100 +@@ -110,13 +110,13 @@ static int probe_raid0(blkid_probe pr, b + uint64_t size; + + if (pr->size < MD_RESERVED_BYTES) +- return -1; ++ return 1; + mdp0 = (struct mdp0_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct mdp0_super_block)); + if (!mdp0) +- return -1; ++ return errno ? -errno : 1; + + memset(uuid.ints, 0, sizeof(uuid.ints)); + +@@ -173,12 +173,12 @@ static int probe_raid0(blkid_probe pr, b + } + + if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic), + (unsigned char *) &mdp0->md_magic)) +- return -1; ++ return 1; + return 0; + } + +@@ -191,24 +191,24 @@ static int probe_raid1(blkid_probe pr, o + off, + sizeof(struct mdp1_super_block)); + if (!mdp1) +- return -1; ++ return errno ? -errno : 1; + if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) +- return -1; ++ return 1; + if (le32_to_cpu(mdp1->major_version) != 1U) +- return -1; ++ return 1; + if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9) +- return -1; ++ return 1; + if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_uuid_as(pr, + (unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0) +- return -1; ++ return 1; + if (blkid_probe_set_label(pr, mdp1->set_name, + sizeof(mdp1->set_name)) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic), + (unsigned char *) &mdp1->magic)) +- return -1; ++ return 1; + return 0; + } + +@@ -216,35 +216,44 @@ int probe_raid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) + { + const char *ver = NULL; ++ int ret = BLKID_PROBE_NONE; + + if (pr->size > MD_RESERVED_BYTES) { + /* version 0 at the end of the device */ + uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1)) +- - MD_RESERVED_BYTES; +- if (probe_raid0(pr, sboff) == 0) +- return 0; ++ - MD_RESERVED_BYTES; ++ ret = probe_raid0(pr, sboff); ++ if (ret < 1) ++ return ret; /* error */ + + /* version 1.0 at the end of the device */ + sboff = (pr->size & ~(0x1000 - 1)) - 0x2000; +- if (probe_raid1(pr, sboff) == 0) ++ ret = probe_raid1(pr, sboff); ++ if (ret < 0) ++ return ret; /* error */ ++ if (ret == 0) + ver = "1.0"; + } + + if (!ver) { + /* version 1.1 at the start of the device */ +- if (probe_raid1(pr, 0) == 0) ++ ret = probe_raid1(pr, 0); ++ if (ret == 0) + ver = "1.1"; + + /* version 1.2 at 4k offset from the start */ +- else if (probe_raid1(pr, 0x1000) == 0) +- ver = "1.2"; ++ else if (ret == BLKID_PROBE_NONE) { ++ ret = probe_raid1(pr, 0x1000); ++ if (ret == 0) ++ ver = "1.2"; ++ } + } + + if (ver) { + blkid_probe_set_version(pr, ver); +- return 0; ++ return BLKID_PROBE_OK; + } +- return -1; ++ return ret; + } + + +diff -up util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c.kzak 2013-04-08 17:55:40.254856179 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c 2014-03-28 15:11:44.681552026 +0100 +@@ -30,9 +30,9 @@ static int probe_lsiraid(blkid_probe pr, + struct lsi_metadata *lsi; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200) - 1) * 0x200; + lsi = (struct lsi_metadata *) +@@ -40,13 +40,13 @@ static int probe_lsiraid(blkid_probe pr, + off, + sizeof(struct lsi_metadata)); + if (!lsi) +- return -1; ++ return errno ? -errno : 1; + + if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig), + (unsigned char *) lsi->sig)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/luks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/luks.c +--- util-linux-2.23.2/libblkid/src/superblocks/luks.c.kzak 2013-04-08 17:55:40.254856179 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/luks.c 2014-03-28 15:11:44.681552026 +0100 +@@ -45,7 +45,7 @@ static int probe_luks(blkid_probe pr, co + + header = blkid_probe_get_sb(pr, mag, struct luks_phdr); + if (header == NULL) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid, + sizeof(header->uuid)); +diff -up util-linux-2.23.2/libblkid/src/superblocks/lvm.c.kzak util-linux-2.23.2/libblkid/src/superblocks/lvm.c +--- util-linux-2.23.2/libblkid/src/superblocks/lvm.c.kzak 2013-06-13 09:46:10.422650639 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/lvm.c 2014-03-28 15:11:44.681552026 +0100 +@@ -82,7 +82,7 @@ static int probe_lvm2(blkid_probe pr, co + mag->kboff << 10, + 512 + sizeof(struct lvm2_pv_label_header)); + if (!buf) +- return -1; ++ return errno ? -errno : 1; + + /* buf is at 0k or 1k offset; find label inside */ + if (memcmp(buf, "LABELONE", 8) == 0) { +@@ -129,7 +129,7 @@ static int probe_lvm1(blkid_probe pr, co + + label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header); + if (!label) +- return -1; ++ return errno ? -errno : 1; + + version = le16_to_cpu(label->version); + if (version != 1 && version != 2) +@@ -164,7 +164,7 @@ static int probe_verity(blkid_probe pr, + + sb = blkid_probe_get_sb(pr, mag, struct verity_sb); + if (sb == NULL) +- return -1; ++ return errno ? -errno : 1; + + version = le32_to_cpu(sb->version); + if (version != 1) +diff -up util-linux-2.23.2/libblkid/src/superblocks/minix.c.kzak util-linux-2.23.2/libblkid/src/superblocks/minix.c +--- util-linux-2.23.2/libblkid/src/superblocks/minix.c.kzak 2013-06-13 09:46:10.423650647 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/minix.c 2014-03-28 15:11:44.681552026 +0100 +@@ -80,17 +80,17 @@ static int probe_minix(blkid_probe pr, c + max(sizeof(struct minix_super_block), + sizeof(struct minix3_super_block))); + if (!data) +- return -1; ++ return errno ? -errno : 1; + version = get_minix_version(data, &swabme); + if (version < 1) +- return -1; ++ return 1; + + if (version <= 2) { + struct minix_super_block *sb = (struct minix_super_block *) data; + int zones, ninodes, imaps, zmaps, firstz; + + if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) +- return -1; ++ return 1; + + zones = version == 2 ? minix_swab32(swabme, sb->s_zones) : + minix_swab16(swabme, sb->s_nzones); +@@ -101,15 +101,15 @@ static int probe_minix(blkid_probe pr, c + + /* sanity checks to be sure that the FS is really minix */ + if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1) +- return -1; ++ return 1; + if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1) +- return -1; ++ return 1; + + } else if (version == 3) { + struct minix3_super_block *sb = (struct minix3_super_block *) data; + + if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) +- return -1; ++ return 1; + } + + /* unfortunately, some parts of ext3 is sometimes possible to +@@ -117,8 +117,10 @@ static int probe_minix(blkid_probe pr, c + * string. (For extN magic string and offsets see ext.c.) + */ + ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2); +- if (ext && memcmp(ext, "\123\357", 2) == 0) +- return -1; ++ if (!ext) ++ return errno ? -errno : 1; ++ else if (memcmp(ext, "\123\357", 2) == 0) ++ return 1; + + blkid_probe_sprintf_version(pr, "%d", version); + return 0; +diff -up util-linux-2.23.2/libblkid/src/superblocks/netware.c.kzak util-linux-2.23.2/libblkid/src/superblocks/netware.c +--- util-linux-2.23.2/libblkid/src/superblocks/netware.c.kzak 2013-04-08 17:55:40.255856188 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/netware.c 2014-03-28 15:11:44.681552026 +0100 +@@ -71,7 +71,7 @@ static int probe_netware(blkid_probe pr, + + nw = blkid_probe_get_sb(pr, mag, struct netware_super_block); + if (!nw) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_uuid(pr, nw->SBH_PoolID); + +diff -up util-linux-2.23.2/libblkid/src/superblocks/nilfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/nilfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/nilfs.c.kzak 2013-04-08 17:55:40.256856198 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/nilfs.c 2014-03-28 15:11:44.681552026 +0100 +@@ -82,7 +82,7 @@ static int probe_nilfs2(blkid_probe pr, + + sb = blkid_probe_get_sb(pr, mag, struct nilfs_super_block); + if (!sb) +- return -1; ++ return errno ? -errno : 1; + + bytes = le16_to_cpu(sb->s_bytes); + crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff); +@@ -90,7 +90,7 @@ static int probe_nilfs2(blkid_probe pr, + crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4); + + if (crc != le32_to_cpu(sb->s_sum)) +- return -1; ++ return 1; + + if (strlen(sb->s_volume_name)) + blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name, +diff -up util-linux-2.23.2/libblkid/src/superblocks/ntfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ntfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/ntfs.c.kzak 2013-06-13 09:46:10.423650647 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/ntfs.c 2014-03-28 15:11:44.681552026 +0100 +@@ -91,7 +91,7 @@ static int probe_ntfs(blkid_probe pr, co + + ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block); + if (!ns) +- return -1; ++ return errno ? -errno : 1; + + /* + * Check bios parameters block +@@ -158,7 +158,7 @@ static int probe_ntfs(blkid_probe pr, co + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) +- return 1; ++ return errno ? -errno : 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; +@@ -167,7 +167,7 @@ static int probe_ntfs(blkid_probe pr, co + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) +- return 1; ++ return errno ? -errno : 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; +diff -up util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c.kzak 2013-04-08 17:55:40.257856207 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c 2014-03-28 15:11:44.682552036 +0100 +@@ -32,9 +32,9 @@ static int probe_nvraid(blkid_probe pr, + struct nv_metadata *nv; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200) - 2) * 0x200; + nv = (struct nv_metadata *) +@@ -42,15 +42,15 @@ static int probe_nvraid(blkid_probe pr, + off, + sizeof(struct nv_metadata)); + if (!nv) +- return -1; ++ return errno ? -errno : 1; + + if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) +- return -1; ++ return 1; + if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor), + (unsigned char *) nv->vendor)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/ocfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ocfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/ocfs.c.kzak 2013-04-08 17:55:40.257856207 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/ocfs.c 2014-03-28 15:11:44.682552036 +0100 +@@ -109,14 +109,14 @@ static int probe_ocfs(blkid_probe pr, co + buf = blkid_probe_get_buffer(pr, mag->kboff << 10, + sizeof(struct ocfs_volume_header)); + if (!buf) +- return -1; ++ return errno ? -errno : 1; + memcpy(&ovh, buf, sizeof(ovh)); + + /* label */ + buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512, + sizeof(struct ocfs_volume_label)); + if (!buf) +- return -1; ++ return errno ? -errno : 1; + memcpy(&ovl, buf, sizeof(ovl)); + + maj = ocfsmajor(ovh); +@@ -144,7 +144,7 @@ static int probe_ocfs2(blkid_probe pr, c + + osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block); + if (!osb) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label)); + blkid_probe_set_uuid(pr, osb->s_uuid); +@@ -162,7 +162,7 @@ static int probe_oracleasm(blkid_probe p + + dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label); + if (!dl) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id)); + return 0; +diff -up util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c.kzak 2013-06-13 09:46:10.423650647 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c 2014-03-28 15:11:44.682552036 +0100 +@@ -33,9 +33,9 @@ static int probe_pdcraid(blkid_probe pr, + }; + + if (pr->size < 0x40000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + for (i = 0; sectors[i] != 0; i++) { + uint64_t off; +@@ -47,18 +47,18 @@ static int probe_pdcraid(blkid_probe pr, + off, + sizeof(struct promise_metadata)); + if (!pdc) +- return -1; ++ return errno ? -errno : 1; + + if (memcmp(pdc->sig, PDC_SIGNATURE, + sizeof(PDC_SIGNATURE) - 1) == 0) { + + if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig), + (unsigned char *) pdc->sig)) +- return -1; ++ return 1; + return 0; + } + } +- return -1; ++ return 1; + } + + const struct blkid_idinfo pdcraid_idinfo = { +diff -up util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c.kzak 2013-04-08 17:55:40.258856216 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c 2014-03-28 15:11:44.682552036 +0100 +@@ -45,17 +45,17 @@ static int probe_reiser(blkid_probe pr, + + rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block); + if (!rs) +- return -1; ++ return errno ? -errno : 1; + + blocksize = le16_to_cpu(rs->rs_blocksize); + + /* The blocksize must be at least 512B */ + if ((blocksize >> 9) == 0) +- return -BLKID_ERR_PARAM; ++ return 1; + + /* If the superblock is inside the journal, we have the wrong one */ + if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2) +- return -BLKID_ERR_BIG; ++ return 1; + + /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ + if (mag->magic[6] == '2' || mag->magic[6] == '3') { +@@ -82,7 +82,7 @@ static int probe_reiser4(blkid_probe pr, + + rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block); + if (!rs4) +- return -1; ++ return errno ? -errno : 1; + + if (*rs4->rs4_label) + blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label)); +diff -up util-linux-2.23.2/libblkid/src/superblocks/romfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/romfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/romfs.c.kzak 2013-04-08 17:55:40.258856216 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/romfs.c 2014-03-28 15:11:44.682552036 +0100 +@@ -29,7 +29,7 @@ static int probe_romfs(blkid_probe pr, c + + ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block); + if (!ros) +- return -1; ++ return errno ? -errno : 1; + + if (strlen((char *) ros->ros_volume)) + blkid_probe_set_label(pr, ros->ros_volume, +diff -up util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c.kzak 2013-06-13 09:46:10.424650656 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c 2014-03-28 15:11:44.682552036 +0100 +@@ -88,9 +88,9 @@ static int probe_silraid(blkid_probe pr, + struct silicon_metadata *sil; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200) - 1) * 0x200; + +@@ -98,27 +98,27 @@ static int probe_silraid(blkid_probe pr, + blkid_probe_get_buffer(pr, off, + sizeof(struct silicon_metadata)); + if (!sil) +- return -1; ++ return errno ? -errno : 1; + + if (le32_to_cpu(sil->magic) != SILICON_MAGIC) +- return -1; ++ return 1; + if (sil->disk_number >= 8) +- return -1; ++ return 1; + if (!checksum(sil)) { + DBG(LOWPROBE, blkid_debug("silicon raid: incorrect checksum")); +- return -1; ++ return 1; + } + + if (blkid_probe_sprintf_version(pr, "%u.%u", + le16_to_cpu(sil->major_ver), + le16_to_cpu(sil->minor_ver)) != 0) +- return -1; ++ return 1; + + if (blkid_probe_set_magic(pr, + off + offsetof(struct silicon_metadata, magic), + sizeof(sil->magic), + (unsigned char *) &sil->magic)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/squashfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/squashfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/squashfs.c.kzak 2013-04-08 17:55:40.258856216 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/squashfs.c 2014-03-28 15:11:44.682552036 +0100 +@@ -34,7 +34,7 @@ static int probe_squashfs(blkid_probe pr + + sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block); + if (!sq) +- return -1; ++ return errno ? -errno : 1; + + if (strcmp(mag->magic, "sqsh") == 0 || + strcmp(mag->magic, "qshs") == 0) +diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c +--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak 2013-07-30 10:39:26.209738269 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c 2014-03-28 15:11:44.682552036 +0100 +@@ -331,9 +331,10 @@ int blkid_superblocks_get_name(size_t id + static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) + { + size_t i; ++ int rc = BLKID_PROBE_NONE; + + if (!pr || chn->idx < -1) +- return -1; ++ return -EINVAL; + blkid_probe_chain_reset_vals(pr, chn); + + DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]", +@@ -351,38 +352,50 @@ static int superblocks_probe(blkid_probe + const struct blkid_idinfo *id; + const struct blkid_idmag *mag = NULL; + blkid_loff_t off = 0; +- int rc = 0; + + chn->idx = i; + id = idinfos[i]; + + if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) { + DBG(LOWPROBE, blkid_debug("filter out: %s", id->name)); ++ rc = BLKID_PROBE_NONE; + continue; + } + +- if (id->minsz && id->minsz > pr->size) ++ if (id->minsz && id->minsz > pr->size) { ++ rc = BLKID_PROBE_NONE; + continue; /* the device is too small */ ++ } + + /* don't probe for RAIDs, swap or journal on CD/DVDs */ + if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) && +- blkid_probe_is_cdrom(pr)) ++ blkid_probe_is_cdrom(pr)) { ++ rc = BLKID_PROBE_NONE; + continue; ++ } + + /* don't probe for RAIDs on floppies */ +- if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) ++ if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) { ++ rc = BLKID_PROBE_NONE; + continue; ++ } + + DBG(LOWPROBE, blkid_debug("[%zd] %s:", i, id->name)); + +- if (blkid_probe_get_idmag(pr, id, &off, &mag)) ++ rc = blkid_probe_get_idmag(pr, id, &off, &mag); ++ if (rc < 0) ++ break; ++ if (rc != BLKID_PROBE_OK) + continue; + + /* final check by probing function */ + if (id->probefunc) { + DBG(LOWPROBE, blkid_debug("\tcall probefunc()")); +- if (id->probefunc(pr, mag) != 0) { ++ rc = id->probefunc(pr, mag); ++ if (rc != BLKID_PROBE_OK) { + blkid_probe_chain_reset_vals(pr, chn); ++ if (rc < 0) ++ break; + continue; + } + } +@@ -407,13 +420,13 @@ static int superblocks_probe(blkid_probe + + DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]", + id->name, chn->idx)); +- return 0; ++ return BLKID_PROBE_OK; + } + + nothing: +- DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed) [SUBLKS idx=%d]", +- chn->idx)); +- return 1; ++ DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]", ++ rc, chn->idx)); ++ return rc; + } + + /* +diff -up util-linux-2.23.2/libblkid/src/superblocks/swap.c.kzak util-linux-2.23.2/libblkid/src/superblocks/swap.c +--- util-linux-2.23.2/libblkid/src/superblocks/swap.c.kzak 2013-06-13 09:46:10.425650665 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/swap.c 2014-03-28 15:11:44.682552036 +0100 +@@ -44,17 +44,17 @@ static int swap_set_info(blkid_probe pr, + hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024, + sizeof(struct swap_header_v1_2)); + if (!hdr) +- return -1; ++ return errno ? -errno : 1; + + /* SWAPSPACE2 - check for wrong version or zeroed pagecount */ + if (strcmp(version, "2") == 0) { + if (hdr->version != 1 && swab32(hdr->version) != 1) { + DBG(LOWPROBE, blkid_debug("incorrect swap version")); +- return -1; ++ return 1; + } + if (hdr->lastpage == 0) { + DBG(LOWPROBE, blkid_debug("not set last swap page")); +- return -1; ++ return 1; + } + } + +@@ -62,9 +62,9 @@ static int swap_set_info(blkid_probe pr, + if (hdr->padding[32] == 0 && hdr->padding[33] == 0) { + if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume, + sizeof(hdr->volume)) < 0) +- return -1; ++ return 1; + if (blkid_probe_set_uuid(pr, hdr->uuid) < 0) +- return -1; ++ return 1; + } + + blkid_probe_set_version(pr, version); +@@ -76,12 +76,12 @@ static int probe_swap(blkid_probe pr, co + unsigned char *buf; + + if (!mag) +- return -1; ++ return 1; + + /* TuxOnIce keeps valid swap header at the end of the 1st page */ + buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN); + if (!buf) +- return -1; ++ return errno ? -errno : 1; + + if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0) + return 1; /* Ignore swap signature, it's TuxOnIce */ +@@ -94,13 +94,13 @@ static int probe_swap(blkid_probe pr, co + } else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len)) + return swap_set_info(pr, "2"); + +- return -1; ++ return 1; + } + + static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag) + { + if (!mag) +- return -1; ++ return 1; + if (!memcmp(mag->magic, "S1SUSPEND", mag->len)) + return swap_set_info(pr, "s1suspend"); + if (!memcmp(mag->magic, "S2SUSPEND", mag->len)) +@@ -112,7 +112,7 @@ static int probe_swsuspend(blkid_probe p + if (!memcmp(mag->magic, "LINHIB0001", mag->len)) + return swap_set_info(pr, "linhib0001"); + +- return -1; /* no signature detected */ ++ return 1; /* no signature detected */ + } + + const struct blkid_idinfo swap_idinfo = +diff -up util-linux-2.23.2/libblkid/src/superblocks/sysv.c.kzak util-linux-2.23.2/libblkid/src/superblocks/sysv.c +--- util-linux-2.23.2/libblkid/src/superblocks/sysv.c.kzak 2013-04-08 17:55:40.261856245 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/sysv.c 2014-03-28 15:11:44.683552047 +0100 +@@ -80,7 +80,7 @@ static int probe_xenix(blkid_probe pr, c + + sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block); + if (!sb) +- return -1; ++ return errno ? -errno : 1; + blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname)); + return 0; + } +@@ -105,21 +105,21 @@ static int probe_sysv(blkid_probe pr, + off, + sizeof(struct sysv_super_block)); + if (!sb) +- return -1; ++ return errno ? -errno : 1; + + if (sb->s_magic == cpu_to_le32(0xfd187e20) || + sb->s_magic == cpu_to_be32(0xfd187e20)) { + + if (blkid_probe_set_label(pr, sb->s_fname, + sizeof(sb->s_fname))) +- return -1; ++ return 1; + + if (blkid_probe_set_magic(pr, + off + offsetof(struct sysv_super_block, + s_magic), + sizeof(sb->s_magic), + (unsigned char *) &sb->s_magic)) +- return -1; ++ return 1; + + return 0; + } +diff -up util-linux-2.23.2/libblkid/src/superblocks/ubifs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ubifs.c +--- util-linux-2.23.2/libblkid/src/superblocks/ubifs.c.kzak 2013-06-13 09:46:10.426650673 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/ubifs.c 2014-03-28 15:11:44.683552047 +0100 +@@ -99,7 +99,7 @@ static int probe_ubifs(blkid_probe pr, c + + sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node); + if (!sb) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_set_uuid(pr, sb->uuid); + blkid_probe_sprintf_version(pr, "w%dr%d", +diff -up util-linux-2.23.2/libblkid/src/superblocks/udf.c.kzak util-linux-2.23.2/libblkid/src/superblocks/udf.c +--- util-linux-2.23.2/libblkid/src/superblocks/udf.c.kzak 2013-06-13 09:46:10.426650673 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/udf.c 2014-03-28 15:11:44.683552047 +0100 +@@ -85,11 +85,11 @@ static int probe_udf(blkid_probe pr, + UDF_VSD_OFFSET + b, + sizeof(*vsd)); + if (!vsd) +- return 1; ++ return errno ? -errno : 1; + if (vsd->id[0] != '\0') + goto nsr; + } +- return -1; ++ return 1; + + nsr: + /* search the list of VSDs for a NSR descriptor */ +@@ -99,15 +99,15 @@ nsr: + UDF_VSD_OFFSET + ((blkid_loff_t) b * 0x800), + sizeof(*vsd)); + if (!vsd) +- return -1; ++ return errno ? -errno : 1; + if (vsd->id[0] == '\0') +- return -1; ++ return 1; + if (memcmp(vsd->id, "NSR02", 5) == 0) + goto anchor; + if (memcmp(vsd->id, "NSR03", 5) == 0) + goto anchor; + } +- return -1; ++ return 1; + + anchor: + /* read Anchor Volume Descriptor (AVDP), checking block size */ +@@ -115,7 +115,7 @@ anchor: + vd = (struct volume_descriptor *) + blkid_probe_get_buffer(pr, 256 * pbs[i], sizeof(*vd)); + if (!vd) +- return -1; ++ return errno ? -errno : 1; + + type = le16_to_cpu(vd->tag.id); + if (type == 2) /* TAG_ID_AVDP */ +@@ -138,7 +138,7 @@ real_blksz: + (blkid_loff_t) (loc + b) * bs, + sizeof(*vd)); + if (!vd) +- return -1; ++ return errno ? -errno : 1; + } + + /* Try extract all possible ISO9660 information -- if there is +@@ -155,7 +155,7 @@ real_blksz: + (blkid_loff_t) (loc + b) * bs, + sizeof(*vd)); + if (!vd) +- return -1; ++ return errno ? -errno : 1; + type = le16_to_cpu(vd->tag.id); + if (type == 0) + break; +diff -up util-linux-2.23.2/libblkid/src/superblocks/ufs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ufs.c +--- util-linux-2.23.2/libblkid/src/superblocks/ufs.c.kzak 2013-04-08 17:55:40.263856264 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/ufs.c 2014-03-28 15:11:44.683552047 +0100 +@@ -185,7 +185,7 @@ static int probe_ufs(blkid_probe pr, + offsets[i] * 1024, + sizeof(struct ufs_super_block)); + if (!ufs) +- return -1; ++ return errno ? -errno : 1; + + magBE = be32_to_cpu(ufs->fs_magic); + magLE = le32_to_cpu(ufs->fs_magic); +@@ -231,7 +231,7 @@ found: + offsetof(struct ufs_super_block, fs_magic), + sizeof(ufs->fs_magic), + (unsigned char *) &ufs->fs_magic)) +- return -1; ++ return 1; + + return 0; + } +diff -up util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vfat.c +--- util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak 2013-06-13 09:46:10.426650673 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/vfat.c 2014-03-28 15:12:28.036993622 +0100 +@@ -255,16 +255,20 @@ int blkid_probe_is_vfat(blkid_probe pr) + struct vfat_super_block *vs; + struct msdos_super_block *ms; + const struct blkid_idmag *mag = NULL; ++ int rc; + +- if (blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag) || !mag) ++ rc = blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag); ++ if (rc < 0) ++ return rc; /* error */ ++ if (rc != BLKID_PROBE_OK || !mag) + return 0; + + ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); + if (!ms) +- return 0; ++ return errno ? -errno : 0; + vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); + if (!vs) +- return 0; ++ return errno ? -errno : 0; + + return fat_valid_superblock(mag, ms, vs, NULL, NULL); + } +@@ -283,10 +287,12 @@ static int probe_vfat(blkid_probe pr, co + + ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); + if (!ms) +- return 0; ++ return errno ? -errno : 1; ++ + vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); + if (!vs) +- return 0; ++ return errno ? -errno : 1; ++ + if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size)) + return 1; + +@@ -376,16 +382,16 @@ static int probe_vfat(blkid_probe pr, co + (blkid_loff_t) fsinfo_sect * sector_size, + sizeof(struct fat32_fsinfo)); + if (buf == NULL) +- return -1; ++ return errno ? -errno : 1; + + fsinfo = (struct fat32_fsinfo *) buf; + if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 && + memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 && + memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0) +- return -1; ++ return 1; + if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 && + memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0) +- return -1; ++ return 1; + } + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/via_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/via_raid.c +--- util-linux-2.23.2/libblkid/src/superblocks/via_raid.c.kzak 2013-04-08 17:55:40.264856273 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/via_raid.c 2014-03-28 15:11:44.683552047 +0100 +@@ -52,9 +52,9 @@ static int probe_viaraid(blkid_probe pr, + struct via_metadata *v; + + if (pr->size < 0x10000) +- return -1; ++ return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) +- return -1; ++ return 1; + + off = ((pr->size / 0x200)-1) * 0x200; + +@@ -63,19 +63,19 @@ static int probe_viaraid(blkid_probe pr, + off, + sizeof(struct via_metadata)); + if (!v) +- return -1; ++ return errno ? -errno : 1; + if (le16_to_cpu(v->signature) != VIA_SIGNATURE) +- return -1; ++ return 1; + if (v->version_number > 2) +- return -1; ++ return 1; + if (!via_checksum(v)) +- return -1; ++ return 1; + if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0) +- return -1; ++ return 1; + if (blkid_probe_set_magic(pr, off, + sizeof(v->signature), + (unsigned char *) &v->signature)) +- return -1; ++ return 1; + return 0; + } + +diff -up util-linux-2.23.2/libblkid/src/superblocks/vmfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vmfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/vmfs.c.kzak 2013-04-08 17:55:40.264856273 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/vmfs.c 2014-03-28 15:11:44.683552047 +0100 +@@ -28,7 +28,7 @@ static int probe_vmfs_fs(blkid_probe pr, + + header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info); + if (header == NULL) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16, + "%02x%02x%02x%02x-%02x%02x%02x%02x-" +@@ -53,7 +53,7 @@ static int probe_vmfs_volume(blkid_probe + + header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info); + if (header == NULL) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_sprintf_value(pr, "UUID_SUB", + "%02x%02x%02x%02x-%02x%02x%02x%02x-" +diff -up util-linux-2.23.2/libblkid/src/superblocks/vxfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vxfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/vxfs.c.kzak 2013-04-08 17:55:40.264856273 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/vxfs.c 2014-03-28 15:11:44.683552047 +0100 +@@ -20,7 +20,7 @@ static int probe_vxfs(blkid_probe pr, co + + vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block); + if (!vxs) +- return -1; ++ return errno ? -errno : 1; + + blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version); + return 0; +diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak 2013-04-08 17:55:40.265856283 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c 2014-03-28 15:11:44.683552047 +0100 +@@ -40,7 +40,7 @@ static int probe_xfs(blkid_probe pr, con + + xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block); + if (!xs) +- return -1; ++ return errno ? -errno : 1; + + if (strlen(xs->xs_fname)) + blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname, +diff -up util-linux-2.23.2/libblkid/src/superblocks/zfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/zfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/zfs.c.kzak 2013-06-13 09:46:10.427650682 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/zfs.c 2014-03-28 15:11:44.683552047 +0100 +@@ -185,7 +185,7 @@ static int probe_zfs(blkid_probe pr, + blkid_probe_get_buffer(pr, offset, + sizeof(struct zfs_uberblock)); + if (ub == NULL) +- return -1; ++ return errno ? -errno : 1; + + if (ub->ub_magic == UBERBLOCK_MAGIC) { + ub_offset = offset; +@@ -202,7 +202,7 @@ static int probe_zfs(blkid_probe pr, + } + + if (found < 4) +- return -1; ++ return 1; + + /* If we found the 4th uberblock, then we will have exited from the + * scanning loop immediately, and ub will be a valid uberblock. */ +@@ -214,7 +214,7 @@ static int probe_zfs(blkid_probe pr, + if (blkid_probe_set_magic(pr, ub_offset, + sizeof(ub->ub_magic), + (unsigned char *) &ub->ub_magic)) +- return -1; ++ return 1; + + return 0; + } diff --git a/SOURCES/2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch b/SOURCES/2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch new file mode 100644 index 00000000..0eff9fab --- /dev/null +++ b/SOURCES/2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch @@ -0,0 +1,68 @@ +diff -up util-linux-2.23.2/libblkid/src/blkidP.h.kzak util-linux-2.23.2/libblkid/src/blkidP.h +--- util-linux-2.23.2/libblkid/src/blkidP.h.kzak 2013-07-30 10:39:26.205738229 +0200 ++++ util-linux-2.23.2/libblkid/src/blkidP.h 2014-01-23 10:51:10.109593273 +0100 +@@ -224,9 +224,6 @@ struct blkid_struct_probe + + /* private per-probing flags */ + #define BLKID_PROBE_FL_IGNORE_PT (1 << 1) /* ignore partition table */ +-#define BLKID_PROBE_FL_IGNORE_BACKUP (1 << 2) /* ignore backup superblocks or PT */ +- +-extern int blkid_probe_ignore_backup(blkid_probe pr); + + extern blkid_probe blkid_clone_probe(blkid_probe parent); + extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr); +diff -up util-linux-2.23.2/libblkid/src/probe.c.kzak util-linux-2.23.2/libblkid/src/probe.c +--- util-linux-2.23.2/libblkid/src/probe.c.kzak 2013-07-30 10:39:26.208738259 +0200 ++++ util-linux-2.23.2/libblkid/src/probe.c 2014-01-23 10:51:10.109593273 +0100 +@@ -924,7 +924,8 @@ int blkid_do_probe(blkid_probe pr) + * + * This function erases the current signature detected by @pr. The @pr has to + * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags +- * has to be enabled. ++ * has to be enabled (if you want to errase also superblock with broken check ++ * sums then use BLKID_SUBLKS_BADCSUM too). + * + * After successful signature removing the @pr prober will be moved one step + * back and the next blkid_do_probe() call will again call previously called +@@ -1125,8 +1126,6 @@ int blkid_do_safeprobe(blkid_probe pr) + + blkid_probe_start(pr); + +- pr->prob_flags |= BLKID_PROBE_FL_IGNORE_BACKUP; +- + for (i = 0; i < BLKID_NCHAINS; i++) { + struct blkid_chain *chn; + +@@ -1764,8 +1763,3 @@ void blkid_probe_use_wiper(blkid_probe p + blkid_probe_chain_reset_vals(pr, chn); + } + } +- +-int blkid_probe_ignore_backup(blkid_probe pr) +-{ +- return pr && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_BACKUP); +-} +diff -up util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/btrfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak 2013-06-13 09:46:10.421650630 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/btrfs.c 2014-01-23 10:51:10.109593273 +0100 +@@ -63,11 +63,6 @@ static int probe_btrfs(blkid_probe pr, c + { + struct btrfs_super_block *bfs; + +- if (mag->kboff > 64 && blkid_probe_ignore_backup(pr)) { +- DBG(LOWPROBE, blkid_debug("btrfs: found backup superblock, ignore")); +- return 1; +- } +- + bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); + if (!bfs) + return -1; +@@ -92,8 +87,6 @@ const struct blkid_idinfo btrfs_idinfo = + .magics = + { + { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 }, +- { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 * 1024 }, +- { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 256 * 1024 * 1024 }, + { NULL } + } + }; diff --git a/SOURCES/2.25-libblkid-return-codes.patch b/SOURCES/2.25-libblkid-return-codes.patch new file mode 100644 index 00000000..8b03fc46 --- /dev/null +++ b/SOURCES/2.25-libblkid-return-codes.patch @@ -0,0 +1,204 @@ +diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c +--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak 2015-08-11 14:00:27.930573965 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c 2015-08-11 14:13:11.213087814 +0200 +@@ -533,7 +533,7 @@ static int idinfo_probe(blkid_probe pr, + { + const struct blkid_idmag *mag = NULL; + blkid_loff_t off; +- int rc = BLKID_PROBE_NONE; /* = nothing detected */ ++ int rc = BLKID_PROBE_NONE; /* default is nothing */ + + if (pr->size <= 0 || (id->minsz && id->minsz > pr->size)) + goto nothing; /* the device is too small */ +@@ -564,8 +564,10 @@ static int idinfo_probe(blkid_probe pr, + DBG(LOWPROBE, blkid_debug("%s: <--- (rc = %d)", id->name, rc)); + } + +-nothing: + return rc; ++ ++nothing: ++ return BLKID_PROBE_NONE; + } + + /* +@@ -620,7 +622,7 @@ static int partitions_probe(blkid_probe + strlen(name) + 1); + DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]", + name, chn->idx)); +- rc = 0; ++ rc = BLKID_PROBE_OK; + break; + } + +@@ -637,10 +639,16 @@ details_only: + (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) { + + int xrc = blkid_partitions_probe_partition(pr); ++ ++ /* partition entry probing is optional, and "not-found" from ++ * this sub-probing must not to overwrite previous success. */ + if (xrc < 0) +- rc = xrc; /* optional, care about errors only */ ++ rc = xrc; /* always propagate errors */ ++ else if (rc == BLKID_PROBE_NONE) ++ rc = xrc; + } + ++ DBG(LOWPROBE, blkid_debug("partitions probe done [rc=%d]", rc)); + return rc; + } + +@@ -709,7 +717,6 @@ int blkid_partitions_do_subprobe(blkid_p + + static int blkid_partitions_probe_partition(blkid_probe pr) + { +- int rc = BLKID_PROBE_NONE; + blkid_probe disk_pr = NULL; + blkid_partlist ls; + blkid_partition par; +@@ -732,7 +739,9 @@ static int blkid_partitions_probe_partit + goto nothing; + + par = blkid_partlist_devno_to_partition(ls, devno); +- if (par) { ++ if (!par) ++ goto nothing; ++ else { + const char *v; + blkid_parttable tab = blkid_partition_get_table(par); + dev_t disk = blkid_probe_get_devno(disk_pr); +@@ -778,9 +787,13 @@ static int blkid_partitions_probe_partit + blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u", + major(disk), minor(disk)); + } +- rc = BLKID_PROBE_OK; ++ ++ DBG(LOWPROBE, blkid_debug("parts: end probing for partition entry [success]")); ++ return BLKID_PROBE_OK; ++ + nothing: +- return rc; ++ DBG(LOWPROBE, blkid_debug("parts: end probing for partition entry [nothing]")); ++ return BLKID_PROBE_NONE; + } + + /* +diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c +--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak 2015-07-03 10:35:05.456153560 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c 2015-08-11 14:08:42.572674469 +0200 +@@ -335,19 +335,24 @@ static int superblocks_probe(blkid_probe + + if (!pr || chn->idx < -1) + return -EINVAL; +- if (pr->flags & BLKID_FL_NOSCAN_DEV) +- goto nothing; + + blkid_probe_chain_reset_vals(pr, chn); + + DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]", + chn->idx)); + ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return BLKID_PROBE_NONE; ++ + if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode))) + /* Ignore very very small block devices or regular files (e.g. + * extended partitions). Note that size of the UBI char devices + * is 1 byte */ +- goto nothing; ++ return BLKID_PROBE_NONE; ++ ++ ++ DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]", ++ chn->idx)); + + i = chn->idx < 0 ? 0 : chn->idx + 1U; + +@@ -417,7 +422,7 @@ static int superblocks_probe(blkid_probe + (unsigned char *) mag->magic); + if (rc) { + blkid_probe_chain_reset_vals(pr, chn); +- DBG(LOWPROBE, blkid_debug("failed to set result -- ingnore")); ++ DBG(LOWPROBE, blkid_debug("failed to set result -- ignore")); + continue; + } + +@@ -426,7 +431,6 @@ static int superblocks_probe(blkid_probe + return BLKID_PROBE_OK; + } + +-nothing: + DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]", + rc, chn->idx)); + return rc; +@@ -454,13 +458,12 @@ static int superblocks_safeprobe(blkid_p + int rc; + + if (pr->flags & BLKID_FL_NOSCAN_DEV) +- return 1; /* nothing */ ++ return BLKID_PROBE_NONE; + + while ((rc = superblocks_probe(pr, chn)) == 0) { + + if (blkid_probe_is_tiny(pr) && !count) +- /* floppy or so -- returns the first result. */ +- return 0; ++ return BLKID_PROBE_OK; /* floppy or so -- returns the first result. */ + + count++; + +@@ -489,7 +492,7 @@ static int superblocks_safeprobe(blkid_p + return -2; /* error, ambivalent result (more FS) */ + } + if (!count) +- return 1; /* nothing detected */ ++ return BLKID_PROBE_NONE; + + if (idx != -1) { + /* restore the first result */ +@@ -506,7 +509,7 @@ static int superblocks_safeprobe(blkid_p + if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID) + pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT; + +- return 0; ++ return BLKID_PROBE_OK; + } + + int blkid_probe_set_version(blkid_probe pr, const char *version) +diff -up util-linux-2.23.2/libblkid/src/topology/topology.c.kzak util-linux-2.23.2/libblkid/src/topology/topology.c +--- util-linux-2.23.2/libblkid/src/topology/topology.c.kzak 2013-06-13 09:46:10.429650699 +0200 ++++ util-linux-2.23.2/libblkid/src/topology/topology.c 2015-08-11 14:09:35.623361499 +0200 +@@ -150,7 +150,7 @@ static int topology_probe(blkid_probe pr + return -1; + + if (!S_ISBLK(pr->mode)) +- return -1; /* nothing, works with block devices only */ ++ return -EINVAL; /* nothing, works with block devices only */ + + if (chn->binary) { + DBG(LOWPROBE, blkid_debug("initialize topology binary data")); +@@ -163,7 +163,7 @@ static int topology_probe(blkid_probe pr + chn->data = calloc(1, + sizeof(struct blkid_struct_topology)); + if (!chn->data) +- return -1; ++ return -ENOMEM; + } + } + +@@ -193,12 +193,12 @@ static int topology_probe(blkid_probe pr + + DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]", + id->name, chn->idx)); +- return 0; ++ return BLKID_PROBE_OK; + } + + DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]", + chn->idx)); +- return 1; ++ return BLKID_PROBE_NONE; + } + + static void topology_free(blkid_probe pr __attribute__((__unused__)), diff --git a/SOURCES/2.25-libblkid-thinpool.patch b/SOURCES/2.25-libblkid-thinpool.patch new file mode 100644 index 00000000..3c1c5664 --- /dev/null +++ b/SOURCES/2.25-libblkid-thinpool.patch @@ -0,0 +1,237 @@ +diff -up util-linux-2.23.2/fdisks/fdisk.c.kzak util-linux-2.23.2/fdisks/fdisk.c +--- util-linux-2.23.2/fdisks/fdisk.c.kzak 2015-07-02 12:37:24.465906322 +0200 ++++ util-linux-2.23.2/fdisks/fdisk.c 2015-07-02 12:37:57.870673753 +0200 +@@ -34,6 +34,7 @@ + #include "canonicalize.h" + #include "strutils.h" + #include "closestream.h" ++#include "sysfs.h" + + #include "fdisksunlabel.h" + #include "fdisksgilabel.h" +diff -up util-linux-2.23.2/include/sysfs.h.kzak util-linux-2.23.2/include/sysfs.h +--- util-linux-2.23.2/include/sysfs.h.kzak 2015-07-02 12:12:50.408196320 +0200 ++++ util-linux-2.23.2/include/sysfs.h 2015-07-02 12:13:09.708061372 +0200 +@@ -74,6 +74,8 @@ extern int sysfs_devno_to_wholedisk(dev_ + size_t len, dev_t *diskdevno); + extern int sysfs_devno_is_wholedisk(dev_t devno); + ++extern int sysfs_devno_is_lvm_private(dev_t devno); ++ + extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, + int *c, int *t, int *l); + extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt, +diff -up util-linux-2.23.2/libblkid/src/blkidP.h.kzak util-linux-2.23.2/libblkid/src/blkidP.h +--- util-linux-2.23.2/libblkid/src/blkidP.h.kzak 2015-07-02 12:18:27.349840375 +0200 ++++ util-linux-2.23.2/libblkid/src/blkidP.h 2015-07-02 12:19:07.797557558 +0200 +@@ -221,6 +221,7 @@ struct blkid_struct_probe + #define BLKID_FL_PRIVATE_FD (1 << 1) /* see blkid_new_probe_from_filename() */ + #define BLKID_FL_TINY_DEV (1 << 2) /* <= 1.47MiB (floppy or so) */ + #define BLKID_FL_CDROM_DEV (1 << 3) /* is a CD/DVD drive */ ++#define BLKID_FL_NOSCAN_DEV (1 << 4) /* do not scan this device */ + + /* private per-probing flags */ + #define BLKID_PROBE_FL_IGNORE_PT (1 << 1) /* ignore partition table */ +diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c +--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak 2015-07-02 12:19:11.669530485 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c 2015-07-02 12:28:24.166667964 +0200 +@@ -537,6 +537,8 @@ static int idinfo_probe(blkid_probe pr, + + if (pr->size <= 0 || (id->minsz && id->minsz > pr->size)) + goto nothing; /* the device is too small */ ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ goto nothing; + + rc = blkid_probe_get_idmag(pr, id, &off, &mag); + if (rc != BLKID_PROBE_OK) +@@ -576,8 +578,12 @@ static int partitions_probe(blkid_probe + + if (!pr || chn->idx < -1) + return -EINVAL; ++ + blkid_probe_chain_reset_vals(pr, chn); + ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return BLKID_PROBE_NONE; ++ + if (chn->binary) + partitions_init_data(chn); + +@@ -653,6 +659,8 @@ int blkid_partitions_do_subprobe(blkid_p + + if (!pr || !parent || !parent->size) + return -EINVAL; ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return BLKID_PROBE_NONE; + + /* range defined by parent */ + sz = ((blkid_loff_t) parent->size) << 9; +@@ -707,6 +715,9 @@ static int blkid_partitions_probe_partit + blkid_partition par; + dev_t devno; + ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ goto nothing; ++ + devno = blkid_probe_get_devno(pr); + if (!devno) + goto nothing; +@@ -779,7 +790,7 @@ nothing: + int blkid_probe_is_covered_by_pt(blkid_probe pr, + blkid_loff_t offset, blkid_loff_t size) + { +- blkid_probe prc; ++ blkid_probe prc = NULL; + blkid_partlist ls = NULL; + blkid_loff_t start, end; + int nparts, i, rc = 0; +@@ -788,6 +799,9 @@ int blkid_probe_is_covered_by_pt(blkid_p + "=> checking if off=%jd size=%jd covered by PT", + offset, size)); + ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ goto done; ++ + prc = blkid_clone_probe(pr); + if (!prc) + goto done; +diff -up util-linux-2.23.2/libblkid/src/probe.c.kzak util-linux-2.23.2/libblkid/src/probe.c +--- util-linux-2.23.2/libblkid/src/probe.c.kzak 2015-07-02 12:13:48.823787869 +0200 ++++ util-linux-2.23.2/libblkid/src/probe.c 2015-07-02 12:38:20.110518915 +0200 +@@ -110,6 +110,7 @@ + + #include "blkidP.h" + #include "all-io.h" ++#include "sysfs.h" + + /* chains */ + extern const struct blkid_chaindrv superblocks_drv; +@@ -714,8 +715,13 @@ int blkid_probe_set_device(blkid_probe p + if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode)) + pr->flags |= BLKID_FL_TINY_DEV; + ++ if (S_ISBLK(sb.st_mode) && sysfs_devno_is_lvm_private(sb.st_rdev)) { ++ DBG(LOWPROBE, blkid_debug("ignore private LVM device")); ++ pr->flags |= BLKID_FL_NOSCAN_DEV; ++ } ++ + #ifdef CDROM_GET_CAPABILITY +- if (S_ISBLK(sb.st_mode) && ++ else if (S_ISBLK(sb.st_mode) && + !blkid_probe_is_tiny(pr) && + blkid_probe_is_wholedisk(pr) && + ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0) +@@ -892,6 +898,9 @@ int blkid_do_probe(blkid_probe pr) + if (!pr) + return -1; + ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return 1; ++ + do { + struct blkid_chain *chn = pr->cur_chain; + +@@ -1143,6 +1152,8 @@ int blkid_do_safeprobe(blkid_probe pr) + + if (!pr) + return -1; ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return 1; + + blkid_probe_start(pr); + +@@ -1197,6 +1208,8 @@ int blkid_do_fullprobe(blkid_probe pr) + + if (!pr) + return -1; ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return 1; + + blkid_probe_start(pr); + +diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c +--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak 2015-07-02 12:29:32.370193121 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c 2015-07-02 12:31:06.897535008 +0200 +@@ -338,6 +338,9 @@ static int superblocks_probe(blkid_probe + + if (!pr || chn->idx < -1) + return -EINVAL; ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ goto nothing; ++ + blkid_probe_chain_reset_vals(pr, chn); + + DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]", +@@ -453,6 +456,9 @@ static int superblocks_safeprobe(blkid_p + int intol = 0; + int rc; + ++ if (pr->flags & BLKID_FL_NOSCAN_DEV) ++ return 1; /* nothing */ ++ + while ((rc = superblocks_probe(pr, chn)) == 0) { + + if (blkid_probe_is_tiny(pr) && !count) +diff -up util-linux-2.23.2/libblkid/src/verify.c.kzak util-linux-2.23.2/libblkid/src/verify.c +--- util-linux-2.23.2/libblkid/src/verify.c.kzak 2015-07-02 12:15:51.782928121 +0200 ++++ util-linux-2.23.2/libblkid/src/verify.c 2015-07-02 12:16:45.078555470 +0200 +@@ -112,6 +112,10 @@ blkid_dev blkid_verify(blkid_cache cache + (unsigned long)diff)); + #endif + ++ if (sysfs_devno_is_lvm_private(st.st_rdev)) { ++ blkid_free_dev(dev); ++ return NULL; ++ } + if (!cache->probe) { + cache->probe = blkid_new_probe(); + if (!cache->probe) { +diff -up util-linux-2.23.2/lib/sysfs.c.kzak util-linux-2.23.2/lib/sysfs.c +--- util-linux-2.23.2/lib/sysfs.c.kzak 2015-07-02 12:12:29.193344657 +0200 ++++ util-linux-2.23.2/lib/sysfs.c 2015-07-02 12:12:13.565453930 +0200 +@@ -639,6 +639,35 @@ err: + } + + /* ++ * Returns 1 if the device is private LVM device. ++ */ ++int sysfs_devno_is_lvm_private(dev_t devno) ++{ ++ struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; ++ char *uuid = NULL; ++ int rc = 0; ++ ++ if (sysfs_init(&cxt, devno, NULL) != 0) ++ return 0; ++ ++ uuid = sysfs_strdup(&cxt, "dm/uuid"); ++ ++ /* Private LVM devices use "LVM--" uuid format (important ++ * is the "LVM" prefix and "-" postfix). ++ */ ++ if (uuid && strncmp(uuid, "LVM-", 4) == 0) { ++ char *p = strrchr(uuid + 4, '-'); ++ ++ if (p && *(p + 1)) ++ rc = 1; ++ } ++ ++ sysfs_deinit(&cxt); ++ free(uuid); ++ return rc; ++} ++ ++/* + * Return 0 or 1, or < 0 in case of error + */ + int sysfs_devno_is_wholedisk(dev_t devno) +@@ -651,6 +680,9 @@ int sysfs_devno_is_wholedisk(dev_t devno + return devno == disk; + } + ++ ++ ++ + int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l) + { + char buf[PATH_MAX], *hctl; diff --git a/SOURCES/2.25-libblkid-xfs-log.patch b/SOURCES/2.25-libblkid-xfs-log.patch new file mode 100644 index 00000000..be4680aa --- /dev/null +++ b/SOURCES/2.25-libblkid-xfs-log.patch @@ -0,0 +1,133 @@ +diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c +--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak 2015-06-24 12:58:20.790115492 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c 2015-06-24 12:57:57.961286166 +0200 +@@ -49,6 +49,8 @@ + * + * @UUID_SUB: subvolume uuid (e.g. btrfs) + * ++ * @LOGUUID: external log UUID (e.g. xfs) ++ * + * @UUID_RAW: raw UUID from FS superblock + * + * @EXT_JOURNAL: external journal UUID +@@ -113,6 +115,7 @@ static const struct blkid_idinfo *idinfo + &swsuspend_idinfo, + &swap_idinfo, + &xfs_idinfo, ++ &xfs_log_idinfo, + &ext4dev_idinfo, + &ext4_idinfo, + &ext3_idinfo, +diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.h.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.h +--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.h.kzak 2015-06-24 12:58:48.533908071 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.h 2015-06-24 12:59:00.098821476 +0200 +@@ -29,6 +29,7 @@ extern const struct blkid_idinfo ext2_id + extern const struct blkid_idinfo jbd_idinfo; + extern const struct blkid_idinfo jfs_idinfo; + extern const struct blkid_idinfo xfs_idinfo; ++extern const struct blkid_idinfo xfs_log_idinfo; + extern const struct blkid_idinfo gfs_idinfo; + extern const struct blkid_idinfo gfs2_idinfo; + extern const struct blkid_idinfo romfs_idinfo; +diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak 2015-06-24 12:39:34.300507071 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c 2015-06-24 12:39:45.389427015 +0200 +@@ -4,6 +4,7 @@ + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers + * Copyright (C) 2008 Karel Zak ++ * Copyright (C) 2013 Eric Sandeen + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. +@@ -187,3 +188,90 @@ const struct blkid_idinfo xfs_idinfo = + } + }; + ++struct xlog_rec_header { ++ uint32_t h_magicno; ++ uint32_t h_dummy1[1]; ++ uint32_t h_version; ++ uint32_t h_len; ++ uint32_t h_dummy2[71]; ++ uint32_t h_fmt; ++ unsigned char h_uuid[16]; ++} __attribute__((packed)); ++ ++#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe ++ ++/* ++ * For very small filesystems, the minimum log size ++ * can be smaller, but that seems vanishingly unlikely ++ * when used with an external log (which is used for ++ * performance reasons; tiny conflicts with that goal). ++ */ ++#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024) ++ ++#define XLOG_FMT_LINUX_LE 1 ++#define XLOG_FMT_LINUX_BE 2 ++#define XLOG_FMT_IRIX_BE 3 ++ ++#define XLOG_VERSION_1 1 ++#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ ++#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) ++ ++static int xlog_valid_rec_header(struct xlog_rec_header *rhead) ++{ ++ uint32_t hlen; ++ ++ if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) ++ return 0; ++ ++ if (!rhead->h_version || ++ (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))) ++ return 0; ++ ++ /* LR body must have data or it wouldn't have been written */ ++ hlen = be32_to_cpu(rhead->h_len); ++ if (hlen <= 0 || hlen > INT_MAX) ++ return 0; ++ ++ if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) && ++ rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) && ++ rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE)) ++ return 0; ++ ++ return 1; ++} ++ ++/* xlog record header will be in some sector in the first 256k */ ++static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag) ++{ ++ int i; ++ struct xlog_rec_header *rhead; ++ unsigned char *buf; ++ ++ buf = blkid_probe_get_buffer(pr, 0, 256*1024); ++ if (!buf) ++ return errno ? -errno : 1; ++ ++ if (memcmp(buf, "XFSB", 4) == 0) ++ return 1; /* this is regular XFS, ignore */ ++ ++ /* check the first 512 512-byte sectors */ ++ for (i = 0; i < 512; i++) { ++ rhead = (struct xlog_rec_header *)&buf[i*512]; ++ ++ if (xlog_valid_rec_header(rhead)) { ++ blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID"); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++const struct blkid_idinfo xfs_log_idinfo = ++{ ++ .name = "xfs_external_log", ++ .usage = BLKID_USAGE_OTHER, ++ .probefunc = probe_xfs_log, ++ .magics = BLKID_NONE_MAGIC, ++ .minsz = XFS_MIN_LOG_BYTES, ++}; diff --git a/SOURCES/2.25-libblkid-xfs.patch b/SOURCES/2.25-libblkid-xfs.patch new file mode 100644 index 00000000..bccc2298 --- /dev/null +++ b/SOURCES/2.25-libblkid-xfs.patch @@ -0,0 +1,176 @@ +diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c +--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak 2014-09-24 10:59:39.548315524 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c 2014-09-24 11:02:55.595186026 +0200 +@@ -20,20 +20,143 @@ + #include "superblocks.h" + + struct xfs_super_block { +- unsigned char xs_magic[4]; +- uint32_t xs_blocksize; +- uint64_t xs_dblocks; +- uint64_t xs_rblocks; +- uint32_t xs_dummy1[2]; +- unsigned char xs_uuid[16]; +- uint32_t xs_dummy2[15]; +- char xs_fname[12]; +- uint32_t xs_dummy3[2]; +- uint64_t xs_icount; +- uint64_t xs_ifree; +- uint64_t xs_fdblocks; ++ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ ++ uint32_t sb_blocksize; /* logical block size, bytes */ ++ uint64_t sb_dblocks; /* number of data blocks */ ++ uint64_t sb_rblocks; /* number of realtime blocks */ ++ uint64_t sb_rextents; /* number of realtime extents */ ++ unsigned char sb_uuid[16]; /* file system unique id */ ++ uint64_t sb_logstart; /* starting block of log if internal */ ++ uint64_t sb_rootino; /* root inode number */ ++ uint64_t sb_rbmino; /* bitmap inode for realtime extents */ ++ uint64_t sb_rsumino; /* summary inode for rt bitmap */ ++ uint32_t sb_rextsize; /* realtime extent size, blocks */ ++ uint32_t sb_agblocks; /* size of an allocation group */ ++ uint32_t sb_agcount; /* number of allocation groups */ ++ uint32_t sb_rbmblocks; /* number of rt bitmap blocks */ ++ uint32_t sb_logblocks; /* number of log blocks */ ++ ++ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ ++ uint16_t sb_sectsize; /* volume sector size, bytes */ ++ uint16_t sb_inodesize; /* inode size, bytes */ ++ uint16_t sb_inopblock; /* inodes per block */ ++ char sb_fname[12]; /* file system name */ ++ uint8_t sb_blocklog; /* log2 of sb_blocksize */ ++ uint8_t sb_sectlog; /* log2 of sb_sectsize */ ++ uint8_t sb_inodelog; /* log2 of sb_inodesize */ ++ uint8_t sb_inopblog; /* log2 of sb_inopblock */ ++ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ ++ uint8_t sb_rextslog; /* log2 of sb_rextents */ ++ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ ++ uint8_t sb_imax_pct; /* max % of fs for inode space */ ++ /* statistics */ ++ uint64_t sb_icount; /* allocated inodes */ ++ uint64_t sb_ifree; /* free inodes */ ++ uint64_t sb_fdblocks; /* free data blocks */ ++ uint64_t sb_frextents; /* free realtime extents */ ++ ++ /* this is not all... but enough for libblkid */ ++ + } __attribute__((packed)); + ++#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ ++#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ ++#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) ++#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) ++#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ ++#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ ++#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) ++#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) ++ ++#define XFS_DINODE_MIN_LOG 8 ++#define XFS_DINODE_MAX_LOG 11 ++#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) ++#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) ++ ++#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ ++#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64kB */ ++#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4kB */ ++ ++#define XFS_MIN_AG_BLOCKS 64 ++#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks) ++#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) * \ ++ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) ++ ++ ++static void sb_from_disk(struct xfs_super_block *from, ++ struct xfs_super_block *to) ++{ ++ ++ to->sb_magicnum = be32_to_cpu(from->sb_magicnum); ++ to->sb_blocksize = be32_to_cpu(from->sb_blocksize); ++ to->sb_dblocks = be64_to_cpu(from->sb_dblocks); ++ to->sb_rblocks = be64_to_cpu(from->sb_rblocks); ++ to->sb_rextents = be64_to_cpu(from->sb_rextents); ++ to->sb_logstart = be64_to_cpu(from->sb_logstart); ++ to->sb_rootino = be64_to_cpu(from->sb_rootino); ++ to->sb_rbmino = be64_to_cpu(from->sb_rbmino); ++ to->sb_rsumino = be64_to_cpu(from->sb_rsumino); ++ to->sb_rextsize = be32_to_cpu(from->sb_rextsize); ++ to->sb_agblocks = be32_to_cpu(from->sb_agblocks); ++ to->sb_agcount = be32_to_cpu(from->sb_agcount); ++ to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); ++ to->sb_logblocks = be32_to_cpu(from->sb_logblocks); ++ to->sb_versionnum = be16_to_cpu(from->sb_versionnum); ++ to->sb_sectsize = be16_to_cpu(from->sb_sectsize); ++ to->sb_inodesize = be16_to_cpu(from->sb_inodesize); ++ to->sb_inopblock = be16_to_cpu(from->sb_inopblock); ++ to->sb_blocklog = from->sb_blocklog; ++ to->sb_sectlog = from->sb_sectlog; ++ to->sb_inodelog = from->sb_inodelog; ++ to->sb_inopblog = from->sb_inopblog; ++ to->sb_agblklog = from->sb_agblklog; ++ to->sb_rextslog = from->sb_rextslog; ++ to->sb_inprogress = from->sb_inprogress; ++ to->sb_imax_pct = from->sb_imax_pct; ++ to->sb_icount = be64_to_cpu(from->sb_icount); ++ to->sb_ifree = be64_to_cpu(from->sb_ifree); ++ to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); ++ to->sb_frextents = be64_to_cpu(from->sb_frextents); ++} ++ ++static int xfs_verify_sb(struct xfs_super_block *ondisk) ++{ ++ struct xfs_super_block sb, *sbp = &sb; ++ ++ /* beXX_to_cpu(), but don't convert UUID and fsname! */ ++ sb_from_disk(ondisk, sbp); ++ ++ /* sanity checks, we don't want to rely on magic string only */ ++ if (sbp->sb_agcount <= 0 || ++ sbp->sb_sectsize < XFS_MIN_SECTORSIZE || ++ sbp->sb_sectsize > XFS_MAX_SECTORSIZE || ++ sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || ++ sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || ++ sbp->sb_sectsize != (1 << sbp->sb_sectlog) || ++ sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || ++ sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || ++ sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || ++ sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || ++ sbp->sb_blocksize != (1 << sbp->sb_blocklog) || ++ sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || ++ sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || ++ sbp->sb_inodelog < XFS_DINODE_MIN_LOG || ++ sbp->sb_inodelog > XFS_DINODE_MAX_LOG || ++ sbp->sb_inodesize != (1 << sbp->sb_inodelog) || ++ (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || ++ (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || ++ (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || ++ (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) || ++ sbp->sb_dblocks == 0 || ++ sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || ++ sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp)) ++ return 0; ++ ++ /* TODO: version 5 has also checksum CRC32, maybe we can check it too */ ++ ++ return 1; ++} ++ + static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag) + { + struct xfs_super_block *xs; +@@ -42,10 +165,13 @@ static int probe_xfs(blkid_probe pr, con + if (!xs) + return errno ? -errno : 1; + +- if (strlen(xs->xs_fname)) +- blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname, +- sizeof(xs->xs_fname)); +- blkid_probe_set_uuid(pr, xs->xs_uuid); ++ if (!xfs_verify_sb(xs)) ++ return 1; ++ ++ if (strlen(xs->sb_fname)) ++ blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname, ++ sizeof(xs->sb_fname)); ++ blkid_probe_set_uuid(pr, xs->sb_uuid); + return 0; + } diff --git a/SOURCES/2.25-lscpu-d_type.patch b/SOURCES/2.25-lscpu-d_type.patch new file mode 100644 index 00000000..cbab29fb --- /dev/null +++ b/SOURCES/2.25-lscpu-d_type.patch @@ -0,0 +1,12 @@ +diff -up util-linux-2.23.2/sys-utils/lscpu.c.kzak util-linux-2.23.2/sys-utils/lscpu.c +--- util-linux-2.23.2/sys-utils/lscpu.c.kzak 2014-09-24 10:27:29.410899893 +0200 ++++ util-linux-2.23.2/sys-utils/lscpu.c 2014-09-24 10:33:20.960254060 +0200 +@@ -809,7 +809,7 @@ static inline int is_node_dirent(struct + return + d && + #ifdef _DIRENT_HAVE_D_TYPE +- d->d_type == DT_DIR && ++ (d->d_type == DT_DIR || d->d_type == DT_UNKNOWN) && + #endif + strncmp(d->d_name, "node", 4) == 0 && + isdigit_string(d->d_name + 4); diff --git a/SOURCES/2.25-lscpu-discontinuous-NUMA-nodes.patch b/SOURCES/2.25-lscpu-discontinuous-NUMA-nodes.patch new file mode 100644 index 00000000..1600d717 --- /dev/null +++ b/SOURCES/2.25-lscpu-discontinuous-NUMA-nodes.patch @@ -0,0 +1,102 @@ +diff -up util-linux-2.23.2/sys-utils/lscpu.c.kzak util-linux-2.23.2/sys-utils/lscpu.c +--- util-linux-2.23.2/sys-utils/lscpu.c.kzak 2013-07-30 10:39:26.342739583 +0200 ++++ util-linux-2.23.2/sys-utils/lscpu.c 2014-01-14 11:21:51.837599200 +0100 +@@ -49,6 +49,7 @@ + /* /sys paths */ + #define _PATH_SYS_SYSTEM "/sys/devices/system" + #define _PATH_SYS_CPU _PATH_SYS_SYSTEM "/cpu" ++#define _PATH_SYS_NODE _PATH_SYS_SYSTEM "/node" + #define _PATH_PROC_XEN "/proc/xen" + #define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities" + #define _PATH_PROC_CPUINFO "/proc/cpuinfo" +@@ -157,6 +158,7 @@ struct lscpu_desc { + cpu_set_t *online; /* mask with online CPUs */ + + int nnodes; /* number of NUMA modes */ ++ int *idx2nodenum; /* Support for discontinuous nodes */ + cpu_set_t **nodemaps; /* array with NUMA nodes */ + + /* books -- based on book_siblings (internal kernel map of cpuX's +@@ -802,25 +804,59 @@ read_cache(struct lscpu_desc *desc, int + } + } + ++static inline int is_node_dirent(struct dirent *d) ++{ ++ return ++ d && ++#ifdef _DIRENT_HAVE_D_TYPE ++ d->d_type == DT_DIR && ++#endif ++ strncmp(d->d_name, "node", 4) == 0 && ++ isdigit_string(d->d_name + 4); ++} ++ + static void + read_nodes(struct lscpu_desc *desc) + { +- int i; ++ int i = 0; ++ DIR *dir; ++ struct dirent *d; ++ char *path; + + /* number of NUMA node */ +- while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", desc->nnodes)) +- desc->nnodes++; ++ path = path_strdup(_PATH_SYS_NODE); ++ dir = opendir(path); ++ free(path); ++ ++ while (dir && (d = readdir(dir))) { ++ if (is_node_dirent(d)) ++ desc->nnodes++; ++ } + +- if (!desc->nnodes) ++ if (!desc->nnodes) { ++ if (dir) ++ closedir(dir); + return; ++ } + + desc->nodemaps = xcalloc(desc->nnodes, sizeof(cpu_set_t *)); ++ desc->idx2nodenum = xmalloc(desc->nnodes * sizeof(int)); ++ ++ if (dir) { ++ rewinddir(dir); ++ while ((d = readdir(dir)) && i < desc->nnodes) { ++ if (is_node_dirent(d)) ++ desc->idx2nodenum[i++] = strtol_or_err(((d->d_name) + 4), ++ _("Failed to extract the node number")); ++ } ++ closedir(dir); ++ } + + /* information about how nodes share different CPUs */ + for (i = 0; i < desc->nnodes; i++) + desc->nodemaps[i] = path_read_cpuset(maxcpus, + _PATH_SYS_SYSTEM "/node/node%d/cpumap", +- i); ++ desc->idx2nodenum[i]); + } + + static char * +@@ -850,7 +886,7 @@ get_cell_data(struct lscpu_desc *desc, i + case COL_NODE: + if (cpuset_ary_isset(cpu, desc->nodemaps, + desc->nnodes, setsize, &idx) == 0) +- snprintf(buf, bufsz, "%zd", idx); ++ snprintf(buf, bufsz, "%d", desc->idx2nodenum[idx]); + break; + case COL_BOOK: + if (cpuset_ary_isset(cpu, desc->bookmaps, +@@ -1250,7 +1286,7 @@ print_summary(struct lscpu_desc *desc, s + } + + for (i = 0; i < desc->nnodes; i++) { +- snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), i); ++ snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]); + print_cpuset(buf, desc->nodemaps[i], mod->hex); + } + } diff --git a/SOURCES/2.25-lscpu-sort-NUMA.patch b/SOURCES/2.25-lscpu-sort-NUMA.patch new file mode 100644 index 00000000..6e4ccf46 --- /dev/null +++ b/SOURCES/2.25-lscpu-sort-NUMA.patch @@ -0,0 +1,144 @@ +diff -up util-linux-2.23.2/sys-utils/lscpu.c.kzak util-linux-2.23.2/sys-utils/lscpu.c +--- util-linux-2.23.2/sys-utils/lscpu.c.kzak 2014-01-14 14:02:52.228996385 +0100 ++++ util-linux-2.23.2/sys-utils/lscpu.c 2014-01-14 14:04:08.109795733 +0100 +@@ -815,6 +815,13 @@ static inline int is_node_dirent(struct + isdigit_string(d->d_name + 4); + } + ++static int ++nodecmp(const void *ap, const void *bp) ++{ ++ int *a = (int *) ap, *b = (int *) bp; ++ return *a - *b; ++} ++ + static void + read_nodes(struct lscpu_desc *desc) + { +@@ -850,6 +857,7 @@ read_nodes(struct lscpu_desc *desc) + _("Failed to extract the node number")); + } + closedir(dir); ++ qsort(desc->idx2nodenum, desc->nnodes, sizeof(int), nodecmp); + } + + /* information about how nodes share different CPUs */ +diff -up util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu.kzak util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu +--- util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu.kzak 2013-06-13 09:46:10.551651742 +0200 ++++ util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu 2014-01-14 14:04:29.662022613 +0100 +@@ -4,7 +4,7 @@ On-line CPU(s) list: 0-63 + Thread(s) per core: 2 + Core(s) per socket: 8 + Socket(s): 4 +-NUMA node(s): 1 ++NUMA node(s): 3 + Vendor ID: GenuineIntel + CPU family: 6 + Model: 46 +@@ -18,72 +18,74 @@ L1i cache: 32K + L2 cache: 256K + L3 cache: 18432K + NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62 ++NUMA node2 CPU(s): 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61 ++NUMA node3 CPU(s): 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63 + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID + # starting from zero. + # CPU,Core,Socket,Node,,L1d,L1i,L2,L3 + 0,0,0,0,,0,0,0,0 +-1,1,1,,,1,1,1,1 ++1,1,1,2,,1,1,1,1 + 2,2,2,0,,2,2,2,2 +-3,3,3,,,3,3,3,3 ++3,3,3,3,,3,3,3,3 + 4,4,0,0,,4,4,4,0 +-5,5,1,,,5,5,5,1 ++5,5,1,2,,5,5,5,1 + 6,6,2,0,,6,6,6,2 +-7,7,3,,,7,7,7,3 ++7,7,3,3,,7,7,7,3 + 8,8,0,0,,8,8,8,0 +-9,9,1,,,9,9,9,1 ++9,9,1,2,,9,9,9,1 + 10,10,2,0,,10,10,10,2 +-11,11,3,,,11,11,11,3 ++11,11,3,3,,11,11,11,3 + 12,12,0,0,,12,12,12,0 +-13,13,1,,,13,13,13,1 ++13,13,1,2,,13,13,13,1 + 14,14,2,0,,14,14,14,2 +-15,15,3,,,15,15,15,3 ++15,15,3,3,,15,15,15,3 + 16,16,0,0,,16,16,16,0 +-17,17,1,,,17,17,17,1 ++17,17,1,2,,17,17,17,1 + 18,18,2,0,,18,18,18,2 +-19,19,3,,,19,19,19,3 ++19,19,3,3,,19,19,19,3 + 20,20,0,0,,20,20,20,0 +-21,21,1,,,21,21,21,1 ++21,21,1,2,,21,21,21,1 + 22,22,2,0,,22,22,22,2 +-23,23,3,,,23,23,23,3 ++23,23,3,3,,23,23,23,3 + 24,24,0,0,,24,24,24,0 +-25,25,1,,,25,25,25,1 ++25,25,1,2,,25,25,25,1 + 26,26,2,0,,26,26,26,2 +-27,27,3,,,27,27,27,3 ++27,27,3,3,,27,27,27,3 + 28,28,0,0,,28,28,28,0 +-29,29,1,,,29,29,29,1 ++29,29,1,2,,29,29,29,1 + 30,30,2,0,,30,30,30,2 +-31,31,3,,,31,31,31,3 ++31,31,3,3,,31,31,31,3 + 32,0,0,0,,0,0,0,0 +-33,1,1,,,1,1,1,1 ++33,1,1,2,,1,1,1,1 + 34,2,2,0,,2,2,2,2 +-35,3,3,,,3,3,3,3 ++35,3,3,3,,3,3,3,3 + 36,4,0,0,,4,4,4,0 +-37,5,1,,,5,5,5,1 ++37,5,1,2,,5,5,5,1 + 38,6,2,0,,6,6,6,2 +-39,7,3,,,7,7,7,3 ++39,7,3,3,,7,7,7,3 + 40,8,0,0,,8,8,8,0 +-41,9,1,,,9,9,9,1 ++41,9,1,2,,9,9,9,1 + 42,10,2,0,,10,10,10,2 +-43,11,3,,,11,11,11,3 ++43,11,3,3,,11,11,11,3 + 44,12,0,0,,12,12,12,0 +-45,13,1,,,13,13,13,1 ++45,13,1,2,,13,13,13,1 + 46,14,2,0,,14,14,14,2 +-47,15,3,,,15,15,15,3 ++47,15,3,3,,15,15,15,3 + 48,16,0,0,,16,16,16,0 +-49,17,1,,,17,17,17,1 ++49,17,1,2,,17,17,17,1 + 50,18,2,0,,18,18,18,2 +-51,19,3,,,19,19,19,3 ++51,19,3,3,,19,19,19,3 + 52,20,0,0,,20,20,20,0 +-53,21,1,,,21,21,21,1 ++53,21,1,2,,21,21,21,1 + 54,22,2,0,,22,22,22,2 +-55,23,3,,,23,23,23,3 ++55,23,3,3,,23,23,23,3 + 56,24,0,0,,24,24,24,0 +-57,25,1,,,25,25,25,1 ++57,25,1,2,,25,25,25,1 + 58,26,2,0,,26,26,26,2 +-59,27,3,,,27,27,27,3 ++59,27,3,3,,27,27,27,3 + 60,28,0,0,,28,28,28,0 +-61,29,1,,,29,29,29,1 ++61,29,1,2,,29,29,29,1 + 62,30,2,0,,30,30,30,2 +-63,31,3,,,31,31,31,3 ++63,31,3,3,,31,31,31,3 diff --git a/SOURCES/2.25-mount-man-default.patch b/SOURCES/2.25-mount-man-default.patch new file mode 100644 index 00000000..bc2c20fd --- /dev/null +++ b/SOURCES/2.25-mount-man-default.patch @@ -0,0 +1,27 @@ +diff -up util-linux-2.23.2/sys-utils/mount.8.kzak util-linux-2.23.2/sys-utils/mount.8 +--- util-linux-2.23.2/sys-utils/mount.8.kzak 2015-06-24 10:44:54.888929869 +0200 ++++ util-linux-2.23.2/sys-utils/mount.8 2015-06-24 10:48:10.022436703 +0200 +@@ -865,9 +865,10 @@ Some of these options are only useful wh + .I /etc/fstab + file. + +-Some of these options could be enabled or disabled by default +-in the system kernel. To check the current setting see the options +-in /proc/mounts. ++Some of these options could be enabled or disabled by default in the system ++kernel. To check the current setting see the options in /proc/mounts. Note ++that filesystems also have per-filesystem specific default mount options (see ++for example tune2fs -l output for extN filesystems). + + The following options apply to any filesystem that is being + mounted (but not every filesystem actually honors them - e.g., the +@@ -973,6 +974,9 @@ For more details, see + .B defaults + Use default options: + .BR rw ", " suid ", " dev ", " exec ", " auto ", " nouser ", and " async. ++ ++Note that the real set of the all default mount options depends on kernel ++and filesystem type. See the begin of this section for more details. + .TP + .B dev + Interpret character or block special devices on the filesystem. diff --git a/SOURCES/2.25-mount-man-xfs.patch b/SOURCES/2.25-mount-man-xfs.patch new file mode 100644 index 00000000..b8973cd1 --- /dev/null +++ b/SOURCES/2.25-mount-man-xfs.patch @@ -0,0 +1,16 @@ +diff -up util-linux-2.23.2/sys-utils/mount.8.kzak util-linux-2.23.2/sys-utils/mount.8 +--- util-linux-2.23.2/sys-utils/mount.8.kzak 2014-03-12 12:35:46.532369960 +0100 ++++ util-linux-2.23.2/sys-utils/mount.8 2014-03-12 12:35:23.041126143 +0100 +@@ -2598,9 +2598,9 @@ None. + .TP + .BR allocsize=size + Sets the buffered I/O end-of-file preallocation size when +-doing delayed allocation writeout (default size is 64KiB). +-Valid values for this option are page size (typically 4KiB) +-through to 1GiB, inclusive, in power-of-2 increments. ++doing delayed allocation writeout. Valid values for this ++option are page size (typically 4KiB) through to 1GiB, ++inclusive, in power-of-2 increments. + .sp + The default behaviour is for dynamic end-of-file + preallocation size, which uses a set of heuristics to diff --git a/SOURCES/2.25-swapon-discard.patch b/SOURCES/2.25-swapon-discard.patch new file mode 100644 index 00000000..2ce4783f --- /dev/null +++ b/SOURCES/2.25-swapon-discard.patch @@ -0,0 +1,200 @@ +diff -up util-linux-2.23.2/sys-utils/swapon.8.kzak util-linux-2.23.2/sys-utils/swapon.8 +--- util-linux-2.23.2/sys-utils/swapon.8.kzak 2013-06-13 09:46:10.544651682 +0200 ++++ util-linux-2.23.2/sys-utils/swapon.8 2014-09-24 10:57:45.855230767 +0200 +@@ -112,15 +112,25 @@ All devices marked as ``swap'' in + are made available, except for those with the ``noauto'' option. + Devices that are already being used as swap are silently skipped. + .TP +-.B "\-d, \-\-discard" +-Discard freed swap pages before they are reused, if the swap +-device supports the discard or trim operation. This may improve +-performance on some Solid State Devices, but often it does not. ++.B "\-d, \-\-discard\fR [=\fIpolicy\fR]" ++Enable swap discards, if the swap backing device supports the discard or ++trim operation. This may improve performance on some Solid State Devices, ++but often it does not. The option allows one to select between two ++available swap discard policies: ++.BI \-\-discard=once ++to perform a single-time discard operation for the whole swap area at swapon; ++or ++.BI \-\-discard=pages ++to discard freed swap pages before they are reused, while swapping. ++If no policy is selected, the default behavior is to enable both discard types. + The + .I /etc/fstab +-mount option +-.BI discard +-may be also used to enable discard flag. ++mount options ++.BI discard, ++.BI discard=once, ++or ++.BI discard=pages ++may be also used to enable discard flags. + .TP + .B "\-e, \-\-ifexists" + Silently skip devices that do not exist. +diff -up util-linux-2.23.2/sys-utils/swapon.c.kzak util-linux-2.23.2/sys-utils/swapon.c +--- util-linux-2.23.2/sys-utils/swapon.c.kzak 2013-07-30 10:39:26.348739643 +0200 ++++ util-linux-2.23.2/sys-utils/swapon.c 2014-09-24 10:57:45.855230767 +0200 +@@ -34,9 +34,20 @@ + #endif + + #ifndef SWAP_FLAG_DISCARD +-# define SWAP_FLAG_DISCARD 0x10000 /* discard swap cluster after use */ ++# define SWAP_FLAG_DISCARD 0x10000 /* enable discard for swap */ + #endif + ++#ifndef SWAP_FLAG_DISCARD_ONCE ++# define SWAP_FLAG_DISCARD_ONCE 0x20000 /* discard swap area at swapon-time */ ++#endif ++ ++#ifndef SWAP_FLAG_DISCARD_PAGES ++# define SWAP_FLAG_DISCARD_PAGES 0x40000 /* discard page-clusters after use */ ++#endif ++ ++#define SWAP_FLAGS_DISCARD_VALID (SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | \ ++ SWAP_FLAG_DISCARD_PAGES) ++ + #ifndef SWAP_FLAG_PREFER + # define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ + #endif +@@ -70,7 +81,7 @@ enum { + + static int all; + static int priority = -1; /* non-prioritized swap by default */ +-static int discard; ++static int discard; /* don't send swap discards by default */ + + /* If true, don't complain if the device/file doesn't exist */ + static int ifexists; +@@ -567,8 +578,22 @@ static int do_swapon(const char *orig_sp + << SWAP_FLAG_PRIO_SHIFT); + } + #endif +- if (fl_discard) +- flags |= SWAP_FLAG_DISCARD; ++ /* ++ * Validate the discard flags passed and set them ++ * accordingly before calling sys_swapon. ++ */ ++ if (fl_discard && !(fl_discard & ~SWAP_FLAGS_DISCARD_VALID)) { ++ /* ++ * If we get here with both discard policy flags set, ++ * we just need to tell the kernel to enable discards ++ * and it will do correctly, just as we expect. ++ */ ++ if ((fl_discard & SWAP_FLAG_DISCARD_ONCE) && ++ (fl_discard & SWAP_FLAG_DISCARD_PAGES)) ++ flags |= SWAP_FLAG_DISCARD; ++ else ++ flags |= fl_discard; ++ } + + status = swapon(special, flags); + if (status < 0) +@@ -608,12 +633,22 @@ static int swapon_all(void) + while (mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) { + /* defaults */ + int pri = priority, dsc = discard, nofail = ifexists; +- char *p, *src; ++ char *p, *src, *dscarg; + + if (mnt_fs_get_option(fs, "noauto", NULL, NULL) == 0) + continue; +- if (mnt_fs_get_option(fs, "discard", NULL, NULL) == 0) +- dsc = 1; ++ if (mnt_fs_get_option(fs, "discard", &dscarg, NULL) == 0) { ++ dsc |= SWAP_FLAG_DISCARD; ++ if (dscarg) { ++ /* only single-time discards are wanted */ ++ if (strcmp(dscarg, "once") == 0) ++ dsc |= SWAP_FLAG_DISCARD_ONCE; ++ ++ /* do discard for every released swap page */ ++ if (strcmp(dscarg, "pages") == 0) ++ dsc |= SWAP_FLAG_DISCARD_PAGES; ++ } ++ } + if (mnt_fs_get_option(fs, "nofail", NULL, NULL) == 0) + nofail = 1; + if (mnt_fs_get_option(fs, "pri", &p, NULL) == 0 && p) +@@ -643,17 +678,17 @@ static void __attribute__ ((__noreturn__ + fprintf(out, _(" %s [options] []\n"), program_invocation_short_name); + + fputs(USAGE_OPTIONS, out); +- fputs(_(" -a, --all enable all swaps from /etc/fstab\n" +- " -d, --discard discard freed pages before they are reused\n" +- " -e, --ifexists silently skip devices that do not exist\n" +- " -f, --fixpgsz reinitialize the swap space if necessary\n" +- " -p, --priority specify the priority of the swap device\n" +- " -s, --summary display summary about used swap devices\n" +- " --show[=] display summary in definable table\n" +- " --noheadings don't print headings, use with --show\n" +- " --raw use the raw output format, use with --show\n" +- " --bytes display swap size in bytes in --show output\n" +- " -v, --verbose verbose mode\n"), out); ++ fputs(_(" -a, --all enable all swaps from /etc/fstab\n" ++ " -d, --discard[=] enable swap discards, if supported by device\n" ++ " -e, --ifexists silently skip devices that do not exist\n" ++ " -f, --fixpgsz reinitialize the swap space if necessary\n" ++ " -p, --priority specify the priority of the swap device\n" ++ " -s, --summary display summary about used swap devices\n" ++ " --show[=] display summary in definable table\n" ++ " --noheadings don't print headings, use with --show\n" ++ " --raw use the raw output format, use with --show\n" ++ " --bytes display swap size in bytes in --show output\n" ++ " -v, --verbose verbose mode\n"), out); + + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); +@@ -669,6 +704,11 @@ static void __attribute__ ((__noreturn__ + " name of device to be used\n" + " name of file to be used\n"), out); + ++ fputs(_("\nAvailable discard policy types (for --discard):\n" ++ " once : only single-time area discards are issued. (swapon)\n" ++ " pages : discard freed pages before they are reused.\n" ++ " * if no policy is selected both discard types are enabled. (default)\n"), out); ++ + fputs(_("\nAvailable columns (for --show):\n"), out); + for (i = 0; i < NCOLS; i++) + fprintf(out, " %4s %s\n", infos[i].name, _(infos[i].help)); +@@ -693,7 +733,7 @@ int main(int argc, char *argv[]) + + static const struct option long_opts[] = { + { "priority", 1, 0, 'p' }, +- { "discard", 0, 0, 'd' }, ++ { "discard", 2, 0, 'd' }, + { "ifexists", 0, 0, 'e' }, + { "summary", 0, 0, 's' }, + { "fixpgsz", 0, 0, 'f' }, +@@ -716,7 +756,7 @@ int main(int argc, char *argv[]) + mnt_init_debug(0); + mntcache = mnt_new_cache(); + +- while ((c = getopt_long(argc, argv, "ahdefp:svVL:U:", ++ while ((c = getopt_long(argc, argv, "ahd::efp:svVL:U:", + long_opts, NULL)) != -1) { + switch (c) { + case 'a': /* all */ +@@ -736,7 +776,18 @@ int main(int argc, char *argv[]) + add_uuid(optarg); + break; + case 'd': +- discard = 1; ++ discard |= SWAP_FLAG_DISCARD; ++ if (optarg) { ++ if (*optarg == '=') ++ optarg++; ++ ++ if (strcmp(optarg, "once") == 0) ++ discard |= SWAP_FLAG_DISCARD_ONCE; ++ else if (strcmp(optarg, "pages") == 0) ++ discard |= SWAP_FLAG_DISCARD_PAGES; ++ else ++ errx(EXIT_FAILURE, _("unsupported discard policy: %s"), optarg); ++ } + break; + case 'e': /* ifexists */ + ifexists = 1; diff --git a/SOURCES/2.25-taskset-man-fix-permissions.patch b/SOURCES/2.25-taskset-man-fix-permissions.patch new file mode 100644 index 00000000..d6244308 --- /dev/null +++ b/SOURCES/2.25-taskset-man-fix-permissions.patch @@ -0,0 +1,35 @@ +From ab0e0fa7a45bccf8304edcb2a904f30a4f3a48b1 Mon Sep 17 00:00:00 2001 +From: Rik van Riel +Date: Fri, 6 Dec 2013 16:07:54 -0500 +Subject: [PATCH] taskset: fix PERMISSIONS section of taskset man page + +A user is always allowed to change the CPU affinity of his or her +own processes. CAP_SYS_NICE is only required to change the affinity +of another user's process. + +Signed-off-by: Rik van Riel +Reported-by: Joe Mario +--- + schedutils/taskset.1 | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/schedutils/taskset.1 b/schedutils/taskset.1 +index ade202b..fb5738c 100644 +--- a/schedutils/taskset.1 ++++ b/schedutils/taskset.1 +@@ -102,10 +102,11 @@ Or set it: + .B taskset \-p + .I mask pid + .SH PERMISSIONS ++A user can change the CPU affinity of a process belonging to the same user. + A user must possess + .B CAP_SYS_NICE +-to change the CPU affinity of a process. Any user can retrieve the affinity +-mask. ++to change the CPU affinity of a process belonging to another user. ++A user can retrieve the affinity mask of any process. + .SH AUTHOR + Written by Robert M. Love. + .SH COPYRIGHT +-- +1.8.4.2 diff --git a/SOURCES/2.25-uuidd-timeout.patch b/SOURCES/2.25-uuidd-timeout.patch new file mode 100644 index 00000000..f14b1d86 --- /dev/null +++ b/SOURCES/2.25-uuidd-timeout.patch @@ -0,0 +1,12 @@ +diff -up util-linux-2.23.2/misc-utils/uuidd.service.in.kzak util-linux-2.23.2/misc-utils/uuidd.service.in +--- util-linux-2.23.2/misc-utils/uuidd.service.in.kzak 2013-02-27 17:46:29.903020913 +0100 ++++ util-linux-2.23.2/misc-utils/uuidd.service.in 2015-04-20 11:31:44.614013049 +0200 +@@ -3,7 +3,7 @@ Description=Daemon for generating UUIDs + Requires=uuidd.socket + + [Service] +-ExecStart=@usrsbin_execdir@/uuidd --socket-activation --timeout 60 ++ExecStart=@usrsbin_execdir@/uuidd --socket-activation + Restart=no + User=uuidd + Group=uuidd diff --git a/SOURCES/2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch b/SOURCES/2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch new file mode 100644 index 00000000..9023c1cc --- /dev/null +++ b/SOURCES/2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch @@ -0,0 +1,140 @@ +diff -up util-linux-2.23.2/misc-utils/wipefs.8.kzak util-linux-2.23.2/misc-utils/wipefs.8 +--- util-linux-2.23.2/misc-utils/wipefs.8.kzak 2013-07-30 10:39:26.232738496 +0200 ++++ util-linux-2.23.2/misc-utils/wipefs.8 2014-01-23 11:07:54.390022299 +0100 +@@ -23,6 +23,9 @@ does not erase the filesystem itself nor + When used without options \fB-a\fR or \fB-o\fR, it lists all visible filesystems + and the offsets of their basic signatures. + ++.B wipefs ++calls BLKRRPART ioctl when erase partition table to inform kernel about the change. ++ + Note that some filesystems or some partition tables store more magic strings on + the devices. The + .B wipefs +diff -up util-linux-2.23.2/misc-utils/wipefs.c.kzak util-linux-2.23.2/misc-utils/wipefs.c +--- util-linux-2.23.2/misc-utils/wipefs.c.kzak 2013-07-30 10:39:26.232738496 +0200 ++++ util-linux-2.23.2/misc-utils/wipefs.c 2014-01-23 11:12:26.786860550 +0100 +@@ -40,21 +40,24 @@ + #include "c.h" + #include "closestream.h" + #include "optutils.h" ++#include "blkdev.h" + + struct wipe_desc { + loff_t offset; /* magic string offset */ + size_t len; /* length of magic string */ + unsigned char *magic; /* magic string */ + +- int zap; /* zap this offset? */ + char *usage; /* raid, filesystem, ... */ + char *type; /* FS type */ + char *label; /* FS label */ + char *uuid; /* FS uuid */ + +- int on_disk; +- + struct wipe_desc *next; ++ ++ unsigned int zap : 1, ++ on_disk : 1, ++ is_parttable : 1; ++ + }; + + enum { +@@ -72,7 +75,7 @@ print_pretty(struct wipe_desc *wp, int l + printf("----------------------------------------------------------------\n"); + } + +- printf("0x%-17jx %s [%s]", wp->offset, wp->type, wp->usage); ++ printf("0x%-17jx %s [%s]", wp->offset, wp->type, _(wp->usage)); + + if (wp->label && *wp->label) + printf("\n%27s %s", "LABEL:", wp->label); +@@ -141,7 +144,7 @@ add_offset(struct wipe_desc *wp0, loff_t + wp = xcalloc(1, sizeof(struct wipe_desc)); + wp->offset = offset; + wp->next = wp0; +- wp->zap = zap; ++ wp->zap = zap ? 1 : 0; + return wp; + } + +@@ -164,7 +167,7 @@ get_desc_for_probe(struct wipe_desc *wp, + const char *off, *type, *mag, *p, *usage = NULL; + size_t len; + loff_t offset; +- int rc; ++ int rc, ispt = 0; + + /* superblocks */ + if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) { +@@ -181,7 +184,8 @@ get_desc_for_probe(struct wipe_desc *wp, + rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, &len); + if (rc) + return wp; +- usage = "partition table"; ++ usage = N_("partition table"); ++ ispt = 1; + } else + return wp; + +@@ -199,6 +203,7 @@ get_desc_for_probe(struct wipe_desc *wp, + + wp->type = xstrdup(type); + wp->on_disk = 1; ++ wp->is_parttable = ispt ? 1 : 0; + + wp->magic = xmalloc(len); + memcpy(wp->magic, mag, len); +@@ -309,10 +314,25 @@ static void do_wipe_real(blkid_probe pr, + putchar('\n'); + } + ++ ++static void rereadpt(int fd, const char *devname) ++{ ++#ifdef BLKRRPART ++ struct stat st; ++ ++ if (fstat(fd, &st) || !S_ISBLK(st.st_mode)) ++ return; ++ ++ errno = 0; ++ ioctl(fd, BLKRRPART); ++ printf(_("%s: calling ioclt to re-read partition table: %m\n"), devname); ++#endif ++} ++ + static struct wipe_desc * + do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all, int quiet, int force) + { +- int flags; ++ int flags, reread = 0; + blkid_probe pr; + struct wipe_desc *w, *wp0; + int zap = all ? 1 : wp->zap; +@@ -345,8 +365,11 @@ do_wipe(struct wipe_desc *wp, const char + if (!wp->on_disk) + continue; + +- if (zap) ++ if (zap) { + do_wipe_real(pr, devname, wp, noact, quiet); ++ if (wp->is_parttable) ++ reread = 1; ++ } + } + + for (w = wp0; w != NULL; w = w->next) { +@@ -355,6 +378,10 @@ do_wipe(struct wipe_desc *wp, const char + } + + fsync(blkid_probe_get_fd(pr)); ++ ++ if (reread) ++ rereadpt(blkid_probe_get_fd(pr), devname); ++ + close(blkid_probe_get_fd(pr)); + blkid_free_probe(pr); + free_wipe(wp0); diff --git a/SOURCES/2.25-wipefs-nested-pt.patch b/SOURCES/2.25-wipefs-nested-pt.patch new file mode 100644 index 00000000..bab775e2 --- /dev/null +++ b/SOURCES/2.25-wipefs-nested-pt.patch @@ -0,0 +1,53 @@ +diff -up util-linux-2.23.2/misc-utils/wipefs.8.kzak util-linux-2.23.2/misc-utils/wipefs.8 +--- util-linux-2.23.2/misc-utils/wipefs.8.kzak 2014-09-24 10:41:31.061930168 +0200 ++++ util-linux-2.23.2/misc-utils/wipefs.8 2014-09-24 10:46:30.142783728 +0200 +@@ -37,6 +37,11 @@ table will still be visible by another m + When used with option \fB-a\fR, all magic strings that are visible for libblkid are + erased. + ++Note that by default ++.B wipefs ++does not erase nested partition tables on non-whole disk devices. The option ++\-\-force is required. ++ + .SH OPTIONS + .TP + .BR \-a , " \-\-all" +diff -up util-linux-2.23.2/misc-utils/wipefs.c.kzak util-linux-2.23.2/misc-utils/wipefs.c +--- util-linux-2.23.2/misc-utils/wipefs.c.kzak 2014-09-24 10:41:31.061930168 +0200 ++++ util-linux-2.23.2/misc-utils/wipefs.c 2014-09-24 10:50:07.728859738 +0200 +@@ -332,7 +332,7 @@ static void rereadpt(int fd, const char + static struct wipe_desc * + do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all, int quiet, int force) + { +- int flags, reread = 0; ++ int flags, reread = 0, need_force = 0; + blkid_probe pr; + struct wipe_desc *w, *wp0; + int zap = all ? 1 : wp->zap; +@@ -365,6 +365,15 @@ do_wipe(struct wipe_desc *wp, const char + if (!wp->on_disk) + continue; + ++ if (!force ++ && wp->is_parttable ++ && !blkid_probe_is_wholedisk(pr)) { ++ warnx(_("%s: ignore nested \"%s\" partition " ++ "table on non-whole disk device."), devname, wp->type); ++ need_force = 1; ++ continue; ++ } ++ + if (zap) { + do_wipe_real(pr, devname, wp, noact, quiet); + if (wp->is_parttable) +@@ -377,6 +386,9 @@ do_wipe(struct wipe_desc *wp, const char + warnx(_("%s: offset 0x%jx not found"), devname, w->offset); + } + ++ if (need_force) ++ warnx(_("Use the --force option to force erase.")); ++ + fsync(blkid_probe_get_fd(pr)); + + if (reread) diff --git a/SOURCES/2.26-blkdiscard.patch b/SOURCES/2.26-blkdiscard.patch new file mode 100644 index 00000000..55da03f4 --- /dev/null +++ b/SOURCES/2.26-blkdiscard.patch @@ -0,0 +1,259 @@ +diff -up util-linux-2.23.2/sys-utils/blkdiscard.8.kzak util-linux-2.23.2/sys-utils/blkdiscard.8 +--- util-linux-2.23.2/sys-utils/blkdiscard.8.kzak 2013-06-13 09:46:10.532651579 +0200 ++++ util-linux-2.23.2/sys-utils/blkdiscard.8 2014-10-27 10:03:13.650011708 +0100 +@@ -1,5 +1,5 @@ + .\" -*- nroff -*- +-.TH BLKDISCARD 8 "October 2012" "util-linux" "System Administration" ++.TH BLKDISCARD 8 "July 2014" "util-linux" "System Administration" + .SH NAME + blkdiscard \- discard sectors on a device + .SH SYNOPSIS +@@ -15,7 +15,7 @@ blkdiscard \- discard sectors on a devic + .B blkdiscard + is used to discard device sectors. This is useful for solid-state + drivers (SSDs) and thinly-provisioned storage. Unlike +-.BR fstrim (8) ++.BR fstrim (8) , + this command is used directly on the block device. + .PP + By default, +@@ -33,32 +33,44 @@ The + .I offset + and + .I length +-arguments may be followed by the multiplicative suffixes KiB=1024, +-MiB=1024*1024, and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is ++arguments may be followed by the multiplicative suffixes KiB (=1024), ++MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is + optional, e.g., "K" has the same meaning as "KiB") or the suffixes +-KB=1000, MB=1000*1000, and so on for GB, TB, PB, EB, ZB and YB. +-.IP "\fB\-h, \-\-help\fP" +-Print help and exit. +-.IP "\fB\-o, \-\-offset\fP \fIoffset\fP" +-Byte offset in the device from which to discard. Provided value will be +-aligned to the device sector size. Default value is zero. +-.IP "\fB\-l, \-\-length\fP \fIlength\fP" +-Number of bytes after starting point to discard. Provided value will be +-aligned to the device sector size. If the specified value extends past ++KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB. ++.TP ++.BR \-o , " \-\-offset \fIoffset" ++Byte offset into the device from which to start discarding. The provided value ++will be aligned to the device sector size. The default value is zero. ++.TP ++.BR \-l , " \-\-length \fIlength" ++The number of bytes to discard (counting from the starting point). The provided value ++will be aligned to the device sector size. If the specified value extends past + the end of the device, + .B blkdiscard +-will stop at the device size boundary. Default value extends to the end ++will stop at the device size boundary. The default value extends to the end + of the device. +-.IP "\fB\-s, \-\-secure\fP" +-Perform secure discard. Secure discard is the same as regular discard +-except all copies of the discarded blocks possibly created by garbage +-collection must also be erased. It has to be supported by the device. +-.IP "\fB\-v, \-\-verbose\fP" +-Print aligned ++.TP ++.BR \-p , " \-\-step \fIlength" ++The number of bytes to discard within one iteration. The default is to discard ++all by one ioctl call. ++.TP ++.BR \-s , " \-\-secure" ++Perform a secure discard. A secure discard is the same as a regular discard ++except that all copies of the discarded blocks that were possibly created by ++garbage collection must also be erased. This requires support from the device. ++.TP ++.BR \-v , " \-\-verbose" ++Display the aligned values of + .I offset + and +-.I length +-arguments. ++.IR length . ++If the option \fB\-\-step\fR specified than it prints discard progress every second. ++.TP ++.BR \-V , " \-\-version" ++Display version information and exit. ++.TP ++.BR \-h , " \-\-help" ++Display help text and exit. + .SH AUTHOR + .MT lczerner@redhat.com + Lukas Czerner +diff -up util-linux-2.23.2/sys-utils/blkdiscard.c.kzak util-linux-2.23.2/sys-utils/blkdiscard.c +--- util-linux-2.23.2/sys-utils/blkdiscard.c.kzak 2013-07-30 10:39:26.337739534 +0200 ++++ util-linux-2.23.2/sys-utils/blkdiscard.c 2014-10-27 10:03:20.981088614 +0100 +@@ -31,9 +31,11 @@ + #include + #include + #include ++#include + + #include + #include ++#include + #include + + #include "nls.h" +@@ -49,6 +51,10 @@ + #define BLKSECDISCARD _IO(0x12,125) + #endif + ++#define print_stats(path, stats) \ ++ printf(_("%s: Discarded %" PRIu64 " bytes from the " \ ++ "offset %" PRIu64"\n"), path, stats[1], stats[0]); ++ + static void __attribute__((__noreturn__)) usage(FILE *out) + { + fputs(USAGE_HEADER, out); +@@ -57,6 +63,7 @@ static void __attribute__((__noreturn__) + fputs(USAGE_OPTIONS, out); + fputs(_(" -o, --offset offset in bytes to discard from\n" + " -l, --length length of bytes to discard from the offset\n" ++ " -p, --step size of the discard iterations within the offset\n" + " -s, --secure perform secure discard\n" + " -v, --verbose print aligned length and offset\n"), + out); +@@ -70,15 +77,17 @@ static void __attribute__((__noreturn__) + int main(int argc, char **argv) + { + char *path; +- int c, fd, verbose = 0, secure = 0; +- uint64_t end, blksize, secsize, range[2]; ++ int c, fd, verbose = 0, secure = 0, secsize; ++ uint64_t end, blksize, step, range[2], stats[2]; + struct stat sb; ++ struct timespec now, last; + + static const struct option longopts[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "offset", 1, 0, 'o' }, + { "length", 1, 0, 'l' }, ++ { "step", 1, 0, 'p' }, + { "secure", 0, 0, 's' }, + { "verbose", 0, 0, 'v' }, + { NULL, 0, 0, 0 } +@@ -91,8 +100,9 @@ int main(int argc, char **argv) + + range[0] = 0; + range[1] = ULLONG_MAX; ++ step = 0; + +- while ((c = getopt_long(argc, argv, "hVsvo:l:", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "hVsvo:l:p:", longopts, NULL)) != -1) { + switch(c) { + case 'h': + usage(stdout); +@@ -108,6 +118,10 @@ int main(int argc, char **argv) + range[0] = strtosize_or_err(optarg, + _("failed to parse offset")); + break; ++ case 'p': ++ step = strtosize_or_err(optarg, ++ _("failed to parse step")); ++ break; + case 's': + secure = 1; + break; +@@ -121,7 +135,7 @@ int main(int argc, char **argv) + } + + if (optind == argc) +- errx(EXIT_FAILURE, _("no device specified.")); ++ errx(EXIT_FAILURE, _("no device specified")); + + path = argv[optind++]; + +@@ -130,43 +144,69 @@ int main(int argc, char **argv) + usage(stderr); + } + +- if (stat(path, &sb) == -1) +- err(EXIT_FAILURE, _("stat failed %s"), path); +- if (!S_ISBLK(sb.st_mode)) +- errx(EXIT_FAILURE, _("%s: not a block device"), path); +- + fd = open(path, O_WRONLY); + if (fd < 0) + err(EXIT_FAILURE, _("cannot open %s"), path); + ++ if (fstat(fd, &sb) == -1) ++ err(EXIT_FAILURE, _("stat failed %s"), path); ++ if (!S_ISBLK(sb.st_mode)) ++ errx(EXIT_FAILURE, _("%s: not a block device"), path); ++ + if (ioctl(fd, BLKGETSIZE64, &blksize)) + err(EXIT_FAILURE, _("%s: BLKGETSIZE64 ioctl failed"), path); +- + if (ioctl(fd, BLKSSZGET, &secsize)) + err(EXIT_FAILURE, _("%s: BLKSSZGET ioctl failed"), path); + +- /* align range to the sector size */ +- range[0] = (range[0] + secsize - 1) & ~(secsize - 1); +- range[1] &= ~(secsize - 1); ++ /* check offset alignment to the sector size */ ++ if (range[0] % secsize) ++ errx(EXIT_FAILURE, _("%s: offset %" PRIu64 " is not aligned " ++ "to sector size %i"), path, range[0], secsize); + + /* is the range end behind the end of the device ?*/ ++ if (range[0] > blksize) ++ errx(EXIT_FAILURE, _("%s: offset is greater than device size"), path); + end = range[0] + range[1]; + if (end < range[0] || end > blksize) +- range[1] = blksize - range[0]; ++ end = blksize; ++ ++ range[1] = (step > 0) ? step : end - range[0]; ++ ++ /* check length alignment to the sector size */ ++ if (range[1] % secsize) ++ errx(EXIT_FAILURE, _("%s: length %" PRIu64 " is not aligned " ++ "to sector size %i"), path, range[1], secsize); ++ ++ stats[0] = range[0], stats[1] = 0; ++ clock_gettime(CLOCK_MONOTONIC, &last); ++ ++ for (range[0] = range[0]; range[0] < end; range[0] += range[1]) { ++ if (range[0] + range[1] > end) ++ range[1] = end - range[0]; ++ ++ if (secure) { ++ if (ioctl(fd, BLKSECDISCARD, &range)) ++ err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path); ++ } else { ++ if (ioctl(fd, BLKDISCARD, &range)) ++ err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path); ++ } ++ ++ /* reporting progress */ ++ if (verbose && step) { ++ clock_gettime(CLOCK_MONOTONIC, &now); ++ if (last.tv_sec < now.tv_sec) { ++ print_stats(path, stats); ++ stats[0] = range[0], stats[1] = 0; ++ last = now; ++ } ++ } + +- if (secure) { +- if (ioctl(fd, BLKSECDISCARD, &range)) +- err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path); +- } else { +- if (ioctl(fd, BLKDISCARD, &range)) +- err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path); ++ stats[1] += range[1]; + } + + if (verbose) +- /* TRANSLATORS: The standard value here is a very large number. */ +- printf(_("%s: Discarded %" PRIu64 " bytes from the " +- "offset %" PRIu64"\n"), path, +- (uint64_t) range[1], (uint64_t) range[0]); ++ print_stats(path, stats); + + close(fd); + return EXIT_SUCCESS; diff --git a/SOURCES/2.26-libblkid-fat.patch b/SOURCES/2.26-libblkid-fat.patch new file mode 100644 index 00000000..f3159a86 --- /dev/null +++ b/SOURCES/2.26-libblkid-fat.patch @@ -0,0 +1,113 @@ +diff -up util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak util-linux-2.23.2/libblkid/src/partitions/dos.c +--- util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak 2015-08-21 10:16:45.244332027 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/dos.c 2015-08-21 10:22:07.181340367 +0200 +@@ -151,16 +151,6 @@ static int probe_dos_pt(blkid_probe pr, + if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0) + goto nothing; + +- /* +- * Now that the 55aa signature is present, this is probably +- * either the boot sector of a FAT filesystem or a DOS-type +- * partition table. +- */ +- if (blkid_probe_is_vfat(pr) == 1) { +- DBG(LOWPROBE, blkid_debug("probably FAT -- ignore")); +- goto nothing; +- } +- + p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); + + /* +@@ -182,6 +172,16 @@ static int probe_dos_pt(blkid_probe pr, + } + } + ++ /* ++ * Now that the 55aa signature is present, this is probably ++ * either the boot sector of a FAT filesystem or a DOS-type ++ * partition table. ++ */ ++ if (blkid_probe_is_vfat(pr) == 1) { ++ DBG(LOWPROBE, blkid_debug("probably FAT -- ignore")); ++ goto nothing; ++ } ++ + blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET, + 512 - BLKID_MSDOS_PT_OFFSET); + +diff -up util-linux-2.23.2/libblkid/src/partitions/dos.h.kzak util-linux-2.23.2/libblkid/src/partitions/dos.h +--- util-linux-2.23.2/libblkid/src/partitions/dos.h.kzak 2015-08-21 10:34:14.919380422 +0200 ++++ util-linux-2.23.2/libblkid/src/partitions/dos.h 2015-08-21 10:35:45.221807669 +0200 +@@ -12,6 +12,12 @@ struct dos_partition { + + #define BLKID_MSDOS_PT_OFFSET 0x1be + ++static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i) ++{ ++ return (struct dos_partition *) ++ (mbr + BLKID_MSDOS_PT_OFFSET + (i * sizeof(struct dos_partition))); ++} ++ + /* assemble badly aligned little endian integer */ + static inline unsigned int assemble4le(const unsigned char *p) + { +diff -up util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vfat.c +--- util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak 2015-08-21 10:10:12.111906711 +0200 ++++ util-linux-2.23.2/libblkid/src/superblocks/vfat.c 2015-08-21 10:35:07.733045452 +0200 +@@ -16,6 +16,7 @@ + #include + #include + ++#include "partitions/dos.h" + #include "superblocks.h" + + /* Yucky misaligned values */ +@@ -169,7 +170,8 @@ static unsigned char *search_fat_label(b + return NULL; + } + +-static int fat_valid_superblock(const struct blkid_idmag *mag, ++static int fat_valid_superblock(blkid_probe pr, ++ const struct blkid_idmag *mag, + struct msdos_super_block *ms, + struct vfat_super_block *vs, + uint32_t *cluster_count, uint32_t *fat_size) +@@ -243,6 +245,20 @@ static int fat_valid_superblock(const st + if (cluster_count) + *cluster_count = __cluster_count; + ++ if (blkid_probe_is_wholedisk(pr)) { ++ /* OK, seems like FAT, but it's possible that we found boot ++ * sector with crazy FAT-like stuff (magic strings, media, ++ * etc..) before MBR. Let's make sure that there is no MBR with ++ * usable partition. */ ++ unsigned char *buf = (unsigned char *) ms; ++ if (is_valid_mbr_signature(buf)) { ++ struct dos_partition *p0 = mbr_get_partition(buf, 0); ++ if (dos_partition_size(p0) != 0 && ++ (p0->boot_ind == 0 || p0->boot_ind == 0x80)) ++ return 0; ++ } ++ } ++ + return 1; /* valid */ + } + +@@ -270,7 +286,7 @@ int blkid_probe_is_vfat(blkid_probe pr) + if (!vs) + return errno ? -errno : 0; + +- return fat_valid_superblock(mag, ms, vs, NULL, NULL); ++ return fat_valid_superblock(pr, mag, ms, vs, NULL, NULL); + } + + /* FAT label extraction from the root directory taken from Kay +@@ -293,7 +309,7 @@ static int probe_vfat(blkid_probe pr, co + if (!vs) + return errno ? -errno : 1; + +- if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size)) ++ if (!fat_valid_superblock(pr, mag, ms, vs, &cluster_count, &fat_size)) + return 1; + + sector_size = unaligned_le16(&ms->ms_sector_size); diff --git a/SOURCES/2.26-libsmartcols.patch b/SOURCES/2.26-libsmartcols.patch new file mode 100644 index 00000000..5ddcd03a --- /dev/null +++ b/SOURCES/2.26-libsmartcols.patch @@ -0,0 +1,5242 @@ +diff -up util-linux-2.23.2/configure.ac.kzak util-linux-2.23.2/configure.ac +--- util-linux-2.23.2/configure.ac.kzak 2013-07-30 10:39:26.188738061 +0200 ++++ util-linux-2.23.2/configure.ac 2014-09-25 14:41:48.980843829 +0200 +@@ -46,6 +46,13 @@ LIBMOUNT_LT_MINOR=1 + LIBMOUNT_LT_MICRO=0 + LIBMOUNT_VERSION_INFO=`expr $LIBMOUNT_LT_MAJOR + $LIBMOUNT_LT_MINOR`:$LIBMOUNT_LT_MICRO:$LIBMOUNT_LT_MINOR + ++dnl libsmartcols version ++LIBSMARTCOLS_VERSION="$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_RELEASE" ++LIBSMARTCOLS_LT_MAJOR=1 ++LIBSMARTCOLS_LT_MINOR=1 ++LIBSMARTCOLS_LT_MICRO=0 ++LIBSMARTCOLS_VERSION_INFO=`expr $LIBSMARTCOLS_LT_MAJOR + $LIBSMARTCOLS_LT_MINOR`:$LIBSMARTCOLS_LT_MICRO:$LIBSMARTCOLS_LT_MINOR ++ + # Check whether exec_prefix=/usr: + case $exec_prefix:$prefix in + NONE:NONE | NONE:/usr | /usr:*) +@@ -765,6 +772,18 @@ AC_DEFINE_UNQUOTED(LIBMOUNT_VERSION, "$L + + + dnl ++dnl libsmartcols ++dnl ++UL_BUILD_INIT([libsmartcols], [yes]) ++AM_CONDITIONAL([BUILD_LIBSMARTCOLS], [test "x$build_libsmartcols" = xyes]) ++AM_CONDITIONAL([BUILD_LIBSMARTCOLS_TESTS], [test "x$build_libsmartcols" = xyes -a "x$enable_static" = xyes]) ++ ++AC_SUBST([LIBSMARTCOLS_VERSION]) ++AC_SUBST([LIBSMARTCOLS_VERSION_INFO]) ++AC_DEFINE_UNQUOTED([LIBSMARTCOLS_VERSION], ["$LIBSMARTCOLS_VERSION"], [libsmartcols version string]) ++ ++ ++dnl + dnl libfdisk is enabled all time if possible + dnl + UL_BUILD_INIT([libfdisk], [check]) +@@ -1500,6 +1519,9 @@ libblkid/src/blkid.h + libmount/docs/Makefile + libmount/docs/version.xml + libmount/src/libmount.h ++libsmartcols/docs/Makefile ++libsmartcols/docs/version.xml ++libsmartcols/src/libsmartcols.h + po/Makefile.in + ]) + +diff -up util-linux-2.23.2/include/carefulputc.h.kzak util-linux-2.23.2/include/carefulputc.h +--- util-linux-2.23.2/include/carefulputc.h.kzak 2012-11-29 16:18:33.956147961 +0100 ++++ util-linux-2.23.2/include/carefulputc.h 2014-09-25 14:41:48.980843829 +0200 +@@ -26,4 +26,39 @@ static inline int carefulputc(int c, FIL + return (ret < 0) ? EOF : 0; + } + ++static inline void fputs_quoted(const char *data, FILE *out) ++{ ++ const char *p; ++ ++ fputc('"', out); ++ for (p = data; p && *p; p++) { ++ if ((unsigned char) *p == 0x22 || /* " */ ++ (unsigned char) *p == 0x5c || /* \ */ ++ !isprint((unsigned char) *p) || ++ iscntrl((unsigned char) *p)) { ++ ++ fprintf(out, "\\x%02x", (unsigned char) *p); ++ } else ++ fputc(*p, out); ++ } ++ fputc('"', out); ++} ++ ++static inline void fputs_nonblank(const char *data, FILE *out) ++{ ++ const char *p; ++ ++ for (p = data; p && *p; p++) { ++ if (isblank((unsigned char) *p) || ++ (unsigned char) *p == 0x5c || /* \ */ ++ !isprint((unsigned char) *p) || ++ iscntrl((unsigned char) *p)) { ++ ++ fprintf(out, "\\x%02x", (unsigned char) *p); ++ ++ } else ++ fputc(*p, out); ++ } ++} ++ + #endif /* _CAREFUULPUTC_H */ +diff -up util-linux-2.23.2/include/debug.h.kzak util-linux-2.23.2/include/debug.h +--- util-linux-2.23.2/include/debug.h.kzak 2014-09-25 14:41:48.981843839 +0200 ++++ util-linux-2.23.2/include/debug.h 2014-09-25 14:41:48.981843839 +0200 +@@ -0,0 +1,126 @@ ++/* ++ * Copyright (C) 2014 Ondrej Oprala ++ * ++ * This file may be distributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++#ifndef UTIL_LINUX_DEBUG_H ++#define UTIL_LINUX_DEBUG_H ++ ++#include ++#include ++ ++struct dbg_mask { char *mname; int val; }; ++#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0 }} ++ ++#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask ++#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m) ++#define UL_DEBUG_DEFINE_MASKANEMS(m) static const struct dbg_mask m ## _masknames[] ++ ++/* p - flag prefix, m - flag postfix */ ++#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m ++ ++/* l - library name, p - flag prefix, m - flag postfix, x - function */ ++#define __UL_DBG(l, p, m, x) \ ++ do { \ ++ if ((p ## m) & l ## _debug_mask) { \ ++ fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \ ++ x; \ ++ } \ ++ } while (0) ++ ++#define __UL_DBG_CALL(l, p, m, x) \ ++ do { \ ++ if ((p ## m) & l ## _debug_mask) { \ ++ x; \ ++ } \ ++ } while (0) ++ ++#define __UL_DBG_FLUSH(l, p) \ ++ do { \ ++ if (l ## _debug_mask && \ ++ l ## _debug_mask != p ## INIT) { \ ++ fflush(stderr); \ ++ } \ ++ } while (0) ++ ++ ++#define __UL_INIT_DEBUG(lib, pref, mask, env) \ ++ do { \ ++ if (lib ## _debug_mask & pref ## INIT) \ ++ ; \ ++ else if (!mask) { \ ++ char *str = getenv(# env); \ ++ if (str) \ ++ lib ## _debug_mask = parse_envmask(lib ## _masknames, str); \ ++ } else \ ++ lib ## _debug_mask = mask; \ ++ lib ## _debug_mask |= pref ## INIT; \ ++ if (lib ## _debug_mask != pref ## INIT) { \ ++ __UL_DBG(lib, pref, INIT, ul_debug("library debug mask: 0x%04x", \ ++ lib ## _debug_mask)); \ ++ } \ ++ } while (0) ++ ++ ++static inline void __attribute__ ((__format__ (__printf__, 1, 2))) ++ul_debug(const char *mesg, ...) ++{ ++ va_list ap; ++ va_start(ap, mesg); ++ vfprintf(stderr, mesg, ap); ++ va_end(ap); ++ fputc('\n', stderr); ++} ++ ++static inline void __attribute__ ((__format__ (__printf__, 2, 3))) ++ul_debugobj(void *handler, const char *mesg, ...) ++{ ++ va_list ap; ++ ++ if (handler) ++ fprintf(stderr, "[%p]: ", handler); ++ va_start(ap, mesg); ++ vfprintf(stderr, mesg, ap); ++ va_end(ap); ++ fputc('\n', stderr); ++} ++ ++static inline int parse_envmask(const struct dbg_mask const flagnames[], ++ const char *mask) ++{ ++ int res; ++ char *ptr; ++ ++ /* let's check for a numeric mask first */ ++ res = strtoul(mask, &ptr, 0); ++ ++ /* perhaps it's a comma-separated string? */ ++ if (*ptr != '\0' && flagnames) { ++ char *msbuf, *ms, *name; ++ res = 0; ++ ++ ms = msbuf = strdup(mask); ++ if (!ms) ++ return res; ++ ++ while ((name = strtok_r(ms, ",", &ptr))) { ++ size_t i = 0; ++ ms = ptr; ++ ++ while (flagnames[i].mname) { ++ if (!strcmp(name, flagnames[i].mname)) { ++ res |= flagnames[i].val; ++ break; ++ } ++ ++i; ++ } ++ /* nothing else we can do by OR-ing the mask */ ++ if (res == 0xffff) ++ break; ++ } ++ free(msbuf); ++ } ++ return res; ++} ++#endif /* UTIL_LINUX_DEBUG_H */ +diff -up util-linux-2.23.2/include/list.h.kzak util-linux-2.23.2/include/list.h +--- util-linux-2.23.2/include/list.h.kzak 2013-06-13 09:46:10.396650417 +0200 ++++ util-linux-2.23.2/include/list.h 2014-09-25 14:41:48.981843839 +0200 +@@ -212,14 +212,16 @@ _INLINE_ void list_splice(struct list_he + * sentinel head node, "prev" links not maintained. + */ + _INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a, +- struct list_head *b), ++ struct list_head *b, ++ void *data), ++ void *data, + struct list_head *a, struct list_head *b) + { + struct list_head head, *tail = &head; + + while (a && b) { + /* if equal, take 'a' -- important for sort stability */ +- if ((*cmp)(a, b) <= 0) { ++ if ((*cmp)(a, b, data) <= 0) { + tail->next = a; + a = a->next; + } else { +@@ -240,7 +242,9 @@ _INLINE_ struct list_head *merge(int (*c + * throughout. + */ + _INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a, +- struct list_head *b), ++ struct list_head *b, ++ void *data), ++ void *data, + struct list_head *head, + struct list_head *a, struct list_head *b) + { +@@ -248,7 +252,7 @@ _INLINE_ void merge_and_restore_back_lin + + while (a && b) { + /* if equal, take 'a' -- important for sort stability */ +- if ((*cmp)(a, b) <= 0) { ++ if ((*cmp)(a, b, data) <= 0) { + tail->next = a; + a->prev = tail; + a = a->next; +@@ -268,7 +272,7 @@ _INLINE_ void merge_and_restore_back_lin + * element comparison is needed, so the client's cmp() + * routine can invoke cond_resched() periodically. + */ +- (*cmp)(tail->next, tail->next); ++ (*cmp)(tail->next, tail->next, data); + + tail->next->prev = tail; + tail = tail->next; +@@ -294,7 +298,9 @@ _INLINE_ void merge_and_restore_back_lin + */ + _INLINE_ void list_sort(struct list_head *head, + int (*cmp)(struct list_head *a, +- struct list_head *b)) ++ struct list_head *b, ++ void *data), ++ void *data) + { + struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists + -- last slot is a sentinel */ +@@ -316,7 +322,7 @@ _INLINE_ void list_sort(struct list_head + cur->next = NULL; + + for (lev = 0; part[lev]; lev++) { +- cur = merge(cmp, part[lev], cur); ++ cur = merge(cmp, data, part[lev], cur); + part[lev] = NULL; + } + if (lev > max_lev) { +@@ -330,11 +336,12 @@ _INLINE_ void list_sort(struct list_head + + for (lev = 0; lev < max_lev; lev++) + if (part[lev]) +- list = merge(cmp, part[lev], list); ++ list = merge(cmp, data, part[lev], list); + +- merge_and_restore_back_links(cmp, head, part[max_lev], list); ++ merge_and_restore_back_links(cmp, data, head, part[max_lev], list); + } + ++ + #undef _INLINE_ + + #endif /* UTIL_LINUX_LIST_H */ +diff -up util-linux-2.23.2/include/mbsalign.h.kzak util-linux-2.23.2/include/mbsalign.h +--- util-linux-2.23.2/include/mbsalign.h.kzak 2013-06-13 09:46:10.397650425 +0200 ++++ util-linux-2.23.2/include/mbsalign.h 2014-09-25 14:41:48.981843839 +0200 +@@ -1,5 +1,6 @@ + /* Align/Truncate a string in a given screen width + Copyright (C) 2009-2010 Free Software Foundation, Inc. ++ Copyright (C) 2010-2013 Karel Zak + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by +@@ -13,8 +14,9 @@ + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ +- +-#include ++#ifndef UTIL_LINUX_MBSALIGN_H ++# define UTIL_LINUX_MBSALIGN_H ++# include + + typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t; + +@@ -43,3 +45,12 @@ extern size_t mbs_truncate(char *str, si + extern size_t mbsalign (const char *src, char *dest, + size_t dest_size, size_t *width, + mbs_align_t align, int flags); ++ ++extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz); ++extern size_t mbs_safe_width(const char *s); ++ ++extern char *mbs_safe_encode(const char *s, size_t *width); ++extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf); ++extern size_t mbs_safe_encode_size(size_t bytes); ++ ++#endif /* UTIL_LINUX_MBSALIGN_H */ +diff -up util-linux-2.23.2/lib/mbsalign.c.kzak util-linux-2.23.2/lib/mbsalign.c +--- util-linux-2.23.2/lib/mbsalign.c.kzak 2013-07-30 10:39:26.203738210 +0200 ++++ util-linux-2.23.2/lib/mbsalign.c 2014-09-25 14:41:48.982843848 +0200 +@@ -23,17 +23,193 @@ + #include + #include + #include ++#include + + #include "c.h" + #include "mbsalign.h" + #include "widechar.h" + +- + #ifdef HAVE_WIDECHAR + /* Replace non printable chars. + Note \t and \n etc. are non printable. + Return 1 if replacement made, 0 otherwise. */ + ++/* ++ * Counts number of cells in multibyte string. For all control and ++ * non-printable chars is the result width enlarged to store \x?? hex ++ * sequence. See mbs_safe_encode(). ++ * ++ * Returns: number of cells, @sz returns number of bytes. ++ */ ++size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz) ++{ ++ mbstate_t st; ++ const char *p = buf, *last = buf; ++ size_t width = 0, bytes = 0; ++ ++ memset(&st, 0, sizeof(st)); ++ ++ if (p && *p && bufsz) ++ last = p + (bufsz - 1); ++ ++ while (p && *p && p <= last) { ++ if (iscntrl((unsigned char) *p)) { ++ width += 4, bytes += 4; /* *p encoded to \x?? */ ++ p++; ++ } ++#ifdef HAVE_WIDECHAR ++ else { ++ wchar_t wc; ++ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); ++ ++ if (len == 0) ++ break; ++ ++ if (len == (size_t) -1 || len == (size_t) -2) { ++ len = 1; ++ if (isprint((unsigned char) *p)) ++ width += 1, bytes += 1; ++ else ++ width += 4, bytes += 4; ++ ++ } else if (!iswprint(wc)) { ++ width += len * 4; /* hex encode whole sequence */ ++ bytes += len * 4; ++ } else { ++ width += wcwidth(wc); /* number of cells */ ++ bytes += len; /* number of bytes */ ++ } ++ p += len; ++ } ++#else ++ else if (!isprint((unsigned char) *p)) { ++ width += 4, bytes += 4; /* *p encoded to \x?? */ ++ p++; ++ } else { ++ width++, bytes++; ++ p++; ++ } ++#endif ++ } ++ ++ if (sz) ++ *sz = bytes; ++ return width; ++} ++ ++size_t mbs_safe_width(const char *s) ++{ ++ if (!s || !*s) ++ return 0; ++ return mbs_safe_nwidth(s, strlen(s), NULL); ++} ++ ++/* ++ * Copy @s to @buf and replace control and non-printable chars with ++ * \x?? hex sequence. The @width returns number of cells. ++ * ++ * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s))) ++ * bytes. ++ */ ++char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf) ++{ ++ mbstate_t st; ++ const char *p = s; ++ char *r; ++ size_t sz = s ? strlen(s) : 0; ++ ++ if (!sz || !buf) ++ return NULL; ++ ++ memset(&st, 0, sizeof(st)); ++ ++ r = buf; ++ *width = 0; ++ ++ while (p && *p) { ++ if (iscntrl((unsigned char) *p)) { ++ sprintf(r, "\\x%02x", (unsigned char) *p); ++ r += 4; ++ *width += 4; ++ p++; ++ } ++#ifdef HAVE_WIDECHAR ++ else { ++ wchar_t wc; ++ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); ++ ++ if (len == 0) ++ break; /* end of string */ ++ ++ if (len == (size_t) -1 || len == (size_t) -2) { ++ len = 1; ++ /* ++ * Not valid multibyte sequence -- maybe it's ++ * printable char according to the current locales. ++ */ ++ if (!isprint((unsigned char) *p)) { ++ sprintf(r, "\\x%02x", (unsigned char) *p); ++ r += 4; ++ *width += 4; ++ } else { ++ width++; ++ *r++ = *p; ++ } ++ } else if (!iswprint(wc)) { ++ size_t i; ++ for (i = 0; i < len; i++) { ++ sprintf(r, "\\x%02x", (unsigned char) *p); ++ r += 4; ++ *width += 4; ++ } ++ } else { ++ memcpy(r, p, len); ++ r += len; ++ *width += wcwidth(wc); ++ } ++ p += len; ++ } ++#else ++ else if (!isprint((unsigned char) *p)) { ++ sprintf(r, "\\x%02x", (unsigned char) *p); ++ p++; ++ r += 4; ++ *width += 4; ++ } else { ++ *r++ = *p++; ++ *width++; ++ } ++#endif ++ } ++ ++ *r = '\0'; ++ ++ return buf; ++} ++ ++size_t mbs_safe_encode_size(size_t bytes) ++{ ++ return (bytes * 4) + 1; ++} ++ ++/* ++ * Returns allocated string where all control and non-printable chars are ++ * replaced with \x?? hex sequence. ++ */ ++char *mbs_safe_encode(const char *s, size_t *width) ++{ ++ size_t sz = s ? strlen(s) : 0; ++ char *buf; ++ ++ if (!sz) ++ return NULL; ++ buf = malloc(mbs_safe_encode_size(sz)); ++ if (!buf) ++ return NULL; ++ ++ return mbs_safe_encode_to_buffer(s, width, buf); ++} ++ + static bool + wc_ensure_printable (wchar_t *wchars) + { +@@ -254,8 +430,8 @@ mbsalign_unibyte: + if (dest_size != 0) + { + char *dest_end = dest + dest_size - 1; +- size_t start_spaces = n_spaces / 2 + n_spaces % 2; +- size_t end_spaces = n_spaces / 2; ++ size_t start_spaces; ++ size_t end_spaces; + + switch (align) + { +diff -up util-linux-2.23.2/libsmartcols/COPYING.kzak util-linux-2.23.2/libsmartcols/COPYING +--- util-linux-2.23.2/libsmartcols/COPYING.kzak 2014-09-25 14:41:48.983843858 +0200 ++++ util-linux-2.23.2/libsmartcols/COPYING 2014-09-25 14:41:48.983843858 +0200 +@@ -0,0 +1,8 @@ ++This library is free software; you can redistribute it and/or ++modify it under the terms of the GNU Lesser General Public ++License as published by the Free Software Foundation; either ++version 2.1 of the License, or (at your option) any later ++version. ++ ++The complete text of the license is available in the ++../Documentation/licenses/COPYING.LGPLv2.1 file. +diff -up util-linux-2.23.2/libsmartcols/docs/.gitignore.kzak util-linux-2.23.2/libsmartcols/docs/.gitignore +--- util-linux-2.23.2/libsmartcols/docs/.gitignore.kzak 2014-09-25 14:41:48.983843858 +0200 ++++ util-linux-2.23.2/libsmartcols/docs/.gitignore 2014-09-25 14:41:48.983843858 +0200 +@@ -0,0 +1,18 @@ ++*-decl-list.txt ++*-decl.txt ++*-overrides.txt ++*-undeclared.txt ++*-undocumented.txt ++*-unused.txt ++*.args ++*.bak ++*.hierarchy ++*.interfaces ++*.prerequisites ++*.signals ++*.stamp ++*.types ++html/* ++tmpl/* ++version.xml ++xml/* +diff -up util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml.kzak util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml +--- util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml.kzak 2014-09-25 14:41:48.984843867 +0200 ++++ util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml 2014-09-25 14:41:48.984843867 +0200 +@@ -0,0 +1,52 @@ ++ ++ ++]> ++ ++ ++ libsmartcols Reference Manual ++ for libsmartcols version &version; ++ ++ 2014 ++ Karel Zak <kzak@redhat.com> ++ ++ ++ ++ ++ libsmartcols Overview ++ ++ ++The libsmartcols library is used for smart adaptive formatting of tabular data. ++ ++ ++The library is part of the util-linux package since version 2.25 and is ++available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/. ++ ++ ++ ++ ++ ++ Data manipulation ++ ++ ++ ++ ++ ++ ++ ++ Printing ++ ++ ++ ++ Misc ++ ++ ++ ++ ++ ++ API Index ++ ++ ++ +diff -up util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt.kzak util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt +--- util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt.kzak 2014-09-25 14:41:48.984843867 +0200 ++++ util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt 2014-09-25 14:41:48.984843867 +0200 +@@ -0,0 +1,146 @@ ++
++cell ++libscols_cell ++scols_cell_copy_content ++scols_cell_get_color ++scols_cell_get_data ++scols_cell_get_userdata ++scols_cell_refer_data ++scols_cell_set_color ++scols_cell_set_data ++scols_cell_set_userdata ++scols_cmpstr_cells ++scols_reset_cell ++
++ ++
++column ++libscols_column ++scols_column_get_color ++scols_column_get_flags ++scols_column_get_header ++scols_column_get_whint ++scols_column_is_noextremes ++scols_column_is_right ++scols_column_is_strict_width ++scols_column_is_tree ++scols_column_is_trunc ++scols_column_set_cmpfunc ++scols_column_set_color ++scols_column_set_flags ++scols_column_set_whint ++scols_copy_column ++scols_new_column ++scols_ref_column ++scols_unref_column ++
++ ++
++iter ++libscols_iter ++scols_free_iter ++scols_iter_get_direction ++scols_new_iter ++scols_reset_iter ++
++ ++
++line ++libscols_line ++scols_copy_line ++scols_line_add_child ++scols_line_alloc_cells ++scols_line_free_cells ++scols_line_get_cell ++scols_line_get_color ++scols_line_get_column_cell ++scols_line_get_ncells ++scols_line_get_parent ++scols_line_get_userdata ++scols_line_has_children ++scols_line_next_child ++scols_line_refer_data ++scols_line_remove_child ++scols_line_set_color ++scols_line_set_data ++scols_line_set_userdata ++scols_new_line ++scols_ref_line ++scols_unref_line ++
++ ++
++symbols ++libscols_symbols ++scols_copy_symbols ++scols_new_symbols ++scols_ref_symbols ++scols_symbols_set_branch ++scols_symbols_set_right ++scols_symbols_set_vertical ++scols_unref_symbols ++
++ ++
++table ++libscols_table ++scols_copy_table ++scols_new_table ++scols_ref_table ++scols_table_add_column ++scols_table_add_line ++scols_table_colors_wanted ++scols_table_enable_ascii ++scols_table_enable_colors ++scols_table_enable_export ++scols_table_enable_maxout ++scols_table_enable_noheadings ++scols_table_enable_raw ++scols_table_get_column ++scols_table_get_column_separator ++scols_table_get_line ++scols_table_get_line_separator ++scols_table_get_ncols ++scols_table_get_nlines ++scols_table_get_stream ++scols_table_is_ascii ++scols_table_is_empty ++scols_table_is_export ++scols_table_is_maxout ++scols_table_is_noheadings ++scols_table_is_raw ++scols_table_is_tree ++scols_table_new_column ++scols_table_new_line ++scols_table_next_column ++scols_table_next_line ++scols_table_reduce_termwidth ++scols_table_remove_column ++scols_table_remove_columns ++scols_table_remove_line ++scols_table_remove_lines ++scols_table_set_column_separator ++scols_table_set_line_separator ++scols_table_set_stream ++scols_table_set_symbols ++scols_sort_table ++scols_unref_table ++
++ ++
++table_print ++scols_print_table ++scols_print_table_to_string ++
++ ++
++version-utils ++scols_get_library_version ++scols_parse_version_string ++LIBSMARTCOLS_VERSION ++
++ ++
++init ++scols_init_debug ++
+diff -up util-linux-2.23.2/libsmartcols/docs/Makefile.am.kzak util-linux-2.23.2/libsmartcols/docs/Makefile.am +--- util-linux-2.23.2/libsmartcols/docs/Makefile.am.kzak 2014-09-25 14:41:48.984843867 +0200 ++++ util-linux-2.23.2/libsmartcols/docs/Makefile.am 2014-09-25 14:41:48.984843867 +0200 +@@ -0,0 +1,93 @@ ++## Process this file with automake to produce Makefile.in ++ ++# We require automake 1.10 at least. ++AUTOMAKE_OPTIONS = 1.10 ++ ++# This is a blank Makefile.am for using gtk-doc. ++# Copy this to your project's API docs directory and modify the variables to ++# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples ++# of using the various options. ++ ++# The name of the module, e.g. 'glib'. ++DOC_MODULE=libsmartcols ++ ++# Uncomment for versioned docs and specify the version of the module, e.g. '2'. ++#DOC_MODULE_VERSION=2 ++ ++# The top-level SGML file. You can change this if you want to. ++DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml ++ ++# The directory containing the source code. Relative to $(srcdir). ++# gtk-doc will search all .c & .h files beneath here for inline comments ++# documenting the functions and macros. ++# e.g. DOC_SOURCE_DIR=../../../gtk ++DOC_SOURCE_DIR=../src ++ ++# Extra options to pass to gtkdoc-scangobj. Not normally needed. ++SCANGOBJ_OPTIONS= ++ ++# Extra options to supply to gtkdoc-scan. ++# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" ++SCAN_OPTIONS= ++ ++# Extra options to supply to gtkdoc-mkdb. ++# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml ++MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space mnt ++ ++# Extra options to supply to gtkdoc-mktmpl ++# e.g. MKTMPL_OPTIONS=--only-section-tmpl ++MKTMPL_OPTIONS= ++ ++# Extra options to supply to gtkdoc-mkhtml ++MKHTML_OPTIONS= ++ ++# Extra options to supply to gtkdoc-fixref. Not normally needed. ++# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html ++FIXXREF_OPTIONS= ++ ++# Used for dependencies. The docs will be rebuilt if any of these change. ++# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h ++# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c ++HFILE_GLOB=$(top_builddir)/libsmartcols/src/libsmartcols.h ++CFILE_GLOB=$(top_srcdir)/libsmartcols/src/*.c ++ ++# Extra header to include when scanning, which are not under DOC_SOURCE_DIR ++# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h ++EXTRA_HFILES= ++ ++# Header files to ignore when scanning. Use base file name, no paths ++# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h ++IGNORE_HFILES=smartcolsP.h ++ ++# Images to copy into HTML directory. ++# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png ++HTML_IMAGES= ++ ++# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). ++# e.g. content_files=running.sgml building.sgml changes-2.0.sgml ++content_files = $(builddir)/version.xml ++ ++# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded ++# These files must be listed here *and* in content_files ++# e.g. expand_content_files=running.sgml ++expand_content_files= ++ ++# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. ++# Only needed if you are using gtkdoc-scangobj to dynamically query widget ++# signals and properties. ++# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) ++# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) ++GTKDOC_CFLAGS= ++GTKDOC_LIBS= ++ ++# This includes the standard gtk-doc make rules, copied by gtkdocize. ++include $(top_srcdir)/config/gtk-doc.make ++ ++# Other files to distribute ++# e.g. EXTRA_DIST += version.xml.in ++EXTRA_DIST += version.xml.in ++ ++# Files not to distribute ++# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types ++# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt ++DISTCLEANFILES += version.xml +diff -up util-linux-2.23.2/libsmartcols/docs/version.xml.in.kzak util-linux-2.23.2/libsmartcols/docs/version.xml.in +--- util-linux-2.23.2/libsmartcols/docs/version.xml.in.kzak 2014-09-25 14:41:48.985843877 +0200 ++++ util-linux-2.23.2/libsmartcols/docs/version.xml.in 2014-09-25 14:41:48.984843867 +0200 +@@ -0,0 +1 @@ ++@VERSION@ +diff -up util-linux-2.23.2/libsmartcols/Makemodule.am.kzak util-linux-2.23.2/libsmartcols/Makemodule.am +--- util-linux-2.23.2/libsmartcols/Makemodule.am.kzak 2014-09-25 14:41:48.983843858 +0200 ++++ util-linux-2.23.2/libsmartcols/Makemodule.am 2014-09-25 14:41:48.983843858 +0200 +@@ -0,0 +1,14 @@ ++if BUILD_LIBSMARTCOLS ++ ++include libsmartcols/src/Makemodule.am ++ ++if ENABLE_GTK_DOC ++# Docs uses separate Makefiles ++SUBDIRS += libsmartcols/docs ++endif ++ ++# noinst for RHEL7: pkgconfig_DATA += libsmartcols/smartcols.pc ++PATHFILES += libsmartcols/smartcols.pc ++EXTRA_DIST += libsmartcols/COPYING ++ ++endif # BUILD_LIBSMARTCOLS +diff -up util-linux-2.23.2/libsmartcols/smartcols.pc.in.kzak util-linux-2.23.2/libsmartcols/smartcols.pc.in +--- util-linux-2.23.2/libsmartcols/smartcols.pc.in.kzak 2014-09-25 14:41:48.985843877 +0200 ++++ util-linux-2.23.2/libsmartcols/smartcols.pc.in 2014-09-25 14:41:48.985843877 +0200 +@@ -0,0 +1,10 @@ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++libdir=@usrlib_execdir@ ++includedir=@includedir@ ++ ++Name: smartcols ++Description: table or tree library ++Version: @LIBSMARTCOLS_VERSION@ ++Cflags: -I${includedir}/libsmartcols ++Libs: -L${libdir} -lsmartcols +diff -up util-linux-2.23.2/libsmartcols/src/cell.c.kzak util-linux-2.23.2/libsmartcols/src/cell.c +--- util-linux-2.23.2/libsmartcols/src/cell.c.kzak 2014-09-25 14:41:48.986843886 +0200 ++++ util-linux-2.23.2/libsmartcols/src/cell.c 2014-09-25 14:41:48.986843886 +0200 +@@ -0,0 +1,242 @@ ++/* ++ * cell.c - functions for table handling at the cell level ++ * ++ * Copyright (C) 2014 Ondrej Oprala ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: cell ++ * @title: Cell ++ * @short_description: cell API ++ * ++ * An API to access and modify per-cell data and information. Note that cell is ++ * always part of the line. If you destroy (un-reference) a line than it ++ * destroys all line cells too. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "smartcolsP.h" ++ ++/* ++ * The cell has no ref-counting, free() and new() functions. All is ++ * handled by libscols_line. ++ */ ++ ++/** ++ * scols_reset_cell: ++ * @ce: pointer to a struct libscols_cell instance ++ * ++ * Frees the cell's internal data and resets its status. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_reset_cell(struct libscols_cell *ce) ++{ ++ assert(ce); ++ ++ if (!ce) ++ return -EINVAL; ++ ++ /*DBG(CELL, ul_debugobj(ce, "reset"));*/ ++ free(ce->data); ++ free(ce->color); ++ memset(ce, 0, sizeof(*ce)); ++ return 0; ++} ++ ++/** ++ * scols_cell_set_data: ++ * @ce: a pointer to a struct libscols_cell instance ++ * @str: data (used for scols_printtable()) ++ * ++ * Stores a copy of the @str in @ce. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_cell_set_data(struct libscols_cell *ce, const char *str) ++{ ++ char *p = NULL; ++ ++ assert(ce); ++ ++ if (!ce) ++ return -EINVAL; ++ if (str) { ++ p = strdup(str); ++ if (!p) ++ return -ENOMEM; ++ } ++ free(ce->data); ++ ce->data = p; ++ return 0; ++} ++ ++/** ++ * scols_cell_refer_data: ++ * @ce: a pointer to a struct libscols_cell instance ++ * @str: data (used for scols_printtable()) ++ * ++ * Adds a reference to @str to @ce. The pointer is deallocated by ++ * scols_reset_cell() or scols_unref_line(). This function is mostly designed ++ * for situations when the data for the cell are already composed in allocated ++ * memory (e.g. asprintf()) to avoid extra unnecessary strdup(). ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_cell_refer_data(struct libscols_cell *ce, char *str) ++{ ++ assert(ce); ++ ++ if (!ce) ++ return -EINVAL; ++ free(ce->data); ++ ce->data = str; ++ return 0; ++} ++ ++/** ++ * scols_cell_get_data: ++ * @ce: a pointer to a struct libscols_cell instance ++ * ++ * Returns: data in @ce or NULL. ++ */ ++const char *scols_cell_get_data(const struct libscols_cell *ce) ++{ ++ assert(ce); ++ return ce ? ce->data : NULL; ++} ++ ++/** ++ * scols_cell_set_userdata: ++ * @ce: a pointer to a struct libscols_cell instance ++ * @data: private user data ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_cell_set_userdata(struct libscols_cell *ce, void *data) ++{ ++ assert(ce); ++ ++ if (!ce) ++ return -EINVAL; ++ ce->userdata = data; ++ return 0; ++} ++ ++/** ++ * scols_cell_get_userdata ++ * @ce: a pointer to a struct libscols_cell instance ++ * ++ * Returns: user data ++ */ ++void *scols_cell_get_userdata(struct libscols_cell *ce) ++{ ++ return ce ? ce->userdata : NULL; ++} ++ ++/** ++ * scols_cmpstr_cells: ++ * @a: pointer to cell ++ * @b: pointer to cell ++ * @data: unused pointer to private data (defined by API) ++ * ++ * Compares cells data by strcmp(). The function is designed for ++ * scols_column_set_cmpfunc() and scols_sort_table(). ++ * ++ * Returns: follows strcmp() return values. ++ */ ++int scols_cmpstr_cells(struct libscols_cell *a, ++ struct libscols_cell *b, ++ __attribute__((__unused__)) void *data) ++{ ++ const char *adata, *bdata; ++ ++ if (a == b) ++ return 0; ++ ++ adata = scols_cell_get_data(a); ++ bdata = scols_cell_get_data(b); ++ ++ if (adata == NULL && bdata == NULL) ++ return 0; ++ if (adata == NULL) ++ return -1; ++ if (bdata == NULL) ++ return 1; ++ return strcmp(adata, bdata); ++} ++ ++/** ++ * scols_cell_set_color: ++ * @ce: a pointer to a struct libscols_cell instance ++ * @color: ESC sequence ++ * ++ * Set the color of @ce to @color. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_cell_set_color(struct libscols_cell *ce, const char *color) ++{ ++ char *p = NULL; ++ ++ assert(ce); ++ ++ if (!ce) ++ return -EINVAL; ++ if (color) { ++ p = strdup(color); ++ if (!p) ++ return -ENOMEM; ++ } ++ free(ce->color); ++ ce->color = p; ++ return 0; ++} ++ ++/** ++ * scols_cell_get_color: ++ * @ce: a pointer to a struct libscols_cell instance ++ * ++ * Returns: the current color of @ce. ++ */ ++const char *scols_cell_get_color(const struct libscols_cell *ce) ++{ ++ assert(ce); ++ return ce ? ce->color : NULL; ++} ++ ++/** ++ * scols_cell_copy_content: ++ * @dest: a pointer to a struct libscols_cell instance ++ * @src: a pointer to an immutable struct libscols_cell instance ++ * ++ * Copy the contents of @src into @dest. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_cell_copy_content(struct libscols_cell *dest, ++ const struct libscols_cell *src) ++{ ++ int rc; ++ ++ assert(dest); ++ assert(src); ++ ++ rc = scols_cell_set_data(dest, scols_cell_get_data(src)); ++ if (!rc) ++ rc = scols_cell_set_color(dest, scols_cell_get_color(src)); ++ if (!rc) ++ dest->userdata = src->userdata; ++ ++ DBG(CELL, ul_debugobj((void *) src, "copy into %p", dest)); ++ return rc; ++} +diff -up util-linux-2.23.2/libsmartcols/src/column.c.kzak util-linux-2.23.2/libsmartcols/src/column.c +--- util-linux-2.23.2/libsmartcols/src/column.c.kzak 2014-09-25 14:41:48.986843886 +0200 ++++ util-linux-2.23.2/libsmartcols/src/column.c 2014-09-25 14:41:48.986843886 +0200 +@@ -0,0 +1,337 @@ ++/* ++ * column.c - functions for table handling at the column level ++ * ++ * Copyright (C) 2014 Ondrej Oprala ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: column ++ * @title: Column ++ * @short_description: column API ++ * ++ * An API to access and modify per-column data and information. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "smartcolsP.h" ++ ++/** ++ * scols_new_column: ++ * ++ * Allocates space for a new column. ++ * ++ * Returns: a pointer to a new struct libscols_cell instance, NULL in case of an ENOMEM error. ++ */ ++struct libscols_column *scols_new_column(void) ++{ ++ struct libscols_column *cl; ++ ++ cl = calloc(1, sizeof(*cl)); ++ if (!cl) ++ return NULL; ++ DBG(COL, ul_debugobj(cl, "alloc")); ++ cl->refcount = 1; ++ INIT_LIST_HEAD(&cl->cl_columns); ++ return cl; ++} ++ ++/** ++ * scols_ref_column: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Increases the refcount of @cl. ++ */ ++void scols_ref_column(struct libscols_column *cl) ++{ ++ if (cl) ++ cl->refcount++; ++} ++ ++/** ++ * scols_unref_column: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Decreases the refcount of @cl. When the count falls to zero, the instance ++ * is automatically deallocated. ++ */ ++void scols_unref_column(struct libscols_column *cl) ++{ ++ if (cl && --cl->refcount <= 0) { ++ DBG(COL, ul_debugobj(cl, "dealloc")); ++ list_del(&cl->cl_columns); ++ scols_reset_cell(&cl->header); ++ free(cl->color); ++ free(cl); ++ } ++} ++ ++/** ++ * scols_copy_column: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Creates a new column and copies @cl's data over to it. ++ * ++ * Returns: a pointer to a new struct libscols_column instance. ++ */ ++struct libscols_column *scols_copy_column(const struct libscols_column *cl) ++{ ++ struct libscols_column *ret; ++ ++ assert (cl); ++ if (!cl) ++ return NULL; ++ ret = scols_new_column(); ++ if (!ret) ++ return NULL; ++ ++ DBG(COL, ul_debugobj((void *) cl, "copy to %p", ret)); ++ ++ if (scols_column_set_color(ret, cl->color)) ++ goto err; ++ if (scols_cell_copy_content(&ret->header, &cl->header)) ++ goto err; ++ ++ ret->width = cl->width; ++ ret->width_min = cl->width_min; ++ ret->width_max = cl->width_max; ++ ret->width_avg = cl->width_avg; ++ ret->width_hint = cl->width_hint; ++ ret->flags = cl->flags; ++ ret->is_extreme = cl->is_extreme; ++ ++ return ret; ++err: ++ scols_unref_column(ret); ++ return NULL; ++} ++ ++/** ++ * scols_column_set_whint: ++ * @cl: a pointer to a struct libscols_column instance ++ * @whint: a width hint ++ * ++ * Sets the width hint of column @cl to @whint. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_column_set_whint(struct libscols_column *cl, double whint) ++{ ++ assert(cl); ++ ++ if (!cl) ++ return -EINVAL; ++ ++ cl->width_hint = whint; ++ return 0; ++} ++ ++/** ++ * scols_column_get_whint: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Returns: The width hint of column @cl, a negative value in case of an error. ++ */ ++double scols_column_get_whint(struct libscols_column *cl) ++{ ++ assert(cl); ++ return cl ? cl->width_hint : -EINVAL; ++} ++ ++/** ++ * scols_column_set_flags: ++ * @cl: a pointer to a struct libscols_column instance ++ * @flags: a flag mask ++ * ++ * Sets the flags of @cl to @flags. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_column_set_flags(struct libscols_column *cl, int flags) ++{ ++ assert(cl); ++ ++ if (!cl) ++ return -EINVAL; ++ ++ cl->flags = flags; ++ return 0; ++} ++ ++/** ++ * scols_column_get_flags: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Returns: The flag mask of @cl, a negative value in case of an error. ++ */ ++int scols_column_get_flags(struct libscols_column *cl) ++{ ++ assert(cl); ++ return cl ? cl->flags : -EINVAL; ++} ++ ++/** ++ * scols_column_get_header: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Returns: A pointer to a struct libscols_cell instance, representing the ++ * header info of column @cl or NULL in case of an error. ++ */ ++struct libscols_cell *scols_column_get_header(struct libscols_column *cl) ++{ ++ assert(cl); ++ return cl ? &cl->header : NULL; ++} ++ ++/** ++ * scols_column_set_color: ++ * @cl: a pointer to a struct libscols_column instance ++ * @color: ESC sequence ++ * ++ * The default color for data cells and column header. ++ * ++ * If you want to set header specific color then use scols_column_get_header() ++ * and scols_cell_set_color(). ++ * ++ * If you want to set data cell specific color the use scols_line_get_cell() + ++ * scols_cell_set_color(). ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_column_set_color(struct libscols_column *cl, const char *color) ++{ ++ char *p = NULL; ++ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ if (color) { ++ p = strdup(color); ++ if (!p) ++ return -ENOMEM; ++ } ++ ++ free(cl->color); ++ cl->color = p; ++ return 0; ++} ++ ++/** ++ * scols_column_get_color: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Returns: The current color setting of the column @cl. ++ */ ++const char *scols_column_get_color(struct libscols_column *cl) ++{ ++ assert(cl); ++ return cl ? cl->color : NULL; ++} ++ ++ ++/** ++ * scols_column_set_cmpfunc: ++ * @cl: column ++ * @cmp: pointer to compare function ++ * @data: private data for cmp function ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_column_set_cmpfunc(struct libscols_column *cl, ++ int (*cmp)(struct libscols_cell *, ++ struct libscols_cell *, ++ void *), ++ void *data) ++{ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ ++ cl->cmpfunc = cmp; ++ cl->cmpfunc_data = data; ++ return 0; ++} ++ ++/** ++ * scols_column_is_trunc: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Gets the value of @cl's flag trunc. ++ * ++ * Returns: trunc flag value, negative value in case of an error. ++ */ ++int scols_column_is_trunc(struct libscols_column *cl) ++{ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ return cl->flags & SCOLS_FL_TRUNC; ++} ++/** ++ * scols_column_is_tree: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Gets the value of @cl's flag tree. ++ * ++ * Returns: tree flag value, negative value in case of an error. ++ */ ++int scols_column_is_tree(struct libscols_column *cl) ++{ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ return cl->flags & SCOLS_FL_TREE; ++} ++/** ++ * scols_column_is_right: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Gets the value of @cl's flag right. ++ * ++ * Returns: right flag value, negative value in case of an error. ++ */ ++int scols_column_is_right(struct libscols_column *cl) ++{ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ return cl->flags & SCOLS_FL_RIGHT; ++} ++/** ++ * scols_column_is_strict_width: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Gets the value of @cl's flag strict_width. ++ * ++ * Returns: strict_width flag value, negative value in case of an error. ++ */ ++int scols_column_is_strict_width(struct libscols_column *cl) ++{ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ return cl->flags & SCOLS_FL_STRICTWIDTH; ++} ++/** ++ * scols_column_is_noextremes: ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Gets the value of @cl's flag no_extremes. ++ * ++ * Returns: no_extremes flag value, negative value in case of an error. ++ */ ++int scols_column_is_noextremes(struct libscols_column *cl) ++{ ++ assert(cl); ++ if (!cl) ++ return -EINVAL; ++ return cl->flags & SCOLS_FL_NOEXTREMES; ++} +diff -up util-linux-2.23.2/libsmartcols/src/.gitignore.kzak util-linux-2.23.2/libsmartcols/src/.gitignore +--- util-linux-2.23.2/libsmartcols/src/.gitignore.kzak 2014-09-25 14:41:48.985843877 +0200 ++++ util-linux-2.23.2/libsmartcols/src/.gitignore 2014-09-25 14:41:48.985843877 +0200 +@@ -0,0 +1 @@ ++libsmartcols.h +diff -up util-linux-2.23.2/libsmartcols/src/init.c.kzak util-linux-2.23.2/libsmartcols/src/init.c +--- util-linux-2.23.2/libsmartcols/src/init.c.kzak 2014-09-25 14:41:48.987843896 +0200 ++++ util-linux-2.23.2/libsmartcols/src/init.c 2014-09-25 14:41:48.987843896 +0200 +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: init ++ * @title: Library initialization ++ * @short_description: initialize debugging ++ * ++ * The library debug stuff. ++ */ ++ ++#include ++ ++#include "smartcolsP.h" ++ ++UL_DEBUG_DEFINE_MASK(libsmartcols); ++ ++static const struct dbg_mask libsmartcols_masknames [] = { ++ { "all", SCOLS_DEBUG_ALL }, ++ { "cell", SCOLS_DEBUG_CELL }, ++ { "line", SCOLS_DEBUG_LINE }, ++ { "tab", SCOLS_DEBUG_TAB }, ++ { "col", SCOLS_DEBUG_COL }, ++ { "buff", SCOLS_DEBUG_BUFF }, ++ { NULL, 0 } ++}; ++/** ++ * scols_init_debug: ++ * @mask: debug mask (0xffff to enable full debugging) ++ * ++ * If the @mask is not specified, then this function reads ++ * the LIBSMARTCOLS_DEBUG environment variable to get the mask. ++ * ++ * Already initialized debugging stuff cannot be changed. Calling ++ * this function twice has no effect. ++ */ ++void scols_init_debug(int mask) ++{ ++ __UL_INIT_DEBUG(libsmartcols, SCOLS_DEBUG_, mask, LIBSMARTCOLS_DEBUG); ++ ++ if (libsmartcols_debug_mask != SCOLS_DEBUG_INIT) { ++ const char *ver = NULL; ++ ++ scols_get_library_version(&ver); ++ ++ DBG(INIT, ul_debug("library version: %s", ver)); ++ } ++} +diff -up util-linux-2.23.2/libsmartcols/src/iter.c.kzak util-linux-2.23.2/libsmartcols/src/iter.c +--- util-linux-2.23.2/libsmartcols/src/iter.c.kzak 2014-09-25 14:41:48.987843896 +0200 ++++ util-linux-2.23.2/libsmartcols/src/iter.c 2014-09-25 14:41:48.987843896 +0200 +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2009-2014 Karel Zak ++ * Copyright (C) 2014 Ondrej Oprala ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: iter ++ * @title: Iterator ++ * @short_description: unified iterator ++ * ++ * The iterator keeps the direction and the last position ++ * for access to the internal library tables/lists. ++ */ ++ ++#include ++#include ++ ++#include "smartcolsP.h" ++ ++/** ++ * scols_new_iter: ++ * @direction: SCOLS_INTER_{FOR,BACK}WARD direction ++ * ++ * Returns: newly allocated generic libmount iterator. ++ */ ++struct libscols_iter *scols_new_iter(int direction) ++{ ++ struct libscols_iter *itr = calloc(1, sizeof(*itr)); ++ if (!itr) ++ return NULL; ++ itr->direction = direction; ++ return itr; ++} ++ ++/** ++ * scols_free_iter: ++ * @itr: iterator pointer ++ * ++ * Deallocates the iterator. ++ */ ++void scols_free_iter(struct libscols_iter *itr) ++{ ++ free(itr); ++} ++ ++/** ++ * scols_reset_iter: ++ * @itr: iterator pointer ++ * @direction: SCOLS_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged ++ * ++ * Resets the iterator. ++ */ ++void scols_reset_iter(struct libscols_iter *itr, int direction) ++{ ++ if (direction == -1) ++ direction = itr->direction; ++ ++ memset(itr, 0, sizeof(*itr)); ++ itr->direction = direction; ++} ++ ++/** ++ * scols_iter_get_direction: ++ * @itr: iterator pointer ++ * ++ * Returns: SCOLS_INTER_{FOR,BACK}WARD ++ */ ++int scols_iter_get_direction(struct libscols_iter *itr) ++{ ++ return itr->direction; ++} +diff -up util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in.kzak util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in +--- util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in.kzak 2014-09-25 14:41:48.988843905 +0200 ++++ util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in 2014-09-25 14:41:48.988843905 +0200 +@@ -0,0 +1,229 @@ ++/* ++ * Prints table or tree. ++ * ++ * Copyright (C) 2014 Ondrej Oprala ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++#ifndef _LIBSMARTCOLS_H ++#define _LIBSMARTCOLS_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++#include ++#include ++ ++/** ++ * LIBSMARTCOLS_VERSION: ++ * ++ * Library version string ++ */ ++#define LIBSMARTCOLS_VERSION "@LIBSMARTCOLS_VERSION@" ++ ++/** ++ * libscols_iter: ++ * ++ * Generic iterator ++ */ ++struct libscols_iter; ++ ++/** ++ * libscols_symbols: ++ * ++ * Symbol groups for printing tree hierarchies ++ */ ++struct libscols_symbols; ++ ++/** ++ * libscols_cell: ++ * ++ * A cell - the smallest library object ++ */ ++struct libscols_cell; ++ ++/** ++ * libscols_line: ++ * ++ * A line - an array of cells ++ */ ++struct libscols_line; ++ ++/** ++ * libscols_table: ++ * ++ * A table - The most abstract object, encapsulating lines, columns, symbols and cells ++ */ ++struct libscols_table; ++ ++/** ++ * libscols_column: ++ * ++ * A column - defines the number of columns and column names ++ */ ++struct libscols_column; ++ ++/* iter.c */ ++enum { ++ ++ SCOLS_ITER_FORWARD = 0, ++ SCOLS_ITER_BACKWARD ++}; ++ ++/* ++ * Column flags ++ */ ++enum { ++ SCOLS_FL_TRUNC = (1 << 0), /* truncate fields data if necessary */ ++ SCOLS_FL_TREE = (1 << 1), /* use tree "ascii art" */ ++ SCOLS_FL_RIGHT = (1 << 2), /* align to the right */ ++ SCOLS_FL_STRICTWIDTH = (1 << 3), /* don't reduce width if column is empty */ ++ SCOLS_FL_NOEXTREMES = (1 << 4), /* ignore extreme fields when count column width*/ ++}; ++ ++extern struct libscols_iter *scols_new_iter(int direction); ++extern void scols_free_iter(struct libscols_iter *itr); ++extern void scols_reset_iter(struct libscols_iter *itr, int direction); ++extern int scols_iter_get_direction(struct libscols_iter *itr); ++ ++/* init.c */ ++extern void scols_init_debug(int mask); ++ ++/* version.c */ ++extern int scols_parse_version_string(const char *ver_string); ++extern int scols_get_library_version(const char **ver_string); ++ ++/* symbols.c */ ++extern struct libscols_symbols *scols_new_symbols(void); ++extern void scols_ref_symbols(struct libscols_symbols *sy); ++extern void scols_unref_symbols(struct libscols_symbols *sy); ++extern struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb); ++extern int scols_symbols_set_branch(struct libscols_symbols *sb, const char *str); ++extern int scols_symbols_set_vertical(struct libscols_symbols *sb, const char *str); ++extern int scols_symbols_set_right(struct libscols_symbols *sb, const char *str); ++ ++/* cell.c */ ++extern int scols_reset_cell(struct libscols_cell *ce); ++extern int scols_cell_copy_content(struct libscols_cell *dest, ++ const struct libscols_cell *src); ++extern int scols_cell_set_data(struct libscols_cell *ce, const char *str); ++extern int scols_cell_refer_data(struct libscols_cell *ce, char *str); ++extern const char *scols_cell_get_data(const struct libscols_cell *ce); ++extern int scols_cell_set_color(struct libscols_cell *ce, const char *color); ++extern const char *scols_cell_get_color(const struct libscols_cell *ce); ++ ++extern void *scols_cell_get_userdata(struct libscols_cell *ce); ++extern int scols_cell_set_userdata(struct libscols_cell *ce, void *data); ++ ++extern int scols_cmpstr_cells(struct libscols_cell *a, ++ struct libscols_cell *b, void *data); ++/* column.c */ ++extern int scols_column_is_tree(struct libscols_column *cl); ++extern int scols_column_is_trunc(struct libscols_column *cl); ++extern int scols_column_is_right(struct libscols_column *cl); ++extern int scols_column_is_strict_width(struct libscols_column *cl); ++extern int scols_column_is_noextremes(struct libscols_column *cl); ++ ++extern int scols_column_set_flags(struct libscols_column *cl, int flags); ++extern int scols_column_get_flags(struct libscols_column *cl); ++extern struct libscols_column *scols_new_column(void); ++extern void scols_ref_column(struct libscols_column *cl); ++extern void scols_unref_column(struct libscols_column *cl); ++extern struct libscols_column *scols_copy_column(const struct libscols_column *cl); ++extern int scols_column_set_whint(struct libscols_column *cl, double whint); ++extern double scols_column_get_whint(struct libscols_column *cl); ++extern struct libscols_cell *scols_column_get_header(struct libscols_column *cl); ++extern int scols_column_set_color(struct libscols_column *cl, const char *color); ++extern const char *scols_column_get_color(struct libscols_column *cl); ++ ++extern int scols_column_set_cmpfunc(struct libscols_column *cl, ++ int (*cmp)(struct libscols_cell *a, ++ struct libscols_cell *b, void *), ++ void *data); ++ ++/* line.c */ ++extern struct libscols_line *scols_new_line(void); ++extern void scols_ref_line(struct libscols_line *ln); ++extern void scols_unref_line(struct libscols_line *ln); ++extern int scols_line_alloc_cells(struct libscols_line *ln, size_t n); ++extern void scols_line_free_cells(struct libscols_line *ln); ++extern int scols_line_set_userdata(struct libscols_line *ln, void *data); ++extern void *scols_line_get_userdata(struct libscols_line *ln); ++extern int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child); ++extern int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child); ++extern int scols_line_has_children(struct libscols_line *ln); ++extern int scols_line_next_child(struct libscols_line *ln, ++ struct libscols_iter *itr, struct libscols_line **chld); ++extern struct libscols_line *scols_line_get_parent(struct libscols_line *ln); ++extern int scols_line_set_color(struct libscols_line *ln, const char *color); ++extern const char *scols_line_get_color(struct libscols_line *ln); ++extern size_t scols_line_get_ncells(struct libscols_line *ln); ++extern struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, size_t n); ++extern struct libscols_cell *scols_line_get_column_cell( ++ struct libscols_line *ln, ++ struct libscols_column *cl); ++extern int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data); ++extern int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data); ++extern struct libscols_line *scols_copy_line(struct libscols_line *ln); ++ ++/* table */ ++extern int scols_table_colors_wanted(struct libscols_table *tb); ++extern int scols_table_is_raw(struct libscols_table *tb); ++extern int scols_table_is_ascii(struct libscols_table *tb); ++extern int scols_table_is_noheadings(struct libscols_table *tb); ++extern int scols_table_is_empty(struct libscols_table *tb); ++extern int scols_table_is_export(struct libscols_table *tb); ++extern int scols_table_is_maxout(struct libscols_table *tb); ++extern int scols_table_is_tree(struct libscols_table *tb); ++ ++extern int scols_table_enable_colors(struct libscols_table *tb, int enable); ++extern int scols_table_enable_raw(struct libscols_table *tb, int enable); ++extern int scols_table_enable_ascii(struct libscols_table *tb, int enable); ++extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable); ++extern int scols_table_enable_export(struct libscols_table *tb, int enable); ++extern int scols_table_enable_maxout(struct libscols_table *tb, int enable); ++ ++extern int scols_table_set_column_separator(struct libscols_table *tb, const char *sep); ++extern int scols_table_set_line_separator(struct libscols_table *tb, const char *sep); ++ ++extern struct libscols_table *scols_new_table(void); ++extern void scols_ref_table(struct libscols_table *tb); ++extern void scols_unref_table(struct libscols_table *tb); ++extern int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl); ++extern int scols_table_remove_column(struct libscols_table *tb, struct libscols_column *cl); ++extern int scols_table_remove_columns(struct libscols_table *tb); ++extern struct libscols_column *scols_table_new_column(struct libscols_table *tb, const char *name, double whint, int flags); ++extern int scols_table_next_column(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_column **cl); ++extern char *scols_table_get_column_separator(struct libscols_table *tb); ++extern char *scols_table_get_line_separator(struct libscols_table *tb); ++extern int scols_table_get_ncols(struct libscols_table *tb); ++extern int scols_table_get_nlines(struct libscols_table *tb); ++extern struct libscols_column *scols_table_get_column(struct libscols_table *tb, size_t n); ++extern int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln); ++extern int scols_table_remove_line(struct libscols_table *tb, struct libscols_line *ln); ++extern void scols_table_remove_lines(struct libscols_table *tb); ++extern int scols_table_next_line(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_line **ln); ++extern struct libscols_line *scols_table_new_line(struct libscols_table *tb, struct libscols_line *parent); ++extern struct libscols_line *scols_table_get_line(struct libscols_table *tb, size_t n); ++extern struct libscols_table *scols_copy_table(struct libscols_table *tb); ++extern int scols_table_set_symbols(struct libscols_table *tb, struct libscols_symbols *sy); ++ ++extern int scols_table_set_stream(struct libscols_table *tb, FILE *stream); ++extern FILE *scols_table_get_stream(struct libscols_table *tb); ++extern int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce); ++ ++extern int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl); ++ ++/* table_print.c */ ++extern int scols_print_table(struct libscols_table *tb); ++extern int scols_print_table_to_string(struct libscols_table *tb, char **data); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _LIBSMARTCOLS_H */ +diff -up util-linux-2.23.2/libsmartcols/src/libsmartcols.sym.kzak util-linux-2.23.2/libsmartcols/src/libsmartcols.sym +--- util-linux-2.23.2/libsmartcols/src/libsmartcols.sym.kzak 2014-09-25 14:41:48.988843905 +0200 ++++ util-linux-2.23.2/libsmartcols/src/libsmartcols.sym 2014-09-25 14:41:48.988843905 +0200 +@@ -0,0 +1,112 @@ ++/* ++ * symbols since util-linux 2.25 ++ */ ++SMARTCOLS_2.25 { ++global: ++ scols_cell_copy_content; ++ scols_cell_get_color; ++ scols_cell_get_data; ++ scols_cell_get_userdata; ++ scols_cell_refer_data; ++ scols_cell_set_color; ++ scols_cell_set_data; ++ scols_cell_set_userdata; ++ scols_cmpstr_cells; ++ scols_column_get_color; ++ scols_column_get_flags; ++ scols_column_get_header; ++ scols_column_get_whint; ++ scols_column_is_noextremes; ++ scols_column_is_right; ++ scols_column_is_strict_width; ++ scols_column_is_tree; ++ scols_column_is_trunc; ++ scols_column_set_cmpfunc; ++ scols_column_set_color; ++ scols_column_set_flags; ++ scols_column_set_whint; ++ scols_copy_column; ++ scols_copy_line; ++ scols_copy_symbols; ++ scols_copy_table; ++ scols_free_iter; ++ scols_get_library_version; ++ scols_init_debug; ++ scols_iter_get_direction; ++ scols_line_add_child; ++ scols_line_alloc_cells; ++ scols_line_free_cells; ++ scols_line_get_cell; ++ scols_line_get_color; ++ scols_line_get_column_cell; ++ scols_line_get_ncells; ++ scols_line_get_parent; ++ scols_line_get_userdata; ++ scols_line_has_children; ++ scols_line_next_child; ++ scols_line_refer_data; ++ scols_line_remove_child; ++ scols_line_set_color; ++ scols_line_set_data; ++ scols_line_set_userdata; ++ scols_new_column; ++ scols_new_iter; ++ scols_new_line; ++ scols_new_symbols; ++ scols_new_table; ++ scols_parse_version_string; ++ scols_print_table; ++ scols_print_table_to_string; ++ scols_ref_column; ++ scols_ref_line; ++ scols_ref_symbols; ++ scols_ref_table; ++ scols_reset_cell; ++ scols_reset_iter; ++ scols_sort_table; ++ scols_symbols_set_branch; ++ scols_symbols_set_right; ++ scols_symbols_set_vertical; ++ scols_table_add_column; ++ scols_table_add_line; ++ scols_table_colors_wanted; ++ scols_table_enable_ascii; ++ scols_table_enable_colors; ++ scols_table_enable_export; ++ scols_table_enable_maxout; ++ scols_table_enable_noheadings; ++ scols_table_enable_raw; ++ scols_table_get_column; ++ scols_table_get_column_separator; ++ scols_table_get_line; ++ scols_table_get_line_separator; ++ scols_table_get_ncols; ++ scols_table_get_nlines; ++ scols_table_get_stream; ++ scols_table_is_ascii; ++ scols_table_is_empty; ++ scols_table_is_export; ++ scols_table_is_maxout; ++ scols_table_is_noheadings; ++ scols_table_is_raw; ++ scols_table_is_tree; ++ scols_table_new_column; ++ scols_table_new_line; ++ scols_table_next_column; ++ scols_table_next_line; ++ scols_table_reduce_termwidth; ++ scols_table_remove_column; ++ scols_table_remove_columns; ++ scols_table_remove_line; ++ scols_table_remove_lines; ++ scols_table_set_column_separator; ++ scols_table_set_line_separator; ++ scols_table_set_stream; ++ scols_table_set_symbols; ++ scols_unref_column; ++ scols_unref_line; ++ scols_unref_symbols; ++ scols_unref_table; ++local: ++ *; ++}; +diff -up util-linux-2.23.2/libsmartcols/src/line.c.kzak util-linux-2.23.2/libsmartcols/src/line.c +--- util-linux-2.23.2/libsmartcols/src/line.c.kzak 2014-09-25 14:41:48.989843915 +0200 ++++ util-linux-2.23.2/libsmartcols/src/line.c 2014-09-25 14:41:48.989843915 +0200 +@@ -0,0 +1,456 @@ ++/* ++ * line.c - functions for table handling at the line level ++ * ++ * Copyright (C) 2014 Karel Zak ++ * Copyright (C) 2014 Ondrej Oprala ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: line ++ * @title: Line ++ * @short_description: line API ++ * ++ * An API to access and modify per-line data and information. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "smartcolsP.h" ++ ++/** ++ * scols_new_line: ++ * ++ * Note that the line is allocated without cells, the cells will be allocated ++ * later when you add the line to the table. If you want to use the line ++ * without table then you have to explicitly allocate the cells by ++ * scols_line_alloc_cells(). ++ * ++ * Returns: a pointer to a new struct libscols_line instance. ++ */ ++struct libscols_line *scols_new_line(void) ++{ ++ struct libscols_line *ln; ++ ++ ln = calloc(1, sizeof(*ln)); ++ if (!ln) ++ return NULL; ++ ++ DBG(LINE, ul_debugobj(ln, "alloc")); ++ ln->refcount = 1; ++ INIT_LIST_HEAD(&ln->ln_lines); ++ INIT_LIST_HEAD(&ln->ln_children); ++ INIT_LIST_HEAD(&ln->ln_branch); ++ return ln; ++} ++ ++/** ++ * scols_ref_line: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Increases the refcount of @ln. ++ */ ++void scols_ref_line(struct libscols_line *ln) ++{ ++ if (ln) ++ ln->refcount++; ++} ++ ++/** ++ * scols_unref_line: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Decreases the refcount of @ln. When the count falls to zero, the instance ++ * is automatically deallocated. ++ */ ++void scols_unref_line(struct libscols_line *ln) ++{ ++ ++ if (ln && --ln->refcount <= 0) { ++ DBG(CELL, ul_debugobj(ln, "dealloc")); ++ list_del(&ln->ln_lines); ++ list_del(&ln->ln_children); ++ scols_line_free_cells(ln); ++ free(ln->color); ++ free(ln); ++ return; ++ } ++} ++ ++/** ++ * scols_line_free_cells: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Frees the allocated cells referenced to by @ln. ++ */ ++void scols_line_free_cells(struct libscols_line *ln) ++{ ++ size_t i; ++ ++ if (!ln || !ln->cells) ++ return; ++ ++ DBG(LINE, ul_debugobj(ln, "free cells")); ++ ++ for (i = 0; i < ln->ncells; i++) ++ scols_reset_cell(&ln->cells[i]); ++ ++ free(ln->cells); ++ ln->ncells = 0; ++ ln->cells = NULL; ++} ++ ++/** ++ * scols_line_alloc_cells: ++ * @ln: a pointer to a struct libscols_line instance ++ * @n: the number of elements ++ * ++ * Allocates space for @n cells. This function is optional, ++ * and libsmartcols automatically allocates necessary cells ++ * according to number of columns in the table when you add ++ * the line to the table. See scols_table_add_line(). ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_alloc_cells(struct libscols_line *ln, size_t n) ++{ ++ struct libscols_cell *ce; ++ ++ assert(ln); ++ ++ if (!ln) ++ return -EINVAL; ++ if (ln->ncells == n) ++ return 0; ++ ++ if (!n) { ++ scols_line_free_cells(ln); ++ return 0; ++ } ++ ++ DBG(LINE, ul_debugobj(ln, "alloc %zu cells", n)); ++ ++ ce = realloc(ln->cells, n * sizeof(struct libscols_cell)); ++ if (!ce) ++ return -errno; ++ ++ if (n > ln->ncells) ++ memset(ce + ln->ncells, 0, ++ (n - ln->ncells) * sizeof(struct libscols_cell)); ++ ++ ln->cells = ce; ++ ln->ncells = n; ++ return 0; ++} ++ ++/** ++ * scols_line_set_userdata: ++ * @ln: a pointer to a struct libscols_line instance ++ * @data: user data ++ * ++ * Binds @data to @ln. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_set_userdata(struct libscols_line *ln, void *data) ++{ ++ assert(ln); ++ if (!ln) ++ return -EINVAL; ++ ln->userdata = data; ++ return 0; ++} ++ ++/** ++ * scols_line_get_userdata: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++void *scols_line_get_userdata(struct libscols_line *ln) ++{ ++ assert(ln); ++ return ln ? ln->userdata : NULL; ++} ++ ++/** ++ * scols_line_remove_child: ++ * @ln: a pointer to a struct libscols_line instance ++ * @child: a pointer to a struct libscols_line instance ++ * ++ * Removes @child as a child of @ln. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child) ++{ ++ assert(ln); ++ assert(child); ++ ++ if (!ln || !child) ++ return -EINVAL; ++ ++ DBG(LINE, ul_debugobj(ln, "remove child %p", child)); ++ ++ list_del_init(&child->ln_children); ++ child->parent = NULL; ++ scols_unref_line(child); ++ ++ scols_unref_line(ln); ++ return 0; ++} ++ ++/** ++ * scols_line_add_child: ++ * @ln: a pointer to a struct libscols_line instance ++ * @child: a pointer to a struct libscols_line instance ++ * ++ * Sets @child as a child of @ln. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child) ++{ ++ assert(ln); ++ assert(child); ++ ++ if (!ln || !child) ++ return -EINVAL; ++ ++ /* unref old<->parent */ ++ if (child->parent) ++ scols_line_remove_child(child->parent, child); ++ ++ DBG(LINE, ul_debugobj(ln, "add child %p", child)); ++ ++ /* new reference from parent to child */ ++ list_add_tail(&child->ln_children, &ln->ln_branch); ++ scols_ref_line(child); ++ ++ /* new reference from child to parent */ ++ child->parent = ln; ++ scols_ref_line(ln); ++ ++ return 0; ++} ++ ++/** ++ * scols_line_get_parent: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Returns: a pointer to @ln's parent, NULL in case it has no parent or if there was an error. ++ */ ++struct libscols_line *scols_line_get_parent(struct libscols_line *ln) ++{ ++ assert(ln); ++ return ln ? ln->parent : NULL; ++} ++ ++/** ++ * scols_line_has_children: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Returns: 1 if @ln has any children, otherwise 0. ++ */ ++int scols_line_has_children(struct libscols_line *ln) ++{ ++ assert(ln); ++ return ln ? !list_empty(&ln->ln_branch) : 0; ++} ++ ++/** ++ * scols_line_next_child: ++ * @ln: a pointer to a struct libscols_line instance ++ * @itr: a pointer to a struct libscols_iter instance ++ * @chld: a pointer to a pointer to a struct libscols_line instance ++ * ++ * Finds the next child and returns a pointer to it via @chld. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_next_child(struct libscols_line *ln, ++ struct libscols_iter *itr, ++ struct libscols_line **chld) ++{ ++ int rc = 1; ++ ++ if (!ln || !itr || !chld) ++ return -EINVAL; ++ *chld = NULL; ++ ++ if (!itr->head) ++ SCOLS_ITER_INIT(itr, &ln->ln_branch); ++ if (itr->p != itr->head) { ++ SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children); ++ rc = 0; ++ } ++ ++ return rc; ++} ++ ++/** ++ * scols_line_set_color: ++ * @ln: a pointer to a struct libscols_line instance ++ * @color: ESC sequence ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_set_color(struct libscols_line *ln, const char *color) ++{ ++ char *p = NULL; ++ ++ assert(ln); ++ if (!ln) ++ return -EINVAL; ++ if (color) { ++ p = strdup(color); ++ if (!p) ++ return -ENOMEM; ++ } ++ ++ free(ln->color); ++ ln->color = p; ++ return 0; ++} ++ ++/** ++ * scols_line_get_color: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Returns: @ln's color string, NULL in case of an error. ++ */ ++const char *scols_line_get_color(struct libscols_line *ln) ++{ ++ assert(ln); ++ return ln ? ln->color : NULL; ++} ++ ++/** ++ * scols_line_get_ncells: ++ * @ln: a pointer to a struct libscols_line instance ++ * ++ * Returns: @ln's number of cells ++ */ ++size_t scols_line_get_ncells(struct libscols_line *ln) ++{ ++ assert(ln); ++ return ln ? ln->ncells : 0; ++} ++ ++/** ++ * scols_line_get_cell: ++ * @ln: a pointer to a struct libscols_line instance ++ * @n: cell number to retrieve ++ * ++ * Returns: the @n-th cell in @ln, NULL in case of an error. ++ */ ++struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, ++ size_t n) ++{ ++ assert(ln); ++ ++ if (!ln || n >= ln->ncells) ++ return NULL; ++ return &ln->cells[n]; ++} ++ ++/** ++ * scols_line_get_column_cell: ++ * @ln: a pointer to a struct libscols_line instance ++ * @cl: pointer to cell ++ * ++ * Like scols_line_get_cell() by cell is referenced by column. ++ * ++ * Returns: the @n-th cell in @ln, NULL in case of an error. ++ */ ++struct libscols_cell *scols_line_get_column_cell( ++ struct libscols_line *ln, ++ struct libscols_column *cl) ++{ ++ assert(ln); ++ assert(cl); ++ ++ return scols_line_get_cell(ln, cl->seqnum); ++} ++ ++/** ++ * scols_line_set_data: ++ * @ln: a pointer to a struct libscols_cell instance ++ * @n: number of the cell, whose data is to be set ++ * @data: actual data to set ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data) ++{ ++ struct libscols_cell *ce = scols_line_get_cell(ln, n); ++ ++ if (!ce) ++ return -EINVAL; ++ return scols_cell_set_data(ce, data); ++} ++ ++/** ++ * scols_line_refer_data: ++ * @ln: a pointer to a struct libscols_cell instance ++ * @n: number of the cell which will refer to @data ++ * @data: actual data to refer to ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data) ++{ ++ struct libscols_cell *ce = scols_line_get_cell(ln, n); ++ ++ if (!ce) ++ return -EINVAL; ++ return scols_cell_refer_data(ce, data); ++} ++ ++/** ++ * scols_copy_line: ++ * @ln: a pointer to a struct libscols_cell instance ++ * ++ * Returns: A newly allocated copy of @ln, NULL in case of an error. ++ */ ++struct libscols_line *scols_copy_line(struct libscols_line *ln) ++{ ++ struct libscols_line *ret; ++ size_t i; ++ ++ assert (ln); ++ if (!ln) ++ return NULL; ++ ++ ret = scols_new_line(); ++ if (!ret) ++ return NULL; ++ if (scols_line_set_color(ret, ln->color)) ++ goto err; ++ if (scols_line_alloc_cells(ret, ln->ncells)) ++ goto err; ++ ++ ret->userdata = ln->userdata; ++ ret->ncells = ln->ncells; ++ ret->seqnum = ln->seqnum; ++ ++ DBG(LINE, ul_debugobj(ln, "copy to %p", ret)); ++ ++ for (i = 0; i < ret->ncells; ++i) { ++ if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i])) ++ goto err; ++ } ++ ++ return ret; ++err: ++ scols_unref_line(ret); ++ return NULL; ++} ++ ++ +diff -up util-linux-2.23.2/libsmartcols/src/Makemodule.am.kzak util-linux-2.23.2/libsmartcols/src/Makemodule.am +--- util-linux-2.23.2/libsmartcols/src/Makemodule.am.kzak 2014-09-25 14:41:48.985843877 +0200 ++++ util-linux-2.23.2/libsmartcols/src/Makemodule.am 2014-09-25 14:42:10.471048869 +0200 +@@ -0,0 +1,75 @@ ++ ++ ++## smartcols.h is generated, so it's stored in builddir! (no distribute in RHEL7) ++#smartcolsincdir = $(includedir)/libsmartcols ++#nodist_smartcolsinc_HEADERS = $(top_builddir)/libsmartcols/src/libsmartcols.h ++ ++noinst_LTLIBRARIES += libsmartcols.la ++libsmartcols_la_SOURCES= \ ++ include/list.h \ ++ \ ++ libsmartcols/src/smartcolsP.h \ ++ libsmartcols/src/iter.c \ ++ libsmartcols/src/symbols.c \ ++ libsmartcols/src/cell.c \ ++ libsmartcols/src/column.c \ ++ libsmartcols/src/line.c \ ++ libsmartcols/src/table.c \ ++ libsmartcols/src/table_print.c \ ++ libsmartcols/src/version.c \ ++ libsmartcols/src/init.c \ ++ $(nodist_smartcolsinc_HEADERS) ++ ++nodist_libsmartcols_la_SOURCES = libsmartcols/src/smartcolsP.h ++ ++libsmartcols_la_LIBADD = libcommon.la ++ ++libsmartcols_la_CFLAGS = \ ++ $(SOLIB_CFLAGS) \ ++ -I$(ul_libsmartcols_incdir) \ ++ -I$(top_srcdir)/libsmartcols/src ++ ++libsmartcols_la_DEPENDENCIES = \ ++ libcommon.la \ ++ libsmartcols/src/libsmartcols.sym \ ++ libsmartcols/src/libsmartcols.h.in ++ ++libsmartcols_la_LDFLAGS = \ ++ $(SOLIB_LDFLAGS) \ ++ -Wl,--version-script=$(top_srcdir)/libsmartcols/src/libsmartcols.sym \ ++ -version-info $(LIBSMARTCOLS_VERSION_INFO) ++ ++EXTRA_DIST += \ ++ libsmartcols/src/libsmartcols.sym \ ++ libsmartcols/src/libsmartcols.h.in ++ ++ ++if BUILD_LIBSMARTCOLS_TESTS ++check_PROGRAMS += test_smartcols ++ ++libsmartcols_tests_cflags = $(libsmartcols_la_CFLAGS) ++libsmartcols_tests_ldadd = libsmartcols.la libcommon.la ++ ++test_smartcols_SOURCES = libsmartcols/src/test.c ++test_smartcols_CFLAGS = $(libsmartcols_tests_cflags) ++test_smartcols_LDADD = $(libsmartcols_tests_ldadd) ++endif # BUILD_LIBSMARTCOLS_TESTS ++ ++ ++# move lib from $(usrlib_execdir) to $(libdir) if needed ++install-exec-hook-libsmartcols: ++ if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libsmartcols.so"; then \ ++ mkdir -p $(DESTDIR)$(libdir); \ ++ mv $(DESTDIR)$(usrlib_execdir)/libsmartcols.so.* $(DESTDIR)$(libdir); \ ++ so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libsmartcols.so); \ ++ so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ ++ (cd $(DESTDIR)$(usrlib_execdir) && \ ++ rm -f libsmartcols.so && \ ++ $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libsmartcols.so); \ ++ fi ++ ++uninstall-hook-libsmartcols: ++ rm -f $(DESTDIR)$(libdir)/libsmartcols.so* ++ ++INSTALL_EXEC_HOOKS += install-exec-hook-libsmartcols ++UNINSTALL_HOOKS += uninstall-hook-libsmartcols +diff -up util-linux-2.23.2/libsmartcols/src/smartcolsP.h.kzak util-linux-2.23.2/libsmartcols/src/smartcolsP.h +--- util-linux-2.23.2/libsmartcols/src/smartcolsP.h.kzak 2014-09-25 14:41:48.989843915 +0200 ++++ util-linux-2.23.2/libsmartcols/src/smartcolsP.h 2014-09-25 14:41:48.989843915 +0200 +@@ -0,0 +1,173 @@ ++/* ++ * smartcolsP.h - private library header file ++ * ++ * Copyright (C) 2014 Ondrej Oprala ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++#ifndef _LIBSMARTCOLS_PRIVATE_H ++#define _LIBSMARTCOLS_PRIVATE_H ++ ++#include "c.h" ++#include "list.h" ++#include "colors.h" ++#include "debug.h" ++ ++#include "libsmartcols.h" ++ ++/* features */ ++#define CONFIG_LIBSMARTCOLS_ASSERT ++ ++#ifdef CONFIG_LIBSMARTCOLS_ASSERT ++# include ++#else ++# define assert(x) ++#endif ++ ++/* ++ * Debug ++ */ ++#define SCOLS_DEBUG_INIT (1 << 1) ++#define SCOLS_DEBUG_CELL (1 << 2) ++#define SCOLS_DEBUG_LINE (1 << 3) ++#define SCOLS_DEBUG_TAB (1 << 4) ++#define SCOLS_DEBUG_COL (1 << 5) ++#define SCOLS_DEBUG_BUFF (1 << 6) ++#define SCOLS_DEBUG_ALL 0xFFFF ++ ++UL_DEBUG_DECLARE_MASK(libsmartcols); ++#define DBG(m, x) __UL_DBG(libsmartcols, SCOLS_DEBUG_, m, x) ++#define ON_DBG(m, x) __UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x) ++#define DBG_FLUSH __UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_) ++ ++/* ++ * Generic iterator ++ */ ++struct libscols_iter { ++ struct list_head *p; /* current position */ ++ struct list_head *head; /* start position */ ++ int direction; /* SCOLS_ITER_{FOR,BACK}WARD */ ++}; ++ ++/* ++ * Tree symbols ++ */ ++struct libscols_symbols { ++ int refcount; ++ char *branch; ++ char *vert; ++ char *right; ++}; ++ ++/* ++ * Table cells ++ */ ++struct libscols_cell { ++ char *data; ++ char *color; ++ void *userdata; ++}; ++ ++ ++/* ++ * Table column ++ */ ++struct libscols_column { ++ int refcount; /* reference counter */ ++ size_t seqnum; /* column index */ ++ ++ size_t width; /* real column width */ ++ size_t width_min; /* minimal width (usually header width) */ ++ size_t width_max; /* maximal width */ ++ size_t width_avg; /* average width, used to detect extreme fields */ ++ double width_hint; /* hint (N < 1 is in percent of termwidth) */ ++ ++ int flags; ++ int is_extreme; ++ char *color; /* default column color */ ++ ++ int (*cmpfunc)(struct libscols_cell *, ++ struct libscols_cell *, ++ void *); /* cells comparison function */ ++ void *cmpfunc_data; ++ ++ struct libscols_cell header; ++ struct list_head cl_columns; ++}; ++ ++/* ++ * Table line ++ */ ++struct libscols_line { ++ int refcount; ++ size_t seqnum; ++ ++ void *userdata; ++ char *color; /* default line color */ ++ ++ struct libscols_cell *cells; /* array with data */ ++ size_t ncells; /* number of cells */ ++ ++ struct list_head ln_lines; /* table lines */ ++ struct list_head ln_branch; /* begin of branch (head of ln_children) */ ++ struct list_head ln_children; ++ ++ struct libscols_line *parent; ++}; ++ ++enum { ++ SCOLS_FMT_HUMAN = 0, /* default, human readable */ ++ SCOLS_FMT_RAW, /* space separated */ ++ SCOLS_FMT_EXPORT /* COLNAME="data" ... */ ++}; ++ ++/* ++ * The table ++ */ ++struct libscols_table { ++ int refcount; ++ size_t ncols; /* number of columns */ ++ size_t ntreecols; /* number of columns with SCOLS_FL_TREE */ ++ size_t nlines; /* number of lines */ ++ size_t termwidth; /* terminal width */ ++ size_t termreduce; /* extra blank space */ ++ FILE *out; /* output stream */ ++ ++ char *colsep; /* column separator */ ++ char *linesep; /* line separator */ ++ ++ struct list_head tb_columns; ++ struct list_head tb_lines; ++ struct libscols_symbols *symbols; ++ ++ int format; /* SCOLS_FMT_* */ ++ ++ /* flags */ ++ unsigned int ascii :1, /* don't use unicode */ ++ colors_wanted :1, /* enable colors */ ++ is_term :1, /* isatty() */ ++ maxout :1, /* maximalize output */ ++ no_headings :1; /* don't print header */ ++}; ++ ++#define IS_ITER_FORWARD(_i) ((_i)->direction == SCOLS_ITER_FORWARD) ++#define IS_ITER_BACKWARD(_i) ((_i)->direction == SCOLS_ITER_BACKWARD) ++ ++#define SCOLS_ITER_INIT(itr, list) \ ++ do { \ ++ (itr)->p = IS_ITER_FORWARD(itr) ? \ ++ (list)->next : (list)->prev; \ ++ (itr)->head = (list); \ ++ } while(0) ++ ++#define SCOLS_ITER_ITERATE(itr, res, restype, member) \ ++ do { \ ++ res = list_entry((itr)->p, restype, member); \ ++ (itr)->p = IS_ITER_FORWARD(itr) ? \ ++ (itr)->p->next : (itr)->p->prev; \ ++ } while(0) ++ ++#endif /* _LIBSMARTCOLS_PRIVATE_H */ +diff -up util-linux-2.23.2/libsmartcols/src/symbols.c.kzak util-linux-2.23.2/libsmartcols/src/symbols.c +--- util-linux-2.23.2/libsmartcols/src/symbols.c.kzak 2014-09-25 14:41:48.989843915 +0200 ++++ util-linux-2.23.2/libsmartcols/src/symbols.c 2014-09-25 14:41:48.989843915 +0200 +@@ -0,0 +1,175 @@ ++/* ++ * symbols.c - routines for symbol handling ++ * ++ * Copyright (C) 2014 Ondrej Oprala ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: symbols ++ * @title: Symbols ++ * @short_description: symbols API ++ * ++ * An API to access and modify data and information per symbol/symbol group. ++ */ ++ ++ ++#include ++#include ++#include ++ ++#include "smartcolsP.h" ++ ++/** ++ * scols_new_symbols: ++ * ++ * Returns: a pointer to a newly allocated struct libscols_symbols instance. ++ */ ++struct libscols_symbols *scols_new_symbols(void) ++{ ++ struct libscols_symbols *sy = calloc(1, sizeof(struct libscols_symbols)); ++ ++ if (!sy) ++ return NULL; ++ sy->refcount = 1; ++ return sy; ++} ++ ++/** ++ * scols_ref_symbols: ++ * @sy: a pointer to a struct libscols_symbols instance ++ * ++ * Increases the refcount of @sy. ++ */ ++void scols_ref_symbols(struct libscols_symbols *sy) ++{ ++ if (sy) ++ sy->refcount++; ++} ++ ++/** ++ * scols_unref_symbols: ++ * @sy: a pointer to a struct libscols_symbols instance ++ * ++ * Decreases the refcount of @sy. ++ */ ++void scols_unref_symbols(struct libscols_symbols *sy) ++{ ++ if (sy && --sy->refcount <= 0) { ++ free(sy->branch); ++ free(sy->vert); ++ free(sy->right); ++ free(sy); ++ } ++} ++ ++/** ++ * scols_symbols_set_branch: ++ * @sb: a pointer to a struct libscols_symbols instance ++ * @str: a string which will represent the branch part of a tree output ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_symbols_set_branch(struct libscols_symbols *sb, const char *str) ++{ ++ char *p = NULL; ++ ++ assert(sb); ++ ++ if (!sb) ++ return -EINVAL; ++ if (str) { ++ p = strdup(str); ++ if (!p) ++ return -ENOMEM; ++ } ++ free(sb->branch); ++ sb->branch = p; ++ return 0; ++} ++ ++/** ++ * scols_symbols_set_vertical: ++ * @sb: a pointer to a struct libscols_symbols instance ++ * @str: a string which will represent the vertical part of a tree output ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_symbols_set_vertical(struct libscols_symbols *sb, const char *str) ++{ ++ char *p = NULL; ++ ++ assert(sb); ++ ++ if (!sb) ++ return -EINVAL; ++ if (str) { ++ p = strdup(str); ++ if (!p) ++ return -ENOMEM; ++ } ++ free(sb->vert); ++ sb->vert = p; ++ return 0; ++} ++ ++/** ++ * scols_symbols_set_right: ++ * @sb: a pointer to a struct libscols_symbols instance ++ * @str: a string which will represent the right part of a tree output ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_symbols_set_right(struct libscols_symbols *sb, const char *str) ++{ ++ char *p = NULL; ++ ++ assert(sb); ++ ++ if (!sb) ++ return -EINVAL; ++ if (str) { ++ p = strdup(str); ++ if (!p) ++ return -ENOMEM; ++ } ++ free(sb->right); ++ sb->right = p; ++ return 0; ++} ++ ++/** ++ * scols_copy_symbols: ++ * @sb: a pointer to a struct libscols_symbols instance ++ * ++ * Returns: a newly allocated copy of the @sb symbol group or NULL in caes of an error. ++ */ ++struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb) ++{ ++ struct libscols_symbols *ret; ++ int rc; ++ ++ assert(sb); ++ if (!sb) ++ return NULL; ++ ++ ret = scols_new_symbols(); ++ if (!ret) ++ return NULL; ++ ++ rc = scols_symbols_set_branch(ret, sb->branch); ++ if (!rc) ++ rc = scols_symbols_set_vertical(ret, sb->vert); ++ if (!rc) ++ rc = scols_symbols_set_right(ret, sb->right); ++ if (!rc) ++ return ret; ++ ++ scols_unref_symbols(ret); ++ return NULL; ++ ++} ++ ++ +diff -up util-linux-2.23.2/libsmartcols/src/table.c.kzak util-linux-2.23.2/libsmartcols/src/table.c +--- util-linux-2.23.2/libsmartcols/src/table.c.kzak 2014-09-25 14:41:48.991843934 +0200 ++++ util-linux-2.23.2/libsmartcols/src/table.c 2014-09-25 14:41:48.991843934 +0200 +@@ -0,0 +1,1049 @@ ++/* ++ * table.c - functions handling the data at the table level ++ * ++ * Copyright (C) 2010-2014 Karel Zak ++ * Copyright (C) 2014 Ondrej Oprala ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: table ++ * @title: Table ++ * @short_description: table data API ++ * ++ * Table data manipulation API. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "nls.h" ++#include "widechar.h" ++#include "smartcolsP.h" ++ ++#ifdef HAVE_WIDECHAR ++#define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */ ++#define UTF_VR "\342\224\234" /* U+251C, Vertical and right */ ++#define UTF_H "\342\224\200" /* U+2500, Horizontal */ ++#define UTF_UR "\342\224\224" /* U+2514, Up and right */ ++#endif /* !HAVE_WIDECHAR */ ++ ++#define is_last_column(_tb, _cl) \ ++ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns) ++ ++ ++/** ++ * scols_new_table: ++ * ++ * Returns: A newly allocated table. ++ */ ++struct libscols_table *scols_new_table(void) ++{ ++ struct libscols_table *tb; ++ ++ tb = calloc(1, sizeof(struct libscols_table)); ++ if (!tb) ++ return NULL; ++ ++ tb->refcount = 1; ++ tb->out = stdout; ++ ++ INIT_LIST_HEAD(&tb->tb_lines); ++ INIT_LIST_HEAD(&tb->tb_columns); ++ ++ DBG(TAB, ul_debugobj(tb, "alloc")); ++ return tb; ++} ++ ++/** ++ * scols_ref_table: ++ * @tb: a pointer to a struct libscols_table instance ++ * ++ * Increases the refcount of @tb. ++ */ ++void scols_ref_table(struct libscols_table *tb) ++{ ++ if (tb) ++ tb->refcount++; ++} ++ ++/** ++ * scols_unref_table: ++ * @tb: a pointer to a struct libscols_table instance ++ * ++ * Decreases the refcount of @tb. When the count falls to zero, the instance ++ * is automatically deallocated. ++ */ ++void scols_unref_table(struct libscols_table *tb) ++{ ++ if (tb && (--tb->refcount <= 0)) { ++ DBG(TAB, ul_debugobj(tb, "dealloc")); ++ scols_table_remove_lines(tb); ++ scols_table_remove_columns(tb); ++ scols_unref_symbols(tb->symbols); ++ free(tb->linesep); ++ free(tb->colsep); ++ free(tb); ++ } ++} ++ ++/** ++ * scols_table_add_column: ++ * @tb: a pointer to a struct libscols_table instance ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Adds @cl to @tb's column list. ++ * ++ * Returns: 0, a negative number in case of an error. ++ */ ++int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl) ++{ ++ assert(tb); ++ assert(cl); ++ ++ if (!tb || !cl || !list_empty(&tb->tb_lines)) ++ return -EINVAL; ++ ++ if (cl->flags & SCOLS_FL_TREE) ++ tb->ntreecols++; ++ ++ DBG(TAB, ul_debugobj(tb, "add column %p", cl)); ++ list_add_tail(&cl->cl_columns, &tb->tb_columns); ++ cl->seqnum = tb->ncols++; ++ scols_ref_column(cl); ++ ++ /* TODO: ++ * ++ * Currently it's possible to add/remove columns only if the table is ++ * empty (see list_empty(tb->tb_lines) above). It would be nice to ++ * enlarge/reduce lines cells[] always when we add/remove a new column. ++ */ ++ return 0; ++} ++ ++/** ++ * scols_table_remove_column: ++ * @tb: a pointer to a struct libscols_table instance ++ * @cl: a pointer to a struct libscols_column instance ++ * ++ * Removes @cl from @tb. ++ * ++ * Returns: 0, a negative number in case of an error. ++ */ ++int scols_table_remove_column(struct libscols_table *tb, ++ struct libscols_column *cl) ++{ ++ assert(tb); ++ assert(cl); ++ ++ if (!tb || !cl || !list_empty(&tb->tb_lines)) ++ return -EINVAL; ++ ++ if (cl->flags & SCOLS_FL_TREE) ++ tb->ntreecols--; ++ ++ DBG(TAB, ul_debugobj(tb, "remove column %p", cl)); ++ list_del_init(&cl->cl_columns); ++ tb->ncols--; ++ scols_unref_column(cl); ++ return 0; ++} ++ ++/** ++ * scols_table_remove_columns: ++ * @tb: a pointer to a struct libscols_table instance ++ * ++ * Removes all of @tb's columns. ++ * ++ * Returns: 0, a negative number in case of an error. ++ */ ++int scols_table_remove_columns(struct libscols_table *tb) ++{ ++ assert(tb); ++ ++ if (!tb || !list_empty(&tb->tb_lines)) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "remove all columns")); ++ while (!list_empty(&tb->tb_columns)) { ++ struct libscols_column *cl = list_entry(tb->tb_columns.next, ++ struct libscols_column, cl_columns); ++ scols_table_remove_column(tb, cl); ++ } ++ return 0; ++} ++ ++ ++/** ++ * scols_table_new_column: ++ * @tb: table ++ * @name: column header ++ * @whint: column width hint (absolute width: N > 1; relative width: N < 1) ++ * @flags: flags integer ++ * ++ * This is shortcut for ++ * ++ * cl = scols_new_column(); ++ * scols_column_set_....(cl, ...); ++ * scols_table_add_column(tb, cl); ++ * ++ * The column width is possible to define by three ways: ++ * ++ * @whint = 0..1 : relative width, percent of terminal width ++ * ++ * @whint = 1..N : absolute width, empty colum will be truncated to ++ * the column header width ++ * ++ * @whint = 1..N ++ * ++ * The column is necessary to address by ++ * sequential number. The first defined column has the colnum = 0. For example: ++ * ++ * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0 ++ * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1 ++ * . ++ * . ++ * scols_line_get_cell(line, 0); // FOO column ++ * scols_line_get_cell(line, 1); // BAR column ++ * ++ * Returns: newly allocated column ++ */ ++struct libscols_column *scols_table_new_column(struct libscols_table *tb, ++ const char *name, ++ double whint, ++ int flags) ++{ ++ struct libscols_column *cl; ++ struct libscols_cell *hr; ++ ++ assert (tb); ++ if (!tb) ++ return NULL; ++ ++ DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d", ++ name, whint, flags)); ++ cl = scols_new_column(); ++ if (!cl) ++ return NULL; ++ ++ /* set column name */ ++ hr = scols_column_get_header(cl); ++ if (!hr) ++ goto err; ++ if (scols_cell_set_data(hr, name)) ++ goto err; ++ ++ scols_column_set_whint(cl, whint); ++ scols_column_set_flags(cl, flags); ++ ++ if (scols_table_add_column(tb, cl)) /* this increments column ref-counter */ ++ goto err; ++ ++ scols_unref_column(cl); ++ return cl; ++err: ++ scols_unref_column(cl); ++ return NULL; ++} ++ ++/** ++ * scols_table_next_column: ++ * @tb: a pointer to a struct libscols_table instance ++ * @itr: a pointer to a struct libscols_iter instance ++ * @cl: a pointer to a pointer to a struct libscols_column instance ++ * ++ * Returns the next column of @tb via @cl. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_next_column(struct libscols_table *tb, ++ struct libscols_iter *itr, ++ struct libscols_column **cl) ++{ ++ int rc = 1; ++ ++ if (!tb || !itr || !cl) ++ return -EINVAL; ++ *cl = NULL; ++ ++ if (!itr->head) ++ SCOLS_ITER_INIT(itr, &tb->tb_columns); ++ if (itr->p != itr->head) { ++ SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns); ++ rc = 0; ++ } ++ ++ return rc; ++} ++ ++ ++/** ++ * scols_table_get_ncols: ++ * @tb: table ++ * ++ * Returns: the ncols table member, a negative number in case of an error. ++ */ ++int scols_table_get_ncols(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb ? tb->ncols : -EINVAL; ++} ++ ++/** ++ * scols_table_get_nlines: ++ * @tb: table ++ * ++ * Returns: the nlines table member, a negative number in case of an error. ++ */ ++int scols_table_get_nlines(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb ? tb->nlines : -EINVAL; ++} ++ ++/** ++ * scols_table_set_stream: ++ * @tb: table ++ * @stream: output stream ++ * ++ * Sets the output stream for table @tb. ++ * ++ * Returns: 0, a negative number in case of an error. ++ */ ++int scols_table_set_stream(struct libscols_table *tb, FILE *stream) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "setting alternative stream")); ++ tb->out = stream; ++ return 0; ++} ++ ++/** ++ * scols_table_get_stream: ++ * @tb: table ++ * ++ * Gets the output stream for table @tb. ++ * ++ * Returns: stream pointer, NULL in case of an error or an unset stream. ++ */ ++FILE *scols_table_get_stream(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb ? tb->out: NULL; ++} ++ ++/** ++ * scols_table_reduce_termwidth: ++ * @tb: table ++ * @reduce: width ++ * ++ * Reduce the output width to @reduce. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce)); ++ tb->termreduce = reduce; ++ return 0; ++} ++ ++/** ++ * scols_table_get_column: ++ * @tb: table ++ * @n: number of column (0..N) ++ * ++ * Returns: pointer to column or NULL ++ */ ++struct libscols_column *scols_table_get_column(struct libscols_table *tb, ++ size_t n) ++{ ++ struct libscols_iter itr; ++ struct libscols_column *cl; ++ ++ assert(tb); ++ if (!tb) ++ return NULL; ++ if (n >= tb->ncols) ++ return NULL; ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ if (cl->seqnum == n) ++ return cl; ++ } ++ return NULL; ++} ++ ++/** ++ * scols_table_add_line: ++ * @tb: table ++ * @ln: line ++ * ++ * Note that this function calls scols_line_alloc_cells() if number ++ * of the cells in the line is too small for @tb. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln) ++{ ++ ++ assert(tb); ++ assert(ln); ++ ++ if (!tb || !ln) ++ return -EINVAL; ++ ++ if (tb->ncols > ln->ncells) { ++ int rc = scols_line_alloc_cells(ln, tb->ncols); ++ if (rc) ++ return rc; ++ } ++ ++ DBG(TAB, ul_debugobj(tb, "add line %p", ln)); ++ list_add_tail(&ln->ln_lines, &tb->tb_lines); ++ ln->seqnum = tb->nlines++; ++ scols_ref_line(ln); ++ return 0; ++} ++ ++/** ++ * scols_table_remove_line: ++ * @tb: table ++ * @ln: line ++ * ++ * Note that this function does not destroy the parent<->child relationship between lines. ++ * You have to call scols_line_remove_child() ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_remove_line(struct libscols_table *tb, ++ struct libscols_line *ln) ++{ ++ assert(tb); ++ assert(ln); ++ ++ if (!tb || !ln) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "remove line %p", ln)); ++ list_del_init(&ln->ln_lines); ++ tb->nlines--; ++ scols_unref_line(ln); ++ return 0; ++} ++ ++/** ++ * scols_table_remove_lines: ++ * @tb: table ++ * ++ * This empties the table and also destroys all the parent<->child relationships. ++ */ ++void scols_table_remove_lines(struct libscols_table *tb) ++{ ++ assert(tb); ++ if (!tb) ++ return; ++ ++ DBG(TAB, ul_debugobj(tb, "remove all lines")); ++ while (!list_empty(&tb->tb_lines)) { ++ struct libscols_line *ln = list_entry(tb->tb_lines.next, ++ struct libscols_line, ln_lines); ++ if (ln->parent) ++ scols_line_remove_child(ln->parent, ln); ++ scols_table_remove_line(tb, ln); ++ } ++} ++ ++/** ++ * scols_table_next_line: ++ * @tb: a pointer to a struct libscols_table instance ++ * @itr: a pointer to a struct libscols_iter instance ++ * @ln: a pointer to a pointer to a struct libscols_line instance ++ * ++ * Finds the next line and returns a pointer to it via @ln. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_next_line(struct libscols_table *tb, ++ struct libscols_iter *itr, ++ struct libscols_line **ln) ++{ ++ int rc = 1; ++ ++ if (!tb || !itr || !ln) ++ return -EINVAL; ++ *ln = NULL; ++ ++ if (!itr->head) ++ SCOLS_ITER_INIT(itr, &tb->tb_lines); ++ if (itr->p != itr->head) { ++ SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines); ++ rc = 0; ++ } ++ ++ return rc; ++} ++ ++/** ++ * scols_table_new_line: ++ * @tb: table ++ * @parent: parental line or NULL ++ * ++ * This is shortcut for ++ * ++ * ln = scols_new_line(); ++ * scols_table_add_line(tb, ln); ++ * scols_line_add_child(parent, ln); ++ * ++ * ++ * Returns: newly allocate line ++ */ ++struct libscols_line *scols_table_new_line(struct libscols_table *tb, ++ struct libscols_line *parent) ++{ ++ struct libscols_line *ln; ++ ++ assert(tb); ++ assert(tb->ncols); ++ ++ if (!tb || !tb->ncols) ++ return NULL; ++ ++ ln = scols_new_line(); ++ if (!ln) ++ return NULL; ++ ++ if (scols_table_add_line(tb, ln)) ++ goto err; ++ if (parent) ++ scols_line_add_child(parent, ln); ++ ++ scols_unref_line(ln); /* ref-counter incremented by scols_table_add_line() */ ++ return ln; ++err: ++ scols_unref_line(ln); ++ return NULL; ++} ++ ++/** ++ * scols_table_get_line: ++ * @tb: table ++ * @n: column number (0..N) ++ * ++ * This is a shortcut for ++ * ++ * ln = scols_new_line(); ++ * scols_line_set_....(cl, ...); ++ * scols_table_add_line(tb, ln); ++ * ++ * Returns: a newly allocate line ++ */ ++struct libscols_line *scols_table_get_line(struct libscols_table *tb, ++ size_t n) ++{ ++ struct libscols_iter itr; ++ struct libscols_line *ln; ++ ++ assert(tb); ++ if (!tb) ++ return NULL; ++ if (n >= tb->nlines) ++ return NULL; ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_line(tb, &itr, &ln) == 0) { ++ if (ln->seqnum == n) ++ return ln; ++ } ++ return NULL; ++} ++ ++/** ++ * scols_copy_table: ++ * @tb: table ++ * ++ * Creates a new independent table copy, except struct libscols_symbols that ++ * are shared between the tables. ++ * ++ * Returns: a newly allocated copy of @tb ++ */ ++struct libscols_table *scols_copy_table(struct libscols_table *tb) ++{ ++ struct libscols_table *ret; ++ struct libscols_line *ln; ++ struct libscols_column *cl; ++ struct libscols_iter itr; ++ ++ assert(tb); ++ if (!tb) ++ return NULL; ++ ret = scols_new_table(); ++ if (!ret) ++ return NULL; ++ ++ DBG(TAB, ul_debugobj(tb, "copy into %p", ret)); ++ ++ if (tb->symbols) ++ scols_table_set_symbols(ret, tb->symbols); ++ ++ /* columns */ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ cl = scols_copy_column(cl); ++ if (!cl) ++ goto err; ++ if (scols_table_add_column(ret, cl)) ++ goto err; ++ scols_unref_column(cl); ++ } ++ ++ /* lines */ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_line(tb, &itr, &ln) == 0) { ++ struct libscols_line *newln = scols_copy_line(ln); ++ if (!newln) ++ goto err; ++ if (scols_table_add_line(ret, newln)) ++ goto err; ++ if (ln->parent) { ++ struct libscols_line *p = ++ scols_table_get_line(ret, ln->parent->seqnum); ++ if (p) ++ scols_line_add_child(p, newln); ++ } ++ scols_unref_line(newln); ++ } ++ ++ /* separators */ ++ if (scols_table_set_column_separator(ret, tb->colsep) || ++ scols_table_set_line_separator(ret, tb->linesep)) ++ goto err; ++ ++ return ret; ++err: ++ scols_unref_table(ret); ++ return NULL; ++} ++ ++/** ++ * scols_table_set_symbols: ++ * @tb: table ++ * @sy: symbols or NULL ++ * ++ * Add a reference to @sy from the table. The symbols are used by library to ++ * draw tree output. If no symbols are specified then library checks the ++ * current environment to select ASCII or UTF8 symbols. This default behavior ++ * could be controlled by scols_table_enable_ascii(). ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_set_symbols(struct libscols_table *tb, ++ struct libscols_symbols *sy) ++{ ++ assert(tb); ++ ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "setting alternative symbols %p", sy)); ++ ++ if (tb->symbols) /* unref old */ ++ scols_unref_symbols(tb->symbols); ++ if (sy) { /* ref user defined */ ++ tb->symbols = sy; ++ scols_ref_symbols(sy); ++ } else { /* default symbols */ ++ tb->symbols = scols_new_symbols(); ++ if (!tb->symbols) ++ return -ENOMEM; ++#if defined(HAVE_WIDECHAR) ++ if (!scols_table_is_ascii(tb) && ++ !strcmp(nl_langinfo(CODESET), "UTF-8")) { ++ scols_symbols_set_branch(tb->symbols, UTF_VR UTF_H); ++ scols_symbols_set_vertical(tb->symbols, UTF_V " "); ++ scols_symbols_set_right(tb->symbols, UTF_UR UTF_H); ++ } else ++#endif ++ { ++ scols_symbols_set_branch(tb->symbols, "|-"); ++ scols_symbols_set_vertical(tb->symbols, "| "); ++ scols_symbols_set_right(tb->symbols, "`-"); ++ } ++ } ++ ++ return 0; ++} ++/** ++ * scols_table_enable_colors: ++ * @tb: table ++ * @enable: 1 or 0 ++ * ++ * Enable/disable colors. ++ * ++ * Returns: 0 on success, negative number in case of an error. ++ */ ++int scols_table_enable_colors(struct libscols_table *tb, int enable) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE")); ++ tb->colors_wanted = enable; ++ return 0; ++} ++/** ++ * scols_table_enable_raw: ++ * @tb: table ++ * @enable: 1 or 0 ++ * ++ * Enable/disable raw output format. The parsable output formats ++ * (export and raw) are mutually exclusive. ++ * ++ * Returns: 0 on success, negative number in case of an error. ++ */ ++int scols_table_enable_raw(struct libscols_table *tb, int enable) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE")); ++ if (enable) ++ tb->format = SCOLS_FMT_RAW; ++ else if (tb->format == SCOLS_FMT_RAW) ++ tb->format = 0; ++ return 0; ++} ++ ++/** ++ * scols_table_enable_export: ++ * @tb: table ++ * @enable: 1 or 0 ++ * ++ * Enable/disable export output format (COLUMNAME="value" ...). ++ * The parsable output formats (export and raw) are mutually exclusive. ++ * ++ * Returns: 0 on success, negative number in case of an error. ++ */ ++int scols_table_enable_export(struct libscols_table *tb, int enable) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE")); ++ if (enable) ++ tb->format = SCOLS_FMT_EXPORT; ++ else if (tb->format == SCOLS_FMT_EXPORT) ++ tb->format = 0; ++ return 0; ++} ++ ++/** ++ * scols_table_enable_ascii: ++ * @tb: table ++ * @enable: 1 or 0 ++ * ++ * The ASCII-only output is relevant for tree-like outputs. The library ++ * checks if the current environment is UTF8 compatible by default. This ++ * function overrides this check and force the library to use ASCII chars ++ * for the tree. ++ * ++ * If a custom libcols_symbols are specified (see scols_table_set_symbols() ++ * then ASCII flag setting is ignored. ++ * ++ * Returns: 0 on success, negative number in case of an error. ++ */ ++int scols_table_enable_ascii(struct libscols_table *tb, int enable) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE")); ++ tb->ascii = enable ? 1 : 0; ++ return 0; ++} ++ ++/** ++ * scols_table_enable_noheadings: ++ * @tb: table ++ * @enable: 1 or 0 ++ * ++ * Enable/disable header line. ++ * ++ * Returns: 0 on success, negative number in case of an error. ++ */ ++int scols_table_enable_noheadings(struct libscols_table *tb, int enable) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE")); ++ tb->no_headings = enable ? 1 : 0; ++ return 0; ++} ++ ++/** ++ * scols_table_enable_maxout: ++ * @tb: table ++ * @enable: 1 or 0 ++ * ++ * The extra space after last column is ignored by default. The output ++ * maximization use the extra space for all columns. ++ * ++ * Returns: 0 on success, negative number in case of an error. ++ */ ++int scols_table_enable_maxout(struct libscols_table *tb, int enable) ++{ ++ assert(tb); ++ if (!tb) ++ return -EINVAL; ++ DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE")); ++ tb->maxout = enable ? 1 : 0; ++ return 0; ++} ++ ++/** ++ * scols_table_colors_wanted: ++ * @tb: table ++ * ++ * Returns: 1 if colors are enabled. ++ */ ++int scols_table_colors_wanted(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->colors_wanted; ++} ++ ++/** ++ * scols_table_is_empty: ++ * @tb: table ++ * ++ * Returns: 1 if the table is empty. ++ */ ++int scols_table_is_empty(struct libscols_table *tb) ++{ ++ assert(tb); ++ return !tb || !tb->nlines; ++} ++ ++/** ++ * scols_table_is_ascii: ++ * @tb: table ++ * ++ * Returns: 1 if ASCII tree is enabled. ++ */ ++int scols_table_is_ascii(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->ascii; ++} ++ ++/** ++ * scols_table_is_noheadings: ++ * @tb: table ++ * ++ * Returns: 1 if header output is disabled. ++ */ ++int scols_table_is_noheadings(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->no_headings; ++} ++ ++/** ++ * scols_table_is_export: ++ * @tb: table ++ * ++ * Returns: 1 if export output format is enabled. ++ */ ++int scols_table_is_export(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->format == SCOLS_FMT_EXPORT; ++} ++ ++/** ++ * scols_table_is_raw: ++ * @tb: table ++ * ++ * Returns: 1 if raw output format is enabled. ++ */ ++int scols_table_is_raw(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->format == SCOLS_FMT_RAW; ++} ++ ++ ++/** ++ * scols_table_is_maxout ++ * @tb: table ++ * ++ * Returns: 1 if output maximization is enabled, negative value in case of an error. ++ */ ++int scols_table_is_maxout(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->maxout; ++} ++ ++/** ++ * scols_table_is_tree: ++ * @tb: table ++ * ++ * Returns: returns 1 tree-like output is expected. ++ */ ++int scols_table_is_tree(struct libscols_table *tb) ++{ ++ assert(tb); ++ return tb && tb->ntreecols > 0; ++} ++ ++/** ++ * scols_table_set_column_separator: ++ * @tb: table ++ * @sep: separator ++ * ++ * Sets the column separator of @tb to @sep. ++ * Please note that @sep should always take up a single cell in the output. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_set_column_separator(struct libscols_table *tb, const char *sep) ++{ ++ char *p = NULL; ++ ++ assert (tb); ++ ++ if (!tb) ++ return -EINVAL; ++ ++ if (sep) { ++ p = strdup(sep); ++ if (!p) ++ return -ENOMEM; ++ } ++ ++ DBG(TAB, ul_debugobj(tb, "new columns separator: %s", sep)); ++ free(tb->colsep); ++ tb->colsep = p; ++ return 0; ++} ++ ++/** ++ * scols_table_set_line_separator: ++ * @tb: table ++ * @sep: separator ++ * ++ * Sets the line separator of @tb to @sep. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_table_set_line_separator(struct libscols_table *tb, const char *sep) ++{ ++ char *p = NULL; ++ ++ assert (tb); ++ ++ if (!tb) ++ return -EINVAL; ++ ++ if (sep) { ++ p = strdup(sep); ++ if (!p) ++ return -ENOMEM; ++ } ++ ++ DBG(TAB, ul_debugobj(tb, "new lines separator: %s", sep)); ++ free(tb->linesep); ++ tb->linesep = p; ++ return 0; ++} ++ ++/** ++ * scols_table_get_column_separator: ++ * @tb: table ++ * ++ * Returns: @tb column separator, NULL in case of an error ++ */ ++char *scols_table_get_column_separator(struct libscols_table *tb) ++{ ++ assert (tb); ++ ++ if (!tb) ++ return NULL; ++ return tb->colsep; ++} ++ ++/** ++ * scols_table_get_line_separator: ++ * @tb: table ++ * ++ * Returns: @tb line separator, NULL in case of an error ++ */ ++char *scols_table_get_line_separator(struct libscols_table *tb) ++{ ++ assert (tb); ++ ++ if (!tb) ++ return NULL; ++ return tb->linesep; ++ ++} ++ ++static int cells_cmp_wrapper(struct list_head *a, struct list_head *b, void *data) ++{ ++ struct libscols_column *cl = (struct libscols_column *) data; ++ struct libscols_line *ra, *rb; ++ struct libscols_cell *ca, *cb; ++ ++ assert(a); ++ assert(b); ++ assert(cl); ++ ++ ra = list_entry(a, struct libscols_line, ln_lines); ++ rb = list_entry(b, struct libscols_line, ln_lines); ++ ca = scols_line_get_cell(ra, cl->seqnum); ++ cb = scols_line_get_cell(rb, cl->seqnum); ++ ++ return cl->cmpfunc(ca, cb, cl->cmpfunc_data); ++} ++ ++/** ++ * scols_sort_table: ++ * @tb: table ++ * @cl: order by this column ++ * ++ * Orders the table by the column. See also scols_column_set_cmpfunc(). ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl) ++{ ++ assert(tb); ++ assert(cl); ++ ++ if (!tb || !cl) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "sorting table")); ++ list_sort(&tb->tb_lines, cells_cmp_wrapper, cl); ++ return 0; ++} +diff -up util-linux-2.23.2/libsmartcols/src/table_print.c.kzak util-linux-2.23.2/libsmartcols/src/table_print.c +--- util-linux-2.23.2/libsmartcols/src/table_print.c.kzak 2014-09-25 14:41:48.992843944 +0200 ++++ util-linux-2.23.2/libsmartcols/src/table_print.c 2014-09-25 14:41:48.992843944 +0200 +@@ -0,0 +1,841 @@ ++/* ++ * table.c - functions handling the data at the table level ++ * ++ * Copyright (C) 2010-2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++ ++/** ++ * SECTION: table_print ++ * @title: Table print ++ * @short_description: table print API ++ * ++ * Table output API. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "nls.h" ++#include "mbsalign.h" ++#include "widechar.h" ++#include "ttyutils.h" ++#include "carefulputc.h" ++#include "smartcolsP.h" ++ ++/* This is private struct to work with output data */ ++struct libscols_buffer { ++ char *begin; /* begin of the buffer */ ++ char *cur; /* current end of the buffer */ ++ char *encdata; /* encoded buffer mbs_safe_encode() */ ++ ++ size_t bufsz; /* size of the buffer */ ++ size_t art_idx; /* begin of the tree ascii art or zero */ ++}; ++ ++static struct libscols_buffer *new_buffer(size_t sz) ++{ ++ struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer)); ++ ++ if (!buf) ++ return NULL; ++ ++ buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer); ++ buf->encdata = NULL; ++ buf->bufsz = sz; ++ ++ DBG(BUFF, ul_debugobj(buf, "alloc (size=%zu)", sz)); ++ return buf; ++} ++ ++static void free_buffer(struct libscols_buffer *buf) ++{ ++ if (!buf) ++ return; ++ DBG(BUFF, ul_debugobj(buf, "dealloc")); ++ free(buf->encdata); ++ free(buf); ++} ++ ++static int buffer_reset_data(struct libscols_buffer *buf) ++{ ++ if (!buf) ++ return -EINVAL; ++ ++ /*DBG(BUFF, ul_debugobj(buf, "reset data"));*/ ++ buf->begin[0] = '\0'; ++ buf->cur = buf->begin; ++ buf->art_idx = 0; ++ return 0; ++} ++ ++static int buffer_append_data(struct libscols_buffer *buf, const char *str) ++{ ++ size_t maxsz, sz; ++ ++ if (!buf) ++ return -EINVAL; ++ if (!str || !*str) ++ return 0; ++ ++ sz = strlen(str); ++ maxsz = buf->bufsz - (buf->cur - buf->begin); ++ ++ if (maxsz <= sz) ++ return -EINVAL; ++ ++ memcpy(buf->cur, str, sz + 1); ++ buf->cur += sz; ++ return 0; ++} ++ ++static int buffer_set_data(struct libscols_buffer *buf, const char *str) ++{ ++ int rc = buffer_reset_data(buf); ++ return rc ? rc : buffer_append_data(buf, str); ++} ++ ++/* save the current buffer possition to art_idx */ ++static void buffer_set_art_index(struct libscols_buffer *buf) ++{ ++ if (buf) { ++ buf->art_idx = buf->cur - buf->begin; ++ /*DBG(BUFF, ul_debugobj(buf, "art index: %zu", buf->art_idx));*/ ++ } ++} ++ ++static char *buffer_get_data(struct libscols_buffer *buf) ++{ ++ return buf ? buf->begin : NULL; ++} ++ ++/* encode data by mbs_safe_encode() to avoid control and non-printable chars */ ++static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells) ++{ ++ char *data = buffer_get_data(buf); ++ char *res = NULL; ++ ++ if (!data) ++ goto nothing; ++ ++ if (!buf->encdata) { ++ buf->encdata = malloc(mbs_safe_encode_size(buf->bufsz) + 1); ++ if (!buf->encdata) ++ goto nothing; ++ } ++ ++ res = mbs_safe_encode_to_buffer(data, cells, buf->encdata); ++ if (!res || !*cells || *cells == (size_t) -1) ++ goto nothing; ++ return res; ++nothing: ++ *cells = 0; ++ return NULL; ++} ++ ++/* returns size in bytes of the ascii art (according to art_idx) in safe encoding */ ++static size_t buffer_get_safe_art_size(struct libscols_buffer *buf) ++{ ++ char *data = buffer_get_data(buf); ++ size_t bytes = 0; ++ ++ if (!data || !buf->art_idx) ++ return 0; ++ ++ mbs_safe_nwidth(data, buf->art_idx, &bytes); ++ return bytes; ++} ++ ++#define is_last_column(_tb, _cl) \ ++ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns) ++ ++#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ") ++#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n") ++ ++static int print_data(struct libscols_table *tb, ++ struct libscols_column *cl, ++ struct libscols_line *ln, /* optional */ ++ struct libscols_cell *ce, /* optional */ ++ struct libscols_buffer *buf) ++{ ++ size_t len = 0, i, width, bytes; ++ const char *color = NULL; ++ char *data; ++ ++ assert(tb); ++ assert(cl); ++ ++ DBG(TAB, ul_debugobj(tb, ++ " -> data, column=%p, line=%p, cell=%p, buff=%p", ++ cl, ln, ce, buf)); ++ ++ data = buffer_get_data(buf); ++ if (!data) ++ data = ""; ++ ++ /* raw mode */ ++ if (scols_table_is_raw(tb)) { ++ fputs_nonblank(data, tb->out); ++ if (!is_last_column(tb, cl)) ++ fputs(colsep(tb), tb->out); ++ return 0; ++ } ++ ++ /* NAME=value mode */ ++ if (scols_table_is_export(tb)) { ++ fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header)); ++ fputs_quoted(data, tb->out); ++ if (!is_last_column(tb, cl)) ++ fputs(colsep(tb), tb->out); ++ return 0; ++ } ++ ++ if (tb->colors_wanted) { ++ if (ce && !color) ++ color = ce->color; ++ if (ln && !color) ++ color = ln->color; ++ if (!color) ++ color = cl->color; ++ } ++ ++ /* encode, note that 'len' and 'width' are number of cells, not bytes */ ++ data = buffer_get_safe_data(buf, &len); ++ if (!data) ++ data = ""; ++ width = cl->width; ++ bytes = strlen(data); ++ ++ if (is_last_column(tb, cl) && len < width && !scols_table_is_maxout(tb)) ++ width = len; ++ ++ /* truncate data */ ++ if (len > width && scols_column_is_trunc(cl)) { ++ len = width; ++ bytes = mbs_truncate(data, &len); /* updates 'len' */ ++ ++ if (!data || bytes == (size_t) -1) { ++ bytes = len = 0; ++ data = NULL; ++ } ++ } ++ ++ if (data) { ++ if (scols_column_is_right(cl)) { ++ size_t xw = cl->width; ++ if (color) ++ fputs(color, tb->out); ++ fprintf(tb->out, "%*s", (int) xw, data); ++ if (color) ++ fputs(UL_COLOR_RESET, tb->out); ++ if (len < xw) ++ len = xw; ++ } else if (color) { ++ char *p = data; ++ size_t art = buffer_get_safe_art_size(buf); ++ ++ /* we don't want to colorize tree ascii art */ ++ if (scols_column_is_tree(cl) && art && art < bytes) { ++ fwrite(p, 1, art, tb->out); ++ p += art; ++ } ++ ++ fputs(color, tb->out); ++ fputs(p, tb->out); ++ fputs(UL_COLOR_RESET, tb->out); ++ } else ++ fputs(data, tb->out); ++ } ++ for (i = len; i < width; i++) ++ fputs(" ", tb->out); /* padding */ ++ ++ if (!is_last_column(tb, cl)) { ++ if (len > width && !scols_column_is_trunc(cl)) { ++ fputs(linesep(tb), tb->out); ++ for (i = 0; i <= (size_t) cl->seqnum; i++) { ++ struct libscols_column *x = scols_table_get_column(tb, i); ++ fprintf(tb->out, "%*s ", -((int)x->width), " "); ++ } ++ } else ++ fputs(colsep(tb), tb->out); /* columns separator */ ++ } ++ ++ return 0; ++} ++ ++/* returns pointer to the end of used data */ ++static int line_ascii_art_to_buffer(struct libscols_table *tb, ++ struct libscols_line *ln, ++ struct libscols_buffer *buf) ++{ ++ const char *art; ++ int rc; ++ ++ assert(ln); ++ assert(buf); ++ ++ if (!ln->parent) ++ return 0; ++ ++ rc = line_ascii_art_to_buffer(tb, ln->parent, buf); ++ if (rc) ++ return rc; ++ ++ if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) ++ art = " "; ++ else ++ art = tb->symbols->vert; ++ ++ return buffer_append_data(buf, art); ++} ++ ++static int cell_to_buffer(struct libscols_table *tb, ++ struct libscols_line *ln, ++ struct libscols_column *cl, ++ struct libscols_buffer *buf) ++{ ++ const char *data; ++ struct libscols_cell *ce; ++ int rc = 0; ++ ++ assert(tb); ++ assert(ln); ++ assert(cl); ++ assert(buf); ++ assert(cl->seqnum <= tb->ncols); ++ ++ buffer_reset_data(buf); ++ ++ ce = scols_line_get_cell(ln, cl->seqnum); ++ data = ce ? scols_cell_get_data(ce) : NULL; ++ if (!data) ++ return 0; ++ ++ if (!scols_column_is_tree(cl)) ++ return buffer_set_data(buf, data); ++ ++ /* ++ * Tree stuff ++ */ ++ if (ln->parent) { ++ rc = line_ascii_art_to_buffer(tb, ln->parent, buf); ++ ++ if (!rc && list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) ++ rc = buffer_append_data(buf, tb->symbols->right); ++ else if (!rc) ++ rc = buffer_append_data(buf, tb->symbols->branch); ++ if (!rc) ++ buffer_set_art_index(buf); ++ } ++ ++ if (!rc) ++ rc = buffer_append_data(buf, data); ++ return rc; ++} ++ ++/* ++ * Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and ++ * control and non-printable chars maybe encoded in \x?? hex encoding. ++ */ ++static int print_line(struct libscols_table *tb, ++ struct libscols_line *ln, ++ struct libscols_buffer *buf) ++{ ++ int rc = 0; ++ struct libscols_column *cl; ++ struct libscols_iter itr; ++ ++ assert(ln); ++ ++ DBG(TAB, ul_debugobj(tb, "printing line, line=%p, buff=%p", ln, buf)); ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { ++ rc = cell_to_buffer(tb, ln, cl, buf); ++ if (!rc) ++ rc = print_data(tb, cl, ln, ++ scols_line_get_cell(ln, cl->seqnum), ++ buf); ++ } ++ ++ if (rc == 0) ++ fputs(linesep(tb), tb->out); ++ return 0; ++} ++ ++static int print_header(struct libscols_table *tb, struct libscols_buffer *buf) ++{ ++ int rc = 0; ++ struct libscols_column *cl; ++ struct libscols_iter itr; ++ ++ assert(tb); ++ ++ if (scols_table_is_noheadings(tb) || ++ scols_table_is_export(tb) || ++ list_empty(&tb->tb_lines)) ++ return 0; ++ ++ DBG(TAB, ul_debugobj(tb, "printing header")); ++ ++ /* set width according to the size of data ++ */ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) { ++ rc = buffer_set_data(buf, scols_cell_get_data(&cl->header)); ++ if (!rc) ++ rc = print_data(tb, cl, NULL, &cl->header, buf); ++ } ++ ++ if (rc == 0) ++ fputs(linesep(tb), tb->out); ++ return rc; ++} ++ ++static int print_table(struct libscols_table *tb, struct libscols_buffer *buf) ++{ ++ int rc; ++ struct libscols_line *ln; ++ struct libscols_iter itr; ++ ++ assert(tb); ++ ++ rc = print_header(tb, buf); ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) ++ rc = print_line(tb, ln, buf); ++ ++ return rc; ++} ++ ++static int print_tree_line(struct libscols_table *tb, ++ struct libscols_line *ln, ++ struct libscols_buffer *buf) ++{ ++ int rc; ++ struct list_head *p; ++ ++ rc = print_line(tb, ln, buf); ++ if (rc) ++ return rc; ++ if (list_empty(&ln->ln_branch)) ++ return 0; ++ ++ /* print all children */ ++ list_for_each(p, &ln->ln_branch) { ++ struct libscols_line *chld = ++ list_entry(p, struct libscols_line, ln_children); ++ rc = print_tree_line(tb, chld, buf); ++ if (rc) ++ break; ++ } ++ ++ return rc; ++} ++ ++static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf) ++{ ++ int rc; ++ struct libscols_line *ln; ++ struct libscols_iter itr; ++ ++ assert(tb); ++ ++ DBG(TAB, ul_debugobj(tb, "printing tree")); ++ ++ rc = print_header(tb, buf); ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) { ++ if (ln->parent) ++ continue; ++ rc = print_tree_line(tb, ln, buf); ++ } ++ ++ return rc; ++} ++ ++static void dbg_column(struct libscols_table *tb, struct libscols_column *cl) ++{ ++ DBG(COL, ul_debugobj(cl, "%15s seq=%zu, width=%zd, " ++ "hint=%d, avg=%zu, max=%zu, min=%zu, " ++ "extreme=%s", ++ ++ cl->header.data, cl->seqnum, cl->width, ++ cl->width_hint > 1 ? (int) cl->width_hint : ++ (int) (cl->width_hint * tb->termwidth), ++ cl->width_avg, ++ cl->width_max, ++ cl->width_min, ++ cl->is_extreme ? "yes" : "not")); ++} ++ ++static void dbg_columns(struct libscols_table *tb) ++{ ++ struct libscols_iter itr; ++ struct libscols_column *cl; ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) ++ dbg_column(tb, cl); ++} ++ ++/* ++ * This function counts column width. ++ * ++ * For the SCOLS_FL_NOEXTREMES columns is possible to call this function two ++ * times. The first pass counts width and average width. If the column ++ * contains too large fields (width greater than 2 * average) then the column ++ * is marked as "extreme". In the second pass all extreme fields are ignored ++ * and column width is counted from non-extreme fields only. ++ */ ++static int count_column_width(struct libscols_table *tb, ++ struct libscols_column *cl, ++ struct libscols_buffer *buf) ++{ ++ struct libscols_line *ln; ++ struct libscols_iter itr; ++ int count = 0, rc = 0; ++ size_t sum = 0; ++ ++ assert(tb); ++ assert(cl); ++ ++ cl->width = 0; ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_line(tb, &itr, &ln) == 0) { ++ size_t len; ++ char *data; ++ ++ rc = cell_to_buffer(tb, ln, cl, buf); ++ if (rc) ++ return rc; ++ ++ data = buffer_get_data(buf); ++ len = data ? mbs_safe_width(data) : 0; ++ ++ if (len == (size_t) -1) /* ignore broken multibyte strings */ ++ len = 0; ++ if (len > cl->width_max) ++ cl->width_max = len; ++ ++ if (cl->is_extreme && len > cl->width_avg * 2) ++ continue; ++ else if (scols_column_is_noextremes(cl)) { ++ sum += len; ++ count++; ++ } ++ if (len > cl->width) ++ cl->width = len; ++ } ++ ++ if (count && cl->width_avg == 0) { ++ cl->width_avg = sum / count; ++ ++ if (cl->width_max > cl->width_avg * 2) ++ cl->is_extreme = 1; ++ } ++ ++ /* check and set minimal column width */ ++ if (scols_cell_get_data(&cl->header)) ++ cl->width_min = mbs_safe_width(scols_cell_get_data(&cl->header)); ++ ++ /* enlarge to minimal width */ ++ if (cl->width < cl->width_min && !scols_column_is_strict_width(cl)) ++ cl->width = cl->width_min; ++ ++ /* use relative size for large columns */ ++ else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint ++ && cl->width_min < (size_t) cl->width_hint) ++ ++ cl->width = (size_t) cl->width_hint; ++ ++ ON_DBG(COL, dbg_column(tb, cl)); ++ return rc; ++} ++ ++ ++/* ++ * This is core of the scols_* voodo... ++ */ ++static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf) ++{ ++ struct libscols_column *cl; ++ struct libscols_iter itr; ++ size_t width = 0; /* output width */ ++ int trunc_only, rc = 0; ++ int extremes = 0; ++ ++ ++ DBG(TAB, ul_debugobj(tb, "recounting widths (termwidth=%zu)", tb->termwidth)); ++ ++ /* set basic columns width ++ */ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ rc = count_column_width(tb, cl, buf); ++ if (rc) ++ return rc; ++ ++ width += cl->width + (is_last_column(tb, cl) ? 0 : 1); ++ extremes += cl->is_extreme; ++ } ++ ++ if (!tb->is_term) ++ return 0; ++ ++ /* reduce columns with extreme fields ++ */ ++ if (width > tb->termwidth && extremes) { ++ DBG(TAB, ul_debugobj(tb, " reduce width (extreme columns)")); ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ size_t org_width; ++ ++ if (!cl->is_extreme) ++ continue; ++ ++ org_width = cl->width; ++ rc = count_column_width(tb, cl, buf); ++ if (rc) ++ return rc; ++ ++ if (org_width > cl->width) ++ width -= org_width - cl->width; ++ else ++ extremes--; /* hmm... nothing reduced */ ++ } ++ } ++ ++ if (width < tb->termwidth) { ++ if (extremes) { ++ DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)")); ++ ++ /* enlarge the first extreme column */ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ size_t add; ++ ++ if (!cl->is_extreme) ++ continue; ++ ++ /* this column is tooo large, ignore? ++ if (cl->width_max - cl->width > ++ (tb->termwidth - width)) ++ continue; ++ */ ++ ++ add = tb->termwidth - width; ++ if (add && cl->width + add > cl->width_max) ++ add = cl->width_max - cl->width; ++ ++ cl->width += add; ++ width += add; ++ ++ if (width == tb->termwidth) ++ break; ++ } ++ } ++ ++ if (width < tb->termwidth && scols_table_is_maxout(tb)) { ++ DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)")); ++ ++ /* try enlarge all columns */ ++ while (width < tb->termwidth) { ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ cl->width++; ++ width++; ++ if (width == tb->termwidth) ++ break; ++ } ++ } ++ } else if (width < tb->termwidth) { ++ /* enlarge the last column */ ++ struct libscols_column *cl = list_entry( ++ tb->tb_columns.prev, struct libscols_column, cl_columns); ++ ++ DBG(TAB, ul_debugobj(tb, " enlarge width (last column)")); ++ ++ if (!scols_column_is_right(cl) && tb->termwidth - width > 0) { ++ cl->width += tb->termwidth - width; ++ width = tb->termwidth; ++ } ++ } ++ } ++ ++ /* bad, we have to reduce output width, this is done in two steps: ++ * 1/ reduce columns with a relative width and with truncate flag ++ * 2) reduce columns with a relative width without truncate flag ++ */ ++ trunc_only = 1; ++ while (width > tb->termwidth) { ++ size_t org = width; ++ ++ DBG(TAB, ul_debugobj(tb, " reduce width (current=%zu, " ++ "wanted=%zu, mode=%s)", ++ width, tb->termwidth, ++ trunc_only ? "trunc-only" : "all-relative")); ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_column(tb, &itr, &cl) == 0) { ++ if (width <= tb->termwidth) ++ break; ++ if (cl->width_hint > 1 && !scols_column_is_trunc(cl)) ++ continue; /* never truncate columns with absolute sizes */ ++ if (scols_column_is_tree(cl)) ++ continue; /* never truncate the tree */ ++ if (trunc_only && !scols_column_is_trunc(cl)) ++ continue; ++ if (cl->width == cl->width_min) ++ continue; ++ ++ /* truncate column with relative sizes */ ++ if (cl->width_hint < 1 && cl->width > 0 && width > 0 && ++ cl->width > cl->width_hint * tb->termwidth) { ++ cl->width--; ++ width--; ++ } ++ /* truncate column with absolute size */ ++ if (cl->width_hint > 1 && cl->width > 0 && width > 0 && ++ !trunc_only) { ++ cl->width--; ++ width--; ++ } ++ ++ } ++ if (org == width) { ++ if (trunc_only) ++ trunc_only = 0; ++ else ++ break; ++ } ++ } ++ ++ DBG(TAB, ul_debugobj(tb, " result: %zu", width)); ++ ON_DBG(TAB, dbg_columns(tb)); ++ ++ return rc; ++} ++ ++static size_t strlen_line(struct libscols_line *ln) ++{ ++ size_t i, sz = 0; ++ ++ assert(ln); ++ ++ for (i = 0; i < ln->ncells; i++) { ++ struct libscols_cell *ce = scols_line_get_cell(ln, i); ++ const char *data = ce ? scols_cell_get_data(ce) : NULL; ++ ++ sz += data ? strlen(data) : 0; ++ } ++ ++ return sz; ++} ++ ++ ++ ++/** ++ * scols_print_table: ++ * @tb: table ++ * ++ * Prints the table to the output stream. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_print_table(struct libscols_table *tb) ++{ ++ int rc = 0; ++ size_t bufsz; ++ struct libscols_line *ln; ++ struct libscols_iter itr; ++ struct libscols_buffer *buf; ++ ++ assert(tb); ++ if (!tb) ++ return -1; ++ ++ DBG(TAB, ul_debugobj(tb, "printing")); ++ if (!tb->symbols) ++ scols_table_set_symbols(tb, NULL); /* use default */ ++ ++ tb->is_term = isatty(STDOUT_FILENO) ? 1 : 0; ++ tb->termwidth = tb->is_term ? get_terminal_width() : 0; ++ if (tb->termwidth <= 0) ++ tb->termwidth = 80; ++ tb->termwidth -= tb->termreduce; ++ ++ bufsz = tb->termwidth; ++ ++ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); ++ while (scols_table_next_line(tb, &itr, &ln) == 0) { ++ size_t sz = strlen_line(ln); ++ if (sz > bufsz) ++ bufsz = sz; ++ } ++ ++ buf = new_buffer(bufsz + 1); /* data + space for \0 */ ++ if (!buf) ++ return -ENOMEM; ++ ++ if (!(scols_table_is_raw(tb) || scols_table_is_export(tb))) { ++ rc = recount_widths(tb, buf); ++ if (rc != 0) ++ goto done; ++ } ++ ++ if (scols_table_is_tree(tb)) ++ rc = print_tree(tb, buf); ++ else ++ rc = print_table(tb, buf); ++ ++done: ++ free_buffer(buf); ++ return rc; ++} ++ ++/** ++ * scols_print_table_to_string: ++ * @tb: table ++ * @data: pointer to the beginning of a memory area to print to ++ * ++ * Prints the table to @data. ++ * ++ * Returns: 0, a negative value in case of an error. ++ */ ++int scols_print_table_to_string(struct libscols_table *tb, char **data) ++{ ++#ifdef HAVE_OPEN_MEMSTREAM ++ FILE *stream; ++ size_t sz; ++ int rc; ++ ++ if (!tb) ++ return -EINVAL; ++ ++ DBG(TAB, ul_debugobj(tb, "printing to string")); ++ ++ /* create a stream for output */ ++ stream = open_memstream(data, &sz); ++ if (!stream) ++ return -ENOMEM; ++ ++ scols_table_set_stream(tb, stream); ++ rc = scols_print_table(tb); ++ fclose(stream); ++ ++ return rc; ++#else ++ return -ENOSYS; ++#endif ++} ++ +diff -up util-linux-2.23.2/libsmartcols/src/test.c.kzak util-linux-2.23.2/libsmartcols/src/test.c +--- util-linux-2.23.2/libsmartcols/src/test.c.kzak 2014-09-25 14:41:48.993843953 +0200 ++++ util-linux-2.23.2/libsmartcols/src/test.c 2014-09-25 14:41:48.993843953 +0200 +@@ -0,0 +1,218 @@ ++/* ++ * Copyright (C) 2010-2014 Karel Zak ++ * ++ * This file may be redistributed under the terms of the ++ * GNU Lesser General Public License. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "c.h" ++#include "nls.h" ++#include "strutils.h" ++ ++#include "libsmartcols.h" ++ ++static int add_children(struct libscols_table *tb, ++ struct libscols_line *ln, int fd); ++ ++ ++enum { COL_MODE, COL_SIZE, COL_NAME }; ++ ++/* add columns to the @tb */ ++static void setup_columns(struct libscols_table *tb, int notree) ++{ ++ if (!scols_table_new_column(tb, "MODE", 0.3, 0)) ++ goto fail; ++ if (!scols_table_new_column(tb, "SIZE", 5, SCOLS_FL_RIGHT)) ++ goto fail; ++ if (!scols_table_new_column(tb, "NAME", 0.5, ++ (notree ? 0 : SCOLS_FL_TREE) | SCOLS_FL_NOEXTREMES)) ++ goto fail; ++ ++ return; ++fail: ++ scols_unref_table(tb); ++ err(EXIT_FAILURE, "faild to create output columns"); ++} ++ ++/* add a new line to @tb, the content is based on @st */ ++static int add_line_from_stat(struct libscols_table *tb, ++ struct libscols_line *parent, ++ int parent_fd, ++ struct stat *st, ++ const char *name) ++{ ++ struct libscols_line *ln; ++ char modbuf[11], *p; ++ mode_t mode = st->st_mode; ++ int rc = 0; ++ ++ ln = scols_table_new_line(tb, parent); ++ if (!ln) ++ err(EXIT_FAILURE, "failed to create output line"); ++ ++ /* MODE; local buffer, use scols_line_set_data() that calls strdup() */ ++ strmode(mode, modbuf); ++ if (scols_line_set_data(ln, COL_MODE, modbuf)) ++ goto fail; ++ ++ /* SIZE; already allocated string, use scols_line_refer_data() */ ++ p = size_to_human_string(0, st->st_size); ++ if (!p || scols_line_refer_data(ln, COL_SIZE, p)) ++ goto fail; ++ ++ /* NAME */ ++ if (scols_line_set_data(ln, COL_NAME, name)) ++ goto fail; ++ ++ /* colors */ ++ if (scols_table_colors_wanted(tb)) { ++ struct libscols_cell *ce = scols_line_get_cell(ln, COL_NAME); ++ ++ if (S_ISDIR(mode)) ++ scols_cell_set_color(ce, "blue"); ++ else if (S_ISLNK(mode)) ++ scols_cell_set_color(ce, "cyan"); ++ else if (S_ISBLK(mode)) ++ scols_cell_set_color(ce, "magenta"); ++ else if ((mode & S_IXOTH) || (mode & S_IXGRP) || (mode & S_IXUSR)) ++ scols_cell_set_color(ce, "green"); ++ } ++ ++ if (S_ISDIR(st->st_mode)) { ++ int fd; ++ ++ if (parent_fd >= 0) ++ fd = openat(parent_fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); ++ else ++ fd = open(name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); ++ if (fd >= 0) { ++ rc = add_children(tb, ln, fd); ++ close(fd); ++ } ++ } ++ return rc; ++fail: ++ err(EXIT_FAILURE, "failed to create cell data"); ++ return -1; ++} ++ ++/* read all entrines from directory addressed by @fd */ ++static int add_children(struct libscols_table *tb, ++ struct libscols_line *ln, ++ int fd) ++{ ++ DIR *dir; ++ struct dirent *d; ++ ++ dir = fdopendir(fd); ++ if (!dir) ++ return -errno; ++ ++ while ((d = readdir(dir))) { ++ struct stat st; ++ ++ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) ++ continue; ++ if (fstatat(fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) ++ continue; ++ add_line_from_stat(tb, ln, fd, &st, d->d_name); ++ } ++ closedir(dir); ++ return 0; ++} ++ ++static void add_lines(struct libscols_table *tb, const char *dirname) ++{ ++ struct stat st; ++ ++ if (lstat(dirname, &st)) ++ err(EXIT_FAILURE, "%s", dirname); ++ ++ add_line_from_stat(tb, NULL, -1, &st, dirname); ++} ++ ++static void __attribute__((__noreturn__)) usage(FILE *out) ++{ ++ fprintf(out, " %s [options] [ ...]\n\n", program_invocation_short_name); ++ fputs(" -c, --csv display a csv-like output\n", out); ++ fputs(" -i, --ascii use ascii characters only\n", out); ++ fputs(" -l, --list use list format output\n", out); ++ fputs(" -n, --noheadings don't print headings\n", out); ++ fputs(" -p, --pairs use key=\"value\" output format\n", out); ++ fputs(" -r, --raw use raw output format\n", out); ++ ++ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct libscols_table *tb; ++ int c, notree = 0; ++ ++ static const struct option longopts[] = { ++ { "ascii", 0, 0, 'i' }, ++ { "csv", 0, 0, 'c' }, ++ { "list", 0, 0, 'l' }, ++ { "noheadings", 0, 0, 'n' }, ++ { "pairs", 0, 0, 'p' }, ++ { "raw", 0, 0, 'r' }, ++ ++ { NULL, 0, 0, 0 }, ++ }; ++ ++ setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */ ++ ++ scols_init_debug(0); ++ ++ tb = scols_new_table(); ++ if (!tb) ++ err(EXIT_FAILURE, "faild to create output table"); ++ ++ while((c = getopt_long(argc, argv, "cilnpr", longopts, NULL)) != -1) { ++ switch(c) { ++ case 'c': ++ scols_table_set_column_separator(tb, ","); ++ scols_table_enable_raw(tb, 1); ++ notree = 1; ++ break; ++ case 'i': ++ scols_table_enable_ascii(tb, 1); ++ break; ++ case 'l': ++ notree = 1; ++ break; ++ case 'n': ++ scols_table_enable_noheadings(tb, 1); ++ break; ++ case 'p': ++ scols_table_enable_export(tb, 1); ++ notree = 1; ++ break; ++ case 'r': ++ scols_table_enable_raw(tb, 1); ++ notree = 1; ++ break; ++ default: ++ usage(stderr); ++ } ++ } ++ ++ scols_table_enable_colors(tb, 1); ++ setup_columns(tb, notree); ++ ++ while (optind < argc) ++ add_lines(tb, argv[optind++]); ++ ++ scols_print_table(tb); ++ scols_unref_table(tb); ++ ++ return EXIT_SUCCESS; ++} +diff -up util-linux-2.23.2/libsmartcols/src/version.c.kzak util-linux-2.23.2/libsmartcols/src/version.c +--- util-linux-2.23.2/libsmartcols/src/version.c.kzak 2014-09-25 14:41:48.993843953 +0200 ++++ util-linux-2.23.2/libsmartcols/src/version.c 2014-09-25 14:41:48.993843953 +0200 +@@ -0,0 +1,62 @@ ++/* ++ * version.c - Return the version of the library ++ * ++ * Copyright (C) 2014 Karel Zak ++ * ++ * See COPYING.libmount for the License of this software. ++ */ ++ ++/** ++ * SECTION: version-utils ++ * @title: Version functions ++ * @short_description: functions to get the library version. ++ * ++ * Note that library version is not the same thing as SONAME version. The ++ * libsmarcols uses symbols versioning and SONAME is not modified for releases. ++ * ++ * The library version and symbols version follow util-linux package versioning. ++ */ ++ ++#include ++ ++#include "smartcolsP.h" ++ ++static const char *lib_version = LIBSMARTCOLS_VERSION; ++ ++/** ++ * scols_parse_version_string: ++ * @ver_string: version string (e.g "2.18.0") ++ * ++ * Returns: release version code. ++ */ ++int scols_parse_version_string(const char *ver_string) ++{ ++ const char *cp; ++ int version = 0; ++ ++ assert(ver_string); ++ ++ for (cp = ver_string; *cp; cp++) { ++ if (*cp == '.') ++ continue; ++ if (!isdigit(*cp)) ++ break; ++ version = (version * 10) + (*cp - '0'); ++ } ++ return version; ++} ++ ++/** ++ * scols_get_library_version: ++ * @ver_string: return pointer to the static library version string if not NULL ++ * ++ * Returns: release version number. ++ */ ++int scols_get_library_version(const char **ver_string) ++{ ++ if (ver_string) ++ *ver_string = lib_version; ++ ++ return scols_parse_version_string(lib_version); ++} ++ +diff -up util-linux-2.23.2/lib/tt.c.kzak util-linux-2.23.2/lib/tt.c +--- util-linux-2.23.2/lib/tt.c.kzak 2013-07-15 10:25:46.280049032 +0200 ++++ util-linux-2.23.2/lib/tt.c 2014-09-25 14:41:48.982843848 +0200 +@@ -52,140 +52,6 @@ static const struct tt_symbols utf8_tt_s + #define is_last_column(_tb, _cl) \ + list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns) + +-/* +- * Counts number of cells in multibyte string. For all control and +- * non-printable chars is the result width enlarged to store \x?? hex +- * sequence. See mbs_safe_encode(). +- */ +-static size_t mbs_safe_width(const char *s) +-{ +- mbstate_t st; +- const char *p = s; +- size_t width = 0; +- +- memset(&st, 0, sizeof(st)); +- +- while (p && *p) { +- if (iscntrl((unsigned char) *p)) { +- width += 4; /* *p encoded to \x?? */ +- p++; +- } +-#ifdef HAVE_WIDECHAR +- else { +- wchar_t wc; +- size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); +- +- if (len == 0) +- break; +- +- if (len == (size_t) -1 || len == (size_t) -2) { +- len = 1; +- width += (isprint((unsigned char) *p) ? 1 : 4); +- +- } if (!iswprint(wc)) +- width += len * 4; /* hex encode whole sequence */ +- else +- width += wcwidth(wc); /* number of cells */ +- p += len; +- } +-#else +- else if (!isprint((unsigned char) *p)) { +- width += 4; /* *p encoded to \x?? */ +- p++; +- } else { +- width++; +- p++; +- } +-#endif +- } +- +- return width; +-} +- +-/* +- * Returns allocated string where all control and non-printable chars are +- * replaced with \x?? hex sequence. +- */ +-static char *mbs_safe_encode(const char *s, size_t *width) +-{ +- mbstate_t st; +- const char *p = s; +- char *res, *r; +- size_t sz = s ? strlen(s) : 0; +- +- +- if (!sz) +- return NULL; +- +- memset(&st, 0, sizeof(st)); +- +- res = malloc((sz * 4) + 1); +- if (!res) +- return NULL; +- +- r = res; +- *width = 0; +- +- while (p && *p) { +- if (iscntrl((unsigned char) *p)) { +- sprintf(r, "\\x%02x", (unsigned char) *p); +- r += 4; +- *width += 4; +- p++; +- } +-#ifdef HAVE_WIDECHAR +- else { +- wchar_t wc; +- size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); +- +- if (len == 0) +- break; /* end of string */ +- +- if (len == (size_t) -1 || len == (size_t) -2) { +- len = 1; +- /* +- * Not valid multibyte sequence -- maybe it's +- * printable char according to the current locales. +- */ +- if (!isprint((unsigned char) *p)) { +- sprintf(r, "\\x%02x", (unsigned char) *p); +- r += 4; +- *width += 4; +- } else { +- width++; +- *r++ = *p; +- } +- } else if (!iswprint(wc)) { +- size_t i; +- for (i = 0; i < len; i++) { +- sprintf(r, "\\x%02x", (unsigned char) *p); +- r += 4; +- *width += 4; +- } +- } else { +- memcpy(r, p, len); +- r += len; +- *width += wcwidth(wc); +- } +- p += len; +- } +-#else +- else if (!isprint((unsigned char) *p)) { +- sprintf(r, "\\x%02x", (unsigned char) *p); +- p++; +- r += 4; +- *width += 4; +- } else { +- *r++ = *p++; +- *width++; +- } +-#endif +- } +- +- *r = '\0'; +- +- return res; +-} + + /* + * @flags: TT_FL_* flags (usually TT_FL_{ASCII,RAW}) +diff -up util-linux-2.23.2/Makefile.am.kzak util-linux-2.23.2/Makefile.am +--- util-linux-2.23.2/Makefile.am.kzak 2013-06-13 09:46:10.334649886 +0200 ++++ util-linux-2.23.2/Makefile.am 2014-09-25 14:41:48.979843819 +0200 +@@ -22,6 +22,7 @@ dist_noinst_DATA = $(dist_man_MANS) + # + ul_libblkid_incdir = $(top_builddir)/libblkid/src + ul_libmount_incdir = $(top_builddir)/libmount/src ++ul_libsmartcols_incdir = $(top_builddir)/libsmartcols/src + ul_libuuid_incdir = $(top_srcdir)/libuuid/src + ul_libfdisk_incdir = $(top_srcdir)/libfdisk/src + +@@ -77,6 +78,7 @@ include lib/Makemodule.am + include libuuid/Makemodule.am + include libblkid/Makemodule.am + include libmount/Makemodule.am ++include libsmartcols/Makemodule.am + include libfdisk/Makemodule.am + + include schedutils/Makemodule.am diff --git a/SOURCES/2.26-logger-man-kern.patch b/SOURCES/2.26-logger-man-kern.patch new file mode 100644 index 00000000..b7b94343 --- /dev/null +++ b/SOURCES/2.26-logger-man-kern.patch @@ -0,0 +1,72 @@ +diff -up util-linux-2.23.2/misc-utils/logger.1.kzak util-linux-2.23.2/misc-utils/logger.1 +--- util-linux-2.23.2/misc-utils/logger.1.kzak 2015-06-24 12:18:23.938735038 +0200 ++++ util-linux-2.23.2/misc-utils/logger.1 2015-06-24 12:18:33.154667053 +0200 +@@ -125,28 +125,49 @@ flag is not provided, standard input is + The + .B logger + utility exits 0 on success, and >0 if an error occurs. +-.PP ++.SH FACILITIES AND LEVELS + Valid facility names are: +-.IR auth , \ authpriv +-(for security information of a sensitive nature), +-.IR cron , \ daemon , \ ftp , \ kern +-(can't be generated from user process), +-.IR lpr , \ mail , \ news , \ security +-(deprecated synonym for +-.IR auth ), \ syslog , \ user , \ uucp , +-and +-.IR local0 \ to \ local7 , +-inclusive. ++.IP ++.TS ++tab(:); ++left l l. ++\fBauth ++\fBauthpriv\fR:for security information of a sensitive nature ++\fBcron ++\fBdaemon ++\fBftp ++\fBkern\fR:cannot be generated from userspace process, automatically converted to \fBuser ++\fBlpr ++\fBmail ++\fBnews ++\fBsyslog ++\fBuser ++\fBuucp ++\fBlocal0 ++ to: ++\fBlocal7 ++\fBsecurity\fR:deprecated synonym for \fBauth ++.TE + .PP + Valid level names are: +-.IR alert , \ crit , \ debug , \ emerg , \ err , \ error +-(deprecated synonym for +-.IR err ), \ info , \ notice , \ panic +-(deprecated synonym for +-.IR emerg ), \ warning , \ warn +-(deprecated synonym for +-.IR warning ). +-For the priority order and intended purposes of these levels, see ++.IP ++.TS ++tab(:); ++left l l. ++\fBemerg ++\fBalert ++\fBcrit ++\fBerr ++\fBwarning ++\fBnotice ++\fBinfo ++\fBdebug ++\fBpanic\fR:deprecated synonym for \fBemerg ++\fBerror\fR:deprecated synonym for \fBerr ++\fBwarn\fR:deprecated synonym for \fBwarning ++.TE ++.PP ++For the priority order and intended purposes of these facilities and levels, see + .BR syslog (3). + .SH EXAMPLES + logger System rebooted diff --git a/SOURCES/2.26-login-SIGXFSZ.patch b/SOURCES/2.26-login-SIGXFSZ.patch new file mode 100644 index 00000000..51c858ed --- /dev/null +++ b/SOURCES/2.26-login-SIGXFSZ.patch @@ -0,0 +1,39 @@ +diff -up util-linux-2.23.2/login-utils/login.c.kzak util-linux-2.23.2/login-utils/login.c +--- util-linux-2.23.2/login-utils/login.c.kzak 2015-06-24 11:03:45.123285155 +0200 ++++ util-linux-2.23.2/login-utils/login.c 2015-06-24 11:46:19.168114438 +0200 +@@ -495,6 +495,7 @@ static void log_audit(struct login_conte + + static void log_lastlog(struct login_context *cxt) + { ++ struct sigaction sa, oldsa_xfsz; + struct lastlog ll; + time_t t; + int fd; +@@ -502,9 +503,14 @@ static void log_lastlog(struct login_con + if (!cxt->pwd) + return; + ++ /* lastlog is huge on systems with large UIDs, ignore SIGXFSZ */ ++ memset(&sa, 0, sizeof(sa)); ++ sa.sa_handler = SIG_IGN; ++ sigaction(SIGXFSZ, &sa, &oldsa_xfsz); ++ + fd = open(_PATH_LASTLOG, O_RDWR | O_CREAT, 0); + if (fd < 0) +- return; ++ goto done; + + if (lseek(fd, (off_t) cxt->pwd->pw_uid * sizeof(ll), SEEK_SET) == -1) + goto done; +@@ -542,7 +548,10 @@ static void log_lastlog(struct login_con + if (write_all(fd, (char *)&ll, sizeof(ll))) + warn(_("write lastlog failed")); + done: +- close(fd); ++ if (fd >= 0) ++ close(fd); ++ ++ sigaction(SIGXFSZ, &oldsa_xfsz, NULL); /* restore original setting */ + } + + /* diff --git a/SOURCES/2.26-lsblk-mpath.patch b/SOURCES/2.26-lsblk-mpath.patch new file mode 100644 index 00000000..1d698e13 --- /dev/null +++ b/SOURCES/2.26-lsblk-mpath.patch @@ -0,0 +1,63 @@ +diff -up util-linux-2.23.2/misc-utils/lsblk.c.kzak util-linux-2.23.2/misc-utils/lsblk.c +--- util-linux-2.23.2/misc-utils/lsblk.c.kzak 2015-06-25 11:01:10.543344225 +0200 ++++ util-linux-2.23.2/misc-utils/lsblk.c 2015-06-25 11:14:17.085404974 +0200 +@@ -953,11 +953,13 @@ static void set_tt_data(struct blkdev_cx + }; + } + +-static void print_device(struct blkdev_cxt *cxt, struct tt_line *tt_parent) ++static void fill_table_line(struct blkdev_cxt *cxt, struct tt_line *tt_parent) + { + int i; + + cxt->tt_line = tt_add_line(lsblk->tt, tt_parent); ++ if (!cxt->tt_line) ++ return; + + for (i = 0; i < ncolumns; i++) + set_tt_data(cxt, i, get_column_id(i), cxt->tt_line); +@@ -1084,7 +1086,7 @@ static int list_partitions(struct blkdev + goto next; + + wholedisk_cxt->parent = &part_cxt; +- print_device(&part_cxt, parent_cxt ? parent_cxt->tt_line : NULL); ++ fill_table_line(&part_cxt, parent_cxt ? parent_cxt->tt_line : NULL); + if (!lsblk->nodeps) + process_blkdev(wholedisk_cxt, &part_cxt, 0, NULL); + } else { +@@ -1098,7 +1100,7 @@ static int list_partitions(struct blkdev + + /* Print whole disk only once */ + if (r) +- print_device(wholedisk_cxt, parent_cxt ? parent_cxt->tt_line : NULL); ++ fill_table_line(wholedisk_cxt, parent_cxt ? parent_cxt->tt_line : NULL); + if (ps == 0 && !lsblk->nodeps) + process_blkdev(&part_cxt, wholedisk_cxt, 0, NULL); + } +@@ -1171,9 +1173,11 @@ static int list_deps(struct blkdev_cxt * + process_blkdev(&dep, cxt, 1, d->d_name); + } + /* The dependency is a whole device. */ +- else if (!set_cxt(&dep, cxt, NULL, d->d_name)) +- process_blkdev(&dep, cxt, 1, NULL); +- ++ else if (!set_cxt(&dep, cxt, NULL, d->d_name)) { ++ /* For inverse tree we don't want to show partitions ++ * if the dependence is pn whle-disk */ ++ process_blkdev(&dep, cxt, lsblk->inverse ? 0 : 1, NULL); ++ } + reset_blkdev_cxt(&dep); + } + closedir(dir); +@@ -1185,9 +1189,10 @@ static int process_blkdev(struct blkdev_ + int do_partitions, const char *part_name) + { + if (do_partitions && cxt->npartitions) +- return list_partitions(cxt, parent, part_name); ++ list_partitions(cxt, parent, part_name); /* partitoins + whole-disk */ ++ else ++ fill_table_line(cxt, parent ? parent->tt_line : NULL); /* whole-disk only */ + +- print_device(cxt, parent ? parent->tt_line : NULL); + return list_deps(cxt); + } diff --git a/SOURCES/2.26-lslogins.patch b/SOURCES/2.26-lslogins.patch new file mode 100644 index 00000000..c092348f --- /dev/null +++ b/SOURCES/2.26-lslogins.patch @@ -0,0 +1,2131 @@ +diff -up util-linux-2.23.2/configure.ac.kzak util-linux-2.23.2/configure.ac +--- util-linux-2.23.2/configure.ac.kzak 2014-12-12 15:27:43.505631342 +0100 ++++ util-linux-2.23.2/configure.ac 2014-12-12 15:28:30.571177081 +0100 +@@ -1027,6 +1027,11 @@ UL_REQUIRES_HAVE([lscpu], [cpu_set_t], [ + AM_CONDITIONAL(BUILD_LSCPU, test "x$build_lscpu" = xyes) + + ++UL_BUILD_INIT([lslogins], [check]) ++UL_REQUIRES_BUILD([lslogins], [libsmartcols]) ++AM_CONDITIONAL([BUILD_LSLOGINS], [test "x$build_lslogins" = xyes]) ++ ++ + UL_BUILD_INIT([chcpu], [check]) + UL_REQUIRES_LINUX([chcpu]) + UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type]) +@@ -1404,6 +1409,37 @@ fi + AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != "xno" ]) + + ++# ++# Backport from upstrem to RHEL7.1 ++# ++AC_ARG_WITH([systemd], ++ AS_HELP_STRING([--with-systemd], [build with support for systemd]), ++ [], [with_systemd=check] ++) ++ ++have_systemd=no ++AS_IF([test "x$with_systemd" != xno], [ ++ # new version -- all libsystemd-* libs merged into libsystemd ++ PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [have_systemd=yes], [have_systemd=no]) ++ # old versions ++ AS_IF([test "x$have_systemd" != "xyes"], [ ++ PKG_CHECK_MODULES([SYSTEMD_DAEMON], [libsystemd-daemon], ++ [have_systemd_daemon=yes], [have_systemd_daemon=no]) ++ PKG_CHECK_MODULES([SYSTEMD_JOURNAL], [libsystemd-journal], ++ [have_systemd_journal=yes], [have_systemd_journal=no]) ++ AS_IF([test "x$have_systemd_daemon" = "xyes" -a "x$have_systemd_journal" = "xyes" ],[ ++ have_systemd=yes]) ++ ]) ++ AS_CASE([$with_systemd:$have_systemd], ++ [yes:no], ++ [AC_MSG_ERROR([systemd expected but libsystemd not found])], ++ [*:yes], ++ AC_DEFINE([HAVE_LIBSYSTEMD], [1], [Define if libsystemd is available]) ++ ) ++]) ++ ++ ++ + AC_ARG_WITH([bashcompletiondir], + AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]), + [], +diff -up util-linux-2.23.2/include/Makemodule.am.kzak util-linux-2.23.2/include/Makemodule.am +--- util-linux-2.23.2/include/Makemodule.am.kzak 2013-07-15 10:25:46.277049008 +0200 ++++ util-linux-2.23.2/include/Makemodule.am 2014-12-12 15:28:30.571177081 +0100 +@@ -35,6 +35,7 @@ dist_noinst_HEADERS += \ + include/procutils.h \ + include/randutils.h \ + include/rpmatch.h \ ++ include/readutmp.h \ + include/setproctitle.h \ + include/strutils.h \ + include/swapheader.h \ +diff -up util-linux-2.23.2/include/readutmp.h.kzak util-linux-2.23.2/include/readutmp.h +--- util-linux-2.23.2/include/readutmp.h.kzak 2014-12-12 15:28:30.571177081 +0100 ++++ util-linux-2.23.2/include/readutmp.h 2014-12-12 15:28:30.571177081 +0100 +@@ -0,0 +1,28 @@ ++/* Declarations for GNU's read utmp module. ++ ++ Copyright (C) 1992-2007, 2009-2014 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Written by jla; revised by djm */ ++ ++#ifndef READUTMP_H ++#define READUTMP_H ++ ++#include ++#include ++ ++int read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf); ++ ++#endif /* READUTMP_H */ +diff -up util-linux-2.23.2/lib/Makemodule.am.kzak util-linux-2.23.2/lib/Makemodule.am +--- util-linux-2.23.2/lib/Makemodule.am.kzak 2013-07-30 10:39:26.202738200 +0200 ++++ util-linux-2.23.2/lib/Makemodule.am 2014-12-12 15:28:30.572177092 +0100 +@@ -25,7 +25,8 @@ libcommon_la_SOURCES = \ + lib/wholedisk.c \ + lib/ttyutils.c \ + lib/xgetpass.c \ +- lib/exec_shell.c ++ lib/exec_shell.c \ ++ lib/readutmp.c + + if LINUX + libcommon_la_SOURCES += \ +diff -up util-linux-2.23.2/lib/readutmp.c.kzak util-linux-2.23.2/lib/readutmp.c +--- util-linux-2.23.2/lib/readutmp.c.kzak 2014-12-12 15:28:30.572177092 +0100 ++++ util-linux-2.23.2/lib/readutmp.c 2014-12-12 15:28:30.572177092 +0100 +@@ -0,0 +1,76 @@ ++/* GNU's read utmp module. ++ ++ Copyright (C) 1992-2001, 2003-2006, 2009-2014 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Written by jla; revised by djm */ ++/* extracted for util-linux by ooprala */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xalloc.h" ++#include "readutmp.h" ++ ++/* Read the utmp entries corresponding to file FILE into freshly- ++ malloc'd storage, set *UTMP_BUF to that pointer, set *N_ENTRIES to ++ the number of entries, and return zero. If there is any error, ++ return -1, setting errno, and don't modify the parameters. ++ If OPTIONS & READ_UTMP_CHECK_PIDS is nonzero, omit entries whose ++ process-IDs do not currently exist. */ ++int ++read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf) ++{ ++ size_t n_read = 0; ++ size_t n_alloc = 0; ++ struct utmp *utmp = NULL; ++ struct utmp *u; ++ ++ /* Ignore the return value for now. ++ Solaris' utmpname returns 1 upon success -- which is contrary ++ to what the GNU libc version does. In addition, older GNU libc ++ versions are actually void. */ ++ utmpname(file); ++ ++ setutent(); ++ ++ errno = 0; ++ while ((u = getutent()) != NULL) { ++ if (n_read == n_alloc) { ++ n_alloc += 32; ++ utmp = xrealloc(utmp, n_alloc * sizeof (struct utmp)); ++ if (!utmp) ++ return -1; ++ } ++ utmp[n_read++] = *u; ++ } ++ if (!u && errno) ++ return -1; ++ ++ endutent(); ++ ++ *n_entries = n_read; ++ *utmp_buf = utmp; ++ ++ return 0; ++} +diff -up util-linux-2.23.2/login-utils/login.c.kzak util-linux-2.23.2/login-utils/login.c +--- util-linux-2.23.2/login-utils/login.c.kzak 2014-12-12 15:27:43.436630542 +0100 ++++ util-linux-2.23.2/login-utils/login.c 2014-12-12 15:28:30.573177104 +0100 +@@ -923,124 +923,6 @@ static void loginpam_session(struct logi + } + + /* +- * We need to check effective UID/GID. For example $HOME could be on root +- * squashed NFS or on NFS with UID mapping and access(2) uses real UID/GID. +- * The open(2) seems as the surest solution. +- * -- kzak@redhat.com (10-Apr-2009) +- */ +-static int effective_access(const char *path, int mode) +-{ +- int fd = open(path, mode); +- if (fd != -1) +- close(fd); +- return fd == -1 ? -1 : 0; +-} +- +-/* +- * Check per accout or global hush-login setting. +- * +- * Hushed mode is enabled: +- * +- * a) if global (e.g. /etc/hushlogins) hush file exists: +- * 1) for ALL ACCOUNTS if the file is empty +- * 2) for the current user if the username or shell are found in the file +- * +- * b) if ~/.hushlogin file exists +- * +- * The ~/.hushlogin is ignored if the global hush file exists. +- * +- * The HUSHLOGIN_FILE login.def variable overwrites the default hush filename. +- * +- * Note that shadow-utils login(1) does not support "a1)". The "a1)" is +- * necessary if you want to use PAM for "Last login" message. +- * +- * -- Karel Zak (26-Aug-2011) +- * +- * +- * Per-account check requires some explanation: As root we may not be able to +- * read the directory of the user if it is on an NFS mounted filesystem. We +- * temporarily set our effective uid to the user-uid making sure that we keep +- * root privs. in the real uid. +- * +- * A portable solution would require a fork(), but we rely on Linux having the +- * BSD setreuid() +- */ +-static int get_hushlogin_status(struct passwd *pwd) +-{ +- const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL }; +- const char *file; +- char buf[BUFSIZ]; +- int i; +- +- file = getlogindefs_str("HUSHLOGIN_FILE", NULL); +- if (file) { +- if (!*file) +- return 0; /* empty HUSHLOGIN_FILE defined */ +- +- files[0] = file; +- files[1] = NULL; +- } +- +- for (i = 0; files[i]; i++) { +- int ok = 0; +- +- file = files[i]; +- +- /* Global hush-file*/ +- if (*file == '/') { +- struct stat st; +- FILE *f; +- +- if (stat(file, &st) != 0) +- continue; /* file does not exist */ +- +- if (st.st_size == 0) +- return 1; /* for all accounts */ +- +- f = fopen(file, "r"); +- if (!f) +- continue; /* ignore errors... */ +- +- while (ok == 0 && fgets(buf, sizeof(buf), f)) { +- buf[strlen(buf) - 1] = '\0'; +- ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell : +- pwd->pw_name); +- } +- fclose(f); +- if (ok) +- return 1; /* found username/shell */ +- +- return 0; /* ignore per-account files */ +- } +- +- /* Per-account setting */ +- if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf)) +- continue; +- else { +- uid_t ruid = getuid(); +- gid_t egid = getegid(); +- +- sprintf(buf, "%s/%s", pwd->pw_dir, file); +- +- if (setregid(-1, pwd->pw_gid) == 0 && +- setreuid(0, pwd->pw_uid) == 0) +- ok = effective_access(buf, O_RDONLY) == 0; +- +- if (setuid(0) != 0 || +- setreuid(ruid, 0) != 0 || +- setregid(-1, egid) != 0) { +- syslog(LOG_ALERT, _("hush login status: restore original IDs failed")); +- exit(EXIT_FAILURE); +- } +- if (ok) +- return 1; /* enabled by user */ +- } +- } +- +- return 0; +-} +- +-/* + * Detach the controlling terminal, fork, restore syslog stuff and create a new + * session. + */ +@@ -1372,7 +1254,7 @@ int main(int argc, char **argv) + + endpwent(); + +- cxt.quiet = get_hushlogin_status(pwd); ++ cxt.quiet = get_hushlogin_status(pwd, 1); + + log_utmp(&cxt); + log_audit(&cxt, 1); +diff -up util-linux-2.23.2/login-utils/logindefs.c.kzak util-linux-2.23.2/login-utils/logindefs.c +--- util-linux-2.23.2/login-utils/logindefs.c.kzak 2013-06-13 09:46:10.442650810 +0200 ++++ util-linux-2.23.2/login-utils/logindefs.c 2014-12-12 15:28:30.573177104 +0100 +@@ -27,6 +27,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "c.h" + #include "closestream.h" +@@ -259,6 +262,135 @@ int logindefs_setenv(const char *name, c + return val ? setenv(name, val, 1) : -1; + } + ++/* ++ * We need to check the effective UID/GID. For example, $HOME could be on a ++ * root-squashed NFS or on an NFS with UID mapping, and access(2) uses the ++ * real UID/GID. Then open(2) seems as the surest solution. ++ * -- kzak@redhat.com (10-Apr-2009) ++ */ ++int effective_access(const char *path, int mode) ++{ ++ int fd = open(path, mode); ++ if (fd != -1) ++ close(fd); ++ return fd == -1 ? -1 : 0; ++} ++ ++ ++/* ++ * Check the per-account or the global hush-login setting. ++ * ++ * Hushed mode is enabled: ++ * ++ * a) if a global (e.g. /etc/hushlogins) hush file exists: ++ * 1) for ALL ACCOUNTS if the file is empty ++ * 2) for the current user if the username or shell is found in the file ++ * ++ * b) if a ~/.hushlogin file exists ++ * ++ * The ~/.hushlogin file is ignored if the global hush file exists. ++ * ++ * The HUSHLOGIN_FILE login.def variable overrides the default hush filename. ++ * ++ * Note that shadow-utils login(1) does not support "a1)". The "a1)" is ++ * necessary if you want to use PAM for "Last login" message. ++ * ++ * -- Karel Zak (26-Aug-2011) ++ * ++ * ++ * The per-account check requires some explanation: As root we may not be able ++ * to read the directory of the user if it is on an NFS-mounted filesystem. We ++ * temporarily set our effective uid to the user-uid, making sure that we keep ++ * root privileges in the real uid. ++ * ++ * A portable solution would require a fork(), but we rely on Linux having the ++ * BSD setreuid(). ++ */ ++ ++int get_hushlogin_status(struct passwd *pwd, int force_check) ++{ ++ const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL }; ++ const char *file; ++ char buf[BUFSIZ]; ++ int i; ++ ++ file = getlogindefs_str("HUSHLOGIN_FILE", NULL); ++ if (file) { ++ if (!*file) ++ return 0; /* empty HUSHLOGIN_FILE defined */ ++ ++ files[0] = file; ++ files[1] = NULL; ++ } ++ ++ for (i = 0; files[i]; i++) { ++ int ok = 0; ++ ++ file = files[i]; ++ ++ /* global hush-file */ ++ if (*file == '/') { ++ struct stat st; ++ FILE *f; ++ ++ if (stat(file, &st) != 0) ++ continue; /* file does not exist */ ++ ++ if (st.st_size == 0) ++ return 1; /* for all accounts */ ++ ++ f = fopen(file, "r"); ++ if (!f) ++ continue; /* ignore errors... */ ++ ++ while (ok == 0 && fgets(buf, sizeof(buf), f)) { ++ buf[strlen(buf) - 1] = '\0'; ++ ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell : ++ pwd->pw_name); ++ } ++ fclose(f); ++ if (ok) ++ return 1; /* found username/shell */ ++ ++ return 0; /* ignore per-account files */ ++ } ++ ++ /* per-account setting */ ++ if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf)) ++ continue; ++ ++ sprintf(buf, "%s/%s", pwd->pw_dir, file); ++ ++ if (force_check) { ++ uid_t ruid = getuid(); ++ gid_t egid = getegid(); ++ ++ if (setregid(-1, pwd->pw_gid) == 0 && ++ setreuid(0, pwd->pw_uid) == 0) ++ ok = effective_access(buf, O_RDONLY) == 0; ++ ++ if (setuid(0) != 0 || ++ setreuid(ruid, 0) != 0 || ++ setregid(-1, egid) != 0) { ++ syslog(LOG_ALERT, _("hush login status: restore original IDs failed")); ++ exit(EXIT_FAILURE); ++ } ++ if (ok) ++ return 1; /* enabled by user */ ++ } ++ else { ++ int rc; ++ rc = effective_access(buf, O_RDONLY); ++ if (rc == 0) ++ return 1; ++ else if (rc == -1 && errno == EACCES) ++ return -1; ++ } ++ ++ } ++ ++ return 0; ++} + #ifdef TEST_PROGRAM + int main(int argc, char *argv[]) + { +diff -up util-linux-2.23.2/login-utils/logindefs.h.kzak util-linux-2.23.2/login-utils/logindefs.h +--- util-linux-2.23.2/login-utils/logindefs.h.kzak 2013-02-27 17:46:29.887020770 +0100 ++++ util-linux-2.23.2/login-utils/logindefs.h 2014-12-12 15:28:30.573177104 +0100 +@@ -8,5 +8,7 @@ extern unsigned long getlogindefs_num(co + extern const char *getlogindefs_str(const char *name, const char *dflt); + extern void free_getlogindefs_data(void); + extern int logindefs_setenv(const char *name, const char *conf, const char *dflt); ++extern int effective_access(const char *path, int mode); ++extern int get_hushlogin_status(struct passwd *pwd, int force_check); + + #endif /* UTIL_LINUX_LOGINDEFS_H */ +diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1 +--- util-linux-2.23.2/login-utils/lslogins.1.kzak 2014-12-12 15:28:30.574177115 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.1 2014-12-12 15:28:30.574177115 +0100 +@@ -0,0 +1,132 @@ ++.\" Copyright 2014 Ondrej Oprala (ondrej.oprala@gmail.com) ++.\" May be distributed under the GNU General Public License ++.TH LSLOGINS "1" "April 2014" "util-linux" "User Commands" ++.SH NAME ++lslogins \- display information about known users in the system ++.SH SYNOPSIS ++.B lslogins ++[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR] ++.SH DESCRIPTION ++.PP ++Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd ++and output the desired data. ++.PP ++The default action is to list info about all the users in the system. ++.SH OPTIONS ++Mandatory arguments to long options are mandatory for short options too. ++.TP ++\fB\-a\fR, \fB\-\-acc\-expiration\fR ++Display data about the date of last password change and the account expiration ++date (see \fBshadow\fR(5) for more info). (Requires root priviliges.) ++.TP ++\fB\-\-btmp\-file \fIpath\fP ++Alternate path for btmp. ++.TP ++\fB\-c\fR, \fB\-\-colon\-separate\fR ++Separate info about each user with a colon instead of a newline. ++.TP ++\fB\-e\fR, \fB\-\-export\fR ++Output data in the format of NAME=VALUE. ++.TP ++\fB\-f\fR, \fB\-\-failed\fR ++Display data about the users' last failed login attempts. ++.TP ++\fB\-G\fR, \fB\-\-groups\-info\fR ++Show information about groups. ++.TP ++\fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR ++Only show data of users belonging to \fIgroups\fR. More than one group ++may be specified; the list has to be comma-separated. ++.TP ++\fB\-h\fR, \fB\-\-help\fR ++Display help information and exit. ++.TP ++\fB\-L\fR, \fB\-\-last\fR ++Display data containing information about the users' last login sessions. ++.TP ++\fB\-l\fR, \fB\-\-logins\fR=\fIlogins\fR ++Only show data of users with a login specified in \fIlogins\fR (user names or user ++IDS). More than one login may be specified; the list has to be comma-separated. ++.TP ++\fB\-m\fR, \fB\-\-supp\-groups\fR ++Show supplementary groups. ++.TP ++\fB\-n\fR, \fB\-\-newline\fR ++Display each piece of information on a separate line. ++.TP ++\fB\-\-noheadings\fR ++Do not print a header line. ++.TP ++\fB\-\-notruncate\fR ++Don't truncate output. ++.TP ++\fB\-o\fR, \fB\-\-output \fIlist\fP ++Specify which output columns to print. Use ++.B \-\-help ++to get a list of all supported columns. ++.TP ++\fB\-p\fR, \fB\-\-pwd\fR ++Display information related to login by password (see also \fB\-afL). ++.TP ++\fB\-r\fR, \fB\-\-raw\fR ++Raw output (no columnation). ++.TP ++\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR] ++Show system accounts. These are by default all accounts with a UID below 1000 ++(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID ++threshold can also be specified explicitly (necessary for some distributions that ++allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++.TP ++\fB\-\-time-format\fR \fItype\fP ++Display dates in short, full or iso format. The default is short, this time ++format is designed to be space efficient and human readable. ++.TP ++\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR] ++Show user accounts. These are by default all accounts with UID above 1000 ++(inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID ++threshold can also be specified explicitly (necessary for some distributions that ++allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++.TP ++\fB\-V\fR, \fB\-\-version\fR ++Display version information and exit. ++.TP ++\fB\-\-wtmp\-file \fIpath\fP ++Alternate path for wtmp. ++.TP ++\fB\-Z\fR, \fB\-\-context\fR ++Display the users' security context. ++.TP ++\fB\-z\fR, \fB\-\-print0\fR ++Delimit user entries with a nul character, instead of a newline. ++ ++.SH NOTES ++The default UID thresholds are read from /etc/login.defs. ++ ++.SH EXIT STATUS ++.TP ++0 ++if OK, ++.TP ++1 ++if incorrect arguments specified, ++.TP ++2 ++if a serious error occurs (e.g. a corrupt log). ++.SH SEE ALSO ++\fBgroup\fP(5), \fBpasswd\fP(5), \fBshadow\fP(5), \fButmp\fP(5) ++.SH HISTORY ++The \fBlslogins\fP utility is inspired by the \fBlogins\fP utility, which first appeared in FreeBSD 4.10. ++.SH AUTHORS ++.MT ooprala@redhat.com ++Ondrej Oprala ++.ME ++.br ++.MT kzak@redhat.com ++Karel Zak ++.ME ++ ++.SH AVAILABILITY ++The lslogins command is part of the util-linux package and is available from ++.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/ ++Linux Kernel Archive ++.UE . +diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c +--- util-linux-2.23.2/login-utils/lslogins.c.kzak 2014-12-12 15:28:30.575177127 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.c 2014-12-12 15:29:19.084739609 +0100 +@@ -0,0 +1,1476 @@ ++/* ++ * lslogins - List information about users on the system ++ * ++ * Copyright (C) 2014 Ondrej Oprala ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#ifdef HAVE_LIBSELINUX ++# include ++#endif ++ ++#ifdef HAVE_LIBSYSTEMD ++# include ++#endif ++ ++#include "c.h" ++#include "nls.h" ++#include "closestream.h" ++#include "xalloc.h" ++#include "list.h" ++#include "strutils.h" ++#include "optutils.h" ++#include "pathnames.h" ++#include "logindefs.h" ++#include "readutmp.h" ++#include "procutils.h" ++ ++/* ++ * column description ++ */ ++struct lslogins_coldesc { ++ const char *name; ++ const char *help; ++ const char *pretty_name; ++ ++ double whint; /* width hint */ ++ long flag; ++}; ++ ++static int lslogins_flag; ++ ++#define UL_UID_MIN 1000 ++#define UL_UID_MAX 60000 ++#define UL_SYS_UID_MIN 201 ++#define UL_SYS_UID_MAX 999 ++ ++/* we use the value of outmode to determine ++ * appropriate flags for the libsmartcols table ++ * (e.g., a value of out_newline would imply a raw ++ * table with the column separator set to '\n'). ++ */ ++static int outmode; ++/* ++ * output modes ++ */ ++enum { ++ OUT_COLON = 1, ++ OUT_EXPORT, ++ OUT_NEWLINE, ++ OUT_RAW, ++ OUT_NUL, ++ OUT_PRETTY ++}; ++ ++struct lslogins_user { ++ char *login; ++ uid_t uid; ++ char *group; ++ gid_t gid; ++ char *gecos; ++ ++ int pwd_empty; ++ int nologin; ++ int pwd_lock; ++ int pwd_deny; ++ ++ gid_t *sgroups; ++ size_t nsgroups; ++ ++ char *pwd_ctime; ++ char *pwd_warn; ++ char *pwd_expire; ++ char *pwd_ctime_min; ++ char *pwd_ctime_max; ++ ++ char *last_login; ++ char *last_tty; ++ char *last_hostname; ++ ++ char *failed_login; ++ char *failed_tty; ++ ++#ifdef HAVE_LIBSELINUX ++ security_context_t context; ++#endif ++ char *homedir; ++ char *shell; ++ char *pwd_status; ++ int hushed; ++ char *nprocs; ++ ++}; ++ ++/* ++ * time modes ++ * */ ++enum { ++ TIME_INVALID = 0, ++ TIME_SHORT, ++ TIME_FULL, ++ TIME_ISO, ++}; ++ ++/* ++ * flags ++ */ ++enum { ++ F_SYSAC = (1 << 3), ++ F_USRAC = (1 << 4), ++}; ++ ++/* ++ * IDs ++ */ ++enum { ++ COL_USER = 0, ++ COL_UID, ++ COL_GECOS, ++ COL_HOME, ++ COL_SHELL, ++ COL_NOLOGIN, ++ COL_PWDLOCK, ++ COL_PWDEMPTY, ++ COL_PWDDENY, ++ COL_GROUP, ++ COL_GID, ++ COL_SGROUPS, ++ COL_SGIDS, ++ COL_LAST_LOGIN, ++ COL_LAST_TTY, ++ COL_LAST_HOSTNAME, ++ COL_FAILED_LOGIN, ++ COL_FAILED_TTY, ++ COL_HUSH_STATUS, ++ COL_PWD_WARN, ++ COL_PWD_CTIME, ++ COL_PWD_CTIME_MIN, ++ COL_PWD_CTIME_MAX, ++ COL_PWD_EXPIR, ++ COL_SELINUX, ++ COL_NPROCS, ++}; ++ ++#define is_wtmp_col(x) ((x) == COL_LAST_LOGIN || \ ++ (x) == COL_LAST_TTY || \ ++ (x) == COL_LAST_HOSTNAME) ++ ++#define is_btmp_col(x) ((x) == COL_FAILED_LOGIN || \ ++ (x) == COL_FAILED_TTY) ++ ++enum { ++ STATUS_FALSE = 0, ++ STATUS_TRUE, ++ STATUS_UNKNOWN ++}; ++ ++static const char *const status[] = { ++ [STATUS_FALSE] = "0", ++ [STATUS_TRUE] = "1", ++ [STATUS_UNKNOWN]= NULL ++}; ++ ++static const char *const pretty_status[] = { ++ [STATUS_FALSE] = N_("no"), ++ [STATUS_TRUE] = N_("yes"), ++ [STATUS_UNKNOWN]= NULL ++}; ++ ++#define get_status(x) (outmode == OUT_PRETTY ? pretty_status[(x)] : status[(x)]) ++ ++static const struct lslogins_coldesc coldescs[] = ++{ ++ [COL_USER] = { "USER", N_("user name"), N_("Username"), 0.1, SCOLS_FL_NOEXTREMES }, ++ [COL_UID] = { "UID", N_("user ID"), "UID", 1, SCOLS_FL_RIGHT}, ++ [COL_PWDEMPTY] = { "PWD-EMPTY", N_("password not required"), N_("Password not required"), 1, SCOLS_FL_RIGHT }, ++ [COL_PWDDENY] = { "PWD-DENY", N_("login by password disabled"), N_("Login by password disabled"), 1, SCOLS_FL_RIGHT }, ++ [COL_PWDLOCK] = { "PWD-LOCK", N_("password defined, but locked"), N_("Password is locked"), 1, SCOLS_FL_RIGHT }, ++ [COL_NOLOGIN] = { "NOLOGIN", N_("log in disabled by nologin(8) or pam_nologin(8)"), N_("No login"), 1, SCOLS_FL_RIGHT }, ++ [COL_GROUP] = { "GROUP", N_("primary group name"), N_("Primary group"), 0.1 }, ++ [COL_GID] = { "GID", N_("primary group ID"), "GID", 1, SCOLS_FL_RIGHT }, ++ [COL_SGROUPS] = { "SUPP-GROUPS", N_("supplementary group names"), N_("Supplementary groups"), 0.1 }, ++ [COL_SGIDS] = { "SUPP-GIDS", N_("supplementary group IDs"), N_("Supplementary group IDs"), 0.1 }, ++ [COL_HOME] = { "HOMEDIR", N_("home directory"), N_("Home directory"), 0.1 }, ++ [COL_SHELL] = { "SHELL", N_("login shell"), N_("Shell"), 0.1 }, ++ [COL_GECOS] = { "GECOS", N_("full user name"), N_("Gecos field"), 0.1, SCOLS_FL_TRUNC }, ++ [COL_LAST_LOGIN] = { "LAST-LOGIN", N_("date of last login"), N_("Last login"), 0.1, SCOLS_FL_RIGHT }, ++ [COL_LAST_TTY] = { "LAST-TTY", N_("last tty used"), N_("Last terminal"), 0.05 }, ++ [COL_LAST_HOSTNAME] = { "LAST-HOSTNAME",N_("hostname during the last session"), N_("Last hostname"), 0.1}, ++ [COL_FAILED_LOGIN] = { "FAILED-LOGIN", N_("date of last failed login"), N_("Failed login"), 0.1 }, ++ [COL_FAILED_TTY] = { "FAILED-TTY", N_("where did the login fail?"), N_("Failed login terminal"), 0.05 }, ++ [COL_HUSH_STATUS] = { "HUSHED", N_("user's hush settings"), N_("Hushed"), 1, SCOLS_FL_RIGHT }, ++ [COL_PWD_WARN] = { "PWD-WARN", N_("days user is warned of password expiration"), N_("Password expiration warn interval"), 0.1, SCOLS_FL_RIGHT }, ++ [COL_PWD_EXPIR] = { "PWD-EXPIR", N_("password expiration date"), N_("Password expiration"), 0.1, SCOLS_FL_RIGHT }, ++ [COL_PWD_CTIME] = { "PWD-CHANGE", N_("date of last password change"), N_("Password changed"), 0.1, SCOLS_FL_RIGHT}, ++ [COL_PWD_CTIME_MIN] = { "PWD-MIN", N_("number of days required between changes"), N_("Minimum change time"), 0.1, SCOLS_FL_RIGHT }, ++ [COL_PWD_CTIME_MAX] = { "PWD-MAX", N_("max number of days a password may remain unchanged"), N_("Maximum change time"), 0.1, SCOLS_FL_RIGHT }, ++ [COL_SELINUX] = { "CONTEXT", N_("the user's security context"), N_("Selinux context"), 0.1 }, ++ [COL_NPROCS] = { "PROC", N_("number of processes run by the user"), N_("Running processes"), 1, SCOLS_FL_RIGHT }, ++}; ++ ++struct lslogins_control { ++ struct utmp *wtmp; ++ size_t wtmp_size; ++ ++ struct utmp *btmp; ++ size_t btmp_size; ++ ++ void *usertree; ++ ++ uid_t uid; ++ uid_t UID_MIN; ++ uid_t UID_MAX; ++ ++ uid_t SYS_UID_MIN; ++ uid_t SYS_UID_MAX; ++ ++ char **ulist; ++ size_t ulsiz; ++ ++ unsigned int time_mode; ++ ++ const char *journal_path; ++ ++ unsigned int selinux_enabled : 1, ++ ulist_on : 1, ++ noheadings : 1, ++ notrunc : 1; ++}; ++ ++/* these have to remain global since there's no other reasonable way to pass ++ * them for each call of fill_table() via twalk() */ ++static struct libscols_table *tb; ++ ++/* columns[] array specifies all currently wanted output column. The columns ++ * are defined by coldescs[] array and you can specify (on command line) each ++ * column twice. That's enough, dynamically allocated array of the columns is ++ * unnecessary overkill and over-engineering in this case */ ++static int columns[ARRAY_SIZE(coldescs) * 2]; ++static int ncolumns; ++ ++static inline size_t err_columns_index(size_t arysz, size_t idx) ++{ ++ if (idx >= arysz) ++ errx(EXIT_FAILURE, _("too many columns specified, " ++ "the limit is %zu columns"), ++ arysz - 1); ++ return idx; ++} ++ ++#define add_column(ary, n, id) \ ++ ((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id)) ++ ++static struct timeval now; ++ ++static int date_is_today(time_t t) ++{ ++ if (now.tv_sec == 0) ++ gettimeofday(&now, NULL); ++ return t / (3600 * 24) == now.tv_sec / (3600 * 24); ++} ++ ++static int date_is_thisyear(time_t t) ++{ ++ if (now.tv_sec == 0) ++ gettimeofday(&now, NULL); ++ return t / (3600 * 24 * 365) == now.tv_sec / (3600 * 24 * 365); ++} ++ ++static int column_name_to_id(const char *name, size_t namesz) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(coldescs); i++) { ++ const char *cn = coldescs[i].name; ++ ++ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) ++ return i; ++ } ++ warnx(_("unknown column: %s"), name); ++ return -1; ++} ++ ++static char *make_time(int mode, time_t time) ++{ ++ char *s; ++ struct tm tm; ++ char buf[64] = {0}; ++ ++ localtime_r(&time, &tm); ++ ++ switch(mode) { ++ case TIME_FULL: ++ asctime_r(&tm, buf); ++ if (*(s = buf + strlen(buf) - 1) == '\n') ++ *s = '\0'; ++ break; ++ case TIME_SHORT: ++ if (date_is_today(time)) ++ strftime(buf, sizeof(buf), "%H:%M:%S", &tm); ++ else if (date_is_thisyear(time)) ++ strftime(buf, sizeof(buf), "%b%d/%H:%M", &tm); ++ else ++ strftime(buf, sizeof(buf), "%Y-%b%d", &tm); ++ break; ++ case TIME_ISO: ++ strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm); ++ break; ++ default: ++ errx(EXIT_FAILURE, _("unsupported time type")); ++ } ++ return xstrdup(buf); ++} ++ ++ ++static char *uidtostr(uid_t uid) ++{ ++ char *str_uid = NULL; ++ xasprintf(&str_uid, "%u", uid); ++ return str_uid; ++} ++ ++static char *gidtostr(gid_t gid) ++{ ++ char *str_gid = NULL; ++ xasprintf(&str_gid, "%u", gid); ++ return str_gid; ++} ++ ++static char *build_sgroups_string(gid_t *sgroups, size_t nsgroups, int want_names) ++{ ++ size_t n = 0, maxlen, len; ++ char *res, *p; ++ ++ if (!nsgroups) ++ return NULL; ++ ++ len = maxlen = nsgroups * 10; ++ res = p = xmalloc(maxlen); ++ ++ while (n < nsgroups) { ++ int x; ++again: ++ if (!want_names) ++ x = snprintf(p, len, "%u,", sgroups[n]); ++ else { ++ struct group *grp = getgrgid(sgroups[n]); ++ if (!grp) { ++ free(res); ++ return NULL; ++ } ++ x = snprintf(p, len, "%s,", grp->gr_name); ++ } ++ ++ if (x < 0 || (size_t) x + 1 > len) { ++ size_t cur = p - res; ++ ++ maxlen *= 2; ++ res = xrealloc(res, maxlen); ++ p = res + cur; ++ len = maxlen - cur; ++ goto again; ++ } ++ ++ len -= x; ++ p += x; ++ ++n; ++ } ++ ++ if (p > res) ++ *(p - 1) = '\0'; ++ ++ return res; ++} ++ ++static struct utmp *get_last_wtmp(struct lslogins_control *ctl, const char *username) ++{ ++ size_t n = 0; ++ size_t len; ++ ++ if (!username) ++ return NULL; ++ ++ len = strlen(username); ++ n = ctl->wtmp_size - 1; ++ do { ++ if (!strncmp(username, ctl->wtmp[n].ut_user, ++ len < UT_NAMESIZE ? len : UT_NAMESIZE)) ++ return ctl->wtmp + n; ++ } while (n--); ++ return NULL; ++ ++} ++ ++static int require_wtmp(void) ++{ ++ size_t i; ++ for (i = 0; i < (size_t) ncolumns; i++) ++ if (is_wtmp_col(columns[i])) ++ return 1; ++ return 0; ++} ++ ++static int require_btmp(void) ++{ ++ size_t i; ++ for (i = 0; i < (size_t) ncolumns; i++) ++ if (is_btmp_col(columns[i])) ++ return 1; ++ return 0; ++} ++ ++static struct utmp *get_last_btmp(struct lslogins_control *ctl, const char *username) ++{ ++ size_t n = 0; ++ size_t len; ++ ++ if (!username) ++ return NULL; ++ ++ len = strlen(username); ++ n = ctl->btmp_size - 1; ++ do { ++ if (!strncmp(username, ctl->btmp[n].ut_user, ++ len < UT_NAMESIZE ? len : UT_NAMESIZE)) ++ return ctl->btmp + n; ++ }while (n--); ++ return NULL; ++ ++} ++ ++static int parse_wtmp(struct lslogins_control *ctl, char *path) ++{ ++ int rc = 0; ++ ++ rc = read_utmp(path, &ctl->wtmp_size, &ctl->wtmp); ++ if (rc < 0 && errno != EACCES) ++ err(EXIT_FAILURE, "%s", path); ++ return rc; ++} ++ ++static int parse_btmp(struct lslogins_control *ctl, char *path) ++{ ++ int rc = 0; ++ ++ rc = read_utmp(path, &ctl->btmp_size, &ctl->btmp); ++ if (rc < 0 && errno != EACCES) ++ err(EXIT_FAILURE, "%s", path); ++ return rc; ++} ++ ++static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) ++{ ++ size_t n = 0; ++ ++ *len = 0; ++ *list = NULL; ++ ++ /* first let's get a supp. group count */ ++ getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); ++ if (!*len) ++ return -1; ++ ++ *list = xcalloc(1, *len * sizeof(gid_t)); ++ ++ /* now for the actual list of GIDs */ ++ if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) ++ return -1; ++ ++ /* getgroups also returns the user's primary GID - dispose of it */ ++ while (n < *len) { ++ if ((*list)[n] == pwd->pw_gid) ++ break; ++ ++n; ++ } ++ ++ if (*len) ++ (*list)[n] = (*list)[--(*len)]; ++ return 0; ++} ++ ++static int get_nprocs(const uid_t uid) ++{ ++ int nprocs = 0; ++ pid_t pid; ++ struct proc_processes *proc = proc_open_processes(); ++ ++ proc_processes_filter_by_uid(proc, uid); ++ ++ while (!proc_next_pid(proc, &pid)) ++ ++nprocs; ++ ++ proc_close_processes(proc); ++ return nprocs; ++} ++ ++static int valid_pwd(const char *str) ++{ ++ const char *p; ++ ++ for (p = str; p && *p; p++) ++ if (!isalnum((unsigned int) *p)) ++ return 0; ++ return p > str ? 1 : 0; ++} ++ ++static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const char *username) ++{ ++ struct lslogins_user *user; ++ struct passwd *pwd; ++ struct group *grp; ++ struct spwd *shadow; ++ struct utmp *user_wtmp = NULL, *user_btmp = NULL; ++ int n = 0; ++ time_t time; ++ uid_t uid; ++ errno = 0; ++ ++ pwd = username ? getpwnam(username) : getpwent(); ++ if (!pwd) ++ return NULL; ++ ++ ctl->uid = uid = pwd->pw_uid; ++ ++ /* nfsnobody is an exception to the UID_MAX limit. This is "nobody" on ++ * some systems; the decisive point is the UID - 65534 */ ++ if ((lslogins_flag & F_USRAC) && ++ strcmp("nfsnobody", pwd->pw_name) != 0 && ++ uid != 0) { ++ if (uid < ctl->UID_MIN || uid > ctl->UID_MAX) { ++ errno = EAGAIN; ++ return NULL; ++ } ++ ++ } else if ((lslogins_flag & F_SYSAC) && ++ (uid < ctl->SYS_UID_MIN || uid > ctl->SYS_UID_MAX)) { ++ errno = EAGAIN; ++ return NULL; ++ } ++ ++ user = xcalloc(1, sizeof(struct lslogins_user)); ++ ++ grp = getgrgid(pwd->pw_gid); ++ if (!grp) ++ return NULL; ++ ++ if (ctl->wtmp) ++ user_wtmp = get_last_wtmp(ctl, pwd->pw_name); ++ if (ctl->btmp) ++ user_btmp = get_last_btmp(ctl, pwd->pw_name); ++ ++ lckpwdf(); ++ shadow = getspnam(pwd->pw_name); ++ ulckpwdf(); ++ ++ /* required by tseach() stuff */ ++ user->uid = pwd->pw_uid; ++ ++ while (n < ncolumns) { ++ switch (columns[n++]) { ++ case COL_USER: ++ user->login = xstrdup(pwd->pw_name); ++ break; ++ case COL_UID: ++ user->uid = pwd->pw_uid; ++ break; ++ case COL_GROUP: ++ user->group = xstrdup(grp->gr_name); ++ break; ++ case COL_GID: ++ user->gid = pwd->pw_gid; ++ break; ++ case COL_SGROUPS: ++ case COL_SGIDS: ++ if (get_sgroups(&user->sgroups, &user->nsgroups, pwd)) ++ err(EXIT_FAILURE, _("failed to get supplementary groups")); ++ break; ++ case COL_HOME: ++ user->homedir = xstrdup(pwd->pw_dir); ++ break; ++ case COL_SHELL: ++ user->shell = xstrdup(pwd->pw_shell); ++ break; ++ case COL_GECOS: ++ user->gecos = xstrdup(pwd->pw_gecos); ++ break; ++ case COL_LAST_LOGIN: ++ if (user_wtmp) { ++ time = user_wtmp->ut_tv.tv_sec; ++ user->last_login = make_time(ctl->time_mode, time); ++ } ++ break; ++ case COL_LAST_TTY: ++ if (user_wtmp) ++ user->last_tty = xstrdup(user_wtmp->ut_line); ++ break; ++ case COL_LAST_HOSTNAME: ++ if (user_wtmp) ++ user->last_hostname = xstrdup(user_wtmp->ut_host); ++ break; ++ case COL_FAILED_LOGIN: ++ if (user_btmp) { ++ time = user_btmp->ut_tv.tv_sec; ++ user->failed_login = make_time(ctl->time_mode, time); ++ } ++ break; ++ case COL_FAILED_TTY: ++ if (user_btmp) ++ user->failed_tty = xstrdup(user_btmp->ut_line); ++ break; ++ case COL_HUSH_STATUS: ++ user->hushed = get_hushlogin_status(pwd, 0); ++ if (user->hushed == -1) ++ user->hushed = STATUS_UNKNOWN; ++ break; ++ case COL_PWDEMPTY: ++ if (shadow) { ++ if (!*shadow->sp_pwdp) /* '\0' */ ++ user->pwd_empty = STATUS_TRUE; ++ } else ++ user->pwd_empty = STATUS_UNKNOWN; ++ break; ++ case COL_PWDDENY: ++ if (shadow) { ++ if ((*shadow->sp_pwdp == '!' || ++ *shadow->sp_pwdp == '*') && ++ !valid_pwd(shadow->sp_pwdp + 1)) ++ user->pwd_deny = STATUS_TRUE; ++ } else ++ user->pwd_deny = STATUS_UNKNOWN; ++ break; ++ ++ case COL_PWDLOCK: ++ if (shadow) { ++ if (*shadow->sp_pwdp == '!' && valid_pwd(shadow->sp_pwdp + 1)) ++ user->pwd_lock = STATUS_TRUE; ++ } else ++ user->pwd_lock = STATUS_UNKNOWN; ++ break; ++ case COL_NOLOGIN: ++ if (strstr(pwd->pw_shell, "nologin")) ++ user->nologin = 1; ++ else if (pwd->pw_uid) ++ user->nologin = access("/etc/nologin", F_OK) == 0 || ++ access("/var/run/nologin", F_OK) == 0; ++ break; ++ case COL_PWD_WARN: ++ if (shadow && shadow->sp_warn >= 0) ++ xasprintf(&user->pwd_warn, "%ld", shadow->sp_warn); ++ break; ++ case COL_PWD_EXPIR: ++ if (shadow && shadow->sp_expire >= 0) ++ user->pwd_expire = make_time(TIME_SHORT, ++ shadow->sp_expire * 86400); ++ break; ++ case COL_PWD_CTIME: ++ /* sp_lstchg is specified in days, showing hours ++ * (especially in non-GMT timezones) would only serve ++ * to confuse */ ++ if (shadow) ++ user->pwd_ctime = make_time(TIME_SHORT, ++ shadow->sp_lstchg * 86400); ++ break; ++ case COL_PWD_CTIME_MIN: ++ if (shadow && shadow->sp_min > 0) ++ xasprintf(&user->pwd_ctime_min, "%ld", shadow->sp_min); ++ break; ++ case COL_PWD_CTIME_MAX: ++ if (shadow && shadow->sp_max > 0) ++ xasprintf(&user->pwd_ctime_max, "%ld", shadow->sp_max); ++ break; ++ case COL_SELINUX: ++#ifdef HAVE_LIBSELINUX ++ if (ctl->selinux_enabled) { ++ /* typedefs and pointers are pure evil */ ++ security_context_t con = NULL; ++ if (getcon(&con) == 0) ++ user->context = con; ++ } ++#endif ++ break; ++ case COL_NPROCS: ++ xasprintf(&user->nprocs, "%d", get_nprocs(pwd->pw_uid)); ++ break; ++ default: ++ /* something went very wrong here */ ++ err(EXIT_FAILURE, "fatal: unknown error"); ++ break; ++ } ++ } ++ ++ return user; ++} ++ ++/* some UNIX implementations set errno iff a passwd/grp/... ++ * entry was not found. The original UNIX logins(1) utility always ++ * ignores invalid login/group names, so we're going to as well.*/ ++#define IS_REAL_ERRNO(e) !((e) == ENOENT || (e) == ESRCH || \ ++ (e) == EBADF || (e) == EPERM || (e) == EAGAIN) ++ ++/* get a definitive list of users we want info about... */ ++ ++static int str_to_uint(char *s, unsigned int *ul) ++{ ++ char *end; ++ if (!s || !*s) ++ return -1; ++ *ul = strtoul(s, &end, 0); ++ if (!*end) ++ return 0; ++ return 1; ++} ++ ++static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups) ++{ ++ char *u, *g; ++ size_t i = 0, n = 0, *arsiz; ++ struct group *grp; ++ struct passwd *pwd; ++ char ***ar; ++ uid_t uid; ++ gid_t gid; ++ ++ ar = &ctl->ulist; ++ arsiz = &ctl->ulsiz; ++ ++ /* an arbitrary starting value */ ++ *arsiz = 32; ++ *ar = xcalloc(1, sizeof(char *) * (*arsiz)); ++ ++ if (logins) { ++ while ((u = strtok(logins, ","))) { ++ logins = NULL; ++ ++ /* user specified by UID? */ ++ if (!str_to_uint(u, &uid)) { ++ pwd = getpwuid(uid); ++ if (!pwd) ++ continue; ++ u = pwd->pw_name; ++ } ++ (*ar)[i++] = xstrdup(u); ++ ++ if (i == *arsiz) ++ *ar = xrealloc(*ar, sizeof(char *) * (*arsiz += 32)); ++ } ++ ctl->ulist_on = 1; ++ } ++ ++ if (groups) { ++ /* FIXME: this might lead to duplicit entries, although not visible ++ * in output, crunching a user's info multiple times is very redundant */ ++ while ((g = strtok(groups, ","))) { ++ n = 0; ++ groups = NULL; ++ ++ /* user specified by GID? */ ++ if (!str_to_uint(g, &gid)) ++ grp = getgrgid(gid); ++ else ++ grp = getgrnam(g); ++ ++ if (!grp) ++ continue; ++ ++ while ((u = grp->gr_mem[n++])) { ++ (*ar)[i++] = xstrdup(u); ++ ++ if (i == *arsiz) ++ *ar = xrealloc(*ar, sizeof(char *) * (*arsiz += 32)); ++ } ++ } ++ ctl->ulist_on = 1; ++ } ++ *arsiz = i; ++ return 0; ++} ++ ++static void free_ctl(struct lslogins_control *ctl) ++{ ++ size_t n = 0; ++ ++ free(ctl->wtmp); ++ free(ctl->btmp); ++ ++ while (n < ctl->ulsiz) ++ free(ctl->ulist[n++]); ++ ++ free(ctl->ulist); ++ free(ctl); ++} ++ ++static struct lslogins_user *get_next_user(struct lslogins_control *ctl) ++{ ++ struct lslogins_user *u; ++ errno = 0; ++ while (!(u = get_user_info(ctl, NULL))) { ++ /* no "false" errno-s here, iff we're unable to ++ * get a valid user entry for any reason, quit */ ++ if (errno == EAGAIN) ++ continue; ++ return NULL; ++ } ++ return u; ++} ++ ++static int get_user(struct lslogins_control *ctl, struct lslogins_user **user, ++ const char *username) ++{ ++ *user = get_user_info(ctl, username); ++ if (!*user && errno) ++ if (IS_REAL_ERRNO(errno)) ++ return -1; ++ return 0; ++} ++ ++static int cmp_uid(const void *a, const void *b) ++{ ++ uid_t x = ((struct lslogins_user *)a)->uid; ++ uid_t z = ((struct lslogins_user *)b)->uid; ++ return x > z ? 1 : (x < z ? -1 : 0); ++} ++ ++static int create_usertree(struct lslogins_control *ctl) ++{ ++ struct lslogins_user *user = NULL; ++ size_t n = 0; ++ ++ if (ctl->ulist_on) { ++ while (n < ctl->ulsiz) { ++ if (get_user(ctl, &user, ctl->ulist[n])) ++ return -1; ++ if (user) /* otherwise an invalid user name has probably been given */ ++ tsearch(user, &ctl->usertree, cmp_uid); ++ ++n; ++ } ++ } else { ++ while ((user = get_next_user(ctl))) ++ tsearch(user, &ctl->usertree, cmp_uid); ++ } ++ return 0; ++} ++ ++static struct libscols_table *setup_table(struct lslogins_control *ctl) ++{ ++ struct libscols_table *tb = scols_new_table(); ++ int n = 0; ++ ++ if (!tb) ++ errx(EXIT_FAILURE, _("failed to initialize output table")); ++ if (ctl->noheadings) ++ scols_table_enable_noheadings(tb, 1); ++ ++ switch(outmode) { ++ case OUT_COLON: ++ scols_table_enable_raw(tb, 1); ++ scols_table_set_column_separator(tb, ":"); ++ break; ++ case OUT_NEWLINE: ++ scols_table_set_column_separator(tb, "\n"); ++ /* fallthrough */ ++ case OUT_EXPORT: ++ scols_table_enable_export(tb, 1); ++ break; ++ case OUT_NUL: ++ scols_table_set_line_separator(tb, "\0"); ++ /* fallthrough */ ++ case OUT_RAW: ++ scols_table_enable_raw(tb, 1); ++ break; ++ case OUT_PRETTY: ++ scols_table_enable_noheadings(tb, 1); ++ default: ++ break; ++ } ++ ++ while (n < ncolumns) { ++ int flags = coldescs[columns[n]].flag; ++ ++ if (ctl->notrunc) ++ flags &= ~SCOLS_FL_TRUNC; ++ ++ if (!scols_table_new_column(tb, ++ coldescs[columns[n]].name, ++ coldescs[columns[n]].whint, ++ flags)) ++ goto fail; ++ ++n; ++ } ++ ++ return tb; ++fail: ++ scols_unref_table(tb); ++ return NULL; ++} ++ ++static void fill_table(const void *u, const VISIT which, const int depth __attribute__((unused))) ++{ ++ struct libscols_line *ln; ++ struct lslogins_user *user = *(struct lslogins_user **)u; ++ int n = 0; ++ ++ if (which == preorder || which == endorder) ++ return; ++ ++ ln = scols_table_new_line(tb, NULL); ++ while (n < ncolumns) { ++ int rc = 0; ++ ++ switch (columns[n]) { ++ case COL_USER: ++ rc = scols_line_set_data(ln, n, user->login); ++ break; ++ case COL_UID: ++ rc = scols_line_refer_data(ln, n, uidtostr(user->uid)); ++ break; ++ case COL_PWDEMPTY: ++ rc = scols_line_set_data(ln, n, get_status(user->pwd_empty)); ++ break; ++ case COL_NOLOGIN: ++ rc = scols_line_set_data(ln, n, get_status(user->nologin)); ++ break; ++ case COL_PWDLOCK: ++ rc = scols_line_set_data(ln, n, get_status(user->pwd_lock)); ++ break; ++ case COL_PWDDENY: ++ rc = scols_line_set_data(ln, n, get_status(user->pwd_deny)); ++ break; ++ case COL_GROUP: ++ rc = scols_line_set_data(ln, n, user->group); ++ break; ++ case COL_GID: ++ rc = scols_line_refer_data(ln, n, gidtostr(user->gid)); ++ break; ++ case COL_SGROUPS: ++ rc = scols_line_refer_data(ln, n, ++ build_sgroups_string(user->sgroups, ++ user->nsgroups, ++ TRUE)); ++ break; ++ case COL_SGIDS: ++ rc = scols_line_refer_data(ln, n, ++ build_sgroups_string(user->sgroups, ++ user->nsgroups, ++ FALSE)); ++ break; ++ case COL_HOME: ++ rc = scols_line_set_data(ln, n, user->homedir); ++ break; ++ case COL_SHELL: ++ rc = scols_line_set_data(ln, n, user->shell); ++ break; ++ case COL_GECOS: ++ rc = scols_line_set_data(ln, n, user->gecos); ++ break; ++ case COL_LAST_LOGIN: ++ rc = scols_line_set_data(ln, n, user->last_login); ++ break; ++ case COL_LAST_TTY: ++ rc = scols_line_set_data(ln, n, user->last_tty); ++ break; ++ case COL_LAST_HOSTNAME: ++ rc = scols_line_set_data(ln, n, user->last_hostname); ++ break; ++ case COL_FAILED_LOGIN: ++ rc = scols_line_set_data(ln, n, user->failed_login); ++ break; ++ case COL_FAILED_TTY: ++ rc = scols_line_set_data(ln, n, user->failed_tty); ++ break; ++ case COL_HUSH_STATUS: ++ rc = scols_line_set_data(ln, n, get_status(user->hushed)); ++ break; ++ case COL_PWD_WARN: ++ rc = scols_line_set_data(ln, n, user->pwd_warn); ++ break; ++ case COL_PWD_EXPIR: ++ rc = scols_line_set_data(ln, n, user->pwd_expire); ++ break; ++ case COL_PWD_CTIME: ++ rc = scols_line_set_data(ln, n, user->pwd_ctime); ++ break; ++ case COL_PWD_CTIME_MIN: ++ rc = scols_line_set_data(ln, n, user->pwd_ctime_min); ++ break; ++ case COL_PWD_CTIME_MAX: ++ rc = scols_line_set_data(ln, n, user->pwd_ctime_max); ++ break; ++ case COL_SELINUX: ++#ifdef HAVE_LIBSELINUX ++ rc = scols_line_set_data(ln, n, user->context); ++#endif ++ break; ++ case COL_NPROCS: ++ rc = scols_line_set_data(ln, n, user->nprocs); ++ break; ++ default: ++ /* something went very wrong here */ ++ err(EXIT_FAILURE, _("internal error: unknown column")); ++ } ++ ++ if (rc != 0) ++ err(EXIT_FAILURE, _("failed to set data")); ++ ++n; ++ } ++ return; ++} ++#ifdef HAVE_LIBSYSTEMD ++static void print_journal_tail(const char *journal_path, uid_t uid, size_t len) ++{ ++ sd_journal *j; ++ char *match, *buf; ++ uint64_t x; ++ time_t t; ++ const char *identifier, *pid, *message; ++ size_t identifier_len, pid_len, message_len; ++ ++ if (journal_path) ++ sd_journal_open_directory(&j, journal_path, 0); ++ else ++ sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); ++ ++ buf = xmalloc(sizeof(char) * 16); ++ xasprintf(&match, "_UID=%d", uid); ++ ++ sd_journal_add_match(j, match, 0); ++ sd_journal_seek_tail(j); ++ sd_journal_previous_skip(j, len); ++ ++ do { ++ if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER", ++ (const void **) &identifier, &identifier_len)) ++ return; ++ if (0 > sd_journal_get_data(j, "_PID", ++ (const void **) &pid, &pid_len)) ++ return; ++ if (0 > sd_journal_get_data(j, "MESSAGE", ++ (const void **) &message, &message_len)) ++ return; ++ ++ sd_journal_get_realtime_usec(j, &x); ++ t = x / 1000000; ++ strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t)); ++ ++ fprintf(stdout, "%s", buf); ++ ++ identifier = strchr(identifier, '=') + 1; ++ pid = strchr(pid, '=') + 1 ; ++ message = strchr(message, '=') + 1; ++ ++ fprintf(stdout, " %s", identifier); ++ fprintf(stdout, "[%s]:", pid); ++ fprintf(stdout, "%s\n", message); ++ } while (sd_journal_next(j)); ++ ++ free(buf); ++ free(match); ++ sd_journal_flush_matches(j); ++ sd_journal_close(j); ++} ++#endif ++ ++static int print_pretty(struct libscols_table *tb) ++{ ++ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); ++ struct libscols_column *col; ++ struct libscols_cell *data; ++ struct libscols_line *ln; ++ const char *hstr, *dstr; ++ int n = 0; ++ ++ ln = scols_table_get_line(tb, 0); ++ while (!scols_table_next_column(tb, itr, &col)) { ++ ++ data = scols_line_get_cell(ln, n); ++ ++ hstr = _(coldescs[columns[n]].pretty_name); ++ dstr = scols_cell_get_data(data); ++ ++ if (dstr) ++ printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr); ++ ++n; ++ } ++ ++ scols_free_iter(itr); ++ return 0; ++ ++} ++ ++static int print_user_table(struct lslogins_control *ctl) ++{ ++ tb = setup_table(ctl); ++ if (!tb) ++ return -1; ++ ++ twalk(ctl->usertree, fill_table); ++ if (outmode == OUT_PRETTY) { ++ print_pretty(tb); ++#ifdef HAVE_LIBSYSTEMD ++ fprintf(stdout, _("\nLast logs:\n")); ++ print_journal_tail(ctl->journal_path, ctl->uid, 3); ++ fputc('\n', stdout); ++#endif ++ } else ++ scols_print_table(tb); ++ return 0; ++} ++ ++static void free_user(void *f) ++{ ++ struct lslogins_user *u = f; ++ free(u->login); ++ free(u->group); ++ free(u->gecos); ++ free(u->sgroups); ++ free(u->pwd_ctime); ++ free(u->pwd_warn); ++ free(u->pwd_ctime_min); ++ free(u->pwd_ctime_max); ++ free(u->last_login); ++ free(u->last_tty); ++ free(u->last_hostname); ++ free(u->failed_login); ++ free(u->failed_tty); ++ free(u->homedir); ++ free(u->shell); ++ free(u->pwd_status); ++#ifdef HAVE_LIBSELINUX ++ freecon(u->context); ++#endif ++ free(u); ++} ++ ++struct lslogins_timefmt { ++ const char *name; ++ int val; ++}; ++ ++static struct lslogins_timefmt timefmts[] = { ++ { "short", TIME_SHORT }, ++ { "full", TIME_FULL }, ++ { "iso", TIME_ISO }, ++}; ++ ++static void __attribute__((__noreturn__)) usage(FILE *out) ++{ ++ size_t i; ++ ++ fputs(USAGE_HEADER, out); ++ fprintf(out, _(" %s [options]\n"), program_invocation_short_name); ++ ++ fputs(USAGE_OPTIONS, out); ++ fputs(_(" -a, --acc-expiration display info about passwords expiration\n"), out); ++ fputs(_(" -c, --colon-separate display data in a format similar to /etc/passwd\n"), out); ++ fputs(_(" -e, --export display in an export-able output format\n"), out); ++ fputs(_(" -f, --failed display data about the users' last failed logins\n"), out); ++ fputs(_(" -G, --groups-info display information about groups\n"), out); ++ fputs(_(" -g, --groups= display users belonging to a group in \n"), out); ++ fputs(_(" -L, --last show info about the users' last login sessions\n"), out); ++ fputs(_(" -l, --logins= display only users from \n"), out); ++ fputs(_(" -m, --supp-groups display supplementary groups as well\n"), out); ++ fputs(_(" -n, --newline display each piece of information on a new line\n"), out); ++ fputs(_(" --noheadings don't print headings\n"), out); ++ fputs(_(" --notruncate don't truncate output\n"), out); ++ fputs(_(" -o, --output[=] define the columns to output\n"), out); ++ fputs(_(" -p, --pwd display information related to login by password.\n"), out); ++ fputs(_(" -r, --raw display in raw mode\n"), out); ++ fputs(_(" -s, --system-accs display system accounts\n"), out); ++ fputs(_(" --time-format= display dates in short, full or iso format\n"), out); ++ fputs(_(" -u, --user-accs display user accounts\n"), out); ++ fputs(_(" -Z, --context display SELinux contexts\n"), out); ++ fputs(_(" -z, --print0 delimit user entries with a nul character\n"), out); ++ fputs(_(" --wtmp-file set an alternate path for wtmp\n"), out); ++ fputs(_(" --btmp-file set an alternate path for btmp\n"), out); ++ fputs(USAGE_SEPARATOR, out); ++ fputs(USAGE_HELP, out); ++ fputs(USAGE_VERSION, out); ++ ++ fprintf(out, _("\nAvailable columns:\n")); ++ ++ for (i = 0; i < ARRAY_SIZE(coldescs); i++) ++ fprintf(out, " %14s %s\n", coldescs[i].name, ++ _(coldescs[i].help)); ++ ++ fprintf(out, _("\nFor more details see lslogins(1).\n")); ++ ++ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int c, opt_o = 0; ++ char *logins = NULL, *groups = NULL; ++ char *path_wtmp = _PATH_WTMP, *path_btmp = _PATH_BTMP; ++ struct lslogins_control *ctl = xcalloc(1, sizeof(struct lslogins_control)); ++ size_t i; ++ ++ /* long only options. */ ++ enum { ++ OPT_VER = CHAR_MAX + 1, ++ OPT_WTMP, ++ OPT_BTMP, ++ OPT_NOTRUNC, ++ OPT_NOHEAD, ++ OPT_TIME_FMT, ++ }; ++ ++ static const struct option longopts[] = { ++ { "acc-expiration", no_argument, 0, 'a' }, ++ { "colon-separate", no_argument, 0, 'c' }, ++ { "export", no_argument, 0, 'e' }, ++ { "failed", no_argument, 0, 'f' }, ++ { "groups", required_argument, 0, 'g' }, ++ { "help", no_argument, 0, 'h' }, ++ { "logins", required_argument, 0, 'l' }, ++ { "supp-groups", no_argument, 0, 'G' }, ++ { "newline", no_argument, 0, 'n' }, ++ { "notruncate", no_argument, 0, OPT_NOTRUNC }, ++ { "noheadings", no_argument, 0, OPT_NOHEAD }, ++ { "output", required_argument, 0, 'o' }, ++ { "last", no_argument, 0, 'L', }, ++ { "raw", no_argument, 0, 'r' }, ++ { "system-accs", no_argument, 0, 's' }, ++ { "time-format", required_argument, 0, OPT_TIME_FMT }, ++ { "user-accs", no_argument, 0, 'u' }, ++ { "version", no_argument, 0, 'V' }, ++ { "pwd", no_argument, 0, 'p' }, ++ { "print0", no_argument, 0, 'z' }, ++ { "wtmp-file", required_argument, 0, OPT_WTMP }, ++ { "btmp-file", required_argument, 0, OPT_BTMP }, ++#ifdef HAVE_LIBSELINUX ++ { "context", no_argument, 0, 'Z' }, ++#endif ++ { NULL, 0, 0, 0 } ++ }; ++ ++ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ ++ { 'G', 'o' }, ++ { 'L', 'o' }, ++ { 'Z', 'o' }, ++ { 'a', 'o' }, ++ { 'c','n','r','z' }, ++ { 'o', 'p' }, ++ { 0 } ++ }; ++ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; ++ ++ setlocale(LC_ALL, ""); ++ bindtextdomain(PACKAGE, LOCALEDIR); ++ textdomain(PACKAGE); ++ atexit(close_stdout); ++ ++ ctl->time_mode = TIME_SHORT; ++ ++ /* very basic default */ ++ add_column(columns, ncolumns++, COL_UID); ++ add_column(columns, ncolumns++, COL_USER); ++ ++ while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ", ++ longopts, NULL)) != -1) { ++ ++ err_exclusive_options(c, longopts, excl, excl_st); ++ ++ switch (c) { ++ case 'a': ++ add_column(columns, ncolumns++, COL_PWD_WARN); ++ add_column(columns, ncolumns++, COL_PWD_CTIME_MIN); ++ add_column(columns, ncolumns++, COL_PWD_CTIME_MAX); ++ add_column(columns, ncolumns++, COL_PWD_CTIME); ++ add_column(columns, ncolumns++, COL_PWD_EXPIR); ++ break; ++ case 'c': ++ outmode = OUT_COLON; ++ break; ++ case 'e': ++ outmode = OUT_EXPORT; ++ break; ++ case 'f': ++ add_column(columns, ncolumns++, COL_FAILED_LOGIN); ++ add_column(columns, ncolumns++, COL_FAILED_TTY); ++ break; ++ case 'G': ++ add_column(columns, ncolumns++, COL_GID); ++ add_column(columns, ncolumns++, COL_GROUP); ++ add_column(columns, ncolumns++, COL_SGIDS); ++ add_column(columns, ncolumns++, COL_SGROUPS); ++ break; ++ case 'g': ++ groups = optarg; ++ break; ++ case 'h': ++ usage(stdout); ++ break; ++ case 'L': ++ add_column(columns, ncolumns++, COL_LAST_TTY); ++ add_column(columns, ncolumns++, COL_LAST_HOSTNAME); ++ add_column(columns, ncolumns++, COL_LAST_LOGIN); ++ break; ++ case 'l': ++ logins = optarg; ++ break; ++ case 'n': ++ outmode = OUT_NEWLINE; ++ break; ++ case 'o': ++ if (optarg) { ++ if (*optarg == '=') ++ optarg++; ++ ncolumns = string_to_idarray(optarg, ++ columns, ARRAY_SIZE(columns), ++ column_name_to_id); ++ if (ncolumns < 0) ++ return EXIT_FAILURE; ++ } ++ opt_o = 1; ++ break; ++ case 'r': ++ outmode = OUT_RAW; ++ break; ++ case 's': ++ ctl->SYS_UID_MIN = getlogindefs_num("SYS_UID_MIN", UL_SYS_UID_MIN); ++ ctl->SYS_UID_MAX = getlogindefs_num("SYS_UID_MAX", UL_SYS_UID_MAX); ++ lslogins_flag |= F_SYSAC; ++ break; ++ case 'u': ++ ctl->UID_MIN = getlogindefs_num("UID_MIN", UL_UID_MIN); ++ ctl->UID_MAX = getlogindefs_num("UID_MAX", UL_UID_MAX); ++ lslogins_flag |= F_USRAC; ++ break; ++ case 'p': ++ add_column(columns, ncolumns++, COL_PWDEMPTY); ++ add_column(columns, ncolumns++, COL_PWDLOCK); ++ add_column(columns, ncolumns++, COL_PWDDENY); ++ add_column(columns, ncolumns++, COL_NOLOGIN); ++ add_column(columns, ncolumns++, COL_HUSH_STATUS); ++ break; ++ case 'z': ++ outmode = OUT_NUL; ++ break; ++ case OPT_WTMP: ++ path_wtmp = optarg; ++ break; ++ case OPT_BTMP: ++ path_btmp = optarg; ++ break; ++ case OPT_NOTRUNC: ++ ctl->notrunc = 1; ++ break; ++ case OPT_NOHEAD: ++ ctl->noheadings = 1; ++ break; ++ case OPT_TIME_FMT: ++ { ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(timefmts); i++) { ++ if (strcmp(timefmts[i].name, optarg) == 0) { ++ ctl->time_mode = timefmts[i].val; ++ break; ++ } ++ } ++ if (ctl->time_mode == TIME_INVALID) ++ usage(stderr); ++ } ++ break; ++ case 'V': ++ printf(UTIL_LINUX_VERSION); ++ return EXIT_SUCCESS; ++ case 'Z': ++ { ++#ifdef HAVE_LIBSELINUX ++ int sl = is_selinux_enabled(); ++ if (sl < 0) ++ warn(_("failed to request selinux state")); ++ else ++ ctl->selinux_enabled = sl == 1; ++#endif ++ add_column(columns, ncolumns++, COL_SELINUX); ++ break; ++ } ++ default: ++ usage(stderr); ++ } ++ } ++ ++ if (argc - optind == 1) { ++ if (strchr(argv[optind], ',')) ++ errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users.")); ++ logins = argv[optind]; ++ outmode = OUT_PRETTY; ++ } else if (argc != optind) ++ usage(stderr); ++ ++ scols_init_debug(0); ++ ++ /* lslogins -u -s == lslogins */ ++ if (lslogins_flag & F_USRAC && lslogins_flag & F_SYSAC) ++ lslogins_flag &= ~(F_USRAC | F_SYSAC); ++ ++ if (outmode == OUT_PRETTY && !opt_o) { ++ /* all columns for lslogins */ ++ for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++) ++ columns[ncolumns++] = i; ++ ++ } else if (ncolumns == 2 && !opt_o) { ++ /* default colummns */ ++ add_column(columns, ncolumns++, COL_NPROCS); ++ add_column(columns, ncolumns++, COL_PWDLOCK); ++ add_column(columns, ncolumns++, COL_PWDDENY); ++ add_column(columns, ncolumns++, COL_LAST_LOGIN); ++ add_column(columns, ncolumns++, COL_GECOS); ++ } ++ ++ if (require_wtmp()) ++ parse_wtmp(ctl, path_wtmp); ++ if (require_btmp()) ++ parse_btmp(ctl, path_btmp); ++ ++ if (logins || groups) ++ get_ulist(ctl, logins, groups); ++ ++ if (create_usertree(ctl)) ++ return EXIT_FAILURE; ++ ++ print_user_table(ctl); ++ ++ scols_unref_table(tb); ++ tdestroy(ctl->usertree, free_user); ++ free_ctl(ctl); ++ ++ return EXIT_SUCCESS; ++} +diff -up util-linux-2.23.2/login-utils/Makemodule.am.kzak util-linux-2.23.2/login-utils/Makemodule.am +--- util-linux-2.23.2/login-utils/Makemodule.am.kzak 2013-06-13 09:46:10.441650801 +0200 ++++ util-linux-2.23.2/login-utils/Makemodule.am 2014-12-12 15:28:30.576177139 +0100 +@@ -145,6 +145,25 @@ endif + endif # BUILD_NEWGRP + + ++if BUILD_LSLOGINS ++usrbin_exec_PROGRAMS += lslogins ++dist_man_MANS += login-utils/lslogins.1 ++lslogins_SOURCES = \ ++ login-utils/lslogins.c \ ++ login-utils/logindefs.c \ ++ login-utils/logindefs.h ++lslogins_LDADD = $(LDADD) libcommon.la libsmartcols.la ++lslogins_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) ++if HAVE_SELINUX ++lslogins_LDADD += -lselinux ++endif ++if HAVE_SYSTEMD ++lslogins_LDADD += $(SYSTEMD_LIBS) $(SYSTEMD_JOURNAL_LIBS) ++lslogins_CFLAGS += $(SYSTEMD_CFLAGS) $(SYSTEMD_JOURNAL_CFLAGS) ++endif ++endif # BUILD_LSLOGINS ++ ++ + if BUILD_VIPW + usrsbin_exec_PROGRAMS += vipw + dist_man_MANS += \ diff --git a/SOURCES/2.26-mount-man-move.patch b/SOURCES/2.26-mount-man-move.patch new file mode 100644 index 00000000..833e1b21 --- /dev/null +++ b/SOURCES/2.26-mount-man-move.patch @@ -0,0 +1,11 @@ +diff -up util-linux-2.23.2/sys-utils/mount.8.kzak util-linux-2.23.2/sys-utils/mount.8 +--- util-linux-2.23.2/sys-utils/mount.8.kzak 2014-09-25 11:03:25.492822164 +0200 ++++ util-linux-2.23.2/sys-utils/mount.8 2014-09-25 11:04:00.102152375 +0200 +@@ -451,7 +451,7 @@ has to be a mountpoint. + + Note that moving a mount residing under a shared mount is invalid and + unsupported. Use +-.B findmnt -o TARGET,PROPAGATION /dir ++.B findmnt -o TARGET,PROPAGATION + to see the current propagation flags. + .RE diff --git a/SOURCES/2.26-raw-stat.patch b/SOURCES/2.26-raw-stat.patch new file mode 100644 index 00000000..f413b658 --- /dev/null +++ b/SOURCES/2.26-raw-stat.patch @@ -0,0 +1,12 @@ +diff -up util-linux-2.23.2/disk-utils/raw.c.kzak util-linux-2.23.2/disk-utils/raw.c +--- util-linux-2.23.2/disk-utils/raw.c.kzak 2013-06-13 09:46:10.382650297 +0200 ++++ util-linux-2.23.2/disk-utils/raw.c 2015-01-13 14:51:24.877755962 +0100 +@@ -220,7 +220,7 @@ static int query(int minor_raw, const ch + if (raw_name) { + struct stat statbuf; + +- if (!stat(raw_name, &statbuf)) ++ if (stat(raw_name, &statbuf) != 0) + err(EXIT_RAW_ACCESS, + _("Cannot locate raw device '%s'"), raw_name); + if (!S_ISCHR(statbuf.st_mode)) diff --git a/SOURCES/2.26-su-coredump-message.patch b/SOURCES/2.26-su-coredump-message.patch new file mode 100644 index 00000000..1facc2a7 --- /dev/null +++ b/SOURCES/2.26-su-coredump-message.patch @@ -0,0 +1,17 @@ +diff -up util-linux-2.23.2/login-utils/su-common.c.kzak util-linux-2.23.2/login-utils/su-common.c +--- util-linux-2.23.2/login-utils/su-common.c.kzak 2015-06-24 11:14:25.102395082 +0200 ++++ util-linux-2.23.2/login-utils/su-common.c 2015-06-24 11:22:20.472859684 +0200 +@@ -359,10 +359,9 @@ create_watching_parent (void) + if (pid != (pid_t)-1) + if (WIFSIGNALED (status)) + { +- status = WTERMSIG (status) + 128; +- if (WCOREDUMP (status)) +- fprintf (stderr, _("%s (core dumped)\n"), +- strsignal (WTERMSIG (status))); ++ fprintf (stderr, "%s%s\n", strsignal (WTERMSIG (status)), ++ WCOREDUMP (status) ? _(" (core dumped)") : ""); ++ status = WTERMSIG (status) + 128; + } + else + status = WEXITSTATUS (status); diff --git a/SOURCES/2.26-unshare-rebase.patch b/SOURCES/2.26-unshare-rebase.patch new file mode 100644 index 00000000..81b93b5d --- /dev/null +++ b/SOURCES/2.26-unshare-rebase.patch @@ -0,0 +1,757 @@ +diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h +--- util-linux-2.23.2/include/pathnames.h.kzak 2015-06-26 10:00:19.111877564 +0200 ++++ util-linux-2.23.2/include/pathnames.h 2015-06-26 10:00:51.623630869 +0200 +@@ -85,6 +85,10 @@ + #define _PATH_PROC_LOCKS "/proc/locks" + #define _PATH_PROC_CDROMINFO "/proc/sys/dev/cdrom/info" + ++#define _PATH_PROC_UIDMAP "/proc/self/uid_map" ++#define _PATH_PROC_GIDMAP "/proc/self/gid_map" ++#define _PATH_PROC_SETGROUPS "/proc/self/setgroups" ++ + #define _PATH_PROC_ATTR_CURRENT "/proc/self/attr/current" + #define _PATH_PROC_ATTR_EXEC "/proc/self/attr/exec" + #define _PATH_PROC_CAPLASTCAP "/proc/sys/kernel/cap_last_cap" +diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am +diff -up util-linux-2.23.2/sys-utils/nsenter.1.kzak util-linux-2.23.2/sys-utils/nsenter.1 +--- util-linux-2.23.2/sys-utils/nsenter.1.kzak 2015-06-26 09:58:39.468633643 +0200 ++++ util-linux-2.23.2/sys-utils/nsenter.1 2015-06-26 09:58:51.672541041 +0200 +@@ -1,44 +1,45 @@ +-.TH NSENTER 1 "January 2013" "util-linux" "User Commands" ++.TH NSENTER 1 "June 2013" "util-linux" "User Commands" + .SH NAME + nsenter \- run program with namespaces of other processes + .SH SYNOPSIS + .B nsenter +-.RI [ options ] +-.RI [ program ] +-.RI [ arguments ] ++[options] ++.RI [ program ++.RI [ arguments ]] + .SH DESCRIPTION + Enters the namespaces of one or more other processes and then executes the specified + program. Enterable namespaces are: + .TP + .B mount namespace +-mounting and unmounting filesystems will not affect rest of the system ++Mounting and unmounting filesystems will not affect the rest of the system + .RB ( CLONE_\:NEWNS +-flag), except for filesystems which are explicitly marked as shared (by mount +---make-\:shared). See /proc\:/self\:/mountinfo for the shared flag. ++flag), except for filesystems which are explicitly marked as shared (with ++\fBmount --make-\:shared\fP; see \fI/proc\:/self\:/mountinfo\fP for the ++\fBshared\fP flag). + .TP + .B UTS namespace +-setting hostname, domainname will not affect rest of the system ++Setting hostname or domainname will not affect the rest of the system. + .RB ( CLONE_\:NEWUTS +-flag). ++flag) + .TP + .B IPC namespace +-process will have independent namespace for System V message queues, semaphore +-sets and shared memory segments ++The process will have an independent namespace for System V message queues, ++semaphore sets and shared memory segments. + .RB ( CLONE_\:NEWIPC +-flag). ++flag) + .TP + .B network namespace +-process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall +-rules, the ++The process will have independent IPv4 and IPv6 stacks, IP routing tables, ++firewall rules, the + .I /proc\:/net + and + .I /sys\:/class\:/net +-directory trees, sockets etc. ++directory trees, sockets, etc. + .RB ( CLONE_\:NEWNET +-flag). ++flag) + .TP + .B PID namespace +-children will have a set of PID to process mappings separate from the ++Children will have a set of PID to process mappings separate from the + .B nsenter + process + .RB ( CLONE_\:NEWPID +@@ -46,18 +47,18 @@ flag). + .B nsenter + will fork by default if changing the PID namespace, so that the new program + and its children share the same PID namespace and are visible to each other. +-If \-\-no\-fork is used, the new program will be exec'ed without forking. +-.PP +-See the +-.BR clone (2) +-for exact semantics of the flags. ++If \fB\-\-no\-fork\fP is used, the new program will be exec'ed without forking. + .TP +-If program is not given, run ``${SHELL}'' (default: /bin\:/sh). ++.B user namespace ++The process will have a distinct set of UIDs, GIDs and capabilities. ++.RB ( CLONE_\:NEWUSER ++flag) ++.TP ++See \fBclone\fP(2) for the exact semantics of the flags. ++.TP ++If \fIprogram\fP is not given, then ``${SHELL}'' is run (default: /bin\:/sh). + + .SH OPTIONS +-Argument with square brakets, such as [\fIfile\fR], means optional argument. +-Command line syntax to specify optional argument \-\-mount=/path\:/to\:/file. +-Please notice the equals sign. + .TP + \fB\-t\fR, \fB\-\-target\fR \fIpid\fP + Specify a target process to get contexts from. The paths to the contexts +@@ -83,6 +84,9 @@ the network namespace + /proc/\fIpid\fR/ns/pid + the PID namespace + .TP ++/proc/\fIpid\fR/ns/user ++the user namespace ++.TP + /proc/\fIpid\fR/root + the root directory + .TP +@@ -91,51 +95,71 @@ the working directory respectively + .PD + .RE + .TP +-\fB\-m\fR, \fB\-\-mount\fR [\fIfile\fR] +-Enter the mount namespace. If no file is specified enter the mount namespace +-of the target process. If file is specified enter the mount namespace ++\fB\-m\fR, \fB\-\-mount\fR[=\fIfile\fR] ++Enter the mount namespace. If no file is specified, enter the mount namespace ++of the target process. If file is specified, enter the mount namespace + specified by file. + .TP +-\fB\-u\fR, \fB\-\-uts\fR [\fIfile\fR] +-Enter the UTS namespace. If no file is specified enter the UTS namespace of +-the target process. If file is specified enter the UTS namespace specified by ++\fB\-u\fR, \fB\-\-uts\fR[=\fIfile\fR] ++Enter the UTS namespace. If no file is specified, enter the UTS namespace of ++the target process. If file is specified, enter the UTS namespace specified by + file. + .TP +-\fB\-i\fR, \fB\-\-ipc\fR [\fIfile\fR] +-Enter the IPC namespace. If no file is specified enter the IPC namespace of +-the target process. If file is specified enter the IPC namespace specified by ++\fB\-i\fR, \fB\-\-ipc\fR[=\fIfile\fR] ++Enter the IPC namespace. If no file is specified, enter the IPC namespace of ++the target process. If file is specified, enter the IPC namespace specified by + file. + .TP +-\fB\-n\fR, \fB\-\-net\fR [\fIfile\fR] +-Enter the network namespace. If no file is specified enter the network +-namespace of the target process. If file is specified enter the network ++\fB\-n\fR, \fB\-\-net\fR[=\fIfile\fR] ++Enter the network namespace. If no file is specified, enter the network ++namespace of the target process. If file is specified, enter the network + namespace specified by file. + .TP +-\fB\-p\fR, \fB\-\-pid\fR [\fIfile\fR] +-Enter the PID namespace. If no file is specified enter the PID namespace of +-the target process. If file is specified enter the PID namespace specified by ++\fB\-p\fR, \fB\-\-pid\fR[=\fIfile\fR] ++Enter the PID namespace. If no file is specified, enter the PID namespace of ++the target process. If file is specified, enter the PID namespace specified by + file. + .TP +-\fB\-r\fR, \fB\-\-root\fR [\fIdirectory\fR] +-Set the root directory. If no directory is specified set the root directory to +-the root directory of the target process. If directory is specified set the ++\fB\-U\fR, \fB\-\-user\fR[=\fIfile\fR] ++Enter the user namespace. If no file is specified, enter the user namespace of ++the target process. If file is specified, enter the user namespace specified by ++file. See also the \fB\-\-setuid\fR and \fB\-\-setgid\fR options. ++.TP ++\fB\-G\fR, \fB\-\-setgid\fR \fIgid\fR ++Set the group ID which will be used in the entered namespace and drop ++supplementary groups. ++.BR nsenter (1) ++always sets GID for user namespaces, the default is 0. ++.TP ++\fB\-S\fR, \fB\-\-setuid\fR \fIuid\fR ++Set the user ID which will be used in the entered namespace. ++.BR nsenter (1) ++always sets UID for user namespaces, the default is 0. ++.TP ++\fB\-\-preserve\-credentials\fR ++Don't modify UID and GID when enter user namespace. The default is to ++drops supplementary groups and sets GID and UID to 0. ++.TP ++\fB\-r\fR, \fB\-\-root\fR[=\fIdirectory\fR] ++Set the root directory. If no directory is specified, set the root directory to ++the root directory of the target process. If directory is specified, set the + root directory to the specified directory. + .TP +-\fB\-w\fR, \fB\-\-wd\fR [\fIdirectory\fR] +-Set the working directory. If no directory is specified set the working ++\fB\-w\fR, \fB\-\-wd\fR[=\fIdirectory\fR] ++Set the working directory. If no directory is specified, set the working + directory to the working directory of the target process. If directory is +-specified set the working directory to the specified directory. ++specified, set the working directory to the specified directory. + .TP +-\fB\-F\fR, \fB\-\-no-fork\fR +-Do not fork before exec'ing the specified program. By default when entering a +-pid namespace enter calls fork before calling exec so that the children will be +-in the newly entered pid namespace. ++\fB\-F\fR, \fB\-\-no\-fork\fR ++Do not fork before exec'ing the specified program. By default, when entering a ++PID namespace, \fBnsenter\fP calls \fBfork\fP before calling \fBexec\fP so that ++any children will also be in the newly entered PID namespace. + .TP + \fB\-V\fR, \fB\-\-version\fR + Display version information and exit. + .TP + \fB\-h\fR, \fB\-\-help\fR +-Print a help message. ++Display help text and exit. + .SH SEE ALSO + .BR setns (2), + .BR clone (2) +diff -up util-linux-2.23.2/sys-utils/nsenter.c.kzak util-linux-2.23.2/sys-utils/nsenter.c +--- util-linux-2.23.2/sys-utils/nsenter.c.kzak 2015-06-26 09:58:39.468633643 +0200 ++++ util-linux-2.23.2/sys-utils/nsenter.c 2015-06-26 09:58:51.673541033 +0200 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include "strutils.h" + #include "nls.h" +@@ -42,7 +43,12 @@ static struct namespace_file { + int fd; + } namespace_files[] = { + /* Careful the order is significant in this array. ++ * ++ * The user namespace comes first, so that it is entered ++ * first. This gives an unprivileged user the potential to ++ * enter the other namespaces. + */ ++ { .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 }, + { .nstype = CLONE_NEWIPC, .name = "ns/ipc", .fd = -1 }, + { .nstype = CLONE_NEWUTS, .name = "ns/uts", .fd = -1 }, + { .nstype = CLONE_NEWNET, .name = "ns/net", .fd = -1 }, +@@ -56,18 +62,25 @@ static void usage(int status) + FILE *out = status == EXIT_SUCCESS ? stdout : stderr; + + fputs(USAGE_HEADER, out); +- fprintf(out, _(" %s [options] [args...]\n"), ++ fprintf(out, _(" %s [options] [...]\n"), + program_invocation_short_name); + ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Run a program with namespaces of other processes.\n"), out); ++ + fputs(USAGE_OPTIONS, out); + fputs(_(" -t, --target target process to get namespaces from\n"), out); +- fputs(_(" -m, --mount [=] enter mount namespace\n"), out); +- fputs(_(" -u, --uts [=] enter UTS namespace (hostname etc)\n"), out); +- fputs(_(" -i, --ipc [=] enter System V IPC namespace\n"), out); +- fputs(_(" -n, --net [=] enter network namespace\n"), out); +- fputs(_(" -p, --pid [=] enter pid namespace\n"), out); +- fputs(_(" -r, --root [=] set the root directory\n"), out); +- fputs(_(" -w, --wd [=] set the working directory\n"), out); ++ fputs(_(" -m, --mount[=] enter mount namespace\n"), out); ++ fputs(_(" -u, --uts[=] enter UTS namespace (hostname etc)\n"), out); ++ fputs(_(" -i, --ipc[=] enter System V IPC namespace\n"), out); ++ fputs(_(" -n, --net[=] enter network namespace\n"), out); ++ fputs(_(" -p, --pid[=] enter pid namespace\n"), out); ++ fputs(_(" -U, --user[=] enter user namespace\n"), out); ++ fputs(_(" -S, --setuid set uid in entered namespace\n"), out); ++ fputs(_(" -G, --setgid set gid in entered namespace\n"), out); ++ fputs(_(" --preserve-credentials do not touch uids or gids\n"), out); ++ fputs(_(" -r, --root[=] set the root directory\n"), out); ++ fputs(_(" -w, --wd[=] set the working directory\n"), out); + fputs(_(" -F, --no-fork do not fork before exec'ing \n"), out); + + fputs(USAGE_SEPARATOR, out); +@@ -153,6 +166,9 @@ static void continue_as_child(void) + + int main(int argc, char *argv[]) + { ++ enum { ++ OPT_PRESERVE_CRED = CHAR_MAX + 1 ++ }; + static const struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V'}, +@@ -162,24 +178,30 @@ int main(int argc, char *argv[]) + { "ipc", optional_argument, NULL, 'i' }, + { "net", optional_argument, NULL, 'n' }, + { "pid", optional_argument, NULL, 'p' }, ++ { "user", optional_argument, NULL, 'U' }, ++ { "setuid", required_argument, NULL, 'S' }, ++ { "setgid", required_argument, NULL, 'G' }, + { "root", optional_argument, NULL, 'r' }, + { "wd", optional_argument, NULL, 'w' }, + { "no-fork", no_argument, NULL, 'F' }, ++ { "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED }, + { NULL, 0, NULL, 0 } + }; + + struct namespace_file *nsfile; +- int c, namespaces = 0; +- bool do_rd = false, do_wd = false; ++ int c, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0; ++ bool do_rd = false, do_wd = false, force_uid = false, force_gid = false; + int do_fork = -1; /* unknown yet */ ++ uid_t uid = 0; ++ gid_t gid = 0; + +- setlocale(LC_MESSAGES, ""); ++ setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + + while ((c = +- getopt_long(argc, argv, "hVt:m::u::i::n::p::r::w::F", ++ getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::F", + longopts, NULL)) != -1) { + switch (c) { + case 'h': +@@ -221,6 +243,20 @@ int main(int argc, char *argv[]) + else + namespaces |= CLONE_NEWPID; + break; ++ case 'U': ++ if (optarg) ++ open_namespace_fd(CLONE_NEWUSER, optarg); ++ else ++ namespaces |= CLONE_NEWUSER; ++ break; ++ case 'S': ++ uid = strtoul_or_err(optarg, _("failed to parse uid")); ++ force_uid = true; ++ break; ++ case 'G': ++ gid = strtoul_or_err(optarg, _("failed to parse gid")); ++ force_gid = true; ++ break; + case 'F': + do_fork = 0; + break; +@@ -236,6 +272,9 @@ int main(int argc, char *argv[]) + else + do_wd = true; + break; ++ case OPT_PRESERVE_CRED: ++ preserve_cred = 1; ++ break; + default: + usage(EXIT_FAILURE); + } +@@ -253,6 +292,26 @@ int main(int argc, char *argv[]) + open_target_fd(&wd_fd, "cwd", NULL); + + /* ++ * Update namespaces variable to contain all requested namespaces ++ */ ++ for (nsfile = namespace_files; nsfile->nstype; nsfile++) { ++ if (nsfile->fd < 0) ++ continue; ++ namespaces |= nsfile->nstype; ++ } ++ ++ /* for user namespaces we always set UID and GID (default is 0) ++ * and clear root's groups if --preserve-credentials is no specified */ ++ if ((namespaces & CLONE_NEWUSER) && !preserve_cred) { ++ force_uid = true, force_gid = true; ++ ++ /* We call setgroups() before and after we enter user namespace, ++ * let's complain only if both fail */ ++ if (setgroups(0, NULL) != 0) ++ setgroups_nerrs++; ++ } ++ ++ /* + * Now that we know which namespaces we want to enter, enter them. + */ + for (nsfile = namespace_files; nsfile->nstype; nsfile++) { +@@ -302,6 +361,15 @@ int main(int argc, char *argv[]) + if (do_fork == 1) + continue_as_child(); + ++ if (force_uid || force_gid) { ++ if (force_gid && setgroups(0, NULL) != 0 && setgroups_nerrs) /* drop supplementary groups */ ++ err(EXIT_FAILURE, _("setgroups failed")); ++ if (force_gid && setgid(gid) < 0) /* change GID */ ++ err(EXIT_FAILURE, _("setgid failed")); ++ if (force_uid && setuid(uid) < 0) /* change UID */ ++ err(EXIT_FAILURE, _("setuid failed")); ++ } ++ + if (optind < argc) { + execvp(argv[optind], argv + optind); + err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]); +diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1 +--- util-linux-2.23.2/sys-utils/unshare.1.kzak 2015-06-26 09:58:39.484633521 +0200 ++++ util-linux-2.23.2/sys-utils/unshare.1 2015-06-26 09:58:51.673541033 +0200 +@@ -1,28 +1,27 @@ +-.\" Process this file with +-.\" groff -man -Tascii lscpu.1 +-.\" +-.TH UNSHARE 1 "July 2013" "util-linux" "User Commands" ++.TH UNSHARE 1 "July 2014" "util-linux" "User Commands" + .SH NAME + unshare \- run program with some namespaces unshared from parent + .SH SYNOPSIS + .B unshare +-.RI [ options ] ++[options] + .I program + .RI [ arguments ] + .SH DESCRIPTION + Unshares the indicated namespaces from the parent process and then executes +-the specified program. The namespaces to be unshared are indicated via ++the specified \fIprogram\fR. The namespaces to be unshared are indicated via + options. Unshareable namespaces are: + .TP + .BR "mount namespace" + Mounting and unmounting filesystems will not affect the rest of the system + (\fBCLONE_NEWNS\fP flag), except for filesystems which are explicitly marked as +-shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP for the +-\fBshared\fP flags). +- +-It's recommended to use \fBmount --make-rprivate\fP or \fBmount --make-rslave\fP +-after \fBunshare --mount\fP to make sure that mountpoints in the new namespace +-are really unshared from parental namespace. ++shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP or ++\fBfindmnt -o+PROPAGATION\fP for the \fBshared\fP flags). ++.sp ++.B unshare ++automatically sets propagation to \fBprivate\fP ++in the new mount namespace to make sure that the new namespace is really ++unshared. This feature is possible to disable by option \fB\-\-propagation unchanged\fP. ++Note that \fBprivate\fP is the kernel default. + .TP + .BR "UTS namespace" + Setting hostname or domainname will not affect the rest of the system. +@@ -40,13 +39,14 @@ sockets, etc. (\fBCLONE_NEWNET\fP flag) + .BR "pid namespace" + Children will have a distinct set of PID to process mappings from their parent. + (\fBCLONE_NEWPID\fP flag) ++.TP ++.BR "user namespace" ++The process will have a distinct set of UIDs, GIDs and capabilities. ++(\fBCLONE_NEWUSER\fP flag) + .PP + See \fBclone\fR(2) for the exact semantics of the flags. + .SH OPTIONS + .TP +-.BR \-h , " \-\-help" +-Display help text and exit. +-.TP + .BR \-i , " \-\-ipc" + Unshare the IPC namespace. + .TP +@@ -63,16 +63,68 @@ See also the \fB--fork\fP and \fB--mount + .BR \-u , " \-\-uts" + Unshare the UTS namespace. + .TP ++.BR \-U , " \-\-user" ++Unshare the user namespace. ++.TP + .BR \-f , " \-\-fork" + Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than + running it directly. This is useful when creating a new pid namespace. + .TP +-.BR \-\-mount-proc "[=\fImountpoint\fP]" +-Just before running the program, mount the proc filesystem at the \fImountpoint\fP ++.BR \-\-mount\-proc "[=\fImountpoint\fP]" ++Just before running the program, mount the proc filesystem at \fImountpoint\fP + (default is /proc). This is useful when creating a new pid namespace. It also + implies creating a new mount namespace since the /proc mount would otherwise +-mess up existing programs on the system. The new proc filesystem is explicitly ++mess up existing programs on the system. The new proc filesystem is explicitly + mounted as private (by MS_PRIVATE|MS_REC). ++.TP ++.BR \-r , " \-\-map\-root\-user" ++Run the program only after the current effective user and group IDs have been mapped to ++the superuser UID and GID in the newly created user namespace. This makes it possible to ++conveniently gain capabilities needed to manage various aspects of the newly created ++namespaces (such as configuring interfaces in the network namespace or mounting filesystems in ++the mount namespace) even when run unprivileged. As a mere convenience feature, it does not support ++more sophisticated use cases, such as mapping multiple ranges of UIDs and GIDs. ++This option implies --setgroups=deny. ++.TP ++.BR "\-\-propagation \fIprivate|shared|slave|unchanged\fP" ++Recursively sets mount propagation flag in the new mount namespace. The default ++is to set the propagation to \fIprivate\fP, this feature is possible to disable ++by \fIunchanged\fP argument. The options is silently ignored when mount namespace (\fB\-\-mount\fP) ++is not requested. ++.TP ++.BR "\-\-setgroups \fIallow|deny\fP" ++Allow or deny ++.BR setgroups (2) ++syscall in user namespaces. ++ ++.BR setgroups(2) ++is only callable with CAP_SETGID and CAP_SETGID in a user ++namespace (since Linux 3.19) does not give you permission to call setgroups(2) ++until after GID map has been set. The GID map is writable by root when ++.BR setgroups(2) ++is enabled and GID map becomes writable by unprivileged processes when ++.BR setgroups(2) ++is permanently disabled. ++.TP ++.BR \-V , " \-\-version" ++Display version information and exit. ++.TP ++.BR \-h , " \-\-help" ++Display help text and exit. ++.SH EXAMPLES ++.TP ++.B # unshare --fork --pid --mount-proc readlink /proc/self ++.TQ ++1 ++.br ++Establish a PID namespace, ensure we're PID 1 in it against newly mounted ++procfs instance. ++.TP ++.B $ unshare --map-root-user --user sh -c whoami ++.TQ ++root ++.br ++Establish a user namespace as an unprivileged user with a root user within it. + .SH SEE ALSO + .BR unshare (2), + .BR clone (2), +diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c +--- util-linux-2.23.2/sys-utils/unshare.c.kzak 2015-06-26 09:58:39.484633521 +0200 ++++ util-linux-2.23.2/sys-utils/unshare.c 2015-06-26 09:58:51.673541033 +0200 +@@ -32,19 +32,117 @@ + + #include "nls.h" + #include "c.h" ++#include "closestream.h" + #include "namespace.h" + #include "exec_shell.h" + #include "xalloc.h" + #include "pathnames.h" ++#include "all-io.h" + ++/* 'private' is kernel default */ ++#define UNSHARE_PROPAGATION_DEFAULT (MS_REC | MS_PRIVATE) ++ ++enum { ++ SETGROUPS_NONE = -1, ++ SETGROUPS_DENY = 0, ++ SETGROUPS_ALLOW = 1, ++}; ++ ++static const char *setgroups_strings[] = ++{ ++ [SETGROUPS_DENY] = "deny", ++ [SETGROUPS_ALLOW] = "allow" ++}; ++ ++static int setgroups_str2id(const char *str) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(setgroups_strings); i++) ++ if (strcmp(str, setgroups_strings[i]) == 0) ++ return i; ++ ++ errx(EXIT_FAILURE, _("unsupported --setgroups argument '%s'"), str); ++} ++ ++static void setgroups_control(int action) ++{ ++ const char *file = _PATH_PROC_SETGROUPS; ++ const char *cmd; ++ int fd; ++ ++ if (action < 0 || (size_t) action >= ARRAY_SIZE(setgroups_strings)) ++ return; ++ cmd = setgroups_strings[action]; ++ ++ fd = open(file, O_WRONLY); ++ if (fd < 0) { ++ if (errno == ENOENT) ++ return; ++ err(EXIT_FAILURE, _("cannot open %s"), file); ++ } ++ ++ if (write_all(fd, cmd, strlen(cmd))) ++ err(EXIT_FAILURE, _("write failed %s"), file); ++ close(fd); ++} ++ ++static void map_id(const char *file, uint32_t from, uint32_t to) ++{ ++ char *buf; ++ int fd; ++ ++ fd = open(file, O_WRONLY); ++ if (fd < 0) ++ err(EXIT_FAILURE, _("cannot open %s"), file); ++ ++ xasprintf(&buf, "%u %u 1", from, to); ++ if (write_all(fd, buf, strlen(buf))) ++ err(EXIT_FAILURE, _("write failed %s"), file); ++ free(buf); ++ close(fd); ++} ++ ++static unsigned long parse_propagation(const char *str) ++{ ++ size_t i; ++ static const struct prop_opts { ++ const char *name; ++ unsigned long flag; ++ } opts[] = { ++ { "slave", MS_REC | MS_SLAVE }, ++ { "private", MS_REC | MS_PRIVATE }, ++ { "shared", MS_REC | MS_SHARED }, ++ { "unchanged", 0 } ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(opts); i++) { ++ if (strcmp(opts[i].name, str) == 0) ++ return opts[i].flag; ++ } ++ ++ errx(EXIT_FAILURE, _("unsupported propagation mode: %s"), str); ++} ++ ++static void set_propagation(unsigned long flags) ++{ ++ if (flags == 0) ++ return; ++ ++ if (mount("none", "/", NULL, flags, NULL) != 0) ++ err(EXIT_FAILURE, _("cannot change root filesystem propagation")); ++} + + static void usage(int status) + { + FILE *out = status == EXIT_SUCCESS ? stdout : stderr; + + fputs(USAGE_HEADER, out); +- fprintf(out, +- _(" %s [options] [args...]\n"), program_invocation_short_name); ++ fprintf(out, _(" %s [options] [...]\n"), ++ program_invocation_short_name); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Run a program with some namespaces unshared from the parent.\n"), out); + + fputs(USAGE_OPTIONS, out); + fputs(_(" -m, --mount unshare mounts namespace\n"), out); +@@ -52,8 +150,13 @@ static void usage(int status) + fputs(_(" -i, --ipc unshare System V IPC namespace\n"), out); + fputs(_(" -n, --net unshare network namespace\n"), out); + fputs(_(" -p, --pid unshare pid namespace\n"), out); ++ fputs(_(" -U, --user unshare user namespace\n"), out); + fputs(_(" -f, --fork fork before launching \n"), out); + fputs(_(" --mount-proc[=] mount proc filesystem first (implies --mount)\n"), out); ++ fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out); ++ fputs(_(" --propagation \n" ++ " modify mount propagation in mount namespace\n"), out); ++ fputs(_(" -s, --setgroups allow|deny control the setgroups syscall in user namespaces\n"), out); + + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); +@@ -66,7 +169,9 @@ static void usage(int status) + int main(int argc, char *argv[]) + { + enum { +- OPT_MOUNTPROC = CHAR_MAX + 1 ++ OPT_MOUNTPROC = CHAR_MAX + 1, ++ OPT_PROPAGATION, ++ OPT_SETGROUPS + }; + static const struct option longopts[] = { + { "help", no_argument, 0, 'h' }, +@@ -76,20 +181,29 @@ int main(int argc, char *argv[]) + { "ipc", no_argument, 0, 'i' }, + { "net", no_argument, 0, 'n' }, + { "pid", no_argument, 0, 'p' }, ++ { "user", no_argument, 0, 'U' }, + { "fork", no_argument, 0, 'f' }, + { "mount-proc", optional_argument, 0, OPT_MOUNTPROC }, ++ { "map-root-user", no_argument, 0, 'r' }, ++ { "propagation", required_argument, 0, OPT_PROPAGATION }, ++ { "setgroups", required_argument, 0, OPT_SETGROUPS }, + { NULL, 0, 0, 0 } + }; + ++ int setgrpcmd = SETGROUPS_NONE; + int unshare_flags = 0; +- int c, forkit = 0; ++ int c, forkit = 0, maproot = 0; + const char *procmnt = NULL; ++ unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT; ++ uid_t real_euid = geteuid(); ++ gid_t real_egid = getegid();; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); ++ atexit(close_stdout); + +- while ((c = getopt_long(argc, argv, "+fhVmuinp", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "+fhVmuinpUr", longopts, NULL)) != -1) { + switch (c) { + case 'f': + forkit = 1; +@@ -114,10 +228,23 @@ int main(int argc, char *argv[]) + case 'p': + unshare_flags |= CLONE_NEWPID; + break; ++ case 'U': ++ unshare_flags |= CLONE_NEWUSER; ++ break; + case OPT_MOUNTPROC: + unshare_flags |= CLONE_NEWNS; + procmnt = optarg ? optarg : "/proc"; + break; ++ case 'r': ++ unshare_flags |= CLONE_NEWUSER; ++ maproot = 1; ++ break; ++ case OPT_SETGROUPS: ++ setgrpcmd = setgroups_str2id(optarg); ++ break; ++ case OPT_PROPAGATION: ++ propagation = parse_propagation(optarg); ++ break; + default: + usage(EXIT_FAILURE); + } +@@ -146,6 +273,25 @@ int main(int argc, char *argv[]) + } + } + ++ if (maproot) { ++ if (setgrpcmd == SETGROUPS_ALLOW) ++ errx(EXIT_FAILURE, _("options --setgroups=allow and " ++ "--map-root-user are mutually exclusive")); ++ ++ /* since Linux 3.19 unprivileged writing of /proc/self/gid_map ++ * has s been disabled unless /proc/self/setgroups is written ++ * first to permanently disable the ability to call setgroups ++ * in that user namespace. */ ++ setgroups_control(SETGROUPS_DENY); ++ map_id(_PATH_PROC_UIDMAP, 0, real_euid); ++ map_id(_PATH_PROC_GIDMAP, 0, real_egid); ++ ++ } else if (setgrpcmd != SETGROUPS_NONE) ++ setgroups_control(setgrpcmd); ++ ++ if ((unshare_flags & CLONE_NEWNS) && propagation) ++ set_propagation(propagation); ++ + if (procmnt && + (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 || + mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0)) diff --git a/SOURCES/2.27-libblkid-xfs-log.patch b/SOURCES/2.27-libblkid-xfs-log.patch new file mode 100644 index 00000000..9840cd87 --- /dev/null +++ b/SOURCES/2.27-libblkid-xfs-log.patch @@ -0,0 +1,31 @@ +From d5b7d2912afceac3774d1aaea9e8486b54d4e9e9 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 13 Oct 2015 12:01:29 +0200 +Subject: [PATCH] libblkid: make XFS Log visible for wipefs + +Reported-by: Peter Rajnoha +Signed-off-by: root +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/xfs.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c +index a6c04a2..d13c849 100644 +--- a/libblkid/src/superblocks/xfs.c ++++ b/libblkid/src/superblocks/xfs.c +@@ -260,6 +260,12 @@ static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag) + + if (xlog_valid_rec_header(rhead)) { + blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID"); ++ ++ if (blkid_probe_set_magic(pr, i * 512, ++ sizeof(rhead->h_magicno), ++ (unsigned char *) &rhead->h_magicno)) ++ return 1; ++ + return 0; + } + } +-- +2.4.3 diff --git a/SOURCES/2.28-lslogins-1317953.patch b/SOURCES/2.28-lslogins-1317953.patch new file mode 100755 index 00000000..2b2e47fb --- /dev/null +++ b/SOURCES/2.28-lslogins-1317953.patch @@ -0,0 +1,209 @@ +diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h +--- util-linux-2.23.2/include/pathnames.h.kzak 2016-03-16 17:17:02.980243390 +0100 ++++ util-linux-2.23.2/include/pathnames.h 2016-03-16 17:17:37.129015363 +0100 +@@ -36,6 +36,7 @@ + #endif + #define _PATH_MOTDFILE "/etc/motd" + #define _PATH_NOLOGIN "/etc/nologin" ++#define _PATH_VAR_NOLOGIN "/var/run/nologin" + + #define _PATH_LOGIN "/bin/login" + #define _PATH_INITTAB "/etc/inittab" +diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1 +--- util-linux-2.23.2/login-utils/lslogins.1.kzak 2016-03-16 17:17:02.970243457 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.1 2016-03-16 17:17:37.129015363 +0100 +@@ -5,7 +5,10 @@ + lslogins \- display information about known users in the system + .SH SYNOPSIS + .B lslogins +-[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR] ++[options] ++.RB [ \-s | \-u [ =\fIUID ]] ++.RB [ \-g " \fIgroups\fR]" ++.RB [ \-l " \fIlogins\fR]" + .SH DESCRIPTION + .PP + Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd +@@ -17,7 +20,7 @@ Mandatory arguments to long options are + .TP + \fB\-a\fR, \fB\-\-acc\-expiration\fR + Display data about the date of last password change and the account expiration +-date (see \fBshadow\fR(5) for more info). (Requires root priviliges.) ++date (see \fBshadow\fR(5) for more info). (Requires root privileges.) + .TP + \fB\-\-btmp\-file \fIpath\fP + Alternate path for btmp. +@@ -31,7 +34,7 @@ Output data in the format of NAME=VALUE. + \fB\-f\fR, \fB\-\-failed\fR + Display data about the users' last failed login attempts. + .TP +-\fB\-G\fR, \fB\-\-groups\-info\fR ++\fB\-G\fR, \fB\-\-supp\-groups\fR + Show information about groups. + .TP + \fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR +@@ -48,9 +51,6 @@ Display data containing information abou + Only show data of users with a login specified in \fIlogins\fR (user names or user + IDS). More than one login may be specified; the list has to be comma-separated. + .TP +-\fB\-m\fR, \fB\-\-supp\-groups\fR +-Show supplementary groups. +-.TP + \fB\-n\fR, \fB\-\-newline\fR + Display each piece of information on a separate line. + .TP +@@ -71,21 +71,21 @@ Display information related to login by + \fB\-r\fR, \fB\-\-raw\fR + Raw output (no columnation). + .TP +-\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR] ++\fB\-s\fR, \fB\-\-system\-accs\fR + Show system accounts. These are by default all accounts with a UID below 1000 +-(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID +-threshold can also be specified explicitly (necessary for some distributions that +-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). ++This hardcoded default maybe overwritten by parameters SYS_UID_MIN and SYS_UID_MAX in ++the file /etc/login.defs. + .TP +-\fB\-\-time-format\fR \fItype\fP ++\fB\-\-time\-format\fR \fItype\fP + Display dates in short, full or iso format. The default is short, this time + format is designed to be space efficient and human readable. + .TP +-\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR] ++\fB\-u\fR, \fB\-\-user\-accs\fR + Show user accounts. These are by default all accounts with UID above 1000 +-(inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID +-threshold can also be specified explicitly (necessary for some distributions that +-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++(inclusive), with the exception of either nobody or nfsnobody (UID 65534). ++This hardcoded default maybe overwritten by parameters UID_MIN and UID_MAX in ++the file /etc/login.defs. + .TP + \fB\-V\fR, \fB\-\-version\fR + Display version information and exit. +diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c +--- util-linux-2.23.2/login-utils/lslogins.c.kzak 2016-03-16 17:17:02.970243457 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.c 2016-03-16 17:23:47.191484521 +0100 +@@ -396,7 +396,7 @@ again: + x = snprintf(p, len, "%s,", grp->gr_name); + } + +- if (x < 0 || (size_t) x + 1 > len) { ++ if (x < 0 || (size_t) x >= len) { + size_t cur = p - res; + + maxlen *= 2; +@@ -496,21 +496,24 @@ static int parse_btmp(struct lslogins_co + static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) + { + size_t n = 0; ++ int ngroups = 0; + + *len = 0; + *list = NULL; + + /* first let's get a supp. group count */ +- getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); +- if (!*len) ++ getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups); ++ if (!ngroups) + return -1; + +- *list = xcalloc(1, *len * sizeof(gid_t)); ++ *list = xcalloc(1, ngroups * sizeof(gid_t)); + + /* now for the actual list of GIDs */ +- if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) ++ if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups)) + return -1; + ++ *len = (size_t) ngroups; ++ + /* getgroups also returns the user's primary GID - dispose of it */ + while (n < *len) { + if ((*list)[n] == pwd->pw_gid) +@@ -852,7 +855,7 @@ static int get_user(struct lslogins_cont + const char *username) + { + *user = get_user_info(ctl, username); +- if (!*user && errno) ++ if (!*user) + if (IS_REAL_ERRNO(errno)) + return -1; + return 0; +@@ -1193,16 +1196,18 @@ static void __attribute__((__noreturn__) + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options]\n"), program_invocation_short_name); + ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Display information about known users in the system.\n"), out); ++ + fputs(USAGE_OPTIONS, out); + fputs(_(" -a, --acc-expiration display info about passwords expiration\n"), out); + fputs(_(" -c, --colon-separate display data in a format similar to /etc/passwd\n"), out); + fputs(_(" -e, --export display in an export-able output format\n"), out); + fputs(_(" -f, --failed display data about the users' last failed logins\n"), out); +- fputs(_(" -G, --groups-info display information about groups\n"), out); ++ fputs(_(" -G, --supp-groups display information about groups\n"), out); + fputs(_(" -g, --groups= display users belonging to a group in \n"), out); + fputs(_(" -L, --last show info about the users' last login sessions\n"), out); + fputs(_(" -l, --logins= display only users from \n"), out); +- fputs(_(" -m, --supp-groups display supplementary groups as well\n"), out); + fputs(_(" -n, --newline display each piece of information on a new line\n"), out); + fputs(_(" --noheadings don't print headings\n"), out); + fputs(_(" --notruncate don't truncate output\n"), out); +@@ -1226,7 +1231,7 @@ static void __attribute__((__noreturn__) + fprintf(out, " %14s %s\n", coldescs[i].name, + _(coldescs[i].help)); + +- fprintf(out, _("\nFor more details see lslogins(1).\n")); ++ fprintf(out, USAGE_MAN_TAIL("lslogins(1)")); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } +@@ -1241,8 +1246,7 @@ int main(int argc, char *argv[]) + + /* long only options. */ + enum { +- OPT_VER = CHAR_MAX + 1, +- OPT_WTMP, ++ OPT_WTMP = CHAR_MAX + 1, + OPT_BTMP, + OPT_NOTRUNC, + OPT_NOHEAD, +@@ -1300,7 +1304,7 @@ int main(int argc, char *argv[]) + add_column(columns, ncolumns++, COL_UID); + add_column(columns, ncolumns++, COL_USER); + +- while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ", ++ while ((c = getopt_long(argc, argv, "acefGg:hLl:no:prsuVzZ", + longopts, NULL)) != -1) { + + err_exclusive_options(c, longopts, excl, excl_st); +@@ -1397,6 +1401,7 @@ int main(int argc, char *argv[]) + { + size_t i; + ++ ctl->time_mode = TIME_INVALID; + for (i = 0; i < ARRAY_SIZE(timefmts); i++) { + if (strcmp(timefmts[i].name, optarg) == 0) { + ctl->time_mode = timefmts[i].val; +@@ -1404,7 +1409,7 @@ int main(int argc, char *argv[]) + } + } + if (ctl->time_mode == TIME_INVALID) +- usage(stderr); ++ errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); + } + break; + case 'V': +@@ -1433,7 +1438,7 @@ int main(int argc, char *argv[]) + logins = argv[optind]; + outmode = OUT_PRETTY; + } else if (argc != optind) +- usage(stderr); ++ errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users.")); + + scols_init_debug(0); diff --git a/SOURCES/2.28-lslogins-rebase.patch b/SOURCES/2.28-lslogins-rebase.patch new file mode 100644 index 00000000..45b886af --- /dev/null +++ b/SOURCES/2.28-lslogins-rebase.patch @@ -0,0 +1,459 @@ +diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h +--- util-linux-2.23.2/include/pathnames.h.kzak 2016-03-16 15:17:42.648298525 +0100 ++++ util-linux-2.23.2/include/pathnames.h 2016-03-16 15:18:13.769055345 +0100 +@@ -36,6 +36,7 @@ + #endif + #define _PATH_MOTDFILE "/etc/motd" + #define _PATH_NOLOGIN "/etc/nologin" ++#define _PATH_VAR_NOLOGIN "/var/run/nologin" + + #define _PATH_LOGIN "/bin/login" + #define _PATH_INITTAB "/etc/inittab" +diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1 +--- util-linux-2.23.2/login-utils/lslogins.1.kzak 2016-03-16 15:17:42.639298595 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.1 2016-03-16 15:18:13.769055345 +0100 +@@ -5,7 +5,10 @@ + lslogins \- display information about known users in the system + .SH SYNOPSIS + .B lslogins +-[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR] ++[options] ++.RB [ \-s | \-u [ =\fIUID ]] ++.RB [ \-g " \fIgroups\fR]" ++.RB [ \-l " \fIlogins\fR]" + .SH DESCRIPTION + .PP + Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd +@@ -17,7 +20,7 @@ Mandatory arguments to long options are + .TP + \fB\-a\fR, \fB\-\-acc\-expiration\fR + Display data about the date of last password change and the account expiration +-date (see \fBshadow\fR(5) for more info). (Requires root priviliges.) ++date (see \fBshadow\fR(5) for more info). (Requires root privileges.) + .TP + \fB\-\-btmp\-file \fIpath\fP + Alternate path for btmp. +@@ -31,7 +34,7 @@ Output data in the format of NAME=VALUE. + \fB\-f\fR, \fB\-\-failed\fR + Display data about the users' last failed login attempts. + .TP +-\fB\-G\fR, \fB\-\-groups\-info\fR ++\fB\-G\fR, \fB\-\-supp\-groups\fR + Show information about groups. + .TP + \fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR +@@ -48,9 +51,6 @@ Display data containing information abou + Only show data of users with a login specified in \fIlogins\fR (user names or user + IDS). More than one login may be specified; the list has to be comma-separated. + .TP +-\fB\-m\fR, \fB\-\-supp\-groups\fR +-Show supplementary groups. +-.TP + \fB\-n\fR, \fB\-\-newline\fR + Display each piece of information on a separate line. + .TP +@@ -71,21 +71,21 @@ Display information related to login by + \fB\-r\fR, \fB\-\-raw\fR + Raw output (no columnation). + .TP +-\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR] ++\fB\-s\fR, \fB\-\-system\-accs\fR + Show system accounts. These are by default all accounts with a UID below 1000 +-(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID +-threshold can also be specified explicitly (necessary for some distributions that +-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). ++This hardcoded default maybe overwritten by parameters SYS_UID_MIN and SYS_UID_MAX in ++the file /etc/login.defs. + .TP +-\fB\-\-time-format\fR \fItype\fP ++\fB\-\-time\-format\fR \fItype\fP + Display dates in short, full or iso format. The default is short, this time + format is designed to be space efficient and human readable. + .TP +-\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR] ++\fB\-u\fR, \fB\-\-user\-accs\fR + Show user accounts. These are by default all accounts with UID above 1000 +-(inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID +-threshold can also be specified explicitly (necessary for some distributions that +-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++(inclusive), with the exception of either nobody or nfsnobody (UID 65534). ++This hardcoded default maybe overwritten by parameters UID_MIN and UID_MAX in ++the file /etc/login.defs. + .TP + \fB\-V\fR, \fB\-\-version\fR + Display version information and exit. +diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c +--- util-linux-2.23.2/login-utils/lslogins.c.kzak 2016-03-16 15:17:42.639298595 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.c 2016-03-16 15:22:49.845899268 +0100 +@@ -144,6 +144,7 @@ enum { + TIME_SHORT, + TIME_FULL, + TIME_ISO, ++ TIME_ISO_SHORT, + }; + + /* +@@ -350,6 +351,9 @@ static char *make_time(int mode, time_t + case TIME_ISO: + strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm); + break; ++ case TIME_ISO_SHORT: ++ strftime(buf, sizeof(buf), "%Y-%m-%d", &tm); ++ break; + default: + errx(EXIT_FAILURE, _("unsupported time type")); + } +@@ -396,7 +400,7 @@ again: + x = snprintf(p, len, "%s,", grp->gr_name); + } + +- if (x < 0 || (size_t) x + 1 > len) { ++ if (x < 0 || (size_t) x >= len) { + size_t cur = p - res; + + maxlen *= 2; +@@ -496,21 +500,24 @@ static int parse_btmp(struct lslogins_co + static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) + { + size_t n = 0; ++ int ngroups = 0; + + *len = 0; + *list = NULL; + + /* first let's get a supp. group count */ +- getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); +- if (!*len) ++ getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups); ++ if (!ngroups) + return -1; + +- *list = xcalloc(1, *len * sizeof(gid_t)); ++ *list = xcalloc(1, ngroups * sizeof(gid_t)); + + /* now for the actual list of GIDs */ +- if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) ++ if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups)) + return -1; + ++ *len = (size_t) ngroups; ++ + /* getgroups also returns the user's primary GID - dispose of it */ + while (n < *len) { + if ((*list)[n] == pwd->pw_gid) +@@ -520,6 +527,7 @@ static int get_sgroups(gid_t **list, siz + + if (*len) + (*list)[n] = (*list)[--(*len)]; ++ + return 0; + } + +@@ -685,8 +693,8 @@ static struct lslogins_user *get_user_in + if (strstr(pwd->pw_shell, "nologin")) + user->nologin = 1; + else if (pwd->pw_uid) +- user->nologin = access("/etc/nologin", F_OK) == 0 || +- access("/var/run/nologin", F_OK) == 0; ++ user->nologin = access(_PATH_NOLOGIN, F_OK) == 0 || ++ access(_PATH_VAR_NOLOGIN, F_OK) == 0; + break; + case COL_PWD_WARN: + if (shadow && shadow->sp_warn >= 0) +@@ -694,7 +702,8 @@ static struct lslogins_user *get_user_in + break; + case COL_PWD_EXPIR: + if (shadow && shadow->sp_expire >= 0) +- user->pwd_expire = make_time(TIME_SHORT, ++ user->pwd_expire = make_time(ctl->time_mode == TIME_ISO ? ++ TIME_ISO_SHORT : ctl->time_mode, + shadow->sp_expire * 86400); + break; + case COL_PWD_CTIME: +@@ -702,7 +711,8 @@ static struct lslogins_user *get_user_in + * (especially in non-GMT timezones) would only serve + * to confuse */ + if (shadow) +- user->pwd_ctime = make_time(TIME_SHORT, ++ user->pwd_ctime = make_time(ctl->time_mode == TIME_ISO ? ++ TIME_ISO_SHORT : ctl->time_mode, + shadow->sp_lstchg * 86400); + break; + case COL_PWD_CTIME_MIN: +@@ -852,7 +862,7 @@ static int get_user(struct lslogins_cont + const char *username) + { + *user = get_user_info(ctl, username); +- if (!*user && errno) ++ if (!*user) + if (IS_REAL_ERRNO(errno)) + return -1; + return 0; +@@ -887,33 +897,33 @@ static int create_usertree(struct lslogi + + static struct libscols_table *setup_table(struct lslogins_control *ctl) + { +- struct libscols_table *tb = scols_new_table(); ++ struct libscols_table *table = scols_new_table(); + int n = 0; + +- if (!tb) ++ if (!table) + errx(EXIT_FAILURE, _("failed to initialize output table")); + if (ctl->noheadings) +- scols_table_enable_noheadings(tb, 1); ++ scols_table_enable_noheadings(table, 1); + + switch(outmode) { + case OUT_COLON: +- scols_table_enable_raw(tb, 1); +- scols_table_set_column_separator(tb, ":"); ++ scols_table_enable_raw(table, 1); ++ scols_table_set_column_separator(table, ":"); + break; + case OUT_NEWLINE: +- scols_table_set_column_separator(tb, "\n"); ++ scols_table_set_column_separator(table, "\n"); + /* fallthrough */ + case OUT_EXPORT: +- scols_table_enable_export(tb, 1); ++ scols_table_enable_export(table, 1); + break; + case OUT_NUL: +- scols_table_set_line_separator(tb, "\0"); ++ scols_table_set_line_separator(table, "\0"); + /* fallthrough */ + case OUT_RAW: +- scols_table_enable_raw(tb, 1); ++ scols_table_enable_raw(table, 1); + break; + case OUT_PRETTY: +- scols_table_enable_noheadings(tb, 1); ++ scols_table_enable_noheadings(table, 1); + default: + break; + } +@@ -924,7 +934,7 @@ static struct libscols_table *setup_tabl + if (ctl->notrunc) + flags &= ~SCOLS_FL_TRUNC; + +- if (!scols_table_new_column(tb, ++ if (!scols_table_new_column(table, + coldescs[columns[n]].name, + coldescs[columns[n]].whint, + flags)) +@@ -932,9 +942,9 @@ static struct libscols_table *setup_tabl + ++n; + } + +- return tb; ++ return table; + fail: +- scols_unref_table(tb); ++ scols_unref_table(table); + return NULL; + } + +@@ -1050,10 +1060,10 @@ static void fill_table(const void *u, co + return; + } + #ifdef HAVE_LIBSYSTEMD +-static void print_journal_tail(const char *journal_path, uid_t uid, size_t len) ++static void print_journal_tail(const char *journal_path, uid_t uid, size_t len, int time_mode) + { + sd_journal *j; +- char *match, *buf; ++ char *match, *timestamp; + uint64_t x; + time_t t; + const char *identifier, *pid, *message; +@@ -1064,7 +1074,6 @@ static void print_journal_tail(const cha + else + sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + +- buf = xmalloc(sizeof(char) * 16); + xasprintf(&match, "_UID=%d", uid); + + sd_journal_add_match(j, match, 0); +@@ -1074,37 +1083,35 @@ static void print_journal_tail(const cha + do { + if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER", + (const void **) &identifier, &identifier_len)) +- return; ++ goto done; + if (0 > sd_journal_get_data(j, "_PID", + (const void **) &pid, &pid_len)) +- return; ++ goto done; + if (0 > sd_journal_get_data(j, "MESSAGE", + (const void **) &message, &message_len)) +- return; ++ goto done; + + sd_journal_get_realtime_usec(j, &x); + t = x / 1000000; +- strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t)); +- +- fprintf(stdout, "%s", buf); +- ++ timestamp = make_time(time_mode, t); ++ /* Get rid of journal entry field identifiers */ + identifier = strchr(identifier, '=') + 1; +- pid = strchr(pid, '=') + 1 ; ++ pid = strchr(pid, '=') + 1; + message = strchr(message, '=') + 1; + +- fprintf(stdout, " %s", identifier); +- fprintf(stdout, "[%s]:", pid); +- fprintf(stdout, "%s\n", message); ++ fprintf(stdout, "%s %s[%s]: %s\n", timestamp, identifier, pid, ++ message); ++ free(timestamp); + } while (sd_journal_next(j)); + +- free(buf); ++done: + free(match); + sd_journal_flush_matches(j); + sd_journal_close(j); + } + #endif + +-static int print_pretty(struct libscols_table *tb) ++static int print_pretty(struct libscols_table *table) + { + struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); + struct libscols_column *col; +@@ -1113,8 +1120,8 @@ static int print_pretty(struct libscols_ + const char *hstr, *dstr; + int n = 0; + +- ln = scols_table_get_line(tb, 0); +- while (!scols_table_next_column(tb, itr, &col)) { ++ ln = scols_table_get_line(table, 0); ++ while (!scols_table_next_column(table, itr, &col)) { + + data = scols_line_get_cell(ln, n); + +@@ -1142,7 +1149,7 @@ static int print_user_table(struct lslog + print_pretty(tb); + #ifdef HAVE_LIBSYSTEMD + fprintf(stdout, _("\nLast logs:\n")); +- print_journal_tail(ctl->journal_path, ctl->uid, 3); ++ print_journal_tail(ctl->journal_path, ctl->uid, 3, ctl->time_mode); + fputc('\n', stdout); + #endif + } else +@@ -1175,16 +1182,25 @@ static void free_user(void *f) + free(u); + } + +-struct lslogins_timefmt { +- const char *name; +- int val; +-}; ++static int parse_time_mode(const char *optarg) ++{ ++ struct lslogins_timefmt { ++ const char *name; ++ const int val; ++ }; ++ static const struct lslogins_timefmt timefmts[] = { ++ {"iso", TIME_ISO}, ++ {"full", TIME_FULL}, ++ {"short", TIME_SHORT}, ++ }; ++ size_t i; + +-static struct lslogins_timefmt timefmts[] = { +- { "short", TIME_SHORT }, +- { "full", TIME_FULL }, +- { "iso", TIME_ISO }, +-}; ++ for (i = 0; i < ARRAY_SIZE(timefmts); i++) { ++ if (strcmp(timefmts[i].name, optarg) == 0) ++ return timefmts[i].val; ++ } ++ errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); ++} + + static void __attribute__((__noreturn__)) usage(FILE *out) + { +@@ -1193,16 +1209,18 @@ static void __attribute__((__noreturn__) + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options]\n"), program_invocation_short_name); + ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Display information about known users in the system.\n"), out); ++ + fputs(USAGE_OPTIONS, out); + fputs(_(" -a, --acc-expiration display info about passwords expiration\n"), out); + fputs(_(" -c, --colon-separate display data in a format similar to /etc/passwd\n"), out); + fputs(_(" -e, --export display in an export-able output format\n"), out); + fputs(_(" -f, --failed display data about the users' last failed logins\n"), out); +- fputs(_(" -G, --groups-info display information about groups\n"), out); ++ fputs(_(" -G, --supp-groups display information about groups\n"), out); + fputs(_(" -g, --groups= display users belonging to a group in \n"), out); + fputs(_(" -L, --last show info about the users' last login sessions\n"), out); + fputs(_(" -l, --logins= display only users from \n"), out); +- fputs(_(" -m, --supp-groups display supplementary groups as well\n"), out); + fputs(_(" -n, --newline display each piece of information on a new line\n"), out); + fputs(_(" --noheadings don't print headings\n"), out); + fputs(_(" --notruncate don't truncate output\n"), out); +@@ -1226,7 +1244,7 @@ static void __attribute__((__noreturn__) + fprintf(out, " %14s %s\n", coldescs[i].name, + _(coldescs[i].help)); + +- fprintf(out, _("\nFor more details see lslogins(1).\n")); ++ fprintf(out, USAGE_MAN_TAIL("lslogins(1)")); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } +@@ -1241,8 +1259,7 @@ int main(int argc, char *argv[]) + + /* long only options. */ + enum { +- OPT_VER = CHAR_MAX + 1, +- OPT_WTMP, ++ OPT_WTMP = CHAR_MAX + 1, + OPT_BTMP, + OPT_NOTRUNC, + OPT_NOHEAD, +@@ -1300,7 +1317,7 @@ int main(int argc, char *argv[]) + add_column(columns, ncolumns++, COL_UID); + add_column(columns, ncolumns++, COL_USER); + +- while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ", ++ while ((c = getopt_long(argc, argv, "acefGg:hLl:no:prsuVzZ", + longopts, NULL)) != -1) { + + err_exclusive_options(c, longopts, excl, excl_st); +@@ -1394,18 +1411,7 @@ int main(int argc, char *argv[]) + ctl->noheadings = 1; + break; + case OPT_TIME_FMT: +- { +- size_t i; +- +- for (i = 0; i < ARRAY_SIZE(timefmts); i++) { +- if (strcmp(timefmts[i].name, optarg) == 0) { +- ctl->time_mode = timefmts[i].val; +- break; +- } +- } +- if (ctl->time_mode == TIME_INVALID) +- usage(stderr); +- } ++ ctl->time_mode = parse_time_mode(optarg); + break; + case 'V': + printf(UTIL_LINUX_VERSION); +@@ -1433,7 +1439,7 @@ int main(int argc, char *argv[]) + logins = argv[optind]; + outmode = OUT_PRETTY; + } else if (argc != optind) +- usage(stderr); ++ errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users.")); + + scols_init_debug(0); diff --git a/SOURCES/nologin.8 b/SOURCES/nologin.8 new file mode 100644 index 00000000..5cb16013 --- /dev/null +++ b/SOURCES/nologin.8 @@ -0,0 +1,63 @@ +.\" $OpenBSD: nologin.8,v 1.8 1999/06/04 02:45:19 aaron Exp $ +.\" $NetBSD: nologin.8,v 1.3 1995/03/18 14:59:09 cgd Exp $ +.\" +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93 +.\" +.Dd February 15, 1997 +.Dt NOLOGIN 8 +.Os +.Sh NAME +.Nm nologin +.Nd politely refuse a login +.Sh SYNOPSIS +.Nm nologin +.Sh DESCRIPTION +.Nm +displays a message that an account is not available and +exits non-zero. +It is intended as a replacement shell field for accounts that +have been disabled. +.Pp +If the file +.Pa /etc/nologin.txt +exists, +.Nm +displays its contents to the user instead of the default message. +.Sh SEE ALSO +.Xr login 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.4 . diff --git a/SOURCES/nologin.c b/SOURCES/nologin.c new file mode 100644 index 00000000..8a51ba96 --- /dev/null +++ b/SOURCES/nologin.c @@ -0,0 +1,58 @@ +/* $OpenBSD: nologin.c,v 1.2 1997/04/04 16:51:37 millert Exp $ */ + +/* + * Copyright (c) 1997, Jason Downs. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +/* Distinctly different from _PATH_NOLOGIN. */ +#define _PATH_NOLOGIN_TXT "/etc/nologin.txt" + +#define DEFAULT_MESG "This account is currently not available.\n" + +/*ARGSUSED*/ +int main(argc, argv) + int argc; + char *argv[]; +{ + int nfd, nrd; + char nbuf[128]; + + nfd = open(_PATH_NOLOGIN_TXT, O_RDONLY); + if (nfd < 0) { + write(STDOUT_FILENO, DEFAULT_MESG, strlen(DEFAULT_MESG)); + exit (1); + } + + while ((nrd = read(nfd, nbuf, sizeof(nbuf))) > 0) + write(STDOUT_FILENO, nbuf, nrd); + close (nfd); + + exit (1); +} diff --git a/SOURCES/rhel7.0-unshare-user.patch b/SOURCES/rhel7.0-unshare-user.patch new file mode 100644 index 00000000..2e3e60c7 --- /dev/null +++ b/SOURCES/rhel7.0-unshare-user.patch @@ -0,0 +1,154 @@ +diff -up util-linux-2.23.2/sys-utils/nsenter.1.kzak util-linux-2.23.2/sys-utils/nsenter.1 +--- util-linux-2.23.2/sys-utils/nsenter.1.kzak 2014-03-12 12:39:19.283577293 +0100 ++++ util-linux-2.23.2/sys-utils/nsenter.1 2014-03-12 12:42:08.930336415 +0100 +@@ -47,12 +47,7 @@ flag). + will fork by default if changing the PID namespace, so that the new program + and its children share the same PID namespace and are visible to each other. + If \-\-no\-fork is used, the new program will be exec'ed without forking. +-.TP +-.B user namespace +-process will have distinct set of UIDs, GIDs and capabilities +-.RB ( CLONE_\:NEWUSER +-flag). +-.TP ++.PP + See the + .BR clone (2) + for exact semantics of the flags. +@@ -88,9 +83,6 @@ the network namespace + /proc/\fIpid\fR/ns/pid + the PID namespace + .TP +-/proc/\fIpid\fR/ns/user +-the user namespace +-.TP + /proc/\fIpid\fR/root + the root directory + .TP +@@ -124,11 +116,6 @@ Enter the PID namespace. If no file is + the target process. If file is specified enter the PID namespace specified by + file. + .TP +-\fB\-U\fR, \fB\-\-user\fR [\fIfile\fR] +-Enter the user namespace. If no file is specified enter the user namespace of +-the target process. If file is specified enter the user namespace specified by +-file. +-.TP + \fB\-r\fR, \fB\-\-root\fR [\fIdirectory\fR] + Set the root directory. If no directory is specified set the root directory to + the root directory of the target process. If directory is specified set the +diff -up util-linux-2.23.2/sys-utils/nsenter.c.kzak util-linux-2.23.2/sys-utils/nsenter.c +--- util-linux-2.23.2/sys-utils/nsenter.c.kzak 2014-03-12 12:39:10.402485179 +0100 ++++ util-linux-2.23.2/sys-utils/nsenter.c 2014-03-12 12:44:07.986570461 +0100 +@@ -42,12 +42,7 @@ static struct namespace_file { + int fd; + } namespace_files[] = { + /* Careful the order is significant in this array. +- * +- * The user namespace comes first, so that it is entered +- * first. This gives an unprivileged user the potential to +- * enter the other namespaces. + */ +- { .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 }, + { .nstype = CLONE_NEWIPC, .name = "ns/ipc", .fd = -1 }, + { .nstype = CLONE_NEWUTS, .name = "ns/uts", .fd = -1 }, + { .nstype = CLONE_NEWNET, .name = "ns/net", .fd = -1 }, +@@ -71,7 +66,6 @@ static void usage(int status) + fputs(_(" -i, --ipc [=] enter System V IPC namespace\n"), out); + fputs(_(" -n, --net [=] enter network namespace\n"), out); + fputs(_(" -p, --pid [=] enter pid namespace\n"), out); +- fputs(_(" -U, --user [=] enter user namespace\n"), out); + fputs(_(" -r, --root [=] set the root directory\n"), out); + fputs(_(" -w, --wd [=] set the working directory\n"), out); + fputs(_(" -F, --no-fork do not fork before exec'ing \n"), out); +@@ -168,7 +162,6 @@ int main(int argc, char *argv[]) + { "ipc", optional_argument, NULL, 'i' }, + { "net", optional_argument, NULL, 'n' }, + { "pid", optional_argument, NULL, 'p' }, +- { "user", optional_argument, NULL, 'U' }, + { "root", optional_argument, NULL, 'r' }, + { "wd", optional_argument, NULL, 'w' }, + { "no-fork", no_argument, NULL, 'F' }, +@@ -186,7 +179,7 @@ int main(int argc, char *argv[]) + atexit(close_stdout); + + while ((c = +- getopt_long(argc, argv, "hVt:m::u::i::n::p::U::r::w::F", ++ getopt_long(argc, argv, "hVt:m::u::i::n::p::r::w::F", + longopts, NULL)) != -1) { + switch (c) { + case 'h': +@@ -228,12 +221,6 @@ int main(int argc, char *argv[]) + else + namespaces |= CLONE_NEWPID; + break; +- case 'U': +- if (optarg) +- open_namespace_fd(CLONE_NEWUSER, optarg); +- else +- namespaces |= CLONE_NEWUSER; +- break; + case 'F': + do_fork = 0; + break; +diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1 +--- util-linux-2.23.2/sys-utils/unshare.1.kzak 2014-03-12 12:39:41.367806340 +0100 ++++ util-linux-2.23.2/sys-utils/unshare.1 2014-03-12 12:40:25.186260760 +0100 +@@ -34,9 +34,6 @@ etc. (\fBCLONE_NEWNET\fP flag). + .BR "pid namespace" + children will have a distinct set of pid to process mappings than their parent. + (\fBCLONE_NEWPID\fP flag). +-.TP +-.BR "user namespace" +-process will have distinct set of uids, gids and capabilities. (\fBCLONE_NEWUSER\fP flag). + .PP + See the \fBclone\fR(2) for exact semantics of the flags. + .SH OPTIONS +@@ -58,9 +55,6 @@ Unshare the network namespace. + .TP + .BR \-p , " \-\-pid" + Unshare the pid namespace. +-.TP +-.BR \-U , " \-\-user" +-Unshare the user namespace. + .SH SEE ALSO + .BR unshare (2), + .BR clone (2) +diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c +--- util-linux-2.23.2/sys-utils/unshare.c.kzak 2014-03-12 12:39:46.385858383 +0100 ++++ util-linux-2.23.2/sys-utils/unshare.c 2014-03-12 12:44:49.955005384 +0100 +@@ -45,7 +45,6 @@ static void usage(int status) + fputs(_(" -i, --ipc unshare System V IPC namespace\n"), out); + fputs(_(" -n, --net unshare network namespace\n"), out); + fputs(_(" -p, --pid unshare pid namespace\n"), out); +- fputs(_(" -U, --user unshare user namespace\n"), out); + + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); +@@ -65,7 +64,6 @@ int main(int argc, char *argv[]) + { "ipc", no_argument, 0, 'i' }, + { "net", no_argument, 0, 'n' }, + { "pid", no_argument, 0, 'p' }, +- { "user", no_argument, 0, 'U' }, + { NULL, 0, 0, 0 } + }; + +@@ -78,7 +76,7 @@ int main(int argc, char *argv[]) + textdomain(PACKAGE); + atexit(close_stdout); + +- while ((c = getopt_long(argc, argv, "hVmuinpU", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "hVmuinp", longopts, NULL)) != -1) { + switch (c) { + case 'h': + usage(EXIT_SUCCESS); +@@ -100,9 +98,6 @@ int main(int argc, char *argv[]) + case 'p': + unshare_flags |= CLONE_NEWPID; + break; +- case 'U': +- unshare_flags |= CLONE_NEWUSER; +- break; + default: + usage(EXIT_FAILURE); + } diff --git a/SOURCES/v2.26-nsenter-selinux.patch b/SOURCES/v2.26-nsenter-selinux.patch new file mode 100644 index 00000000..a72c62b4 --- /dev/null +++ b/SOURCES/v2.26-nsenter-selinux.patch @@ -0,0 +1,129 @@ +diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am +--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak 2015-06-26 10:21:34.337221288 +0200 ++++ util-linux-2.23.2/sys-utils/Makemodule.am 2015-06-26 10:22:18.719885983 +0200 +@@ -308,7 +308,7 @@ if BUILD_NSENTER + usrbin_exec_PROGRAMS += nsenter + dist_man_MANS += sys-utils/nsenter.1 + nsenter_SOURCES = sys-utils/nsenter.c +-nsenter_LDADD = $(LDADD) libcommon.la ++nsenter_LDADD = $(LDADD) libcommon.la $(SELINUX_LIBS) + endif + + if BUILD_HWCLOCK +diff -up util-linux-2.23.2/sys-utils/nsenter.1.kzak util-linux-2.23.2/sys-utils/nsenter.1 +--- util-linux-2.23.2/sys-utils/nsenter.1.kzak 2015-06-26 10:14:00.947646586 +0200 ++++ util-linux-2.23.2/sys-utils/nsenter.1 2015-06-26 10:21:34.337221288 +0200 +@@ -155,6 +155,11 @@ Do not fork before exec'ing the specifie + PID namespace, \fBnsenter\fP calls \fBfork\fP before calling \fBexec\fP so that + any children will also be in the newly entered PID namespace. + .TP ++\fB\-Z\fR, \fB\-\-follow\-context\fR ++Set the SELinux security context used for executing a new process according to ++already running process specified by \fB\-\-target\fR PID. (The util-linux has ++to be compiled with SELinux support otherwise the option is unavailable.) ++.TP + \fB\-V\fR, \fB\-\-version\fR + Display version information and exit. + .TP +@@ -163,10 +168,14 @@ Display help text and exit. + .SH SEE ALSO + .BR setns (2), + .BR clone (2) +-.SH AUTHOR +-.MT ebiederm@xmission.com ++.SH AUTHORS ++.UR biederm@xmission.com + Eric Biederman +-.ME ++.UE ++.br ++.UR kzak@redhat.com ++Karel Zak ++.UE + .SH AVAILABILITY + The nsenter command is part of the util-linux package and is available from + .UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/ +diff -up util-linux-2.23.2/sys-utils/nsenter.c.kzak util-linux-2.23.2/sys-utils/nsenter.c +--- util-linux-2.23.2/sys-utils/nsenter.c.kzak 2015-06-26 10:14:00.947646586 +0200 ++++ util-linux-2.23.2/sys-utils/nsenter.c 2015-06-26 10:21:34.337221288 +0200 +@@ -30,6 +30,10 @@ + #include + #include + ++#ifdef HAVE_LIBSELINUX ++# include ++#endif ++ + #include "strutils.h" + #include "nls.h" + #include "c.h" +@@ -82,6 +86,9 @@ static void usage(int status) + fputs(_(" -r, --root[=] set the root directory\n"), out); + fputs(_(" -w, --wd[=] set the working directory\n"), out); + fputs(_(" -F, --no-fork do not fork before exec'ing \n"), out); ++#ifdef HAVE_LIBSELINUX ++ fputs(_(" -Z, --follow-context set SELinux context according to --target PID\n"), out); ++#endif + + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); +@@ -185,6 +192,9 @@ int main(int argc, char *argv[]) + { "wd", optional_argument, NULL, 'w' }, + { "no-fork", no_argument, NULL, 'F' }, + { "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED }, ++#ifdef HAVE_LIBSELINUX ++ { "follow-context", no_argument, NULL, 'Z' }, ++#endif + { NULL, 0, NULL, 0 } + }; + +@@ -194,6 +204,9 @@ int main(int argc, char *argv[]) + int do_fork = -1; /* unknown yet */ + uid_t uid = 0; + gid_t gid = 0; ++#ifdef HAVE_LIBSELINUX ++ bool selinux = 0; ++#endif + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); +@@ -201,7 +214,7 @@ int main(int argc, char *argv[]) + atexit(close_stdout); + + while ((c = +- getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::F", ++ getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::FZ", + longopts, NULL)) != -1) { + switch (c) { + case 'h': +@@ -275,11 +288,30 @@ int main(int argc, char *argv[]) + case OPT_PRESERVE_CRED: + preserve_cred = 1; + break; ++#ifdef HAVE_LIBSELINUX ++ case 'Z': ++ selinux = 1; ++ break; ++#endif + default: + usage(EXIT_FAILURE); + } + } + ++#ifdef HAVE_LIBSELINUX ++ if (selinux && is_selinux_enabled() > 0) { ++ char *scon = NULL; ++ ++ if (!namespace_target_pid) ++ errx(EXIT_FAILURE, _("no target PID specified for --follow-context")); ++ if (getpidcon(namespace_target_pid, &scon) < 0) ++ errx(EXIT_FAILURE, _("failed to get %d SELinux context"), ++ (int) namespace_target_pid); ++ if (setexeccon(scon) < 0) ++ errx(EXIT_FAILURE, _("failed to set exec context to '%s'"), scon); ++ freecon(scon); ++ } ++#endif + /* + * Open remaining namespace and directory descriptors. + */ diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec old mode 100755 new mode 100644 index c3008ca7..d8d36196 --- a/SPECS/util-linux.spec +++ b/SPECS/util-linux.spec @@ -2,7 +2,7 @@ Summary: A collection of basic system utilities Name: util-linux Version: 2.23.2 -Release: 26%{?dist}.2 +Release: 52%{?dist} License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain Group: System Environment/Base URL: http://en.wikipedia.org/wiki/Util-linux @@ -57,6 +57,9 @@ Conflicts: e2fsprogs < 1.41.8-5 Obsoletes: util-linux-ng < 2.19 Provides: util-linux-ng = %{version}-%{release} Conflicts: filesystem < 3 +# lsmem and chmem from s390utils +Conflicts: s390utils-base < 2:1.23.0-33 + Provides: /bin/dmesg Provides: /bin/kill Provides: /bin/more @@ -199,12 +202,189 @@ Patch56: 2.25-libblkid-return-codes.patch Patch57: 2.26-libblkid-fat.patch # -# RHEL 7.2.Z +# RHEL7.3 # -# 1302332 - [libblkid] Failed to get offset of the xfs_external_log signature +# 1301091 - [libblkid] Failed to get offset of the xfs_external_log signature Patch58: 2.27-libblkid-xfs-log.patch -# 1317953 - lslogins crash when executed with buggy username -Patch59: 2.28-lslogins-1317953.patch +# 1291554 - lslogins crash when executed with buggy username +Patch59: 2.28-lslogins-rebase.patch +# 1092520 - util-linux - PIE and RELRO check +Patch60: 0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch +# 1248003 - mount only parses = lines from fstab fs_spec field available from blkid block device +Patch61: 0061-libmount-be-more-restrictive-about-valid-tag-names.patch +# 1271850 - mount -a doesn't catch a typo in /etc/fstab and a typo in /etc/fstab can make a system not reboot properly +Patch62: 0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch +# 1290689 - util-linux: /bin/login does not retry getpwnam_r with larger buffers, leading to login failure +Patch63: 0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch +# 1296366 - Bash completion for more(1) handles file names with spaces incorrectly +Patch64: 0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch +# 1296521 - RHEL7: update audit event in hwclock +Patch65: 0065-hwclock-change-audit-message.patch +# 1304426 - [rfe] /bin/su should be improved to reduce stack use +Patch66: 0066-su-clean-up-groups-initialization.patch +# 1326615 - util-linux/lscpu: Fix model and model name on Power Systems +Patch67: 0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch +# 1326615 - util-linux/lscpu: Fix model and model name on Power Systems +Patch68: 0068-lscpu-use-cpu-and-revision-tag-if-available.patch +# 1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora) +Patch69: 0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch +# 1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora) +Patch70: 0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch +# 587393 - [RFE] Make sure util-linux is ready for writable overlays +Patch71: 0071-findmnt-don-t-rely-on-st_dev-for-target.patch +# 587393 - [RFE] Make sure util-linux is ready for writable overlays +Patch72: 0072-libmount-cleanup-fs-root-detection-code.patch +# 587393 - [RFE] Make sure util-linux is ready for writable overlays +Patch73: 0073-libmount-mark-overlay-as-pseudo-FS.patch +# 1344222 - logger port option in help is misleading +Patch74: 0074-logger-be-more-precise-about-port-description.patch +# 1344482 - util-linux fails valid_pmbr() size checks if device is > 2.14TB, Device label type: dos instead of gpt +Patch75: 0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch +# 1332084 - [RFE] Inclusion of lsns command in util-linux Package +Patch76: 0076-lsns-backport-new-command.patch +# 1153770 - backport lsipc +Patch77: 0077-lib-strutils-make-strmode-more-generic.patch +# 1153770 - backport lsipc +Patch78: 0078-lsipc-backport-new-command.patch +# 1327886 - Backport blkdiscard's "-z" flag to RHEL +Patch79: 0079-blkdiscard-backport-zeroout-support.patch +# 1029385 - lack of non-ascii support +Patch80: 0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch +# 1298384 - RFE: add SCHED_DEADLINE support to chrt +Patch81: 0081-chrt-backport-DEADLINE-scheduler-support.patch +# 1304246 - fdisk 'f' subcommand updates partition ranges wrongly +Patch82: 0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch +# 1153770 - backport lsipc +Patch83: 0083-tests-cleanup-tests.patch +# 1281839 - [RFE]Bind mounts should be handled gracefully by the operating system +Patch84: 0084-libmount-add-support-for-bind-ro.patch +# 1007734 - blkid shows devices as /dev/block/$MAJOR:$MINOR +Patch85: 0085-libblkid-store-only-canonical-devnames-to-the-cache.patch +# 1349536 - Extended partition loop in MBR partition table leads to DOS +Patch86: 0086-libblkid-avoid-recursion-in-EBR.patch + +# +# RHEL7.4 +# +# 1405238 - findmnt --target behaviour changed in 7.3, shows all mount-points in chroot +Patch87: 0087-findmnt-fix-target-behaviour.patch +# 1419474 +Patch88: 0088-su-properly-clear-child-PID.patch +# 1344102 - fdisk does not handle 4kN devices correctly in 'Blocks' calculation +Patch89: 0089-fdisk-fix-Blocks-column-calculation.patch +# 1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output +Patch90: 0090-fdisk-fix-menu-for-GPT.patch +# 1323916 - logger unnecessarily splits messages sent via stdin into 1024 byte chunks +Patch91: 0091-logger-backport-size.patch +# 1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present +Patch92: 0092-fdisk-print-header-UUID-for-GPT.patch +# 1362662 - fdisk -l fails/stops on first passive/not ready device, works on RHEL6 +Patch93: 0093-fdisk-improve-l-error-handling.patch +# 1369436 - losetup man page incorrect syntax for Setup loop device +Patch94: 0094-losetup-improve-man-page-SYNOPSIS.patch +# 1392656 - [LLNL 7.4 Bug] fix buffer overflows in util-linux with upstream patch +Patch95: 0095-libblkid-fix-potential-bufer-overflows.patch +# 1370959 - [FJ7.3 Bug]: man 8 umount is wrong. +Patch96: 0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch +# 1357746 - mount -av" report NFS "successfully mounted" but it is not. +Patch97: 0097-mount-fix-all-and-nofail-return-code.patch +# 1417722 - umount -a results in selinux being reported as Disabled +Patch98: 0098-umount-exclude-selinuxfs-from-all.patch +# 1402825 - RHEL7: "sfdisk -s" can't list the disk size +Patch99: 0099-sfdisk-remove-useless-CDROM-detection-for-s.patch +# 1403973 - /usr/bin/more crash on repeat search on failed regex match +Patch100: 0100-more-fix-repeat-search-crash.patch +# 1403971 - /usr/bin/more crash in end_it due to double free +Patch101: 0101-more-avoid-double-free-on-exit.patch +# 1358095 - ipcs shows wrong gid information +Patch102: 0102-ipcs-show-gid-instead-of-uid.patch +# 1358097 - ipcs shows strange status message in ja locale +Patch103: 0103-ipcs-fix-JP-status-message.patch +# 1378100 - fix swapon discard option parsing +Patch104: 0104-swapon-fix-discard-option-parsing.patch +# 1416467 - [RFE] Add support for posix_fallocate(3) call in fallocate(1) utility +Patch105: 0105-fallocate-Added-posix_fallocate-support.patch +# 1358755 - Backport request for zramctl on util-linux v2.23.2 +Patch106: 0106-zramctl-backport-from-v2.29.patch +# 1392661 - [LLNL 7.4 Bug] add zfs patches to util-linux +Patch107: 0107-libblkid-zfs-let-s-keep-compiler-happy.patch +Patch108: 0108-blkid-make-zfs-detection-more-robust.patch +Patch109: 0109-zfs-make-less-syscalls.patch +Patch110: 0110-libblkid-zfs-keep-bufferes-read-only.patch +Patch111: 0111-libblkid-don-t-mark-zfs-as-RAID.patch +Patch112: 0112-tests-update-ZFS-test.patch +Patch113: 0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch +Patch114: 0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch +# 1360764 - SMT: "Threads Per Core" will automatically change when odd or even number of vcpu are enabled online. +# 1397709 - [7.4 FEAT] Refresh code for lscpu to support s390x cpu topology +Patch115: 0115-lscpu-backport-from-v2.29.patch +# 1402183 - [HPE 7.3 Bug] fdisk -l does not list non-BTT NVDIMM devices +Patch116: 0116-fdisk-use-sysfs_devno_is_wholedisk.patch +# 1358755 - Backport request for zramctl on util-linux v2.23.2 +Patch117: 0117-zramctl-add-bash-completion.patch +Patch118: 0118-zramctl-make-mm_stat-parser-more-robust.patch +# 1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output +Patch119: 0119-fdisk-improve-menu-and-u-for-GPT.patch +# 1360764 1397709 - lscpu rebase +Patch120: 0120-tests-update-for-RHEL7.4-changes.patch +# 1358755 - Backport request for zramctl on util-linux v2.23.2 +Patch121: 0121-zramctl-be-more-specific-about-default-output.patch +# 1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present +Patch122: 0122-libfdisk-gpt-fix-UUID-printing.patch +# 1451704 - [Intel 7.4 BUG] IMSM RAID on 4k disks not assembled on boot +Patch123: 0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch +# 1455664 - lscpu causes kernel panic on HPE Comanche / Cavium ThunderX2 (cn99xx) +Patch124: 0124-lscpu-use-sysfs-for-table-access-if-available.patch +# 1457744 - lscpu -e get crashed after offline one host cpu on amd machine +Patch125: 0125-lscpu-improve-for-offline-CPUs-on-AMD.patch + +# +# RHEL7.5 +# +# 1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages +Patch126: 0126-libmount-use-eacess-rather-than-open-to-check-mtab-u.patch +# 1498462 - agetty not parsing /etc/os-release correctly when processing /etc/issue +Patch127: 0127-agetty-fix-etc-os-release-parsing.patch +# 1490984 - Please update fdisk's manual page +Patch128: 0128-fdisk-remove-obsolete-info-about-GPT-from-man-page.patch +# 1487031 - [GSS][RFE]The Ceph disk type is unknown then we run the command "fdisk -l" +Patch129: 0129-libfdisk-gpt-sync-type-UUIDs-with-upstream.patch +# 1468646 - lscpu output missing Hypervisor +Patch130: 0130-lscpu-cleanup-DMI-detection-return-codes.patch +# 1455398 - flock --timeout=0 doesn't work on RHEL7 +Patch131: 0131-flock-zero-timeout-is-valid.patch +# 1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger +Patch132: 0132-logger-add-man-page-note-about-the-default-tag.patch +# 1427500 - util-linux: script does not retry on EINTR when logging command output +Patch133: 0133-script-use-all-io-to-write.patch +# 1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger +Patch134: 0134-logger-do-not-rely-only-getlogin-3-telling-who-ran-t.patch +# 1296233 - login(1) writes 0.0.0.0 IP address to wtmp when executed with "-h " hostname +Patch135: 0135-login-use-IPv4-on-IPv4-mapping-to-IPv6.patch +# 1501953 - blkid shows wrong return code on failure with ambivalent results +Patch136: 0136-blkid-update-man-page-about-lsblk-and-ambivalent-pro.patch +# 1486777 - wipefs printing duplicate gpt clear messages +Patch137: 0137-wipefs-fix-t-filter.patch +# 1454652 - fix test suite +Patch138: 0138-tests-backport-new-ts_scsi_debug_init.patch +Patch139: 0139-tests-ts_scsi_debug_init-must-not-run-in-a-subshell.patch +Patch140: 0140-tests-cleanup-fdisk-outputs.patch +Patch141: 0141-tests-check-for-mdadm.patch +# 1496421 - [Pegas1.1 FEAT] z Systems: Move lsmem and chmem to util-linux (through rebase >= 2.30) +Patch142: 0142-lsmem-chmem-backport-new-commands.patch +Patch143: 0143-lsmem-make-split-optional-follow-output-by-default.patch +# 1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages +Patch144: 0144-libmount-fix-access-utab-write-test.patch +# 1520906 - make hostname in login(1) prompt optional [rhel-7.5] +Patch145: 0145-login-add-LOGIN_PLAIN_PROMPT-to-login.defs.patch +# 1521163 - [RFE] blkid can identify magic number and UUID of VDO volume +Patch146: 0146-libblkid-Add-VDO-superblock-information-into-blkid.patch +# 1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount +Patch147: 0147-include-debug-don-t-print-pointer-address-for-SUID-p.patch +# 1538545 - SELinux error creating swap file +Patch148: 0148-mkswap-tolerate-ENOTSUP-when-failing-to-relabel.patch +# 1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount +Patch149: 0149-libmount-fix-debug-message.patch %description The util-linux package contains a large variety of low-level system @@ -326,9 +506,14 @@ unset LINGUAS || : # unfortunately, we did changes to build-system ./autogen.sh +# we modify .po files by RHEL patches +rm -f po/stamp* + export CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $RPM_OPT_FLAGS" export SUID_CFLAGS="-fpie" export SUID_LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" +export DAEMON_CFLAGS="$SUID_CFLAGS" +export DAEMON_LDFLAGS="$SUID_LDFLAGS" %configure \ --with-systemdsystemunitdir=%{_unitdir} \ --disable-silent-rules \ @@ -456,8 +641,7 @@ chmod 644 misc-utils/getopt-*.{bash,tcsh} rm -f ${RPM_BUILD_ROOT}%{_datadir}/getopt/* rmdir ${RPM_BUILD_ROOT}%{_datadir}/getopt -ln -sf /proc/mounts %{buildroot}/etc/mtab - +ln -sf ../proc/self/mounts %{buildroot}/etc/mtab # remove static libs rm -f $RPM_BUILD_ROOT%{_libdir}/lib{uuid,blkid,mount}.a @@ -495,7 +679,7 @@ if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then fi fi if [ ! -L /etc/mtab ]; then - ln -fs /proc/mounts /etc/mtab + ln -sf ../proc/self/mounts /etc/mtab || : fi %post -n libblkid @@ -580,6 +764,7 @@ fi %{_bindir}/colcrt %{_bindir}/colrm %{_bindir}/column +%{_bindir}/chmem %{_bindir}/dmesg %{_bindir}/eject %{_bindir}/fallocate @@ -593,6 +778,9 @@ fi %{_bindir}/ipcs %{_bindir}/isosize %{_bindir}/kill +%{_bindir}/lsipc +%{_bindir}/lsns +%{_bindir}/lsmem %{_bindir}/logger %{_bindir}/look %{_bindir}/lsblk @@ -647,6 +835,8 @@ fi %{_mandir}/man1/look.1* %{_mandir}/man1/lscpu.1* %{_mandir}/man1/lslogins.1* +%{_mandir}/man1/lsmem.1* +%{_mandir}/man1/lsipc.1* %{_mandir}/man1/mcookie.1* %{_mandir}/man1/more.1* %{_mandir}/man1/mountpoint.1* @@ -678,6 +868,7 @@ fi %{_mandir}/man8/blkid.8* %{_mandir}/man8/blockdev.8* %{_mandir}/man8/chcpu.8* +%{_mandir}/man8/chmem.8* %{_mandir}/man8/ctrlaltdel.8* %{_mandir}/man8/delpart.8* %{_mandir}/man8/fdisk.8* @@ -692,7 +883,8 @@ fi %{_mandir}/man8/ldattach.8* %{_mandir}/man8/losetup.8* %{_mandir}/man8/lsblk.8* -%{_mandir}/man8/lslocks.8.gz +%{_mandir}/man8/lslocks.8* +%{_mandir}/man8/lsns.8* %{_mandir}/man8/mkfs.8* %{_mandir}/man8/mkfs.cramfs.8* %{_mandir}/man8/mkfs.minix.8* @@ -707,14 +899,15 @@ fi %{_mandir}/man8/resizepart.8* %{_mandir}/man8/rtcwake.8* %{_mandir}/man8/setarch.8* -%{_mandir}/man8/sulogin.8.gz +%{_mandir}/man8/sulogin.8* %{_mandir}/man8/swaplabel.8* %{_mandir}/man8/swapoff.8* %{_mandir}/man8/swapon.8* %{_mandir}/man8/switch_root.8* %{_mandir}/man8/umount.8* -%{_mandir}/man8/wdctl.8.gz +%{_mandir}/man8/wdctl.8* %{_mandir}/man8/wipefs.8* +%{_mandir}/man8/zramctl.8* %{_sbindir}/addpart %{_sbindir}/agetty %{_sbindir}/blkdiscard @@ -749,7 +942,7 @@ fi %{_sbindir}/swapon %{_sbindir}/switch_root %{_sbindir}/wipefs - +%{_sbindir}/zramctl %{compldir}/addpart %{compldir}/blkdiscard %{compldir}/blkid @@ -828,6 +1021,7 @@ fi %{compldir}/whereis %{compldir}/wipefs %{compldir}/write +%{compldir}/zramctl %ifnarch s390 s390x %{_sbindir}/clock @@ -924,11 +1118,140 @@ fi %{_libdir}/pkgconfig/uuid.pc %changelog -* Wed Mar 16 2016 Karel Zak 2.23.2-26.el7_2.2 -- fix #1317953 - lslogins crash when executed with buggy username - -* Thu Jan 28 2016 Karel Zak 2.23.2-26.el7_2.1 -- fix #1302332 - [libblkid] Failed to get offset of the xfs_external_log signature +* Fri Feb 02 2018 Karel Zak 2.23.2-52 +- fix #1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount + +* Wed Jan 31 2018 Karel Zak 2.23.2-51 +- fix #1538545 - SELinux error creating swap file + +* Tue Jan 23 2018 Karel Zak 2.23.2-50 +- fix #1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount + +* Mon Dec 11 2017 Karel Zak 2.23.2-49 +- fix #1520906 - make hostname in login(1) prompt optional +- fix #1521163 - [RFE] blkid can identify magic number and UUID of VDO volume + +* Thu Nov 09 2017 Karel Zak 2.23.2-48 +- improve libmount eaccess test (#1499760) + +* Wed Nov 08 2017 Karel Zak 2.23.2-47 +- improve lsmem (#1496421) + +* Mon Oct 23 2017 Karel Zak 2.23.2-46 +- fix #1496421 - Move lsmem and chmem to util-linux + +* Tue Oct 17 2017 Karel Zak 2.23.2-45 +- fix #1501953 - blkid shows wrong return code on failure with ambivalent results +- fix #1486777 - wipefs printing duplicate gpt clear messages +- fix #1454652 - fix test suite + +* Mon Oct 16 2017 Karel Zak 2.23.2-44 +- fix #1478002 - systemd read-only container produces errors +- fix #1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages +- fix #1498462 - agetty not parsing /etc/os-release correctly when processing /etc/issue +- fix #1490984 - Please update fdisk's manual page +- fix #1487031 - [GSS][RFE]The Ceph disk type is unknown then we run the command "fdisk -l" +- fix #1468646 - lscpu output missing Hypervisor +- fix #1455398 - flock --timeout=0 doesn't work on RHEL7 +- fix #1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger +- fix #1427500 - util-linux: script does not retry on EINTR when logging command output +- fix #1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger +- fix #1296233 - login(1) writes 0.0.0.0 IP address to wtmp when executed with "-h " hostname + +* Thu Jun 01 2017 Karel Zak 2.23.2-43 +- fix #1457744 - lscpu -e get crashed after offline one host cpu on amd machine + +* Wed May 31 2017 Karel Zak 2.23.2-42 +- fix #1455664 - lscpu causes kernel panic on HPE Comanche / Cavium ThunderX2 (cn99xx) + +* Tue May 23 2017 Karel Zak 2.23.2-41 +- fix #1451704 - IMSM RAID on 4k disks not assembled on boot +- force gettext messages refresh (for #1358097 bugfix) + +* Wed May 10 2017 Karel Zak 2.23.2-40 +- improve libfdisk GPT UUID printing (#1344726) + +* Tue Apr 04 2017 Karel Zak 2.23.2-39 +- update package regression tests (due to #1360764 #1397709) +- improve zramctl man page (#1358755) + +* Tue Apr 04 2017 Karel Zak 2.23.2-38 +- improve fdisk menu for GPT (#1344720) + +* Thu Mar 30 2017 Karel Zak 2.23.2-37 +- improve zram mm_stat parser (#1358755) + +* Wed Mar 22 2017 Karel Zak 2.23.2-36 +- fix #1344102 - fdisk does not handle 4kN devices correctly in 'Blocks' calculation +- fix #1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output +- fix #1323916 - logger unnecessarily splits messages sent via stdin into 1024 byte chunks +- fix #1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present +- fix #1362662 - fdisk -l fails/stops on first passive/not ready device, works on RHEL6 +- fix #1369436 - losetup man page incorrect syntax for Setup loop device +- fix #1392656 - [LLNL 7.4 Bug] fix buffer overflows in util-linux with upstream patch +- fix #1370959 - [FJ7.3 Bug]: man 8 umount is wrong. +- fix #1357746 - mount -av" report NFS "successfully mounted" but it is not. +- fix #1417722 - umount -a results in selinux being reported as Disabled +- fix #1402825 - RHEL7: "sfdisk -s" can't list the disk size +- fix #1403973 - /usr/bin/more crash on repeat search on failed regex match +- fix #1403971 - /usr/bin/more crash in end_it due to double free +- fix #1358095 - ipcs shows wrong gid information +- fix #1358097 - ipcs shows strange status message in ja locale +- fix #1378100 - fix swapon discard option parsing +- fix #1416467 - [RFE] Add support for posix_fallocate(3) call in fallocate(1) utility +- fix #1358755 - Backport request for zramctl on util-linux v2.23.2 +- fix #1392661 - [LLNL 7.4 Bug] add zfs patches to util-linux +- fix #1360764 - SMT: "Threads Per Core" will automatically change when odd or even number of vcpu are enabled online. +- fix #1397709 - [7.4 FEAT] Refresh code for lscpu to support s390x cpu topology +- fix #1402183 - [HPE 7.3 Bug] fdisk -l does not list non-BTT NVDIMM devices + +* Wed Feb 8 2017 Karel Zak 2.23.2-35 +* fix #1419474 - su: properly clear child PID + +* Mon Jan 23 2017 Karel Zak 2.23.2-34 +- fix #1405238 - findmnt --target behaviour changed in 7.3, shows all mount-points in chroot + +* Tue Jul 12 2016 Karel Zak 2.23.2-33 +- improve patch for #1007734 (libblkid realpaths) + +* Tue Jul 12 2016 Karel Zak 2.23.2-32 +- improve patch for chrt(1) deadline support #1298384 +- fix #1007734 - blkid shows devices as /dev/block/$MAJOR:$MINOR +- fix #1349536 - Extended partition loop in MBR partition table leads to DOS + +* Mon Jul 04 2016 Karel Zak 2.23.2-31 +- improve spec file for #1092520 + +* Fri Jul 01 2016 Karel Zak 2.23.2-30 +- improve patch for chrt(1) deadline support #1298384 +- improve regression tests + +* Thu Jun 30 2016 Karel Zak 2.23.2-29 +- fix #1029385 - lack of non-ascii support +- fix #1092520 - util-linux - PIE and RELRO check +- fix #1153770 - backport lsipc +- fix #1248003 - mount only parses = lines from fstab fs_spec field available from blkid block device +- fix #1271850 - mount -a doesn't catch a typo in /etc/fstab and a typo in /etc/fstab can make a system not reboot properly +- fix #1281839 - [RFE]Bind mounts should be handled gracefully by the operating system +- fix #1290689 - util-linux: /bin/login does not retry getpwnam_r with larger buffers, leading to login failure +- fix #1296366 - Bash completion for more(1) handles file names with spaces incorrectly +- fix #1296521 - RHEL7: update audit event in hwclock +- fix #1298384 - RFE: add SCHED_DEADLINE support to chrt +- fix #1304246 - fdisk 'f' subcommand updates partition ranges wrongly +- fix #1304426 - [rfe] /bin/su should be improved to reduce stack use +- fix #1326615 - util-linux/lscpu: Fix model and model name on Power Systems +- fix #1327886 - Backport blkdiscard's "-z" flag to RHEL +- fix #1332084 - [RFE] Inclusion of lsns command in util-linux Package +- fix #1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora) +- fix #1344222 - logger port option in help is misleading +- fix #1344482 - util-linux fails valid_pmbr() size checks if device is > 2.14TB, Device label type: dos instead of gpt +- fix #587393 - [RFE] Make sure util-linux is ready for writable overlays + +* Wed Mar 16 2016 Karel Zak 2.23.2-28 +- fix #1291554 - lslogins crash when executed with buggy username + +* Thu Jan 28 2016 Karel Zak 2.23.2-27 +- fix #1301091 - [libblkid] Failed to get offset of the xfs_external_log signature * Fri Aug 21 2015 Karel Zak 2.23.2-26 - fix #1182831 - blkid incorrectly detects boot sec + MBR as FAT