cmdline: simplify string splitting
authorRobert Swiecki <robert@swiecki.net>
Sun, 11 Feb 2018 13:56:30 +0000 (14:56 +0100)
committerRobert Swiecki <robert@swiecki.net>
Sun, 11 Feb 2018 13:56:30 +0000 (14:56 +0100)
cmdline.cc
config.cc
user.cc
user.h
util.cc
util.h

index a97ea77..156fcbf 100644 (file)
@@ -43,6 +43,8 @@
 #include <unistd.h>
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "caps.h"
 #include "config.h"
@@ -293,29 +295,16 @@ uint64_t parseRLimit(int res, const char* optarg, unsigned long mul) {
        return val;
 }
 
-/* findSpecDestination mutates spec (source:dest) to have a null byte instead
- * of ':' in between source and dest, then returns a pointer to the dest
- * string. */
-static char* cmdlineSplitStrByColon(char* spec) {
-       if (spec == NULL) {
-               return NULL;
+static std::string argByColon(const char* str, size_t pos) {
+       if (!str) {
+               return "";
        }
-
-       char* dest = spec;
-       while (*dest != ':' && *dest != '\0') {
-               dest++;
-       }
-
-       switch (*dest) {
-       case ':':
-               *dest = '\0';
-               return dest + 1;
-       case '\0':
-               return NULL;
-       default:
-               LOG_F("Impossible condition in cmdlineSplitStrByColon()");
-               return NULL;
+       std::vector<std::string> vec;
+       util::strSplit(str, &vec, ':');
+       if (pos > vec.size()) {
+               return "";
        }
+       return vec[pos];
 }
 
 std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
@@ -568,66 +557,67 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
                        nsjconf->envs.push_back(optarg);
                        break;
                case 'u': {
-                       char* i_id = optarg;
-                       char* o_id = cmdlineSplitStrByColon(i_id);
-                       char* cnt = cmdlineSplitStrByColon(o_id);
-                       size_t count =
-                           (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0);
-                       if (user::parseId(nsjconf.get(), i_id, o_id, count, false /* is_gid */,
-                               false /* is_newidmap */) == false) {
+                       std::string i_id = argByColon(optarg, 0);
+                       std::string o_id = argByColon(optarg, 1);
+                       std::string cnt = argByColon(optarg, 2);
+                       size_t count = std::strtoul(cnt.c_str(), nullptr, 0);
+                       if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ false,
+                               /* is_newidmap= */ false)) {
                                return nullptr;
                        }
                } break;
                case 'g': {
-                       char* i_id = optarg;
-                       char* o_id = cmdlineSplitStrByColon(i_id);
-                       char* cnt = cmdlineSplitStrByColon(o_id);
-                       size_t count =
-                           (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0);
-                       if (user::parseId(nsjconf.get(), i_id, o_id, count, true /* is_gid */,
-                               false /* is_newidmap */) == false) {
+                       std::string i_id = argByColon(optarg, 0);
+                       std::string o_id = argByColon(optarg, 1);
+                       std::string cnt = argByColon(optarg, 2);
+                       size_t count = std::strtoul(cnt.c_str(), nullptr, 0);
+                       if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ true,
+                               /* is_newidmap= */ false)) {
                                return nullptr;
                        }
                } break;
                case 'U': {
-                       char* i_id = optarg;
-                       char* o_id = cmdlineSplitStrByColon(i_id);
-                       char* cnt = cmdlineSplitStrByColon(o_id);
-                       size_t count =
-                           (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0);
-                       if (user::parseId(nsjconf.get(), i_id, o_id, count, false /* is_gid */,
-                               true /* is_newidmap */) == false) {
+                       std::string i_id = argByColon(optarg, 0);
+                       std::string o_id = argByColon(optarg, 1);
+                       std::string cnt = argByColon(optarg, 2);
+                       size_t count = std::strtoul(cnt.c_str(), nullptr, 0);
+                       if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ false,
+                               /* is_newidmap= */ true)) {
                                return nullptr;
                        }
                } break;
                case 'G': {
-                       char* i_id = optarg;
-                       char* o_id = cmdlineSplitStrByColon(i_id);
-                       char* cnt = cmdlineSplitStrByColon(o_id);
-                       size_t count =
-                           (cnt == NULL || strlen(cnt) == 0) ? 1U : (size_t)strtoull(cnt, NULL, 0);
-                       if (user::parseId(nsjconf.get(), i_id, o_id, count, true /* is_gid */,
-                               true /* is_newidmap */) == false) {
+                       std::string i_id = argByColon(optarg, 0);
+                       std::string o_id = argByColon(optarg, 1);
+                       std::string cnt = argByColon(optarg, 2);
+                       size_t count = std::strtoul(cnt.c_str(), nullptr, 0);
+                       if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ true,
+                               /* is_newidmap= */ true)) {
                                return nullptr;
                        }
                } break;
                case 'R': {
-                       const char* dst = cmdlineSplitStrByColon(optarg);
-                       dst = dst ? dst : optarg;
-                       if (!mnt::addMountPtTail(nsjconf.get(), /* src= */ optarg, dst,
-                               /* fs_type= */ "",
-                               /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY,
+                       std::string src = argByColon(optarg, 0);
+                       std::string dst = argByColon(optarg, 1);
+                       if (dst.empty()) {
+                               dst = src;
+                       }
+                       if (!mnt::addMountPtTail(nsjconf.get(), src.c_str(), dst.c_str(),
+                               /* fs_type= */ "", /* options= */ "",
+                               MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY,
                                /* isDir= */ mnt::NS_DIR_MAYBE, /* mandatory= */ true, NULL, NULL,
                                NULL, 0, /* is_symlink= */ false)) {
                                return nullptr;
                        }
                }; break;
                case 'B': {
-                       const char* dst = cmdlineSplitStrByColon(optarg);
-                       dst = dst ? dst : optarg;
-                       if (!mnt::addMountPtTail(nsjconf.get(), /* src= */ optarg, dst,
-                               /* fs_type= */ "",
-                               /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE,
+                       std::string src = argByColon(optarg, 0);
+                       std::string dst = argByColon(optarg, 1);
+                       if (dst.empty()) {
+                               dst = src;
+                       }
+                       if (!mnt::addMountPtTail(nsjconf.get(), src.c_str(), dst.c_str(),
+                               /* fs_type= */ "", /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE,
                                /* isDir= */ mnt::NS_DIR_MAYBE, /* mandatory= */ true, NULL, NULL,
                                NULL, 0, /* is_symlink= */ false)) {
                                return nullptr;
index 52d51b4..5abb1b0 100644 (file)
--- a/config.cc
+++ b/config.cc
@@ -45,8 +45,6 @@
 
 namespace config {
 
-#define VAL_IF_SET_OR_NULL(njc, val) (njc.has_##val() ? njc.val().c_str() : NULL)
-
 static uint64_t configRLimit(
     int res, const nsjail::RLimit& rl, const uint64_t val, unsigned long mul = 1UL) {
        if (rl == nsjail::RLimit::VALUE) {
@@ -186,16 +184,14 @@ static bool configParseInternal(nsjconf_t* nsjconf, const nsjail::NsJailConfig&
        nsjconf->clone_newcgroup = njc.clone_newcgroup();
 
        for (ssize_t i = 0; i < njc.uidmap_size(); i++) {
-               if (!user::parseId(nsjconf, VAL_IF_SET_OR_NULL(njc.uidmap(i), inside_id),
-                       VAL_IF_SET_OR_NULL(njc.uidmap(i), outside_id), njc.uidmap(i).count(),
-                       false /* is_gid */, njc.uidmap(i).use_newidmap())) {
+               if (!user::parseId(nsjconf, njc.uidmap(i).inside_id(), njc.uidmap(i).outside_id(),
+                       njc.uidmap(i).count(), false /* is_gid */, njc.uidmap(i).use_newidmap())) {
                        return false;
                }
        }
        for (ssize_t i = 0; i < njc.gidmap_size(); i++) {
-               if (!user::parseId(nsjconf, VAL_IF_SET_OR_NULL(njc.gidmap(i), inside_id),
-                       VAL_IF_SET_OR_NULL(njc.gidmap(i), outside_id), njc.gidmap(i).count(),
-                       true /* is_gid */, njc.gidmap(i).use_newidmap())) {
+               if (!user::parseId(nsjconf, njc.gidmap(i).inside_id(), njc.gidmap(i).outside_id(),
+                       njc.gidmap(i).count(), true /* is_gid */, njc.gidmap(i).use_newidmap())) {
                        return false;
                }
        }
diff --git a/user.cc b/user.cc
index 827a7ec..d2e5064 100644 (file)
--- a/user.cc
+++ b/user.cc
@@ -265,59 +265,63 @@ bool initNsFromChild(nsjconf_t* nsjconf) {
        return true;
 }
 
-static uid_t parseUid(const char* id) {
-       if (id == NULL || strlen(id) == 0) {
+static uid_t parseUid(const std::string& id) {
+       if (id.empty()) {
                return getuid();
        }
-       struct passwd* pw = getpwnam(id);
+       struct passwd* pw = getpwnam(id.c_str());
        if (pw != NULL) {
                return pw->pw_uid;
        }
-       if (util::isANumber(id)) {
-               return (uid_t)strtoull(id, NULL, 0);
+       if (util::isANumber(id.c_str())) {
+               return (uid_t)strtoull(id.c_str(), NULL, 0);
        }
        return (uid_t)-1;
 }
 
-static gid_t parseGid(const char* id) {
-       if (id == NULL || strlen(id) == 0) {
+static gid_t parseGid(const std::string& id) {
+       if (id.empty()) {
                return getgid();
        }
-       struct group* gr = getgrnam(id);
+       struct group* gr = getgrnam(id.c_str());
        if (gr != NULL) {
                return gr->gr_gid;
        }
-       if (util::isANumber(id)) {
-               return (gid_t)strtoull(id, NULL, 0);
+       if (util::isANumber(id.c_str())) {
+               return (gid_t)strtoull(id.c_str(), NULL, 0);
        }
        return (gid_t)-1;
 }
 
-bool parseId(nsjconf_t* nsjconf, const char* i_id, const char* o_id, size_t cnt, bool is_gid,
-    bool is_newidmap) {
+bool parseId(nsjconf_t* nsjconf, const std::string& i_id, const std::string& o_id, size_t cnt,
+    bool is_gid, bool is_newidmap) {
+       if (cnt < 1) {
+               cnt = 1;
+       }
+
        uid_t inside_id;
        uid_t outside_id;
 
        if (is_gid) {
                inside_id = parseGid(i_id);
                if (inside_id == (uid_t)-1) {
-                       LOG_W("Cannot parse '%s' as GID", i_id);
+                       LOG_W("Cannot parse '%s' as GID", i_id.c_str());
                        return false;
                }
                outside_id = parseGid(o_id);
                if (outside_id == (uid_t)-1) {
-                       LOG_W("Cannot parse '%s' as GID", o_id);
+                       LOG_W("Cannot parse '%s' as GID", o_id.c_str());
                        return false;
                }
        } else {
                inside_id = parseUid(i_id);
                if (inside_id == (uid_t)-1) {
-                       LOG_W("Cannot parse '%s' as UID", i_id);
+                       LOG_W("Cannot parse '%s' as UID", i_id.c_str());
                        return false;
                }
                outside_id = parseUid(o_id);
                if (outside_id == (uid_t)-1) {
-                       LOG_W("Cannot parse '%s' as UID", o_id);
+                       LOG_W("Cannot parse '%s' as UID", o_id.c_str());
                        return false;
                }
        }
diff --git a/user.h b/user.h
index 4e82397..598ea81 100644 (file)
--- a/user.h
+++ b/user.h
 
 #include <stdbool.h>
 
+#include <string>
+
 #include "nsjail.h"
 
 namespace user {
 
 bool initNsFromParent(nsjconf_t* nsjconf, pid_t pid);
 bool initNsFromChild(nsjconf_t* nsjconf);
-
-bool parseId(nsjconf_t* nsjconf, const char* i_id, const char* o_id, size_t cnt, bool is_gid,
-    bool is_newidmap);
+bool parseId(nsjconf_t* nsjconf, const std::string& i_id, const std::string& o_id, size_t cnt,
+    bool is_gid, bool is_newidmap);
 
 }  // namespace user
 
diff --git a/util.cc b/util.cc
index d295712..e48ea59 100644 (file)
--- a/util.cc
+++ b/util.cc
@@ -40,7 +40,9 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <sstream>
 #include <string>
+#include <vector>
 
 #include "logs.h"
 #include "macros.h"
@@ -279,4 +281,12 @@ const std::string timeToStr(time_t t) {
        return timestr;
 }
 
+void strSplit(const std::string str, std::vector<std::string>* vec, char delim) {
+       std::string word;
+       std::istringstream stream(str);
+       for (std::string word; std::getline(stream, word, delim);) {
+               vec->push_back(word);
+       }
+}
+
 }  // namespace util
diff --git a/util.h b/util.h
index 427e4a7..8b9a3cd 100644 (file)
--- a/util.h
+++ b/util.h
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 
 #include <string>
+#include <vector>
 
 #include "nsjail.h"
 
@@ -42,6 +43,7 @@ bool isANumber(const char* s);
 uint64_t rnd64(void);
 const std::string sigName(int signo);
 const std::string timeToStr(time_t t);
+void strSplit(const std::string str, std::vector<std::string>* vec, char delim);
 
 }  // namespace util