return status from chattr
PATCH 1/1 return status from chattr
This is for RH bug #180596, Chattr command doesn't provide expected exit code in case of failure.
(trying to clear out an e2fsprogs bug backlog, can you tell?) :)
This is a little funky as a result of the man page saying that links encountered on recursive traversal are (silently?) ignored.
I changed this a bit so that if it's explicitly listed on the commandline, the link itself gets chattr'd. I'm not quite sure what is intended here; that the links are not *followed* or that they are not chattr'd? Seems a little odd to me.
I tried to follow the way other recursive commands work, for example chmod -R, and carry on in the face of any errors. If any error was encountered, exit with an error. If no errors, exit 0.
Also, if both flags and -v (version) are specified, and the flag set encounters an error, the version set is not attempted. Is this ok or should both commands be tried?
Finally, I'm curious, the utility ignores anything that's not a link, regular file, or dir, but the kernel code doesn't have these checks. Should it?
Comments?
Thanks,
-Eric
misc/chattr.c +36 -21
@@ -182,7 +182,7 @@ static int decode_arg (int * i, int argcstatic int chattr_dir_proc (const char *,struct dirent *,void *); -static void change_attributes (const char * name) +static int change_attributes (const char * name,int cmdline) {unsigned long flags;STRUCT_STAT st;
@@ -190,19 +190,20 @@ static void change_attributes (const chaif (LSTAT (name, &st) ==-1 ) {com_err (program_name, errno,_ ("while trying to stat %s" ), name); -return ; +return -1 ; } -if (S_ISLNK (st.st_mode) && recursive) -return ; -/* Don't try to open device files, fifos etc. We probably -ought to display an error if the file was explicitly given -on the command line (whether or not recursive was -requested). */ -if (!S_ISREG (st.st_mode) && !S_ISLNK (st.st_mode) && - !S_ISDIR (st.st_mode)) -return ; +/* Just silently ignore links found by recursion; +not an error according to the manpage */ +if (S_ISLNK (st.st_mode) && !cmdline) +return 0 ; +/* Don't try to open device files, fifos etc. */ +if (!S_ISREG (st.st_mode) && !S_ISLNK (st.st_mode) && + !S_ISDIR (st.st_mode)) { +com_err (program_name,EINVAL ,_ ("for file %s" ), name); +return -1 ; + }if (set) {if (verbose) {printf (_ ("Flags of %s set as " ), name);
@@ -212,10 +213,11 @@ static void change_attributes (const chaif (fsetflags (name, sf) ==-1 )perror (name); }else { -if (fgetflags (name, &flags) ==-1 ) +if (fgetflags (name, &flags) ==-1 ) {com_err (program_name, errno,_ ("while reading flags on %s" ), name); -else { +return -1 ; + }else {if (rem) flags &= ~rf;if (add)
@@ -227,25 +229,32 @@ static void change_attributes (const cha }if (!S_ISDIR (st.st_mode)) flags &= ~EXT2_DIRSYNC_FL ; -if (fsetflags (name, flags) ==-1 ) +if (fsetflags (name, flags) ==-1 ) {com_err (program_name, errno,_ ("while setting flags on %s" ), name); +return -1 ; + } + } }if (set_version) {if (verbose)printf (_ ("Version of %s set as %lu\n" ), name, version); -if (fsetversion (name, version) ==-1 ) +if (fsetversion (name, version) ==-1 ) {com_err (program_name, errno,_ ("while setting version on %s" ), name); +return -1 ; + } }if (S_ISDIR (st.st_mode) && recursive) -iterate_on_dir (name, chattr_dir_proc,NULL ); +return iterate_on_dir (name, chattr_dir_proc,NULL ); }static int chattr_dir_proc (const char * dir_name,struct dirent * de, void * private EXT2FS_ATTR((unused))) { +int err; +if (strcmp (de->d_name,"." ) &&strcmp (de->d_name,".." )) {char *path;
@@ -253,11 +262,13 @@ static int chattr_dir_proc (const char *if (!path) {fprintf (stderr,_ ("Couldn't allocate path variable " "in chattr_dir_proc" )); -exit (1 ); +return -1 ; }sprintf (path,"%s/%s" , dir_name, de->d_name); -change_attributes (path); + err =change_attributes (path,0 );free (path); +if (err) +return -1 ; }return 0 ; }
@@ -266,6 +277,7 @@ int main (int argc, char ** argv) {int i, j;int end_arg =0 ; +int err, retval =0 ;#ifdef ENABLE_NLS setlocale (LC_MESSAGES ,"" );
@@ -303,7 +315,10 @@ int main (int argc, char ** argv)if (verbose)fprintf (stderr,"chattr %s (%s)\n" ,E2FSPROGS_VERSION ,E2FSPROGS_DATE ); -for (j = i; j < argc; j++) -change_attributes (argv[j]); -exit (0 ); +for (j = i; j < argc; j++) { + err =change_attributes (argv[j],1 ); +if (err) + retval =1 ; + } +exit (retval); }
Quoted 4 lines · Eric Sandeen
This is for RH bug #180596, Chattr command doesn't provide expected exit code in case of failure.
(trying to clear out an e2fsprogs bug backlog, can you tell?) :)
Any comments on this one? Can we commit it if it looks ok?
btw:
Addresses-Red-Hat-Bugzilla: #180596
Thanks,
-Eric
Quoted 7 lines · Eric Sandeen
Quoted 4 lines · Eric Sandeen
This is for RH bug #180596, Chattr command doesn't provide expected exit code in case of failure.
(trying to clear out an e2fsprogs bug backlog, can you tell?) :)
Any comments on this one? Can we commit it if it looks ok?
It turns out you didn't quite completely fix the problem, since the iterate_on_directory() command wasn't reflecting errors up.
Also, while I was at it I cleaned up the code so that it more it attempts to set the flags on special files, instead of just ignoring them. On Linux this will result in an error message, but at least this way the user knows that those files didn't get set, and you can suppress them using the -f flag, just like chmod/chown.
- Ted
PATCH 1/1 libe2p: Use lstat() instead of stat() in fsetflags() and fgetflags()
We can't set the flags on symbolic links, so check for them using lstat().
--- lib/e2p/fgetflags.c | 2 +- lib/e2p/fsetflags.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
lib/e2p/fgetflags.c +1 -1
@@ -65,7 +65,7 @@ int fgetflags (const char * name, unsigned long * flags)#if HAVE_EXT2_IOCTLS int fd, r, f, save_errno =0 ; -if (!stat (name, &buf) && +if (!lstat (name, &buf) && !S_ISREG (buf.st_mode) && !S_ISDIR (buf.st_mode)) { goto notsupp; }
lib/e2p/fsetflags.c +1 -1
@@ -71,7 +71,7 @@ int fsetflags (const char * name, unsigned long flags)#if HAVE_EXT2_IOCTLS int fd, r, f, save_errno =0 ; -if (!stat (name, &buf) && +if (!lstat (name, &buf) && !S_ISREG (buf.st_mode) && !S_ISDIR (buf.st_mode)) { goto notsupp; }
Signature · 1 line
1.5.3.4.1232.g9991d-dirty
PATCH 1/1 libe2p: Change iterate_on_dir so that it counts non-zero returns
To allow error messages to be reflected up, if the callback function returns a non-zero value, bump a counter and return the number of times the callback function signals an error by returning a non-zero status code.
--- lib/e2p/iod.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
lib/e2p/iod.c +4 -3
@@ -27,7 +27,7 @@ int iterate_on_dir (const char * dir_name, {DIR * dir;struct dirent *de, *dep; -int max_len =-1 , len; +int max_len =-1 , len, ret =0 ;#if HAVE_PATHCONF && defined(_PC_NAME_MAX) max_len =pathconf (dir_name, _PC_NAME_MAX);
@@ -64,9 +64,10 @@ int iterate_on_dir (const char * dir_name, len = max_len;#endif memcpy (de, dep, len); - (*func) (dir_name, de, private); +if ((*func)(dir_name, de, private)) + ret++; }free (de);closedir (dir); -return 0 ; +return ret; }
Signature · 1 line
1.5.3.4.1232.g9991d-dirty
PATCH 1/1 chattr: provide an exit code in case of failure and add -f flag
Fix chattr so that if there are errors, it will report it via a non-zero exit code. It will now explicitly give errors when attempting to set files that are not files or directories (which are currently not supported under Linux). The -f flag will suppress error messages from being printed, although the exit status will still be non-zero.
Addresses-Red-Hat-Bugzilla: #180596
--- misc/chattr.1.in | 7 ++-- misc/chattr.c | 83 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 52 insertions(+), 38 deletions(-)
misc/chattr.1.in +4 -3
@@ -5,7 +5,7 @@ chattr \- change file attributes on a Linux second extended file system .SH SYNOPSIS .B chattr [ -.B \-RV +.B \-RVf ] [ .B \-v
@@ -34,12 +34,13 @@ synchronous updates (S), and top of directory hierarchy (T). .TP .B \-R Recursively change attributes of directories and their contents. -Symbolic links encountered during recursive directory traversals are -ignored. .TP .B \-V Be verbose with chattr's output and print the program version. .TP +.B \-f +Suppress most error messages. +.TP .BI \-v " version" Set the file's version/generation number. .SH ATTRIBUTES
misc/chattr.c +48 -35
162 lines not on this page · raw message
Signature · 1 line
1.5.3.4.1232.g9991d-dirty
Quoted 4 lines · Eric Sandeen
I changed this a bit so that if it's explicitly listed on the commandline, the link itself gets chattr'd. I'm not quite sure what is intended here; that the links are not *followed* or that they are not chattr'd? Seems a little odd to me.
Both; you can't chattr a symlink. You can try, but in fact what happens is that you end up chattr'ing the destination of the link, which is probably not what you want.
Quoted 3 lines
I tried to follow the way other recursive commands work, for example chmod -R, and carry on in the face of any errors. If any error was encountered, exit with an error. If no errors, exit 0.
Yep, that makes sense.
Quoted 3 lines
Also, if both flags and -v (version) are specified, and the flag set encounters an error, the version set is not attempted. Is this ok or should both commands be tried?
I think an atomic failure makes the most amount of sense.
Quoted 3 lines
Finally, I'm curious, the utility ignores anything that's not a link, regular file, or dir, but the kernel code doesn't have these checks. Should it?
For better or for worse, the ext2/3/4 flags are set via an ioctl. This means it doesn't work for anything other than a regular file or a directory. For a symlink, it will fail, or follow the symlink. There's a bug in libe2p which I'll fix which causes it to not return EOPNOTSUPP for symlinks because it's using stat() when it should use lstat().
So we should be ignoring symbolic links, as well, since we can't change them.
- Ted