blob: 02e0d42e563b36b8db0ed7d97d9815a51edc203a [file] [log] [blame]
Tom Cherryed506f72017-05-25 15:58:59 -07001/*
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
Tom Cherry81f5d3e2017-06-22 12:53:17 -070024namespace android {
25namespace init {
26
Tom Cherryed506f72017-05-25 15:58:59 -070027bool 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
80bool 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
97bool 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
111bool 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
121bool 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
146void SubsystemParser::EndSection() {
147 subsystems_->emplace_back(std::move(subsystem_));
148}
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700149
150} // namespace init
151} // namespace android