blob: 7156e766fff1bbecbfc75ca5aca7d230c9373684 [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
24bool ParsePermissionsLine(std::vector<std::string>&& args, std::string* err,
25 std::vector<SysfsPermissions>* out_sysfs_permissions,
26 std::vector<Permissions>* out_dev_permissions) {
27 bool is_sysfs = out_sysfs_permissions != nullptr;
28 if (is_sysfs && args.size() != 5) {
29 *err = "/sys/ lines must have 5 entries";
30 return false;
31 }
32
33 if (!is_sysfs && args.size() != 4) {
34 *err = "/dev/ lines must have 4 entries";
35 return false;
36 }
37
38 auto it = args.begin();
39 const std::string& name = *it++;
40
41 std::string sysfs_attribute;
42 if (is_sysfs) sysfs_attribute = *it++;
43
44 // args is now common to both sys and dev entries and contains: <perm> <uid> <gid>
45 std::string& perm_string = *it++;
46 char* end_pointer = 0;
47 mode_t perm = strtol(perm_string.c_str(), &end_pointer, 8);
48 if (end_pointer == nullptr || *end_pointer != '\0') {
49 *err = "invalid mode '" + perm_string + "'";
50 return false;
51 }
52
53 std::string& uid_string = *it++;
54 passwd* pwd = getpwnam(uid_string.c_str());
55 if (!pwd) {
56 *err = "invalid uid '" + uid_string + "'";
57 return false;
58 }
59 uid_t uid = pwd->pw_uid;
60
61 std::string& gid_string = *it++;
62 struct group* grp = getgrnam(gid_string.c_str());
63 if (!grp) {
64 *err = "invalid gid '" + gid_string + "'";
65 return false;
66 }
67 gid_t gid = grp->gr_gid;
68
69 if (is_sysfs) {
70 out_sysfs_permissions->emplace_back(name, sysfs_attribute, perm, uid, gid);
71 } else {
72 out_dev_permissions->emplace_back(name, perm, uid, gid);
73 }
74 return true;
75}
76
77bool SubsystemParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
78 int line, std::string* err) {
79 if (args.size() != 2) {
80 *err = "subsystems must have exactly one name";
81 return false;
82 }
83
84 if (std::find(subsystems_->begin(), subsystems_->end(), args[1]) != subsystems_->end()) {
85 *err = "ignoring duplicate subsystem entry";
86 return false;
87 }
88
89 subsystem_.name_ = args[1];
90
91 return true;
92}
93
94bool SubsystemParser::ParseDevName(std::vector<std::string>&& args, std::string* err) {
95 if (args[1] == "uevent_devname") {
96 subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME;
97 return true;
98 }
99 if (args[1] == "uevent_devpath") {
100 subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH;
101 return true;
102 }
103
104 *err = "invalid devname '" + args[1] + "'";
105 return false;
106}
107
108bool SubsystemParser::ParseDirName(std::vector<std::string>&& args, std::string* err) {
109 if (args[1].front() != '/') {
110 *err = "dirname '" + args[1] + " ' does not start with '/'";
111 return false;
112 }
113
114 subsystem_.dir_name_ = args[1];
115 return true;
116}
117
118bool SubsystemParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) {
119 using OptionParser =
120 bool (SubsystemParser::*)(std::vector<std::string> && args, std::string * err);
121 static class OptionParserMap : public KeywordMap<OptionParser> {
122 private:
123 const Map& map() const override {
124 // clang-format off
125 static const Map option_parsers = {
126 {"devname", {1, 1, &SubsystemParser::ParseDevName}},
127 {"dirname", {1, 1, &SubsystemParser::ParseDirName}},
128 };
129 // clang-format on
130 return option_parsers;
131 }
132 } parser_map;
133
134 auto parser = parser_map.FindFunction(args, err);
135
136 if (!parser) {
137 return false;
138 }
139
140 return (this->*parser)(std::move(args), err);
141}
142
143void SubsystemParser::EndSection() {
144 subsystems_->emplace_back(std::move(subsystem_));
145}