Any comments or suggestions?

On 2020-27-11 10:00 -0600, Aaron Poffenberger <[email protected]> wrote:
> According to rdist(1), the special and cmdspecial commands accept an
> optional list of files. When the <name list> is omitted, the command
> should execute for all files, otherwise it should be executed only
> when one of the listed files is affected.
> 
> The special command works as expected, but cmdspecial runs for all
> files regardless of <name list>.
> 
> The diff fixes cmdspecial by adding "sc_updfilelist" to the subcmd
> structure to hold a list of affected files found in the <name list>
> (sc_args). For cmdspecial commands without a <name list>, the module
> level variable "updfilelist" is used as before.
> 
> The diff also addresses a couple of related issues, which aren't
> technically necessary for the fix, but which helped with debugging and
> testing, and make rdist user messages clearer.  I can break them out
> as separate patches if necessary.
> 
> Changes:
>  - Fix <name list> handling in cmdspecial commands
>  - Modify user message to indicate whether special or cmdspecial
>    commands apply to "any" file or a "list" of files
>  - Show cmdspecial commands that would be executed when the "verify"
>    option is set (rdist shows all other actions, including special
>    commands, when "verify" is enabled)
> 
> 
> Test Script
> -----------
> I've included a shell script that demonstrates the <name list>
> problem. It's attached as a diff for ease of use. I'm not suggesting
> it be committed.
> 
> The script creates a Distfile with special and cmdspecial commands
> with both a <name list> and no <name list> specified to highlight
> the difference in handling by rdist.
> 
> The script runs the base-installed rdist twice, the first time with
> two changed files, the second with just one. In both cases it executes
> a simple sh script to log the env variable executed with the command
> (special or cmdspecial).
> 
> If the script finds an executable rdist in /usr/src/usr.bin/rdist/, it
> then runs that version with the same two test cases.
> 
> The script then displays a diff of the two logs showing that the
> patched rdist executes according to the documentation, otherwise it
> shows the output of the first execution to show the defective handling
> of cmdspecial.
> 
> --Aaron
> 
> cvs diff: Diffing .
> Index: client.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/rdist/client.c,v
> retrieving revision 1.37
> diff -u -p -r1.37 client.c
> --- client.c  28 Jun 2019 13:35:03 -0000      1.37
> +++ client.c  27 Nov 2020 14:45:16 -0000
> @@ -66,7 +66,7 @@ struct namelist     *updfilelist = NULL; /* 
>  
>  static void runspecial(char *, opt_t, char *, int);
>  static void addcmdspecialfile(char *, char *, int);
> -static void freecmdspecialfiles(void);
> +static void freecmdspecialfiles(struct namelist **);
>  static struct linkbuf *linkinfo(struct stat *);
>  static int sendhardlink(opt_t, struct linkbuf *, char *, int);
>  static int sendfile(char *, opt_t, struct stat *, char *, char *, int);
> @@ -172,7 +172,8 @@ runspecial(char *starget, opt_t opts, ch
>                       continue;
>               if (sc->sc_args != NULL && !inlist(sc->sc_args, starget))
>                       continue;
> -             message(MT_CHANGE, "special \"%s\"", sc->sc_name);
> +             message(MT_CHANGE, "special <%s> \"%s\"",
> +                     sc->sc_args == NULL ? "any" : "list", sc->sc_name);
>               if (IS_ON(opts, DO_VERIFY))
>                       continue;
>               (void) sendcmd(C_SPECIAL,
> @@ -201,11 +202,19 @@ addcmdspecialfile(char *starget, char *r
>  
>       rfile = remfilename(source, Tdest, target, rname, destdir);
>  
> -     for (sc = subcmds; sc != NULL && !isokay; sc = sc->sc_next) {
> +     for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
>               if (sc->sc_type != CMDSPECIAL)
>                       continue;
> -             if (sc->sc_args != NULL && !inlist(sc->sc_args, starget))
> +             if (sc->sc_args == NULL) {
> +                     isokay = TRUE;
>                       continue;
> +             } else if (!inlist(sc->sc_args, starget))
> +                     continue;
> +             new = xmalloc(sizeof *new);
> +             new->n_name = xstrdup(rfile);
> +             new->n_regex = NULL;
> +             new->n_next = sc->sc_updfilelist;
> +             sc->sc_updfilelist = new;
>               isokay = TRUE;
>       }
>  
> @@ -222,11 +231,11 @@ addcmdspecialfile(char *starget, char *r
>   * Free the file list
>   */
>  static void
> -freecmdspecialfiles(void)
> +freecmdspecialfiles(struct namelist **list)
>  {
>       struct namelist *ptr, *save;
>  
> -     for (ptr = updfilelist; ptr; ) {
> +     for (ptr = *list; ptr; ) {
>               if (ptr->n_name) (void) free(ptr->n_name);
>               save = ptr->n_next;
>               (void) free(ptr);
> @@ -235,7 +244,7 @@ freecmdspecialfiles(void)
>               else
>                       ptr = NULL;
>       }
> -     updfilelist = NULL;
> +     *list = NULL;
>  }
>  
>  /*
> @@ -251,11 +260,15 @@ runcmdspecial(struct cmd *cmd, opt_t opt
>       for (sc = cmd->c_cmds; sc != NULL; sc = sc->sc_next) {
>               if (sc->sc_type != CMDSPECIAL)
>                       continue;
> -             message(MT_CHANGE, "cmdspecial \"%s\"", sc->sc_name);
> +             if (sc->sc_args != NULL && sc->sc_updfilelist == NULL)
> +                     continue;
> +             message(MT_CHANGE, "cmdspecial <%s> \"%s\"",
> +                     sc->sc_args == NULL ? "any" : "list", sc->sc_name);
>               if (IS_ON(opts, DO_VERIFY))
>                       continue;
>               /* Send all the file names */
> -             for (f = updfilelist; f != NULL; f = f->n_next) {
> +             f = sc->sc_updfilelist != NULL ? sc->sc_updfilelist : 
> updfilelist;
> +             for (; f != NULL; f = f->n_next) {
>                       if (first) {
>                               (void) sendcmd(C_CMDSPECIAL, NULL);
>                               if (response() < 0)
> @@ -277,8 +290,9 @@ runcmdspecial(struct cmd *cmd, opt_t opt
>               while (response() > 0)
>                       ;
>               first = TRUE;   /* Reset in case there are more CMDSPECIAL's */
> +             freecmdspecialfiles(&sc->sc_updfilelist);
>       }
> -     freecmdspecialfiles();
> +     freecmdspecialfiles(&updfilelist);
>  }
>  
>  /*
> @@ -1050,6 +1064,7 @@ statupdate(int u, char *starget, opt_t o
>                               "%s: need to change to perm %#04o, owner %s, 
> group %s",
>                               starget, lmode, user, group);
>                       runspecial(starget, opts, rname, destdir);
> +                     addcmdspecialfile(starget, rname, destdir);
>               }
>               else {
>                       message(MT_CHANGE, "%s: change to perm %#04o, owner %s, 
> group %s", 
> @@ -1079,6 +1094,7 @@ fullupdate(int u, char *starget, opt_t o
>               if (IS_ON(opts, DO_VERIFY)) {
>                       message(MT_INFO, "%s: need to install", starget);
>                       runspecial(starget, opts, rname, destdir);
> +                     addcmdspecialfile(starget, rname, destdir);
>                       return(1);
>               }
>               if (!IS_ON(opts, DO_QUIET))
> @@ -1110,6 +1126,7 @@ fullupdate(int u, char *starget, opt_t o
>                       if (IS_ON(opts, DO_VERIFY)) {
>                               message(MT_INFO, "%s: need to update", starget);
>                               runspecial(starget, opts, rname, destdir);
> +                             addcmdspecialfile(starget, rname, destdir);
>                               return(1);
>                       }
>                       if (!IS_ON(opts, DO_QUIET))
> Index: client.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/rdist/client.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 client.h
> --- client.h  30 Aug 2017 07:42:52 -0000      1.3
> +++ client.h  26 Nov 2020 18:14:08 -0000
> @@ -84,6 +84,7 @@ struct subcmd {
>       opt_t   sc_options;
>       char    *sc_name;
>       struct  namelist *sc_args;
> +     struct  namelist *sc_updfilelist;
>       struct  subcmd *sc_next;
>  };
>  
> Index: gram.y
> ===================================================================
> RCS file: /cvs/src/usr.bin/rdist/gram.y,v
> retrieving revision 1.12
> diff -u -p -r1.12 gram.y
> --- gram.y    20 Jan 2015 09:00:16 -0000      1.12
> +++ gram.y    27 Nov 2020 15:21:31 -0000
> @@ -592,6 +592,7 @@ makesubcmd(int type)
>       sc->sc_type = type;
>       sc->sc_args = NULL;
>       sc->sc_next = NULL;
> +     sc->sc_updfilelist = NULL;
>       sc->sc_name = NULL;
>  
>       return(sc);
> Index: test_cmdspecial
> ===================================================================
> RCS file: test_cmdspecial
> diff -N test_cmdspecial
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ test_cmdspecial   27 Nov 2020 15:44:43 -0000
> @@ -0,0 +1,128 @@
> +#!/bin/sh
> +
> +TEST_DIR=/tmp/rdist
> +rm -Rf $TEST_DIR*
> +mkdir -p "$TEST_DIR/src" "$TEST_DIR/tgt"
> +
> +if [ -x ./rdist ]; then
> +     rdist_p="$(pwd)/rdist"
> +elif [ -x /usr/src/usr.bin/rdist/rdist ]; then
> +     rdist_p="/usr/src/usr.bin/rdist/rdist"
> +fi
> +
> +cd "$TEST_DIR"
> +
> +# Create Distfile
> +cat <<- EOF > Distfile
> +test:
> +src -> localhost
> +  install tgt ;
> +  special src/file "echo special src/file env_REMFILE=\$REMFILE >> \
> +rdist.log" ;
> +  special "echo special any env_REMFILE=\$REMFILE >> rdist.log" ;
> +  cmdspecial src/file "echo cmdspecial src/file env_FILES=\$FILES >> \
> +rdist.log" ;
> +  cmdspecial "echo cmdspecial any env_FILES=\$FILES >> rdist.log" ;
> +EOF
> +
> +# Run unpatched rdist with both files modified
> +# Both special and cmdspecial commands will execute
> +# NOTE: the FILES variable for cmdspecial *with* a <name list>
> +#    will include the names of both files when it should
> +#    only include the affected files in the <name list>
> +
> +echo ""
> +#echo "Unpatched rdist - update both files:" >> rdist.log
> +touch -d 2020-01-01T08:00:00 src/file{,2}
> +/usr/bin/rdist > /dev/null
> +mv rdist{,_orgnl_both_files}.log
> +
> +
> +# Run unpatched rdist with only file2 modified
> +# The special command with no <name list> will execute as it should
> +# The special command *with* a <name list> will not
> +# NOTE: Both cmdspecial commands will execute
> +#       The cmdspecial command *with* a <name list> should
> +#       not execute!
> +
> +#echo "Unpatched rdist - update file2 only:" >> rdist.log
> +touch -d 2020-01-01T09:00:00 src/file2
> +/usr/bin/rdist > /dev/null
> +mv rdist{,_orgnl_file2_only}.log
> +
> +
> +if [ -n "$rdist_p" ]; then
> +     rm src/* tgt/*
> +
> +     # Run unpatched rdist with both files modified
> +     # Both special and cmdspecial commands will execute
> +     # NOTE: the FILES variable for the cmdspecial *with* a
> +     #       <name list> will include only the specified file!
> +
> +     touch -d 2020-01-01T08:00:00 src/file{,2}
> +     "$rdist_p" > /dev/null
> +     mv rdist{,_patch_both_files}.log
> +
> +
> +     # Run unpatched rdist with only file2 modified
> +     # The special command with no <name list> executes as expected
> +     # The special command *with* a <name list> will not
> +     # NOTE: Only the cmdspecial command *without* a <name list>
> +     #       will execute, as it should
> +
> +     touch -d 2020-01-01T09:00:00 src/file2
> +     "$rdist_p" > /dev/null
> +     mv rdist{,_patch_file2_only}.log
> +
> +     cat <<- EOF
> +             Patched rdist: $rdist_p
> +
> +             Diff logs when both files are affected
> +             --------------------------------------
> +             rdist_orgnl_both_files.log:
> +                 - The FILES variable for cmdspecial *with*
> +                   a specified <name list> shows both files!
> +             rdist_patch_both_files.log:
> +                 - FILES shows only the expected file.
> +
> +     EOF
> +     diff -u "$TEST_DIR/rdist_orgnl_both_files.log" \
> +             "$TEST_DIR/rdist_patch_both_files.log"
> +
> +     cat <<- EOF
> +
> +             Diff logs when only one file is affected
> +             ----------------------------------------
> +             rdist_orgnl_file2_only.log:
> +                 - The FILES variable for the cmdspecial *with*
> +                   "src/file" in the <name list> still runs!
> +             rdist_patch_file2_only.log:
> +                 - The cmdspecial doesn't run, as expected.
> +
> +     EOF
> +     diff -u "$TEST_DIR/rdist_orgnl_file2_only.log" \
> +             "$TEST_DIR/rdist_patch_file2_only.log"
> +else
> +     cat <<- EOF
> +             Patched rdist not found
> +
> +             Log when both files are affected
> +             --------------------------------------
> +             rdist_orgnl_both_files.log:
> +                 - The FILES variable for cmdspecial *with*
> +                   a specified <name list> shows both files!
> +     
> +     EOF
> +     cat rdist_orgnl_both_files.log
> +
> +     cat <<- EOF
> +
> +             Log when only one file is affected
> +             ----------------------------------------
> +             rdist_orgnl_file2_only.log:
> +                 - The FILES variable for the cmdspecial *with*
> +                   "src/file" in the <name list> still runs!
> +     
> +     EOF
> +     cat rdist_orgnl_file2_only.log
> +fi
> 

Reply via email to