This is an automated email from the ASF dual-hosted git repository.

dragon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 20e8332  traffic_layout fix option in verify added
20e8332 is described below

commit 20e83321f5120c71c7ec220ec54567b160bca43a
Author: Xavier Chi <chitianha...@gmail.com>
AuthorDate: Thu Apr 26 16:22:49 2018 -0500

    traffic_layout fix option in verify added
---
 cmd/traffic_layout/engine.cc                      | 201 ++++++++++++++++------
 cmd/traffic_layout/engine.h                       |  11 +-
 cmd/traffic_layout/file_system.cc                 |   2 +-
 cmd/traffic_layout/file_system.h                  |   3 -
 cmd/traffic_layout/traffic_layout.cc              |  15 +-
 doc/appendices/command-line/traffic_layout.en.rst |  84 +++++----
 6 files changed, 224 insertions(+), 92 deletions(-)

diff --git a/cmd/traffic_layout/engine.cc b/cmd/traffic_layout/engine.cc
index b2e9a59..dadb0fd 100644
--- a/cmd/traffic_layout/engine.cc
+++ b/cmd/traffic_layout/engine.cc
@@ -29,7 +29,6 @@
 #include "ts/ink_error.h"
 #include "ts/ink_args.h"
 #include "ts/I_Version.h"
-#include "ts/ink_file.h"
 #include "records/I_RecCore.h"
 #include "ts/ink_config.h"
 
@@ -138,13 +137,13 @@ path_handler(const std::string &path, bool run_flag, 
const std::string &command)
 
 // the help message for traffic_layout runroot
 void
-RunrootEngine::runroot_help_message(const bool runflag, const bool cleanflag, 
const bool verifyflag, const bool fixflag)
+RunrootEngine::runroot_help_message(const bool runflag, const bool cleanflag, 
const bool verifyflag)
 {
   if (runflag) {
     std::cout << "\ninit Usage: traffic_layout init ([switch]) (--path 
/path/to/sandbox)\n" << std::endl;
     std::cout << "Sub-switches:\n"
-                 "--path        Specify the path of the runroot to create (the 
path should be the next argument)\n"
-                 "--force       Force to create ts_runroot even directory 
already exists\n"
+                 "--path    Specify the path of the runroot to create (the 
path should be the next argument)\n"
+                 "--force   Force to create ts_runroot even directory already 
exists\n"
                  "--absolute    Produce absolute path in the yaml file\n"
                  "--run-root(=/path)  Using specified TS_RUNROOT as sandbox\n"
               << std::endl;
@@ -152,14 +151,15 @@ RunrootEngine::runroot_help_message(const bool runflag, 
const bool cleanflag, co
   if (cleanflag) {
     std::cout << "\nremove Usage: traffic_layout remove ([switch]) (--path 
/path/to/sandbox)\n" << std::endl;
     std::cout << "Sub-switches:\n"
-                 "--path       specify the path of the runroot to remove (the 
path should be the next argument)\n"
-                 "--force      force to remove ts_runroot even with other 
unknown files\n"
+                 "--path   Specify the path of the runroot to remove (the path 
should be the next argument)\n"
+                 "--force  Force to remove ts_runroot even with other unknown 
files\n"
               << std::endl;
   }
   if (verifyflag) {
-    std::cout << "\nverify Usage: traffic_layout verify (--path 
/path/to/sandbox)\n" << std::endl;
+    std::cout << "\nverify Usage: traffic_layout verify (--fix) (--path 
/path/to/sandbox)\n" << std::endl;
     std::cout << "Sub-switches:\n"
-                 "--path       specify the path of the runroot to verify (the 
path should be the next argument)\n"
+                 "--path   Specify the path of the runroot to verify (the path 
should be the next argument)\n"
+                 "--fix    Fix the premission issues that verify found"
               << std::endl;
   }
   return;
