diff --git a/data/launch/user b/data/launch/user index da2117848d..dc7a75c662 100644 --- a/data/launch/user +++ b/data/launch/user @@ -1,9 +1,33 @@ -service x-vnd.Be-TRAK { - launch /system/Tracker - legacy +target desktop { + service x-vnd.Be-TRAK { + launch /system/Tracker + legacy + } + + service x-vnd.Be-TSKB { + launch /system/Deskbar + legacy + } } -service x-vnd.Be-TSKB { - launch /system/Deskbar - legacy +target first_boot { + job x-vnd.Haiku-FirstBootPrompt { + launch /system/apps/FirstBootPrompt + legacy + } +} + +run { + if { + or { + not file_exists /boot/home/config/settings/Locale\ settings + read_only + } + } + then { + first_boot + } + else { + desktop + } } diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 3c92b49139..fb2d9bef23 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -93,6 +93,9 @@ private: void _AddJobs(Target* target, BMessage& message); void _AddTargets(BMessage& message); + void _AddRunTargets(BMessage& message); + void _AddRunTargets(BMessage& message, + const char* name); void _AddJob(Target* target, bool service, BMessage& message); void _InitJobs(); @@ -112,6 +115,7 @@ private: private: JobMap fJobs; TargetMap fTargets; + BStringList fRunTargets; JobQueue fJobQueue; SessionMap fSessions; MainWorker* fMainWorker; @@ -237,6 +241,13 @@ LaunchDaemon::ReadyToRun() _InitJobs(); _LaunchJobs(NULL); + + // Launch run targets + for (int32 index = 0; index < fRunTargets.CountStrings(); index++) { + Target* target = FindTarget(fRunTargets.StringAt(index)); + if (target != NULL) + _LaunchJobs(target); + } } @@ -457,6 +468,7 @@ LaunchDaemon::_ReadFile(const char* context, BEntry& entry) if (status == B_OK) { _AddJobs(NULL, message); _AddTargets(message); + _AddRunTargets(message); } return status; @@ -516,6 +528,50 @@ LaunchDaemon::_AddTargets(BMessage& message) } +void +LaunchDaemon::_AddRunTargets(BMessage& message) +{ + BMessage runMessage; + for (int32 index = 0; message.FindMessage("run", index, + &runMessage) == B_OK; index++) { + BMessage conditions; + bool pass = true; + if (runMessage.FindMessage("if", &conditions) == B_OK) { + Condition* condition = Conditions::FromMessage(conditions); + if (condition != NULL) { + pass = condition->Test(*this); + debug_printf("Test: %s -> %d\n", condition->ToString().String(), + pass); + delete condition; + } else + debug_printf("Could not parse condition!\n"); + } + + if (pass) { + _AddRunTargets(runMessage, NULL); + _AddRunTargets(runMessage, "then"); + } else { + _AddRunTargets(runMessage, "else"); + } + } +} + + +void +LaunchDaemon::_AddRunTargets(BMessage& message, const char* name) +{ + BMessage targets; + if (name != NULL && message.FindMessage(name, &targets) != B_OK) + return; + + const char* target; + for (int32 index = 0; targets.FindString("target", index, &target) == B_OK; + index++) { + fRunTargets.Add(target); + } +} + + void LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message) { diff --git a/src/servers/launch/SettingsParser.cpp b/src/servers/launch/SettingsParser.cpp index 1df5f35587..083993d4fa 100644 --- a/src/servers/launch/SettingsParser.cpp +++ b/src/servers/launch/SettingsParser.cpp @@ -74,6 +74,29 @@ private: }; +class RunConverter : public DriverSettingsConverter { +public: + status_t ConvertFromDriverSettings(const driver_parameter& parameter, + const char* name, int32 index, uint32 type, BMessage& target) + { + if (parameter.parameter_count == 0) + return target.AddString("target", parameter.values[index]); + + return B_NOT_SUPPORTED; + } + + status_t ConvertEmptyFromDriverSettings( + const driver_parameter& parameter, const char* name, uint32 type, + BMessage& target) + { + if (parameter.parameter_count != 0) + return B_OK; + + return target.AddString("target", name); + } +}; + + const static settings_template kConditionTemplate[] = { {B_STRING_TYPE, NULL, NULL, true, new ConditionConverter()}, {B_MESSAGE_TYPE, "not", kConditionTemplate}, @@ -108,10 +131,24 @@ const static settings_template kTargetTemplate[] = { {0, NULL, NULL} }; +const static settings_template kRunConditionalTemplate[] = { + {B_STRING_TYPE, NULL, NULL, true, new RunConverter()}, + {0, NULL, NULL} +}; + +const static settings_template kRunTemplate[] = { + {B_STRING_TYPE, NULL, NULL, true, new RunConverter()}, + {B_MESSAGE_TYPE, "if", kConditionTemplate}, + {B_MESSAGE_TYPE, "then", kRunConditionalTemplate}, + {B_MESSAGE_TYPE, "else", kRunConditionalTemplate}, + {0, NULL, NULL} +}; + const static settings_template kSettingsTemplate[] = { {B_MESSAGE_TYPE, "target", kTargetTemplate}, {B_MESSAGE_TYPE, "job", kJobTemplate}, {B_MESSAGE_TYPE, "service", kJobTemplate}, + {B_MESSAGE_TYPE, "run", kRunTemplate}, {0, NULL, NULL} }; diff --git a/src/tests/servers/launch/SettingsParserTest.cpp b/src/tests/servers/launch/SettingsParserTest.cpp index f081fdcbf3..add04b9fdb 100644 --- a/src/tests/servers/launch/SettingsParserTest.cpp +++ b/src/tests/servers/launch/SettingsParserTest.cpp @@ -153,7 +153,8 @@ SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs() BString(args.GetString("args", 0, "-"))); CPPUNIT_ASSERT_EQUAL(BString("two"), BString(args.GetString("args", 1, "-"))); - CPPUNIT_ASSERT_EQUAL(2, args.CountNames(B_ANY_TYPE)); + CPPUNIT_ASSERT_EQUAL(1, args.CountNames(B_ANY_TYPE)); + CPPUNIT_ASSERT_EQUAL(2, _ArrayCount(args, "args")); } @@ -177,11 +178,122 @@ SettingsParserTest::TestConditionsMultiLineNot() } +void +SettingsParserTest::TestRunFlat() +{ + SettingsParser parser; + BMessage jobs; + CPPUNIT_ASSERT_EQUAL(B_OK, parser.Parse("run me", jobs)); + CPPUNIT_ASSERT_EQUAL(1, jobs.CountNames(B_ANY_TYPE)); + + BMessage message; + CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message)); + CPPUNIT_ASSERT_EQUAL(BString("me"), + BString(message.GetString("target", "-"))); + CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(message, "target")); + CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE)); +} + + +void +SettingsParserTest::TestRunMultiLine() +{ + SettingsParser parser; + BMessage jobs; + status_t status = parser.Parse("run {\n" + "\tme\n" + "\tyou\n" + "}\n", jobs); + CPPUNIT_ASSERT_EQUAL(B_OK, status); + CPPUNIT_ASSERT_EQUAL(1, jobs.CountNames(B_ANY_TYPE)); + + BMessage message; + CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message)); + CPPUNIT_ASSERT_EQUAL(BString("me"), + BString(message.GetString("target", 0, "-"))); + CPPUNIT_ASSERT_EQUAL(BString("you"), + BString(message.GetString("target", 1, "-"))); + CPPUNIT_ASSERT_EQUAL(2, _ArrayCount(message, "target")); + CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE)); +} + + +void +SettingsParserTest::TestRunIfThenElseFlat() +{ + SettingsParser parser; + BMessage jobs; + status_t status = parser.Parse("run {\n" + "\tif safemode\n" + "\tthen this\n" + "\telse that\n" + "}\n", jobs); + CPPUNIT_ASSERT_EQUAL(B_OK, status); + + BMessage message; + CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message)); + CPPUNIT_ASSERT_EQUAL(3, message.CountNames(B_ANY_TYPE)); + + BMessage then; + CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("then", &then)); + CPPUNIT_ASSERT_EQUAL(BString("this"), + BString(then.GetString("target", "-"))); + CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(then, "target")); + CPPUNIT_ASSERT_EQUAL(1, then.CountNames(B_ANY_TYPE)); + + BMessage otherwise; + CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("else", &otherwise)); + CPPUNIT_ASSERT_EQUAL(BString("that"), + BString(otherwise.GetString("target", "-"))); + CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(otherwise, "target")); + CPPUNIT_ASSERT_EQUAL(1, otherwise.CountNames(B_ANY_TYPE)); +} + + +void +SettingsParserTest::TestRunIfThenElseMultiLine() +{ + SettingsParser parser; + BMessage jobs; + status_t status = parser.Parse("run {\n" + "\tif {\n" + "\t\tread_only\n" + "\t}\n" + "\tthen {\n" + "\t\tthis\n" + "\t}\n" + "\telse {\n" + "\t\tthat\n" + "\t}\n" + "}\n", jobs); + CPPUNIT_ASSERT_EQUAL(B_OK, status); + + BMessage message; + CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message)); + CPPUNIT_ASSERT_EQUAL(3, message.CountNames(B_ANY_TYPE)); + + BMessage then; + CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("then", &then)); + CPPUNIT_ASSERT_EQUAL(BString("this"), + BString(then.GetString("target", "-"))); + CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(then, "target")); + CPPUNIT_ASSERT_EQUAL(1, then.CountNames(B_ANY_TYPE)); + + BMessage otherwise; + CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("else", &otherwise)); + CPPUNIT_ASSERT_EQUAL(BString("that"), + BString(otherwise.GetString("target", "-"))); + CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(otherwise, "target")); + CPPUNIT_ASSERT_EQUAL(1, otherwise.CountNames(B_ANY_TYPE)); +} + + /*static*/ void SettingsParserTest::AddTests(BTestSuite& parent) { CppUnit::TestSuite& suite = *new CppUnit::TestSuite("SettingsParserTest"); + // Conditions suite.addTest(new CppUnit::TestCaller( "SettingsParserTest::TestConditionsMultiLine", &SettingsParserTest::TestConditionsMultiLine)); @@ -207,6 +319,20 @@ SettingsParserTest::AddTests(BTestSuite& parent) "SettingsParserTest::TestConditionsMultiLineNot", &SettingsParserTest::TestConditionsMultiLineNot)); + // Run + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestRunFlat", + &SettingsParserTest::TestRunFlat)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestRunMultiLine", + &SettingsParserTest::TestRunMultiLine)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestRunIfThenElseFlat", + &SettingsParserTest::TestRunIfThenElseFlat)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestRunIfThenElseMultiLine", + &SettingsParserTest::TestRunIfThenElseMultiLine)); + parent.addTest("SettingsParserTest", &suite); } @@ -233,3 +359,14 @@ SettingsParserTest::_ParseCondition(const char* text, BMessage& message) return job.FindMessage("if", &message); } + + +int32 +SettingsParserTest::_ArrayCount(BMessage& message, const char* name) +{ + int32 found; + if (message.GetInfo(name, NULL, &found, NULL) != B_OK) + return 0; + + return found; +} diff --git a/src/tests/servers/launch/SettingsParserTest.h b/src/tests/servers/launch/SettingsParserTest.h index bd99269c23..d9ffa391d4 100644 --- a/src/tests/servers/launch/SettingsParserTest.h +++ b/src/tests/servers/launch/SettingsParserTest.h @@ -26,11 +26,18 @@ public: void TestConditionsMultiLineFlatNotWithArgs(); void TestConditionsMultiLineNot(); + void TestRunFlat(); + void TestRunMultiLine(); + void TestRunIfThenElseFlat(); + void TestRunIfThenElseMultiLine(); + static void AddTests(BTestSuite& suite); private: status_t _ParseCondition(const char* text, BMessage& message); + int32 _ArrayCount(BMessage& message, + const char* name); };