From 981192bf421b706d4134b59d839467556a18f7bf4cc90832b4e252944b352de0 Mon Sep 17 00:00:00 2001 From: Adam Majer Date: Wed, 23 Jan 2019 15:51:22 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/Base:System/shadow?expand=0&rev=59 --- btrfs-subvolumes.patch | 148 +++++++++++++++++++++++++++++++---------- shadow.spec | 2 +- 2 files changed, 113 insertions(+), 37 deletions(-) diff --git a/btrfs-subvolumes.patch b/btrfs-subvolumes.patch index 4ec9807..0ca3525 100644 --- a/btrfs-subvolumes.patch +++ b/btrfs-subvolumes.patch @@ -1,22 +1,90 @@ -commit 7561ce4594254480f42be721553dade3126e7a1c +commit c0dea3bb7f548b93244c5da6eae805444485429f +Author: Adam Majer +Date: Wed Jan 23 16:17:05 2019 +0100 + + Add autotools support for BtrFS option + + Feature is enabled by default, if headers are available. It can be + turned off explictly. + +commit 3ce4a86acec3b96e85cbff291035d24cdcd4b5db Author: Adam Majer Date: Mon Jan 21 09:32:36 2019 +0100 - {WIP} + Add support for btrfs subvolumes for user homes + + new switch added to useradd command, --btrfs-subvolume-home. When + specified *and* the filesystem is detected as btrfs, it will create a + subvolume for user's home instead of a plain directory. This is done via + `btrfs subvolume` command. Specifying the new switch while trying to + create home on non-btrfs will result in an error. + + userdel -r will handle and remove this subvolume transparently via + `btrfs subvolume` command. Previosuly this failed as you can't rmdir a + subvolume. + + usermod, when moving user's home across devices, will detect if the home + is a subvolume and issue an error messages instead of copying it. Moving + user's home (as subvolume) on same btrfs works transparently. +Index: shadow-4.6/configure.ac +=================================================================== +--- shadow-4.6.orig/configure.ac ++++ shadow-4.6/configure.ac +@@ -256,6 +256,9 @@ AC_ARG_WITH(audit, + AC_ARG_WITH(libpam, + [AC_HELP_STRING([--with-libpam], [use libpam for PAM support @<:@default=yes if found@:>@])], + [with_libpam=$withval], [with_libpam=maybe]) ++AC_ARG_WITH(btrfs, ++ [AC_HELP_STRING([--with-btrfs], [add BtrFS support @<:@default=yes if found@:>@])], ++ [with_selinux=$withval], [with_selinux=maybe]) + AC_ARG_WITH(selinux, + [AC_HELP_STRING([--with-selinux], [use SELinux support @<:@default=yes if found@:>@])], + [with_selinux=$withval], [with_selinux=maybe]) +@@ -453,6 +456,20 @@ if test "$with_libcrack" = "yes"; then + AC_DEFINE(HAVE_LIBCRACK_PW, 1, [Defined if it includes *Pw functions.])) + fi + ++if test "$with_btrfs" != "no"; then ++ AC_CHECK_HEADERS([sys/statfs.h linux/magic.h linux/btrfs_tree.h], \ ++ [btrfs_headers="yes"], [btrfs_headers="no"]) ++ if test "$btrfs_headers$with_btrfs" = "noyes" ; then ++ AC_MSG_ERROR([One of sys/statfs.h linux/magic.h linux/btrfs_tree.h is missing]) ++ fi ++ ++ if test "$btrfs_headers" = "yes" ; then ++ AC_DEFINE(WITH_BTRFS, 1, [Build shadow with BtrFS support]) ++ with_btrfs="yes" ++ fi ++fi ++AM_CONDITIONAL(WITH_BTRFS, test x$with_btrfs = xyes) ++ + AC_SUBST(LIBSELINUX) + AC_SUBST(LIBSEMANAGE) + if test "$with_selinux" != "no"; then +@@ -672,6 +689,7 @@ if test "$with_libpam" = "yes"; then + echo " suid account management tools: $enable_acct_tools_setuid" + fi + echo " SELinux support: $with_selinux" ++echo " BtrFS support: $with_btrfs" + echo " ACL support: $with_acl" + echo " Extended Attributes support: $with_attr" + echo " tcb support (incomplete): $with_tcb" Index: shadow-4.6/lib/prototypes.h =================================================================== --- shadow-4.6.orig/lib/prototypes.h +++ shadow-4.6/lib/prototypes.h -@@ -72,6 +72,12 @@ extern int expire (const struct passwd * +@@ -72,6 +72,14 @@ extern int expire (const struct passwd * /* isexpired.c */ extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); +/* btrfs.c */ ++#ifdef WITH_BTRFS +extern int btrfs_create_subvolume(const char *path); +extern int btrfs_remove_subvolume(const char *path); +extern int btrfs_is_subvolume(const char *path); +extern int is_btrfs(const char *path); ++#endif + /* basename() renamed to Basename() to avoid libc name space confusion */ /* basename.c */ @@ -25,14 +93,15 @@ Index: shadow-4.6/libmisc/Makefile.am =================================================================== --- shadow-4.6.orig/libmisc/Makefile.am +++ shadow-4.6/libmisc/Makefile.am -@@ -10,6 +10,7 @@ libmisc_a_SOURCES = \ - age.c \ - audit_help.c \ - basename.c \ -+ btrfs.c \ - chkname.c \ - chkname.h \ - chowndir.c \ +@@ -72,3 +72,8 @@ libmisc_a_SOURCES = \ + xgetspnam.c \ + xmalloc.c \ + yesno.c ++ ++if WITH_BTRFS ++libmisc_a_SOURCES += btrfs.c ++endif ++ Index: shadow-4.6/libmisc/btrfs.c =================================================================== --- /dev/null @@ -136,15 +205,7 @@ Index: shadow-4.6/src/useradd.c =================================================================== --- shadow-4.6.orig/src/useradd.c +++ shadow-4.6/src/useradd.c -@@ -67,6 +67,7 @@ - #include "sgroupio.h" - #endif - #include "shadowio.h" -+#include "spawn.h" - #ifdef ENABLE_SUBIDS - #include "subordinateio.h" - #endif /* ENABLE_SUBIDS */ -@@ -164,6 +165,7 @@ static bool +@@ -164,6 +164,7 @@ static bool oflg = false, /* permit non-unique user ID to be specified with -u */ rflg = false, /* create a system account */ sflg = false, /* shell program for new account */ @@ -152,35 +213,46 @@ Index: shadow-4.6/src/useradd.c uflg = false, /* specify user ID for new account */ Uflg = false; /* create a group having the same name as the user */ -@@ -805,6 +807,7 @@ static void usage (int status) +@@ -805,6 +806,9 @@ static void usage (int status) Prog, Prog, Prog); (void) fputs (_(" -b, --base-dir BASE_DIR base directory for the home directory of the\n" " new account\n"), usageout); ++#ifdef WITH_BTRFS + (void) fputs (_(" --btrfs-subvolume-home use BTRFS subvolume for home directory\n"), usageout); ++#endif (void) fputs (_(" -c, --comment COMMENT GECOS field of the new account\n"), usageout); (void) fputs (_(" -d, --home-dir HOME_DIR home directory of the new account\n"), usageout); (void) fputs (_(" -D, --defaults print or change default useradd configuration\n"), usageout); -@@ -1085,6 +1088,7 @@ static void process_flags (int argc, cha +@@ -1085,6 +1089,9 @@ static void process_flags (int argc, cha int c; static struct option long_options[] = { {"base-dir", required_argument, NULL, 'b'}, ++#ifdef WITH_BTRFS + {"btrfs-subvolume-home", no_argument, NULL, 200}, ++#endif {"comment", required_argument, NULL, 'c'}, {"home-dir", required_argument, NULL, 'd'}, {"defaults", no_argument, NULL, 'D'}, -@@ -1114,9 +1118,9 @@ static void process_flags (int argc, cha +@@ -1113,11 +1120,15 @@ static void process_flags (int argc, cha + {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, ++ "b:" ++#ifdef WITH_BTRFS ++ ":" ++#endif ++ "c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:U" #ifdef WITH_SELINUX - "b:c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:UZ:", -+ "b::c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:UZ:", - #else /* !WITH_SELINUX */ +-#else /* !WITH_SELINUX */ - "b:c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:U", -+ "b::c:d:De:f:g:G:hk:K:lmMNop:rR:P:s:u:U", ++ "Z:" #endif /* !WITH_SELINUX */ ++ , long_options, NULL)) != -1) { switch (c) { -@@ -1131,6 +1135,9 @@ static void process_flags (int argc, cha + case 'b': +@@ -1131,6 +1142,9 @@ static void process_flags (int argc, cha def_home = optarg; bflg = true; break; @@ -190,15 +262,15 @@ Index: shadow-4.6/src/useradd.c case 'c': if (!VALID (optarg)) { fprintf (stderr, -@@ -2049,7 +2056,35 @@ static void create_home (void) +@@ -2049,6 +2063,37 @@ static void create_home (void) strcat (path, "/"); strcat (path, cp); if (access (path, F_OK) != 0) { -- if (mkdir (path, 0) != 0) { + /* Check if parent directory is BTRFS, fail if requesting + subvolume but no BTRFS. The paths cound be different by the + trailing slash + */ ++#if WITH_BTRFS + if (subvolflg && (strlen(prefix_user_home) - (int)strlen(path)) <= 1) { + char *btrfs_check = strdup(path); + @@ -223,19 +295,20 @@ Index: shadow-4.6/src/useradd.c + fail_exit (E_HOMEDIR); + } + } -+ else if (mkdir (path, 0) != 0) { ++ else ++#endif + if (mkdir (path, 0) != 0) { fprintf (stderr, _("%s: cannot create directory %s\n"), - Prog, path); Index: shadow-4.6/src/userdel.c =================================================================== --- shadow-4.6.orig/src/userdel.c +++ shadow-4.6/src/userdel.c -@@ -1273,7 +1273,21 @@ int main (int argc, char **argv) +@@ -1273,6 +1273,23 @@ int main (int argc, char **argv) #endif /* EXTRA_CHECK_HOME_DIR */ if (rflg) { -- if (remove_tree (user_home, true) != 0) { ++#ifdef WITH_BTRFS + int is_subvolume = btrfs_is_subvolume (user_home); + if (is_subvolume < 0) { + errors++; @@ -250,24 +323,27 @@ Index: shadow-4.6/src/userdel.c + /* continue */ + } + } -+ else if (remove_tree (user_home, true) != 0) { ++ else ++#endif + if (remove_tree (user_home, true) != 0) { fprintf (stderr, _("%s: error removing directory %s\n"), - Prog, user_home); Index: shadow-4.6/src/usermod.c =================================================================== --- shadow-4.6.orig/src/usermod.c +++ shadow-4.6/src/usermod.c -@@ -1818,6 +1818,13 @@ static void move_home (void) +@@ -1818,6 +1818,15 @@ static void move_home (void) return; } else { if (EXDEV == errno) { ++#ifdef WITH_BTRFS + if (btrfs_is_subvolume (prefix_user_home) > 0) { + fprintf (stderr, + _("%s: error: cannot move subvolume from %s to %s - different device\n"), + Prog, prefix_user_home, prefix_user_newhome); + fail_exit (E_HOMEDIR); + } ++#endif + if (copy_tree (prefix_user_home, prefix_user_newhome, true, true, diff --git a/shadow.spec b/shadow.spec index d7363bd..d0fbe50 100644 --- a/shadow.spec +++ b/shadow.spec @@ -12,7 +12,7 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ #