diff --git a/src/servers/launch/Conditions.cpp b/src/servers/launch/Conditions.cpp index d577a25483..9e51664046 100644 --- a/src/servers/launch/Conditions.cpp +++ b/src/servers/launch/Conditions.cpp @@ -13,9 +13,7 @@ #include #include -#include -#include -#include +#include "Utility.h" class ConditionContainer : public Condition { @@ -86,7 +84,9 @@ public: virtual BString ToString() const; private: - dev_t fDevice; + BString fPath; + mutable bool fIsReadOnly; + mutable bool fTestPerformed; }; @@ -365,33 +365,28 @@ SafeModeCondition::ToString() const ReadOnlyCondition::ReadOnlyCondition(const BMessage& args) + : + fPath(args.GetString("args")), + fIsReadOnly(false), + fTestPerformed(false) { - fDevice = dev_for_path(args.GetString("args", "/boot")); } bool ReadOnlyCondition::Test(ConditionContext& context) const { - BVolume volume; - status_t status = volume.SetTo(fDevice); - if (status != B_OK) { - fprintf(stderr, "Failed to get BVolume for device %" B_PRIdDEV - ": %s\n", fDevice, strerror(status)); - return false; - } + if (fTestPerformed) + return fIsReadOnly; - BDiskDeviceRoster roster; - BDiskDevice diskDevice; - BPartition* partition; - status = roster.FindPartitionByVolume(volume, &diskDevice, &partition); - if (status != B_OK) { - fprintf(stderr, "Failed to get partition for device %" B_PRIdDEV - ": %s\n", fDevice, strerror(status)); - return false; - } + if (fPath.IsEmpty() || fPath == "/boot") + fIsReadOnly = context.BootVolumeIsReadOnly(); + else + fIsReadOnly = Utility::IsReadOnlyVolume(fPath); - return partition->IsReadOnly(); + fTestPerformed = true; + + return fIsReadOnly; } @@ -406,7 +401,7 @@ BString ReadOnlyCondition::ToString() const { BString string = "readonly "; - string << fDevice; + string << fPath; return string; } diff --git a/src/servers/launch/Conditions.h b/src/servers/launch/Conditions.h index 2414accb4b..485254424e 100644 --- a/src/servers/launch/Conditions.h +++ b/src/servers/launch/Conditions.h @@ -15,6 +15,7 @@ class BMessage; class ConditionContext { public: virtual bool IsSafeMode() const = 0; + virtual bool BootVolumeIsReadOnly() const = 0; }; diff --git a/src/servers/launch/Jamfile b/src/servers/launch/Jamfile index 09d2ec7901..fe663a04cf 100644 --- a/src/servers/launch/Jamfile +++ b/src/servers/launch/Jamfile @@ -14,6 +14,7 @@ Server launch_daemon Job.cpp SettingsParser.cpp Target.cpp + Utility.cpp Worker.cpp # init jobs diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 6143b2820a..9d56171b59 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -37,6 +37,7 @@ #include "Job.h" #include "SettingsParser.h" #include "Target.h" +#include "Utility.h" #include "Worker.h" @@ -78,6 +79,7 @@ public: Session* FindSession(uid_t user) const; virtual bool IsSafeMode() const; + virtual bool BootVolumeIsReadOnly() const; virtual void ReadyToRun(); virtual void MessageReceived(BMessage* message); @@ -123,6 +125,7 @@ private: MainWorker* fMainWorker; Target* fInitTarget; bool fSafeMode; + bool fReadOnlyBootVolume; bool fUserMode; }; @@ -221,11 +224,23 @@ LaunchDaemon::IsSafeMode() const } +bool +LaunchDaemon::BootVolumeIsReadOnly() const +{ + return fReadOnlyBootVolume; +} + + void LaunchDaemon::ReadyToRun() { _RetrieveKernelOptions(); _SetupEnvironment(); + + fReadOnlyBootVolume = Utility::IsReadOnlyVolume("/boot"); + if (fReadOnlyBootVolume) + Utility::BlockMedia("/boot", true); + if (fUserMode) { BLaunchRoster roster; BLaunchRoster::Private(roster).RegisterSessionDaemon(this); diff --git a/src/servers/launch/Utility.cpp b/src/servers/launch/Utility.cpp new file mode 100644 index 0000000000..7d1c727b71 --- /dev/null +++ b/src/servers/launch/Utility.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Utility.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace Utility { + + +bool +IsReadOnlyVolume(dev_t device) +{ + BVolume volume; + status_t status = volume.SetTo(device); + if (status != B_OK) { + fprintf(stderr, "Failed to get BVolume for device %" B_PRIdDEV + ": %s\n", device, strerror(status)); + return false; + } + + BDiskDeviceRoster roster; + BDiskDevice diskDevice; + BPartition* partition; + status = roster.FindPartitionByVolume(volume, &diskDevice, &partition); + if (status != B_OK) { + fprintf(stderr, "Failed to get partition for device %" B_PRIdDEV + ": %s\n", device, strerror(status)); + return false; + } + + return partition->IsReadOnly(); +} + + +bool +IsReadOnlyVolume(const char* path) +{ + return IsReadOnlyVolume(dev_for_path(path)); +} + + +status_t +BlockMedia(const char* path, bool block) +{ + fs_info info; + if (fs_stat_dev(dev_for_path(path), &info) == B_OK) { + if (strcmp(info.fsh_name, "devfs") != 0) + path = info.device_name; + } + + int device = open(path, O_RDONLY); + if (device < 0) + return device; + + status_t status = B_OK; + + if (ioctl(device, B_SCSI_PREVENT_ALLOW, &block, sizeof(block)) != 0) { + fprintf(stderr, "Failed to block media on %s: %s\n", path, + strerror(errno)); + status = errno; + } + close(device); + return status; +} + + +} // namespace Utility diff --git a/src/servers/launch/Utility.h b/src/servers/launch/Utility.h new file mode 100644 index 0000000000..183b21502c --- /dev/null +++ b/src/servers/launch/Utility.h @@ -0,0 +1,20 @@ +/* + * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UTILITY_H +#define UTILITY_H + + +#include + + +namespace Utility { + bool IsReadOnlyVolume(dev_t device); + bool IsReadOnlyVolume(const char* path); + + status_t BlockMedia(const char* path, bool block); +} + + +#endif // UTILITY_H