blob: 2efaeeafabb2084a70e8edfe99a2a7e8b715a2d5 [file] [log] [blame]
Tom Cherry4772f1d2019-07-30 09:34:41 -07001/*
2 * Copyright (C) 2019 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// Note that these check functions cannot check expanded arguments from properties, since they will
18// not know what those properties would be at runtime. They will be passed an empty string in the
19// situation that the input line had a property expansion without a default value, since an empty
20// string is otherwise an impossible value. They should therefore disregard checking empty
21// arguments.
22
23#include "check_builtins.h"
24
25#include <sys/time.h>
26
27#include <android-base/logging.h>
28#include <android-base/parseint.h>
29#include <android-base/strings.h>
30
31#include "builtin_arguments.h"
Daniel Normand2533c32019-08-02 15:13:50 -070032#include "interface_utils.h"
Tom Cherry4772f1d2019-07-30 09:34:41 -070033#include "rlimit_parser.h"
34#include "service.h"
35#include "util.h"
36
37using android::base::ParseInt;
38using android::base::StartsWith;
39
40#define ReturnIfAnyArgsEmpty() \
41 for (const auto& arg : args) { \
42 if (arg.empty()) { \
43 return {}; \
44 } \
45 }
46
47namespace android {
48namespace init {
49
50Result<void> check_chown(const BuiltinArguments& args) {
51 if (!args[1].empty()) {
52 auto uid = DecodeUid(args[1]);
53 if (!uid) {
54 return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
55 }
56 }
57
58 // GID is optional and pushes the index of path out by one if specified.
59 if (args.size() == 4 && !args[2].empty()) {
60 auto gid = DecodeUid(args[2]);
61 if (!gid) {
62 return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
63 }
64 }
65
66 return {};
67}
68
69Result<void> check_exec(const BuiltinArguments& args) {
70 ReturnIfAnyArgsEmpty();
71
72 auto result = Service::MakeTemporaryOneshotService(args.args);
73 if (!result) {
74 return result.error();
75 }
76
77 return {};
78}
79
80Result<void> check_exec_background(const BuiltinArguments& args) {
81 return check_exec(std::move(args));
82}
83
Tom Cherry7896e7a2019-09-04 15:26:52 -070084Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) {
85 BuiltinArguments remaining_args(args.context);
86
87 remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end());
88 remaining_args.args[0] = args[0];
89
90 return check_exec(remaining_args);
91}
92
Daniel Normand2533c32019-08-02 15:13:50 -070093Result<void> check_interface_restart(const BuiltinArguments& args) {
94 if (auto result = IsKnownInterface(args[1]); !result) {
95 return result.error();
96 }
97 return {};
98}
99
100Result<void> check_interface_start(const BuiltinArguments& args) {
101 return check_interface_restart(std::move(args));
102}
103
104Result<void> check_interface_stop(const BuiltinArguments& args) {
105 return check_interface_restart(std::move(args));
106}
107
Tom Cherry4772f1d2019-07-30 09:34:41 -0700108Result<void> check_load_system_props(const BuiltinArguments& args) {
109 return Error() << "'load_system_props' is deprecated";
110}
111
112Result<void> check_loglevel(const BuiltinArguments& args) {
113 ReturnIfAnyArgsEmpty();
114
115 int log_level = -1;
116 ParseInt(args[1], &log_level);
117 if (log_level < 0 || log_level > 7) {
118 return Error() << "loglevel must be in the range of 0-7";
119 }
120 return {};
121}
122
123Result<void> check_mkdir(const BuiltinArguments& args) {
124 if (args.size() >= 4) {
125 if (!args[3].empty()) {
126 auto uid = DecodeUid(args[3]);
127 if (!uid) {
128 return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
129 }
130 }
131
132 if (args.size() == 5 && !args[4].empty()) {
133 auto gid = DecodeUid(args[4]);
134 if (!gid) {
135 return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
136 }
137 }
138 }
139
140 return {};
141}
142
143Result<void> check_restorecon(const BuiltinArguments& args) {
144 ReturnIfAnyArgsEmpty();
145
146 auto restorecon_info = ParseRestorecon(args.args);
147 if (!restorecon_info) {
148 return restorecon_info.error();
149 }
150
151 return {};
152}
153
154Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
155 return check_restorecon(std::move(args));
156}
157
158Result<void> check_setprop(const BuiltinArguments& args) {
159 const std::string& name = args[1];
160 if (name.empty()) {
161 return {};
162 }
163 const std::string& value = args[2];
164
165 if (!IsLegalPropertyName(name)) {
166 return Error() << "'" << name << "' is not a legal property name";
167 }
168
169 if (!value.empty()) {
170 if (auto result = IsLegalPropertyValue(name, value); !result) {
171 return result.error();
172 }
173 }
174
175 if (StartsWith(name, "ctl.")) {
176 return Error()
177 << "Do not set ctl. properties from init; call the Service functions directly";
178 }
179
180 static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
181 if (name == kRestoreconProperty) {
182 return Error() << "Do not set '" << kRestoreconProperty
183 << "' from init; use the restorecon builtin directly";
184 }
185
186 return {};
187}
188
189Result<void> check_setrlimit(const BuiltinArguments& args) {
190 ReturnIfAnyArgsEmpty();
191
192 auto rlimit = ParseRlimit(args.args);
193 if (!rlimit) return rlimit.error();
194 return {};
195}
196
197Result<void> check_sysclktz(const BuiltinArguments& args) {
198 ReturnIfAnyArgsEmpty();
199
200 struct timezone tz = {};
201 if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
202 return Error() << "Unable to parse mins_west_of_gmt";
203 }
204 return {};
205}
206
207Result<void> check_wait(const BuiltinArguments& args) {
208 if (args.size() == 3 && !args[2].empty()) {
209 int timeout_int;
210 if (!android::base::ParseInt(args[2], &timeout_int)) {
211 return Error() << "failed to parse timeout";
212 }
213 }
214 return {};
215}
216
217Result<void> check_wait_for_prop(const BuiltinArguments& args) {
218 return check_setprop(std::move(args));
219}
220
221} // namespace init
222} // namespace android