xref: /haiku/src/servers/launch/Conditions.cpp (revision 6d2f2ec177bf615a117a7428d71be4330545b320)
1 /*
2  * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Conditions.h"
8 
9 #include <stdio.h>
10 
11 #include <Entry.h>
12 #include <ObjectList.h>
13 #include <Message.h>
14 #include <StringList.h>
15 
16 #include "Utility.h"
17 
18 
19 class ConditionContainer : public Condition {
20 protected:
21 								ConditionContainer(const BMessage& args);
22 								ConditionContainer();
23 
24 public:
25 			void				AddCondition(Condition* condition);
26 
27 	virtual	bool				IsConstant(ConditionContext& context) const;
28 
29 protected:
30 			void				AddConditionsToString(BString& string) const;
31 
32 protected:
33 			BObjectList<Condition> fConditions;
34 };
35 
36 
37 class AndCondition : public ConditionContainer {
38 public:
39 								AndCondition(const BMessage& args);
40 								AndCondition();
41 
42 	virtual	bool				Test(ConditionContext& context) const;
43 	virtual	BString				ToString() const;
44 };
45 
46 
47 class OrCondition : public ConditionContainer {
48 public:
49 								OrCondition(const BMessage& args);
50 
51 	virtual	bool				Test(ConditionContext& context) const;
52 	virtual	bool				IsConstant(ConditionContext& context) const;
53 
54 	virtual	BString				ToString() const;
55 };
56 
57 
58 class NotCondition : public ConditionContainer {
59 public:
60 								NotCondition(const BMessage& args);
61 								NotCondition();
62 
63 	virtual	bool				Test(ConditionContext& context) const;
64 	virtual	BString				ToString() const;
65 };
66 
67 
68 class SafeModeCondition : public Condition {
69 public:
70 	virtual	bool				Test(ConditionContext& context) const;
71 	virtual	bool				IsConstant(ConditionContext& context) const;
72 
73 	virtual	BString				ToString() const;
74 };
75 
76 
77 class ReadOnlyCondition : public Condition {
78 public:
79 								ReadOnlyCondition(const BMessage& args);
80 
81 	virtual	bool				Test(ConditionContext& context) const;
82 	virtual	bool				IsConstant(ConditionContext& context) const;
83 
84 	virtual	BString				ToString() const;
85 
86 private:
87 			BString				fPath;
88 	mutable	bool				fIsReadOnly;
89 	mutable	bool				fTestPerformed;
90 };
91 
92 
93 class FileExistsCondition : public Condition {
94 public:
95 								FileExistsCondition(const BMessage& args);
96 
97 	virtual	bool				Test(ConditionContext& context) const;
98 	virtual	BString				ToString() const;
99 
100 private:
101 			BStringList			fPaths;
102 };
103 
104 
105 static Condition*
106 create_condition(const char* name, const BMessage& args)
107 {
108 	if (strcmp(name, "and") == 0 && !args.IsEmpty())
109 		return new AndCondition(args);
110 	if (strcmp(name, "or") == 0 && !args.IsEmpty())
111 		return new OrCondition(args);
112 	if (strcmp(name, "not") == 0 && !args.IsEmpty())
113 		return new NotCondition(args);
114 
115 	if (strcmp(name, "safemode") == 0)
116 		return new SafeModeCondition();
117 	if (strcmp(name, "read_only") == 0)
118 		return new ReadOnlyCondition(args);
119 	if (strcmp(name, "file_exists") == 0)
120 		return new FileExistsCondition(args);
121 
122 	return NULL;
123 }
124 
125 
126 // #pragma mark -
127 
128 
129 Condition::Condition()
130 {
131 }
132 
133 
134 Condition::~Condition()
135 {
136 }
137 
138 
139 bool
140 Condition::IsConstant(ConditionContext& context) const
141 {
142 	return false;
143 }
144 
145 
146 // #pragma mark -
147 
148 
149 ConditionContainer::ConditionContainer(const BMessage& args)
150 	:
151 	fConditions(10, true)
152 {
153 	char* name;
154 	type_code type;
155 	int32 count;
156 	for (int32 index = 0; args.GetInfo(B_MESSAGE_TYPE, index, &name, &type,
157 			&count) == B_OK; index++) {
158 		BMessage message;
159 		for (int32 messageIndex = 0; args.FindMessage(name, messageIndex,
160 				&message) == B_OK; messageIndex++) {
161 			AddCondition(create_condition(name, message));
162 		}
163 	}
164 }
165 
166 
167 ConditionContainer::ConditionContainer()
168 	:
169 	fConditions(10, true)
170 {
171 }
172 
173 
174 void
175 ConditionContainer::AddCondition(Condition* condition)
176 {
177 	if (condition != NULL)
178 		fConditions.AddItem(condition);
179 }
180 
181 
182 /*!	A single constant failing condition makes this constant, too, otherwise,
183 	a single non-constant condition makes this non-constant as well.
184 */
185 bool
186 ConditionContainer::IsConstant(ConditionContext& context) const
187 {
188 	bool fixed = true;
189 	for (int32 index = 0; index < fConditions.CountItems(); index++) {
190 		const Condition* condition = fConditions.ItemAt(index);
191 		if (condition->IsConstant(context)) {
192 			if (!condition->Test(context))
193 				return true;
194 		} else
195 			fixed = false;
196 	}
197 	return fixed;
198 }
199 
200 
201 void
202 ConditionContainer::AddConditionsToString(BString& string) const
203 {
204 	string += "[";
205 
206 	for (int32 index = 0; index < fConditions.CountItems(); index++) {
207 		if (index != 0)
208 			string += ", ";
209 		string += fConditions.ItemAt(index)->ToString();
210 	}
211 	string += "]";
212 }
213 
214 
215 // #pragma mark - and
216 
217 
218 AndCondition::AndCondition(const BMessage& args)
219 	:
220 	ConditionContainer(args)
221 {
222 }
223 
224 
225 AndCondition::AndCondition()
226 {
227 }
228 
229 
230 bool
231 AndCondition::Test(ConditionContext& context) const
232 {
233 	for (int32 index = 0; index < fConditions.CountItems(); index++) {
234 		Condition* condition = fConditions.ItemAt(index);
235 		if (!condition->Test(context))
236 			return false;
237 	}
238 	return true;
239 }
240 
241 
242 BString
243 AndCondition::ToString() const
244 {
245 	BString string = "and ";
246 	ConditionContainer::AddConditionsToString(string);
247 	return string;
248 }
249 
250 
251 // #pragma mark - or
252 
253 
254 OrCondition::OrCondition(const BMessage& args)
255 	:
256 	ConditionContainer(args)
257 {
258 }
259 
260 
261 bool
262 OrCondition::Test(ConditionContext& context) const
263 {
264 	if (fConditions.IsEmpty())
265 		return true;
266 
267 	for (int32 index = 0; index < fConditions.CountItems(); index++) {
268 		Condition* condition = fConditions.ItemAt(index);
269 		if (condition->Test(context))
270 			return true;
271 	}
272 	return false;
273 }
274 
275 
276 /*!	If there is a single succeeding constant condition, this is constant, too.
277 	Otherwise, it is non-constant if there is a single non-constant condition.
278 */
279 bool
280 OrCondition::IsConstant(ConditionContext& context) const
281 {
282 	bool fixed = true;
283 	for (int32 index = 0; index < fConditions.CountItems(); index++) {
284 		const Condition* condition = fConditions.ItemAt(index);
285 		if (condition->IsConstant(context)) {
286 			if (condition->Test(context))
287 				return true;
288 		} else
289 			fixed = false;
290 	}
291 	return fixed;
292 }
293 
294 
295 BString
296 OrCondition::ToString() const
297 {
298 	BString string = "or ";
299 	ConditionContainer::AddConditionsToString(string);
300 	return string;
301 }
302 
303 
304 // #pragma mark - or
305 
306 
307 NotCondition::NotCondition(const BMessage& args)
308 	:
309 	ConditionContainer(args)
310 {
311 }
312 
313 
314 NotCondition::NotCondition()
315 {
316 }
317 
318 
319 bool
320 NotCondition::Test(ConditionContext& context) const
321 {
322 	for (int32 index = 0; index < fConditions.CountItems(); index++) {
323 		Condition* condition = fConditions.ItemAt(index);
324 		if (condition->Test(context))
325 			return false;
326 	}
327 	return true;
328 }
329 
330 
331 BString
332 NotCondition::ToString() const
333 {
334 	BString string = "not ";
335 	ConditionContainer::AddConditionsToString(string);
336 	return string;
337 }
338 
339 
340 // #pragma mark - safemode
341 
342 
343 bool
344 SafeModeCondition::Test(ConditionContext& context) const
345 {
346 	return context.IsSafeMode();
347 }
348 
349 
350 bool
351 SafeModeCondition::IsConstant(ConditionContext& context) const
352 {
353 	return true;
354 }
355 
356 
357 BString
358 SafeModeCondition::ToString() const
359 {
360 	return "safemode";
361 }
362 
363 
364 // #pragma mark - read_only
365 
366 
367 ReadOnlyCondition::ReadOnlyCondition(const BMessage& args)
368 	:
369 	fPath(args.GetString("args")),
370 	fIsReadOnly(false),
371 	fTestPerformed(false)
372 {
373 }
374 
375 
376 bool
377 ReadOnlyCondition::Test(ConditionContext& context) const
378 {
379 	if (fTestPerformed)
380 		return fIsReadOnly;
381 
382 	if (fPath.IsEmpty() || fPath == "/boot")
383 		fIsReadOnly = context.BootVolumeIsReadOnly();
384 	else
385 		fIsReadOnly = Utility::IsReadOnlyVolume(fPath);
386 
387 	fTestPerformed = true;
388 
389 	return fIsReadOnly;
390 }
391 
392 
393 bool
394 ReadOnlyCondition::IsConstant(ConditionContext& context) const
395 {
396 	return true;
397 }
398 
399 
400 BString
401 ReadOnlyCondition::ToString() const
402 {
403 	BString string = "readonly ";
404 	string << fPath;
405 	return string;
406 }
407 
408 
409 // #pragma mark - file_exists
410 
411 
412 FileExistsCondition::FileExistsCondition(const BMessage& args)
413 {
414 	for (int32 index = 0;
415 			const char* path = args.GetString("args", index, NULL); index++) {
416 		fPaths.Add(path);
417 	}
418 }
419 
420 
421 bool
422 FileExistsCondition::Test(ConditionContext& context) const
423 {
424 	for (int32 index = 0; index < fPaths.CountStrings(); index++) {
425 		BEntry entry;
426 		if (entry.SetTo(fPaths.StringAt(index)) != B_OK
427 			|| !entry.Exists())
428 			return false;
429 	}
430 	return true;
431 }
432 
433 
434 BString
435 FileExistsCondition::ToString() const
436 {
437 	BString string = "file_exists [";
438 	for (int32 index = 0; index < fPaths.CountStrings(); index++) {
439 		if (index != 0)
440 			string << ", ";
441 		string << fPaths.StringAt(index);
442 	}
443 	string += "]";
444 	return string;
445 }
446 
447 
448 // #pragma mark -
449 
450 
451 /*static*/ Condition*
452 Conditions::FromMessage(const BMessage& message)
453 {
454 	return create_condition("and", message);
455 }
456 
457 
458 /*static*/ Condition*
459 Conditions::AddNotSafeMode(Condition* condition)
460 {
461 	AndCondition* andCondition = dynamic_cast<AndCondition*>(condition);
462 	if (andCondition == NULL)
463 		andCondition = new AndCondition();
464 	if (andCondition != condition && condition != NULL)
465 		andCondition->AddCondition(condition);
466 
467 	NotCondition* notCondition = new NotCondition();
468 	notCondition->AddCondition(new SafeModeCondition());
469 
470 	andCondition->AddCondition(notCondition);
471 	return andCondition;
472 }
473