@@ -213,7 +213,6 @@ RunrootEngine::runroot_parse()
     // set fix flag
     if (argument == "--fix") {
       fix_flag = true;
-      command_num++;
       continue;
     }
     if (argument == "--path") {
@@ -236,7 +235,7 @@ RunrootEngine::sanity_check()
 {
   // check output help or not
   if (help_flag) {
-    runroot_help_message(run_flag, clean_flag, verify_flag, fix_flag);
+    runroot_help_message(run_flag, clean_flag, verify_flag);
     exit(0);
   }
   if (version_flag) {
@@ -313,7 +312,7 @@ RunrootEngine::clean_runroot()
     }
   } else {
     // handle the map and deleting of each directories specified in the yml 
file
-    std::unordered_map<std::string, std::string> map = runroot_map(clean_root);
+    RunrootMapType map = runroot_map(clean_root);
     map.erase("prefix");
     map.erase("exec_prefix");
     for (auto it : map) {
@@ -404,9 +403,9 @@ RunrootEngine::create_runroot()
   std::string yaml_path = Layout::relative_to(ts_runroot, "runroot_path.yml");
   yamlfile.open(yaml_path);
 
-  for (auto it : path_map) {
+  for (uint i = 0; i < dir_vector.size(); i++) {
     // out put key value pairs of path
-    yamlfile << it.first << ": " << it.second << std::endl;
+    yamlfile << dir_vector[i] << ": " << path_map[dir_vector[i]] << std::endl;
   }
 }
 
@@ -416,7 +415,7 @@ void
 RunrootEngine::copy_runroot(const std::string &original_root, const 
std::string &ts_runroot)
 {
   // map the original build time directory
-  std::unordered_map<std::string, std::string> original_map;
+  RunrootMapType original_map;
 
   original_map["exec_prefix"]   = TS_BUILD_EXEC_PREFIX;
   original_map["bindir"]        = TS_BUILD_BINDIR;
@@ -486,6 +485,7 @@ get_giduid(const char *user)
   return giduid;
 }
 
+// output read permission
 static void
 output_read_permission(const std::string &permission)
 {
@@ -496,6 +496,7 @@ output_read_permission(const std::string &permission)
   }
 }
 
+// output write permission
 static void
 output_write_permission(const std::string &permission)
 {
@@ -506,6 +507,7 @@ output_write_permission(const std::string &permission)
   }
 }
 
+// output execute permission
 static void
 output_execute_permission(const std::string &permission)
 {
@@ -516,73 +518,174 @@ output_execute_permission(const std::string &permission)
   }
 }
 
