1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ueventd_parser.h" 18 19 #include <grp.h> 20 #include <pwd.h> 21 22 #include "keyword_map.h" 23 24 namespace android { 25 namespace init { 26 27 bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err, 28 std::vector<SysfsPermissions>* out_sysfs_permissions, 29 std::vector<Permissions>* out_dev_permissions) { 30 bool is_sysfs = out_sysfs_permissions != nullptr; 31 if (is_sysfs && args.size() != 5) { 32 *err = "/sys/ lines must have 5 entries"; 33 return false; 34 } 35 36 if (!is_sysfs && args.size() != 4) { 37 *err = "/dev/ lines must have 4 entries"; 38 return false; 39 } 40 41 auto it = args.begin(); 42 const std::string& name = *it++; 43 44 std::string sysfs_attribute; 45 if (is_sysfs) sysfs_attribute = *it++; 46 47 // args is now common to both sys and dev entries and contains: <perm> <uid> <gid> 48 std::string& perm_string = *it++; 49 char* end_pointer = 0; 50 mode_t perm = strtol(perm_string.c_str(), &end_pointer, 8); 51 if (end_pointer == nullptr || *end_pointer != '\0') { 52 *err = "invalid mode '" + perm_string + "'"; 53 return false; 54 } 55 56 std::string& uid_string = *it++; 57 passwd* pwd = getpwnam(uid_string.c_str()); 58 if (!pwd) { 59 *err = "invalid uid '" + uid_string + "'"; 60 return false; 61 } 62 uid_t uid = pwd->pw_uid; 63 64 std::string& gid_string = *it++; 65 struct group* grp = getgrnam(gid_string.c_str()); 66 if (!grp) { 67 *err = "invalid gid '" + gid_string + "'"; 68 return false; 69 } 70 gid_t gid = grp->gr_gid; 71 72 if (is_sysfs) { 73 out_sysfs_permissions->emplace_back(name, sysfs_attribute, perm, uid, gid); 74 } else { 75 out_dev_permissions->emplace_back(name, perm, uid, gid); 76 } 77 return true; 78 } 79 80 bool SubsystemParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, 81 int line, std::string* err) { 82 if (args.size() != 2) { 83 *err = "subsystems must have exactly one name"; 84 return false; 85 } 86 87 if (std::find(subsystems_->begin(), subsystems_->end(), args[1]) != subsystems_->end()) { 88 *err = "ignoring duplicate subsystem entry"; 89 return false; 90 } 91 92 subsystem_.name_ = args[1]; 93 94 return true; 95 } 96 97 bool SubsystemParser::ParseDevName(std::vector<std::string>&& args, std::string* err) { 98 if (args[1] == "uevent_devname") { 99 subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME; 100 return true; 101 } 102 if (args[1] == "uevent_devpath") { 103 subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH; 104 return true; 105 } 106 107 *err = "invalid devname '" + args[1] + "'"; 108 return false; 109 } 110 111 bool SubsystemParser::ParseDirName(std::vector<std::string>&& args, std::string* err) { 112 if (args[1].front() != '/') { 113 *err = "dirname '" + args[1] + " ' does not start with '/'"; 114 return false; 115 } 116 117 subsystem_.dir_name_ = args[1]; 118 return true; 119 } 120 121 bool SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) { 122 using OptionParser = 123 bool (SubsystemParser::*)(std::vector<std::string> && args, std::string * err); 124 static class OptionParserMap : public KeywordMap<OptionParser> { 125 private: 126 const Map& map() const override { 127 // clang-format off 128 static const Map option_parsers = { 129 {"devname", {1, 1, &SubsystemParser::ParseDevName}}, 130 {"dirname", {1, 1, &SubsystemParser::ParseDirName}}, 131 }; 132 // clang-format on 133 return option_parsers; 134 } 135 } parser_map; 136 137 auto parser = parser_map.FindFunction(args, err); 138 139 if (!parser) { 140 return false; 141 } 142 143 return (this->*parser)(std::move(args), err); 144 } 145 146 void SubsystemParser::EndSection() { 147 subsystems_->emplace_back(std::move(subsystem_)); 148 } 149 150 } // namespace init 151 } // namespace android 152