blob: 3bd4774708f71f670e4504a174551859b634af22 [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"
32#include "rlimit_parser.h"
33#include "service.h"
34#include "util.h"
35
36using android::base::ParseInt;
37using android::base::StartsWith;
38
39#define ReturnIfAnyArgsEmpty() \
40 for (const auto& arg : args) { \
41 if (arg.empty()) { \
42 return {}; \
43 } \
44 }
45
46namespace android {
47namespace init {
48
49Result<void> check_chown(const BuiltinArguments& args) {
50 if (!args[1].empty()) {
51 auto uid = DecodeUid(args[1]);
52 if (!uid) {
53 return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
54 }
55 }
56
57 // GID is optional and pushes the index of path out by one if specified.
58 if (args.size() == 4 && !args[2].empty()) {
59 auto gid = DecodeUid(args[2]);
60 if (!gid) {
61 return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
62 }
63 }
64
65 return {};
66}
67
68Result<void> check_exec(const BuiltinArguments& args) {
69 ReturnIfAnyArgsEmpty();
70
71 auto result = Service::MakeTemporaryOneshotService(args.args);
72 if (!result) {
73 return result.error();
74 }
75
76 return {};
77}
78
79Result<void> check_exec_background(const BuiltinArguments& args) {
80 return check_exec(std::move(args));
81}
82
83Result<void> check_load_system_props(const BuiltinArguments& args) {
84 return Error() << "'load_system_props' is deprecated";
85}
86
87Result<void> check_loglevel(const BuiltinArguments& args) {
88 ReturnIfAnyArgsEmpty();
89
90 int log_level = -1;
91 ParseInt(args[1], &log_level);
92 if (log_level < 0 || log_level > 7) {
93 return Error() << "loglevel must be in the range of 0-7";
94 }
95 return {};
96}
97
98Result<void> check_mkdir(const BuiltinArguments& args) {
99 if (args.size() >= 4) {
100 if (!args[3].empty()) {
101 auto uid = DecodeUid(args[3]);
102 if (!uid) {
103 return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
104 }
105 }
106
107 if (args.size() == 5 && !args[4].empty()) {
108 auto gid = DecodeUid(args[4]);
109 if (!gid) {
110 return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
111 }
112 }
113 }
114
115 return {};
116}
117
118Result<void> check_restorecon(const BuiltinArguments& args) {
119 ReturnIfAnyArgsEmpty();
120
121 auto restorecon_info = ParseRestorecon(args.args);
122 if (!restorecon_info) {
123 return restorecon_info.error();
124 }
125
126 return {};
127}
128
129Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
130 return check_restorecon(std::move(args));
131}
132
133Result<void> check_setprop(const BuiltinArguments& args) {
134 const std::string& name = args[1];
135 if (name.empty()) {
136 return {};
137 }
138 const std::string& value = args[2];
139
140 if (!IsLegalPropertyName(name)) {
141 return Error() << "'" << name << "' is not a legal property name";
142 }
143
144 if (!value.empty()) {
145 if (auto result = IsLegalPropertyValue(name, value); !result) {
146 return result.error();
147 }
148 }
149
150 if (StartsWith(name, "ctl.")) {
151 return Error()
152 << "Do not set ctl. properties from init; call the Service functions directly";
153 }
154
155 static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
156 if (name == kRestoreconProperty) {
157 return Error() << "Do not set '" << kRestoreconProperty
158 << "' from init; use the restorecon builtin directly";
159 }
160
161 return {};
162}
163
164Result<void> check_setrlimit(const BuiltinArguments& args) {
165 ReturnIfAnyArgsEmpty();
166
167 auto rlimit = ParseRlimit(args.args);
168 if (!rlimit) return rlimit.error();
169 return {};
170}
171
172Result<void> check_sysclktz(const BuiltinArguments& args) {
173 ReturnIfAnyArgsEmpty();
174
175 struct timezone tz = {};
176 if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
177 return Error() << "Unable to parse mins_west_of_gmt";
178 }
179 return {};
180}
181
182Result<void> check_wait(const BuiltinArguments& args) {
183 if (args.size() == 3 && !args[2].empty()) {
184 int timeout_int;
185 if (!android::base::ParseInt(args[2], &timeout_int)) {
186 return Error() << "failed to parse timeout";
187 }
188 }
189 return {};
190}
191
192Result<void> check_wait_for_prop(const BuiltinArguments& args) {
193 return check_setprop(std::move(args));
194}
195
196} // namespace init
197} // namespace android