-void
-RunrootEngine::verify_runroot()
+// the fixing permission of runroot used by verify command
+static void
+fix_runroot(RunrootMapType &path_map, RunrootMapType &permission_map, 
RunrootMapType &usergroup_map)
 {
-  std::pair<int, int> giduid = get_giduid(TS_PKGSYSUSER);
-
-  int gid = giduid.first;
-  int uid = giduid.second;
+  if (getuid() != 0) {
+    ink_error("To fix permission issues, root privileges are required.\nPlease 
run with sudo.");
+    exit(70);
+  }
+  for (auto it : permission_map) {
+    std::string name       = it.first;
+    std::string permission = it.second;
+    std::string usergroup  = usergroup_map[name];
+    std::string path       = path_map[name];
 
-  std::cout << "trafficserver user: " << TS_PKGSYSUSER << std::endl << 
std::endl;
+    int read_permission;
+    int write_permission;
+    int execute_permission;
 
-  if (int(getuid()) != uid) {
-    if (getuid() != 0) {
-      ink_error("In order to test as user '%s', root privileges are 
required.\nPlease run with sudo.", TS_PKGSYSUSER);
+    struct stat stat_buffer;
+    if (stat(path.c_str(), &stat_buffer) < 0) {
+      ink_error("unable to stat() destination path %s: %s", path.c_str(), 
strerror(errno));
       exit(70);
     }
-    if (setregid(gid, gid) != 0) {
-      ink_fatal("failed to set group ID '%d' - %s", gid, strerror(errno));
+
+    if (usergroup == "owner") {
+      read_permission    = S_IRUSR;
+      write_permission   = S_IWUSR;
+      execute_permission = S_IXUSR;
+    } else if (usergroup == "group") {
+      read_permission    = S_IRGRP;
+      write_permission   = S_IWGRP;
+      execute_permission = S_IXGRP;
+    } else {
+      read_permission    = S_IROTH;
+      write_permission   = S_IWOTH;
+      execute_permission = S_IXOTH;
+    }
+    // read
+    if (permission[0] != '1') {
+      if (chmod(path.c_str(), stat_buffer.st_mode | read_permission) < 0) {
+        ink_warning("Unable to change file mode on %s: %s", path.c_str(), 
strerror(errno));
+      }
+    }
+    if (name == "localstatedir" || name == "logdir" || name == "runtimedir" || 
name == "cachedir") {
+      // write
+      if (permission[1] != '1') {
+        if (chmod(path.c_str(), stat_buffer.st_mode | read_permission | 
write_permission) < 0) {
+          ink_warning("Unable to change file mode on %s: %s", path.c_str(), 
strerror(errno));
+        }
+      }
     }
-    if (setreuid(uid, uid) != 0) {
-      ink_fatal("failed to set user ID '%d' - %s", uid, strerror(errno));
+    if (name == "bindir" || name == "sbindir" || name == "libdir" || name == 
"libexecdir") {
+      // execute
+      if (permission[2] != '1') {
+        if (chmod(path.c_str(), stat_buffer.st_mode | read_permission | 
execute_permission) < 0) {
+          ink_warning("Unable to change file mode on %s: %s", path.c_str(), 
strerror(errno));
+        }
+      }
     }
   }
+}
 
-  std::unordered_map<std::string, std::string> path_map = runroot_map(path);
-  std::unordered_map<std::string, std::string> permission_map;
+// set permission to the map in verify runroot
+static void
+set_permission(std::vector<std::string> &dir_vector, RunrootMapType &path_map, 
RunrootMapType &permission_map,
+               RunrootMapType &usergroup_map)
+{
+  // active group and user of the path
+  std::pair<int, int> giduid = get_giduid(TS_PKGSYSUSER);
+
+  int ts_gid = giduid.first;
+  int ts_uid = giduid.second;
+
+  struct stat stat_buffer;
 
   // set up permission map for all permissions
-  for (auto it : path_map) {
-    std::string name  = it.first;
-    std::string value = it.second;
+  for (uint i = 0; i < dir_vector.size(); i++) {
+    std::string name  = dir_vector[i];
+    std::string value = path_map[dir_vector[i]];
 
     if (name == "prefix" || name == "exec_prefix") {
       continue;
     }
 
-    permission_map[name] = "000"; // default rwx all 0
-
-    if (!access(value.c_str(), R_OK)) {
-      permission_map[name][0] = '1';
-    }
-    if (!access(value.c_str(), W_OK)) {
-      permission_map[name][1] = '1';
+    if (stat(value.c_str(), &stat_buffer) < 0) {
+      ink_error("unable to stat() destination path %s: %s", value.c_str(), 
strerror(errno));
+      exit(70);
     }
-    if (!access(value.c_str(), X_OK)) {
-      permission_map[name][2] = '1';
+    int path_gid = int(stat_buffer.st_gid);
+    int path_uid = int(stat_buffer.st_uid);
+
+    permission_map[name] = "000"; // default rwx all 0
+    if (ts_uid == path_uid) {
+      // check for owner permission of st_mode
+      usergroup_map[name] = "owner";
+      if (stat_buffer.st_mode & S_IRUSR) {
+        permission_map[name][0] = '1';
+      }
+      if (stat_buffer.st_mode & S_IWUSR) {
+        permission_map[name][1] = '1';
+      }
+      if (stat_buffer.st_mode & S_IXUSR) {
+        permission_map[name][2] = '1';
+      }
+    } else if (ts_gid == path_gid) {
+      // check for group permission of st_mode
+      usergroup_map[name] = "group";
+      if (stat_buffer.st_mode & S_IRGRP) {
+        permission_map[name][0] = '1';
+      }
+      if (stat_buffer.st_mode & S_IWGRP) {
+        permission_map[name][1] = '1';
+      }
+      if (stat_buffer.st_mode & S_IXGRP) {
+        permission_map[name][2] = '1';
+      }
+    } else {
+      // check for others permission of st_mode
+      usergroup_map[name] = "others";
+      if (stat_buffer.st_mode & S_IROTH) {
+        permission_map[name][0] = '1';
+      }
+      if (stat_buffer.st_mode & S_IWOTH) {
+        permission_map[name][1] = '1';
+      }
+      if (stat_buffer.st_mode & S_IXOTH) {
+        permission_map[name][2] = '1';
+      }
     }
   }
+}
+
+void
+RunrootEngine::verify_runroot()
+{
+  std::cout << "trafficserver user: " << TS_PKGSYSUSER << std::endl << 
std::endl;
+
+  RunrootMapType path_map = runroot_map(path);
+  RunrootMapType permission_map; // contains rwx bits
+  RunrootMapType usergroup_map;  // map: owner, group, others
+
+  set_permission(dir_vector, path_map, permission_map, usergroup_map);
+
+  // if --fix is used
+  if (fix_flag) {
+    fix_runroot(path_map, permission_map, usergroup_map);
+    set_permission(dir_vector, path_map, permission_map, usergroup_map);
+  }
 
   // display pass or fail for permission required
-  for (auto it : permission_map) {
-    std::string name       = it.first;
-    std::string permission = it.second;
+  for (uint i = 2; i < dir_vector.size(); i++) {
+    std::string name       = dir_vector[i];
+    std::string permission = permission_map[dir_vector[i]];
     std::cout << name << ": \x1b[1m" + path_map[name] + "\x1b[0m" << std::endl;
 
-    // check for read permission
+    // output read permission
     if (name == "includedir" || name == "mandir" || name == "sysconfdir" || 
name == "datadir") {
       output_read_permission(permission);
     }
-    // check for write permission
+    // output write permission
     if (name == "localstatedir" || name == "logdir" || name == "runtimedir" || 
name == "cachedir") {
       output_read_permission(permission);
       output_write_permission(permission);
     }
-    // check for execute permission
+    // output execute permission
     if (name == "bindir" || name == "sbindir" || name == "libdir" || name == 
"libexecdir") {
       output_read_permission(permission);
       output_execute_permission(permission);
     }
   }
-}
+}
\ No newline at end of file
diff --git a/cmd/traffic_layout/engine.h b/cmd/traffic_layout/engine.h
index 112f906..0535745 100644
--- a/cmd/traffic_layout/engine.h
+++ b/cmd/traffic_layout/engine.h
@@ -29,6 +29,8 @@
 
 #define RUNROOT_WORD_LENGTH 10
 
+typedef std::unordered_map<std::string, std::string> RunrootMapType;
+
 // structure for informaiton of the runroot passing around
 struct RunrootEngine {
   // the parsing function for traffic runroot program
@@ -43,7 +45,7 @@ struct RunrootEngine {
   // the function of creating runroot
   void create_runroot();
 
-  // the function of verifying runroot
+  // the function of verifying runroot (including fix)
   void verify_runroot();
 
   // copy the stuff from original_root to ts_runroot
@@ -51,7 +53,7 @@ struct RunrootEngine {
   void copy_runroot(const std::string &original_root, const std::string 
&ts_runroot);
 
   // the help message for runroot
-  void runroot_help_message(const bool runflag, const bool cleanflag, const 
bool verifyflag, const bool fixflag);
+  void runroot_help_message(const bool runflag, const bool cleanflag, const 
bool verifyflag);
 
   // the pass in arguments
   std::vector<std::string> _argv;
@@ -70,6 +72,11 @@ struct RunrootEngine {
   // the path for create & remove
   std::string path;
 
+  // vector containing all directory names
+  std::vector<std::string> dir_vector = {"prefix",     "exec_prefix", 
"bindir", "sbindir",    "sysconfdir",
+                                         "datadir",    "includedir",  
"libdir", "libexecdir", "localstatedir",
+                                         "runtimedir", "logdir",      
"mandir", "cachedir"};
+
   // map for yaml file emit
   std::unordered_map<std::string, std::string> path_map;
 };
diff --git a/cmd/traffic_layout/file_system.cc 
b/cmd/traffic_layout/file_system.cc
index e3f5578..1a90e5d 100644
--- a/cmd/traffic_layout/file_system.cc
+++ b/cmd/traffic_layout/file_system.cc
@@ -204,7 +204,7 @@ copy_function(const char *src_path, const struct stat *sb, 
int flag)
       }
     }
     // hardlink bin executable
-    if (sb->st_mode == BIN_MODE) {
+    if (sb->st_mode & S_IEXEC) {
       if (link(src_path, dst_path.c_str()) != 0) {
         if (errno != EEXIST) {
           ink_warning("failed to create hard link - %s", strerror(errno));
diff --git a/cmd/traffic_layout/file_system.h b/cmd/traffic_layout/file_system.h
index 1ed5f61..dc005e6 100644
--- a/cmd/traffic_layout/file_system.h
+++ b/cmd/traffic_layout/file_system.h
@@ -25,9 +25,6 @@
 
 #include <string>
 
-// binary executable mode (for symlink)
-#define BIN_MODE 33261
-
 // some system does not have OPEN_MAX defined
 // size can be changed accordingly
 #define OPEN_MAX_FILE 256
diff --git a/cmd/traffic_layout/traffic_layout.cc 
b/cmd/traffic_layout/traffic_layout.cc
index 8893fd4..d808786 100644
--- a/cmd/traffic_layout/traffic_layout.cc
+++ b/cmd/traffic_layout/traffic_layout.cc
@@ -63,19 +63,20 @@ static void
 help_usage()
 {
   std::cout << "\nSubcommands:\n"
+               "info         Show the layout as default\n"
                "init         Initialize the ts_runroot sandbox\n"
                "remove       Remove the ts_runroot sandbox\n"
-               "info         Show the layout as default\n"
-               "verify:      Verify the ts_runroot paths\n"
+               "verify       Verify the ts_runroot paths\n"
             << std::endl;
   std::cout << "Switches of runroot:\n"
-               "--path       Specify the path of the runroot\n"
-               "--force:     Force to create ts_runroot, only works with 
init\n"
-               "--absolute:  Produce absolute path in the yaml file\n"
+               "--path:      Specify the path of the runroot\n"
+               "--force:     Force to create or remove ts_runroot\n"
+               "--absolute:  Produce absolute path in the yaml file during 
init\n"
                "--run-root(=/path):  Using specified TS_RUNROOT as sandbox\n"
+               "--fix:       fix the premission issues that verify found"
             << std::endl;
   printf("Detailed usage and description in traffic_layout.en.rst\n");
-  printf("General Usage:\n");
+  printf("\nGeneral Usage:\n");
   usage(argument_descriptions, countof(argument_descriptions), nullptr);
 }
 
@@ -129,7 +130,7 @@ traffic_runroot(int argc, const char **argv)
   }
   // parse the command line & put into global variable
   if (!engine.runroot_parse()) {
-    engine.runroot_help_message(true, true, true, true);
+    engine.runroot_help_message(true, true, true);
     return 0;
   }
   // check sanity of the command about the runroot program
diff --git a/doc/appendices/command-line/traffic_layout.en.rst 
b/doc/appendices/command-line/traffic_layout.en.rst
index f4b52b1..8704b58 100644
--- a/doc/appendices/command-line/traffic_layout.en.rst
+++ b/doc/appendices/command-line/traffic_layout.en.rst
@@ -20,73 +20,97 @@
 traffic_layout
 *****************
 
+Synopsis
+========
+:program:`traffic_layout` SUBCOMMAND [OPTIONS]
+
+Options
+=============
 .. program:: traffic_layout
 
-.. option:: --run-root [<path>]
+.. option:: --run-root=[<path>]
 
    Use the run root file at :arg:`path`.
 
+.. option:: -V, --version
+
+    Print version information and exit.
+
 Description
 =============
-Document for the special functionality of ``runroot`` inside 
:program:`traffic_layout` This feature
+Document for the special functionality of ``runroot`` inside 
:program:`traffic_layout`. This feature
 is for the setup of traffic server runroot. It will create a runtime sandbox 
for any program of
 traffic server to run under.
 
-#. Use :program:`traffic_layout` to create sandbox.
-#. Run any program using the sandbox with ``--run-root=/path/to/file`` or 
``--run-root``.
+Use :program:`traffic_layout` to create sandbox.
+Run any program using the sandbox with ``--run-root=/path/to/file`` or 
``--run-root``.
 
-How it works:
+How it works
 --------------
 
 #. Create a sandbox directory for programs to run under.
 #. Copy and symlink build time directories and files to the sandbox, allowing 
users to modify freely.
 #. Emit a yaml file that defines layout structure for other programs to use 
(relative path).
+#. Users are able to remove runroot and verify permission of the runroot.
 
-Options:
+Subcommands
 =============
 
-#. Initialize the runroot: ::
+- Initialize the runroot: ::
 
       traffic_layout init (--path /path/to/sandbox/)
 
-   Use the current working directory or specific path to create runroot.
+      Use the current working directory or the specific path to create runroot.
+      The path can be relative or set up in :envvar:`TS_RUNROOT`.
+
+
+- Remove the runroot: ::
+
+      traffic_layout remove (--path /path/to/sandbox/)
 
-#. Remove the runroot: ::
+      Find the sandbox to remove in following order: 
 
-      traffic_layout remove --path /path/to/sandbox/
+            1. specified in --path as absolute or relative.
+            2. :envvar:`TS_RUNROOT`
+            3. current working directory
+            4. installed directory.
 
-   Remove the sandbox we created(check yaml file).
-   If no path provided, it will check bin executing path and current working 
directory to clean.
+- Verify the runroot: ::
 
-#. Use Force flag for creating: ::
+      traffic_layout verify (--path /path/to/sandbox/)
+
+      Verify the permission of the sandbox.
+
+Subcommands options
+--------------
+- Force option: ::
 
       traffic_layout init --force (--path /path/to/sandbox)
-      traffic_layout remove --force --path /path/to/sandbox
+      traffic_layout remove --force (--path /path/to/sandbox)
 
-   Force create sandbox and overwrite existing directory when directory is not 
empty or has a yaml file in it.
-   Force removing a directory when directory has no yaml file.
+      Force init will create sandbox even if the directory is not empty.
+      Force remove will remove a directory even if directory has no yaml file.
 
-#. Use absolute flag for creating: ::
+- Absolute option: ::
 
       traffic_layout init --absolute (--path /path/to/sandbox)
 
-   create sandbox and put directories in the yaml file with absolute path form.
+      create the sandbox and put directories in the yaml file in the form of 
absolute path.
 
-Usage for other programs:
-==============================================
+- Fix option: ::
 
-Use command line path or use :envvar:`TS_RUNROOT`.
-If command line path and envvar are not found, program will try to find the 
current executing program bin path or current working directory to use as 
runroot if the yaml file is found. 
-For bin path and cwd, it can go one level up to the parent directory to find 
the yaml file. ::
+      traffic_layout verify --fix (--path /path/to/sandbox)
 
-   trafficserver --run-root=/path/to/runroot (use /path/to/runroot as runroot)
-   trafficserver --run-root                  (use $TS_RUNROOT as runroot)
+      Fix the permission issues verify found. ``--fix`` requires root 
privilege (sudo).
 
-.. envvar:: TS_RUNROOT
+Usage for other programs:
+==============================================
 
-   The path to run root directory.
+All programs can find the runroot to use in the following order
 
-Notes
-==========
+      #. specified in --run-root=/path/to/runroot (path needs to be absolute)
+      #. :envvar:`TS_RUNROOT`
+      #. current working directory
+      #. installed directory
 
-.. note:: Path to sandbox must be an absolute path.
+if none of the above is found as runroot, runroot will not be used

-- 
To stop receiving notification emails like this one, please contact
dra...@apache.org.

Reply via email to