• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ParsePermissionsLine(std::vector<std::string> && args,std::string * err,std::vector<SysfsPermissions> * out_sysfs_permissions,std::vector<Permissions> * out_dev_permissions)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 
ParseSection(std::vector<std::string> && args,const std::string & filename,int line,std::string * err)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 
ParseDevName(std::vector<std::string> && args,std::string * err)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 
ParseDirName(std::vector<std::string> && args,std::string * err)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 
ParseLineSection(std::vector<std::string> && args,int line,std::string * err)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 
EndSection()146 void SubsystemParser::EndSection() {
147     subsystems_->emplace_back(std::move(subsystem_));
148 }
149 
150 }  // namespace init
151 }  // namespace android
152