diff options
| -rw-r--r-- | toys/posix/cp.c | 94 | 
1 files changed, 89 insertions, 5 deletions
diff --git a/toys/posix/cp.c b/toys/posix/cp.c index aecd1870..c61190e5 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -9,6 +9,8 @@  USE_CP(NEWTOY(cp, "<2RHLPp"USE_CP_MORE("rdaslvn")"fi[-HLPd]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))  USE_CP_MV(OLDTOY(mv, cp, "<2"USE_CP_MORE("vn")"fi"USE_CP_MORE("[-ni]"), TOYFLAG_BIN)) +USE_INSTALL(NEWTOY(install, "<1cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN)) +*  config CP    bool "cp" @@ -61,14 +63,40 @@ config CP_MV_MORE      -v	verbose      -n	no clobber (don't overwrite DEST) + +config INSTALL +  bool "install" +  default y +  depends on CP && CP_MORE +  help +    usage: install [-dDpsv] [-o USER] [-g GROUP] [-m MODE] [SOURCE...] DEST + +    Copy files and set attributes. + +    -d	Act like mkdir -p +    -D	Create leading directories for DEST +    -g	Make copy belong to GROUP +    -m	Set permissions to MODE +    -o	Make copy belong to USER +    -p	Preserve timestamps +    -s	Call "strip -p" +    -v	Verbose  */  #define FOR_cp  #include "toys.h"  GLOBALS( +  // install's options +  char *group; +  char *user; +  char *mode; +    char *destname;    struct stat top; +  int (*callback)(struct dirtree *try); +  uid_t uid; +  gid_t gid;  )  // Callback from dirtree_read() for each file/directory under a source dir. @@ -124,7 +152,7 @@ int cp_node(struct dirtree *try)      if (flags & FLAG_v) {        char *s = dirtree_path(try, 0); -      printf("cp '%s'\n", s); +      printf("%s '%s'\n", toys.which->name, s);        free(s);      } @@ -249,8 +277,8 @@ int cp_node(struct dirtree *try)      if (fdout != AT_FDCWD) xclose(fdout); -    if (toys.which->name[0] == 'm') -      if (unlinkat(tfd, try->name, S_ISDIR(try->st.st_mode) ? AT_REMOVEDIR : 0)) +    if (CFG_CP_MV && toys.which->name[0] == 'm') +      if (unlinkat(tfd, try->name, S_ISDIR(try->st.st_mode) ? AT_REMOVEDIR :0))          err = "%s";    } @@ -267,6 +295,8 @@ void cp_main(void)    if (toys.which->name[0] == 'm') toys.optflags |= FLAG_d|FLAG_p|FLAG_R;    if (toys.optflags & (FLAG_a|FLAG_p)) umask(0); +  if (!TT.callback) TT.callback = cp_node; +    // Loop through sources    for (i=0; i<toys.optc; i++) { @@ -278,7 +308,7 @@ void cp_main(void)      else TT.destname = destname;      errno = EXDEV; -    if (toys.which->name[0] == 'm') rc = rename(src, TT.destname); +    if (CFG_CP_MV && toys.which->name[0] == 'm') rc = rename(src, TT.destname);      // Skip nonexistent sources      if (rc) { @@ -286,8 +316,62 @@ void cp_main(void)        if (errno != EXDEV || !(new = dirtree_add_node(0, src, symfollow)))            perror_msg("bad '%s'", src); -      else dirtree_handle_callback(new, cp_node); +      else dirtree_handle_callback(new, TT.callback);      }      if (destdir) free(TT.destname);    }  } + +#define CLEANUP_cp +#define FOR_install +#include <generated/flags.h> + +static int install_node(struct dirtree *try) +{ +  if (TT.mode) try->st.st_mode = string_to_mode(TT.mode, try->st.st_mode); +  if (TT.group) try->st.st_gid = TT.gid; +  if (TT.user) try->st.st_uid = TT.uid; + +  // Always returns 0 because no -r +  cp_node(try); + +  // No -r so always one level deep, so destname as set by cp_node() is correct +  if (toys.optflags & FLAG_s) +    if (xpclose(xpopen((char *[]){"strip", "-p", TT.destname, 0}, 0), 0)) +      toys.exitval = 1; + +  return 0; +} + +void install_main(void) +{ +  char **ss; +  int flags = toys.optflags; + +  if (flags & FLAG_d) { +    for (ss = toys.optargs; *ss; ss++) { +      if (mkpathat(AT_FDCWD, *ss, 0777, 3)) perror_msg("%s", *ss); +      if (flags & FLAG_v) printf("%s\n", *ss); +    } + +    return; +  } + +  if (toys.optflags & FLAG_D) { +    if (mkpathat(AT_FDCWD, TT.destname, 0, 2)) +      perror_exit("-D '%s'", TT.destname); +    if (toys.optc == 1) return; +  } +  if (toys.optc < 2) error_exit("needs 2 args"); + +  // Translate flags from install to cp +  toys.optflags = 4;  // Force cp's FLAG_n +  if (flags & FLAG_v) toys.optflags |= 8; // cp's FLAG_v +  if (flags & (FLAG_p|FLAG_o|FLAG_g)) toys.optflags |= 512; // cp's FLAG_p + +  if (TT.user) TT.uid = xgetpwnam(TT.user)->pw_uid; +  if (TT.group) TT.gid = xgetgrnam(TT.group)->gr_gid; + +  TT.callback = install_node; +  cp_main(); +}  | 
