added 2 changesets to branch 'refs/remotes/HaikuPM-github/package-management' old head: 91586bd3b651574c9f0d3010567d4bcc40f4c092 new head: 26296b0aa4ddcc1b8baf1e6c380d0f8634730068 overview: https://github.com/haiku/HaikuPM/compare/91586bd...26296b0 ---------------------------------------------------------------------------- 0c6927b: packagefs: Add ioctl to get basic volume information Also rename the MountType enum and members, since they are no longer packagefs private. 26296b0: Add the humble beginnings of the package daemon It doesn't really do anything yet save for tracking what packagefs volumes are mounted and unmounted. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 20 files changed, 1158 insertions(+), 31 deletions(-) build/jam/HaikuImage | 3 +- data/system/boot/Bootscript | 2 + headers/private/package/packagefs.h | 38 +++ .../kernel/file_systems/packagefs/Jamfile | 2 +- .../file_systems/packagefs/PackageFSRoot.cpp | 12 +- .../packagefs/PackageLinkSymlink.cpp | 8 +- .../kernel/file_systems/packagefs/Volume.cpp | 48 +++- .../kernel/file_systems/packagefs/Volume.h | 12 +- .../file_systems/packagefs/kernel_interface.cpp | 18 +- src/servers/Jamfile | 1 + src/servers/package/DebugSupport.cpp | 150 +++++++++++ src/servers/package/DebugSupport.h | 184 +++++++++++++ src/servers/package/Jamfile | 17 ++ src/servers/package/PackageDaemon.cpp | 267 +++++++++++++++++++ src/servers/package/PackageDaemon.h | 57 ++++ src/servers/package/Root.cpp | 145 ++++++++++ src/servers/package/Root.h | 56 ++++ src/servers/package/Volume.cpp | 99 +++++++ src/servers/package/Volume.h | 55 ++++ src/servers/package/package_daemon.rdef | 15 ++ ############################################################################ Commit: 0c6927b5d7c8f73abd7663168f5f437b39661c6c Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sat Apr 6 02:26:40 2013 UTC packagefs: Add ioctl to get basic volume information Also rename the MountType enum and members, since they are no longer packagefs private. ---------------------------------------------------------------------------- diff --git a/headers/private/package/packagefs.h b/headers/private/package/packagefs.h new file mode 100644 index 0000000..790ac3a --- /dev/null +++ b/headers/private/package/packagefs.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ +#ifndef _PACKAGE__PRIVATE__PACKAGE_FS_H_ +#define _PACKAGE__PRIVATE__PACKAGE_FS_H_ + + +#include <Drivers.h> + + +enum PackageFSMountType { + PACKAGE_FS_MOUNT_TYPE_SYSTEM, + PACKAGE_FS_MOUNT_TYPE_COMMON, + PACKAGE_FS_MOUNT_TYPE_HOME, + PACKAGE_FS_MOUNT_TYPE_CUSTOM +}; + + +enum { + PACKAGE_FS_OPERATION_GET_VOLUME_INFO = B_DEVICE_OP_CODES_END + 1 +}; + + +struct PackageFSVolumeInfo { + PackageFSMountType mountType; + + // device and node id of the respective package FS root scope (e.g. "/boot" + // for the three standard volumes) + dev_t rootDeviceID; + ino_t rootDirectoryID; +}; + + +#endif // _PACKAGE__PRIVATE__PACKAGE_FS_H_ diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index d0576a0..9396497 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems packagefs ; UseLibraryHeaders zlib ; UsePrivateKernelHeaders ; -UsePrivateHeaders shared storage ; +UsePrivateHeaders package shared storage ; HAIKU_PACKAGE_FS_SOURCES = diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index a520416..74ee53b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -96,14 +96,14 @@ PackageFSRoot::RegisterVolume(Volume* volume) const char* relativeRootPath = NULL; switch (volume->MountType()) { - case MOUNT_TYPE_SYSTEM: - case MOUNT_TYPE_COMMON: + case PACKAGE_FS_MOUNT_TYPE_SYSTEM: + case PACKAGE_FS_MOUNT_TYPE_COMMON: relativeRootPath = ".."; break; - case MOUNT_TYPE_HOME: + case PACKAGE_FS_MOUNT_TYPE_HOME: relativeRootPath = "../.."; break; - case MOUNT_TYPE_CUSTOM: + case PACKAGE_FS_MOUNT_TYPE_CUSTOM: default: break; } @@ -217,8 +217,10 @@ PackageFSRoot::_AddVolume(Volume* volume) fVolumes.Add(volume); // TODO: Correct order? - if (fSystemVolume == NULL && volume->MountType() == MOUNT_TYPE_SYSTEM) + if (fSystemVolume == NULL && volume->MountType() + == PACKAGE_FS_MOUNT_TYPE_SYSTEM) { fSystemVolume = volume; + } return B_OK; } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp index ca3e83e..ed674e2 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp @@ -28,13 +28,13 @@ static const char* link_path_for_mount_type(MountType type) { switch (type) { - case MOUNT_TYPE_SYSTEM: + case PACKAGE_FS_MOUNT_TYPE_SYSTEM: return kSystemLinkPath; - case MOUNT_TYPE_COMMON: + case PACKAGE_FS_MOUNT_TYPE_COMMON: return kCommonLinkPath; - case MOUNT_TYPE_HOME: + case PACKAGE_FS_MOUNT_TYPE_HOME: return kHomeLinkPath; - case MOUNT_TYPE_CUSTOM: + case PACKAGE_FS_MOUNT_TYPE_CUSTOM: default: return "?"; } diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 1a4f1bc..6d89b4e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -648,16 +648,16 @@ Volume::Mount(const char* parameterString) // If no volume name is given, infer it from the mount type. if (volumeName == NULL) { switch (fMountType) { - case MOUNT_TYPE_SYSTEM: + case PACKAGE_FS_MOUNT_TYPE_SYSTEM: volumeName = "system"; break; - case MOUNT_TYPE_COMMON: + case PACKAGE_FS_MOUNT_TYPE_COMMON: volumeName = "common"; break; - case MOUNT_TYPE_HOME: + case PACKAGE_FS_MOUNT_TYPE_HOME: volumeName = "home"; break; - case MOUNT_TYPE_CUSTOM: + case PACKAGE_FS_MOUNT_TYPE_CUSTOM: default: volumeName = "Package FS"; break; @@ -728,6 +728,28 @@ Volume::Unmount() } +status_t +Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size) +{ + switch (operation) { + case PACKAGE_FS_OPERATION_GET_VOLUME_INFO: + { + if (size != sizeof(PackageFSVolumeInfo)) + return B_BAD_VALUE; + + PackageFSVolumeInfo info; + info.mountType = fMountType; + info.rootDeviceID = fPackageFSRoot->DeviceID(); + info.rootDirectoryID = fPackageFSRoot->NodeID(); + return user_memcpy(buffer, &info, sizeof(info)); + } + + default: + return B_BAD_VALUE; + } +} + + void Volume::AddNodeListener(NodeListener* listener, Node* node) { @@ -1664,15 +1686,15 @@ status_t Volume::_InitMountType(const char* mountType) { if (mountType == NULL) - fMountType = MOUNT_TYPE_CUSTOM; + fMountType = PACKAGE_FS_MOUNT_TYPE_CUSTOM; else if (strcmp(mountType, "system") == 0) - fMountType = MOUNT_TYPE_SYSTEM; + fMountType = PACKAGE_FS_MOUNT_TYPE_SYSTEM; else if (strcmp(mountType, "common") == 0) - fMountType = MOUNT_TYPE_COMMON; + fMountType = PACKAGE_FS_MOUNT_TYPE_COMMON; else if (strcmp(mountType, "home") == 0) - fMountType = MOUNT_TYPE_HOME; + fMountType = PACKAGE_FS_MOUNT_TYPE_HOME; else if (strcmp(mountType, "custom") == 0) - fMountType = MOUNT_TYPE_CUSTOM; + fMountType = PACKAGE_FS_MOUNT_TYPE_CUSTOM; else RETURN_ERROR(B_BAD_VALUE); @@ -1714,16 +1736,16 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) if (shineThroughSetting == NULL) { // nothing specified -- derive from mount type switch (fMountType) { - case MOUNT_TYPE_SYSTEM: + case PACKAGE_FS_MOUNT_TYPE_SYSTEM: directories = kSystemShineThroughDirectories; break; - case MOUNT_TYPE_COMMON: + case PACKAGE_FS_MOUNT_TYPE_COMMON: directories = kCommonShineThroughDirectories; break; - case MOUNT_TYPE_HOME: + case PACKAGE_FS_MOUNT_TYPE_HOME: directories = kHomeShineThroughDirectories; break; - case MOUNT_TYPE_CUSTOM: + case PACKAGE_FS_MOUNT_TYPE_CUSTOM: return B_OK; } } else if (strcmp(shineThroughSetting, "system") == 0) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index d235618..38a6097 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -14,6 +14,8 @@ #include <util/DoublyLinkedList.h> #include <util/KMessage.h> +#include <packagefs.h> + #include "Index.h" #include "Node.h" #include "NodeListener.h" @@ -29,12 +31,7 @@ class UnpackingNode; typedef IndexHashTable::Iterator IndexDirIterator; -enum MountType { - MOUNT_TYPE_SYSTEM, - MOUNT_TYPE_COMMON, - MOUNT_TYPE_HOME, - MOUNT_TYPE_CUSTOM -}; +typedef PackageFSMountType MountType; class Volume : public DoublyLinkedListLinkImpl<Volume>, @@ -70,6 +67,9 @@ public: Node* FindNode(ino_t nodeID) const { return fNodes.Lookup(nodeID); } + status_t IOCtl(Node* node, uint32 operation, + void* buffer, size_t size); + // node listeners -- volume must be write-locked void AddNodeListener(NodeListener* listener, Node* node); diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 35f5a24..2e330d0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -284,6 +284,22 @@ packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, // #pragma mark - Nodes +status_t +packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, + uint32 operation, void* buffer, size_t size) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, operation: %" B_PRI32u + ", buffer: %p, size: %zu\n", volume, node, node->ID(), cookie, + operation, buffer, size); + TOUCH(cookie); + + return volume->IOCtl(node, operation, buffer, size); +} + + static status_t packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, size_t* _bufferSize) @@ -1179,7 +1195,7 @@ fs_vnode_ops gPackageFSVnodeOps = { NULL, // get_file_map, - NULL, // ioctl, + &packagefs_ioctl, NULL, // set_flags, NULL, // select, NULL, // deselect, ############################################################################ Commit: 26296b0aa4ddcc1b8baf1e6c380d0f8634730068 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sat Apr 6 02:29:34 2013 UTC Add the humble beginnings of the package daemon It doesn't really do anything yet save for tracking what packagefs volumes are mounted and unmounted. ---------------------------------------------------------------------------- diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 835c1a7..799cc0c 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -106,7 +106,8 @@ PRIVATE_SYSTEM_LIBS = ; SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon media_addon_server media_server midi_server mount_server net_server - notification_server power_daemon print_server print_addon_server registrar syslog_daemon + notification_server package_daemon power_daemon print_server + print_addon_server registrar syslog_daemon ; SYSTEM_NETWORK_DEVICES = ethernet loopback ; diff --git a/data/system/boot/Bootscript b/data/system/boot/Bootscript index 8dc3db3..3e4b1f1 100644 --- a/data/system/boot/Bootscript +++ b/data/system/boot/Bootscript @@ -98,6 +98,8 @@ launch $SERVERS/registrar _roster_thread_ # launch registrar launch $SERVERS/debug_server # launch debug_server +launch $SERVERS/package_daemon + # Init Network if [ "$SAFEMODE" != "yes" ]; then launch $SERVERS/net_server # launch net_server diff --git a/src/servers/Jamfile b/src/servers/Jamfile index 141a8ad..e906f7f 100644 --- a/src/servers/Jamfile +++ b/src/servers/Jamfile @@ -13,6 +13,7 @@ SubInclude HAIKU_TOP src servers midi ; SubInclude HAIKU_TOP src servers mount ; SubInclude HAIKU_TOP src servers net ; SubInclude HAIKU_TOP src servers notification ; +SubInclude HAIKU_TOP src servers package ; SubInclude HAIKU_TOP src servers power ; SubInclude HAIKU_TOP src servers print ; SubInclude HAIKU_TOP src servers print_addon ; diff --git a/src/servers/package/DebugSupport.cpp b/src/servers/package/DebugSupport.cpp new file mode 100644 index 0000000..8377cf3 --- /dev/null +++ b/src/servers/package/DebugSupport.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include "DebugSupport.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <OS.h> + + +/*! + \file Debug.cpp + \brief Defines debug output function with printf() signature printing + into a file. + + \note The initialization is not thread safe! +*/ + + +// locking support +static int32 init_counter = 0; +static sem_id dbg_printf_sem = -1; +static thread_id dbg_printf_thread = -1; +static int dbg_printf_nesting = 0; + + +#if DEBUG_PRINT +static int out = -1; +#endif + + +status_t +init_debugging() +{ + status_t error = B_OK; + if (init_counter++ == 0) { + // open the file + #if DEBUG_PRINT + out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC); + if (out < 0) { + error = errno; + init_counter--; + } + #endif // DEBUG_PRINT + // allocate the semaphore + if (error == B_OK) { + dbg_printf_sem = create_sem(1, "dbg_printf"); + if (dbg_printf_sem < 0) + error = dbg_printf_sem; + } + if (error == B_OK) { + #if DEBUG + __out("##################################################\n"); + #endif + } else + exit_debugging(); + } + return error; +} + + +status_t +exit_debugging() +{ + status_t error = B_OK; + if (--init_counter == 0) { + #if DEBUG_PRINT + close(out); + out = -1; + #endif // DEBUG_PRINT + delete_sem(dbg_printf_sem); + } else + error = B_NO_INIT; + return error; +} + + +static inline bool +dbg_printf_lock() +{ + thread_id thread = find_thread(NULL); + if (thread != dbg_printf_thread) { + if (acquire_sem(dbg_printf_sem) != B_OK) + return false; + dbg_printf_thread = thread; + } + dbg_printf_nesting++; + return true; +} + + +static inline void +dbg_printf_unlock() +{ + thread_id thread = find_thread(NULL); + if (thread != dbg_printf_thread) + return; + dbg_printf_nesting--; + if (dbg_printf_nesting == 0) { + dbg_printf_thread = -1; + release_sem(dbg_printf_sem); + } +} + + +void +dbg_printf_begin() +{ + dbg_printf_lock(); +} + + +void +dbg_printf_end() +{ + dbg_printf_unlock(); +} + + +#if DEBUG_PRINT + +void +dbg_printf(const char *format,...) +{ + if (!dbg_printf_lock()) + return; + char buffer[1024]; + va_list args; + va_start(args, format); + // no vsnprintf() on PPC and in kernel + #if defined(__INTEL__) && USER + vsnprintf(buffer, sizeof(buffer) - 1, format, args); + #else + vsprintf(buffer, format, args); + #endif + va_end(args); + buffer[sizeof(buffer) - 1] = '\0'; + write(out, buffer, strlen(buffer)); + dbg_printf_unlock(); +} + +#endif // DEBUG_PRINT diff --git a/src/servers/package/DebugSupport.h b/src/servers/package/DebugSupport.h new file mode 100644 index 0000000..25592d4 --- /dev/null +++ b/src/servers/package/DebugSupport.h @@ -0,0 +1,184 @@ +/* + * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Copyright 200?, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ +#ifndef DEBUG_SUPPORT_H +#define DEBUG_SUPPORT_H + + +#include <string.h> + + +// define all macros we work with -- undefined macros are set to defaults +#ifndef USER +# ifdef _KERNEL_MODE +# define USER 0 +# else +# define USER 1 +# endif +#endif +#ifndef DEBUG +# define DEBUG 0 +#endif +#if !DEBUG +# undef DEBUG_PRINT +# define DEBUG_PRINT 0 +#endif +#ifndef DEBUG_PRINT +# define DEBUG_PRINT 0 +#endif +#ifndef DEBUG_APP +# define DEBUG_APP "package_daemon" +#endif +#ifndef DEBUG_PRINT_FILE +# define DEBUG_PRINT_FILE "/var/log/" DEBUG_APP ".log" +#endif + + +#if !USER +# include <KernelExport.h> +#endif +#include <OS.h> +#include <SupportDefs.h> + + +// define the debug output function +#if USER +# include <stdio.h> +# if DEBUG_PRINT +# define __out dbg_printf +# else +# define __out debug_printf +# endif +#else +# include <KernelExport.h> +# include <null.h> +# if DEBUG_PRINT +# define __out dbg_printf +# else +# define __out dprintf +# endif +#endif + + +// define the PANIC() macro +#ifndef PANIC +# if USER +# define PANIC(str) debugger(str) +# else +# define PANIC(str) panic(str) +# endif +#endif + + +// functions exported by this module +status_t init_debugging(); +status_t exit_debugging(); +void dbg_printf_begin(); +void dbg_printf_end(); +#if DEBUG_PRINT + void dbg_printf(const char *format,...); +#else + static inline void dbg_printf(const char *,...) {} +#endif + + +// Short overview over the debug output macros: +// PRINT() +// is for general messages that very unlikely should appear in a release +// build +// FATAL() +// this is for fatal messages, when something has really gone wrong +// INFORM() +// general information, as disk size, etc. +// REPORT_ERROR(status_t) +// prints out error information +// RETURN_ERROR(status_t) +// calls REPORT_ERROR() and return the value +// D() +// the statements in D() are only included if DEBUG is defined + + +#define DEBUG_THREAD find_thread(NULL) +#define DEBUG_CONTEXT(x) \ +{ \ + dbg_printf_begin(); \ + __out(DEBUG_APP " [%Ld: %5ld] ", system_time(), DEBUG_THREAD); \ + x; \ + dbg_printf_end(); \ +} +#define DEBUG_CONTEXT_FUNCTION(prefix, x) \ +{ \ + dbg_printf_begin(); \ + __out(DEBUG_APP " [%Ld: %5ld] %s" prefix, system_time(), DEBUG_THREAD, \ + __PRETTY_FUNCTION__); \ + x; \ + dbg_printf_end(); \ +} +#define DEBUG_CONTEXT_LINE(x) \ +{ \ + dbg_printf_begin(); \ + __out(DEBUG_APP " [%Ld: %5ld] %s:%d: ", system_time(), DEBUG_THREAD, \ + __PRETTY_FUNCTION__, __LINE__); \ + x; \ + dbg_printf_end(); \ +} + +#define TPRINT(x...) DEBUG_CONTEXT( __out(x) ) +#define TREPORT_ERROR(status) \ + DEBUG_CONTEXT_LINE( __out("%s\n", strerror(status)) ) +#define TRETURN_ERROR(err) \ +{ \ + status_t _status = err; \ + if (_status < B_OK) \ + TREPORT_ERROR(_status); \ + return _status; \ +} +#define TSET_ERROR(var, err) \ +{ \ + status_t _status = err; \ + if (_status < B_OK) \ + TREPORT_ERROR(_status); \ + var = _status; \ +} +#define TFUNCTION(x...) DEBUG_CONTEXT_FUNCTION( ": ", __out(x) ) +#define TFUNCTION_START() DEBUG_CONTEXT_FUNCTION( "\n", ) +#define TFUNCTION_END() DEBUG_CONTEXT_FUNCTION( " done\n", ) + +#if DEBUG + #define PRINT(x...) TPRINT(x) + #define REPORT_ERROR(status) TREPORT_ERROR(status) + #define RETURN_ERROR(err) TRETURN_ERROR(err) + #define SET_ERROR(var, err) TSET_ERROR(var, err) + #define FATAL(x...) DEBUG_CONTEXT( __out(x) ) + #define ERROR(x...) DEBUG_CONTEXT( __out(x) ) + #define WARN(x...) DEBUG_CONTEXT( __out(x) ) + #define INFORM(x...) DEBUG_CONTEXT( __out(x) ) + #define FUNCTION(x...) TFUNCTION(x) + #define FUNCTION_START() TFUNCTION_START() + #define FUNCTION_END() TFUNCTION_END() + #define DARG(x) x + #define D(x) {x;}; +#else + #define PRINT(x...) ; + #define REPORT_ERROR(status) ; + #define RETURN_ERROR(status) return status; + #define SET_ERROR(var, err) var = err; + #define FATAL(x...) DEBUG_CONTEXT( __out(x) ) + #define ERROR(x...) DEBUG_CONTEXT( __out(x) ) + #define WARN(x...) DEBUG_CONTEXT( __out(x) ) + #define INFORM(x...) DEBUG_CONTEXT( __out(x) ) + #define FUNCTION(x...) ; + #define FUNCTION_START() ; + #define FUNCTION_END() ; + #define DARG(x) + #define D(x) ; +#endif + +#ifndef TOUCH +#define TOUCH(var) (void)var +#endif + + +#endif // DEBUG_SUPPORT_H diff --git a/src/servers/package/Jamfile b/src/servers/package/Jamfile new file mode 100644 index 0000000..099f966 --- /dev/null +++ b/src/servers/package/Jamfile @@ -0,0 +1,17 @@ +SubDir HAIKU_TOP src servers package ; + +UsePrivateSystemHeaders ; +UsePrivateHeaders app package shared ; + +Server package_daemon + : + DebugSupport.cpp + PackageDaemon.cpp + Root.cpp + Volume.cpp + : + be package + $(TARGET_LIBSTDC++) + : + package_daemon.rdef +; diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp new file mode 100644 index 0000000..0942049 --- /dev/null +++ b/src/servers/package/PackageDaemon.cpp @@ -0,0 +1,267 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ + + +#include "PackageDaemon.h" + +#include <errno.h> +#include <string.h> + +#include <Directory.h> +#include <NodeMonitor.h> + +#include <AutoDeleter.h> + +#include "DebugSupport.h" +#include "Root.h" +#include "Volume.h" + + +PackageDaemon::PackageDaemon(status_t* _error) + : + BServer("application/x-vnd.haiku-package_daemon", false, _error), + fSystemRoot(NULL), + fRoots(10, true), + fVolumeWatcher() +{ +} + + +PackageDaemon::~PackageDaemon() +{ +// delete fSystemRoot; +} + + +status_t +PackageDaemon::Init() +{ + status_t error = fVolumeWatcher.StartWatching(BMessenger(this, this)); + if (error != B_OK) { + ERROR("PackageDaemon::Init(): failed to start volume watching: %s\n", + strerror(error)); + } + + // register all packagefs volumes + for (int32 cookie = 0;;) { + dev_t device = next_dev(&cookie); + if (device < 0) + break; + + _RegisterVolume(device); + } + + return B_OK; +} + + +void +PackageDaemon::MessageReceived(BMessage* message) +{ + switch (message->what) { + case B_NODE_MONITOR: + { + int32 opcode; + if (message->FindInt32("opcode", &opcode) != B_OK) + break; + if (opcode == B_DEVICE_MOUNTED) + _HandleVolumeMounted(message); + else if (opcode == B_DEVICE_UNMOUNTED) + _HandleVolumeUnmounted(message); + break; + } + default: + BServer::MessageReceived(message); + break; + } +} + + +status_t +PackageDaemon::_RegisterVolume(dev_t deviceID) +{ + // get the FS info and check whether this is a package FS volume at all + fs_info info; + status_t error = fs_stat_dev(deviceID, &info); + if (error != 0) + RETURN_ERROR(error); + + if (strcmp(info.fsh_name, "packagefs") != 0) + RETURN_ERROR(B_BAD_VALUE); + + // open the root directory of the volume + node_ref nodeRef; + nodeRef.device = info.dev; + nodeRef.node = info.root; + BDirectory directory; + error = directory.SetTo(&nodeRef); + if (error != B_OK) { + ERROR("PackageDaemon::_RegisterVolume(): failed to open root: %s\n", + strerror(error)); + return error; + } + + // create a volume + Volume* volume = new(std::nothrow) Volume; + if (volume == NULL) + RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter<Volume> volumeDeleter(volume); + + dev_t rootDeviceID; + ino_t rootNodeID; + error = volume->Init(directory, rootDeviceID, rootNodeID); + if (error != B_OK) + RETURN_ERROR(error); + + if (volume->MountType() == PACKAGE_FS_MOUNT_TYPE_CUSTOM) { +// TODO: Or maybe not? + INFORM("skipping custom mounted volume at \"%s\"\n", + volume->Path().String()); + return B_OK; + } + + // get the root for the volume and register it + Root* root; + error = _GetOrCreateRoot(rootDeviceID, rootNodeID, root); + if (error != B_OK) + RETURN_ERROR(error); + + error = root->RegisterVolume(volume); + if (error != B_OK) { + _PutRoot(root); + RETURN_ERROR(error); + } + volumeDeleter.Detach(); + + INFORM("volume at \"%s\" registered\n", volume->Path().String()); + + return B_OK; +} + + +void +PackageDaemon::_UnregisterVolume(Volume* volume) +{ + Root* root = volume->GetRoot(); + root->UnregisterVolume(volume); + + INFORM("volume at \"%s\" unregistered\n", volume->Path().String()); + + delete volume; + _PutRoot(root); +} + + +status_t +PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root) +{ + Root* root = _FindRoot(deviceID, nodeID); + if (root != NULL) { + root->AcquireReference(); + } else { + root = new(std::nothrow) Root; + if (root == NULL) + RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter<Root> rootDeleter(root); + + status_t error = root->Init(deviceID, nodeID); + if (error != B_OK) + RETURN_ERROR(error); + + if (!fRoots.AddItem(root)) + RETURN_ERROR(B_NO_MEMORY); + + rootDeleter.Detach(); + + INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") " + "registered\n", root->Path().String(), deviceID, nodeID); + } + + _root = root; + return B_OK; +} + + +Root* +PackageDaemon::_FindRoot(dev_t deviceID, ino_t nodeID) const +{ + for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) { + if (root->DeviceID() == deviceID && root->NodeID() == nodeID) + return root; + } + + return NULL; +} + + +void +PackageDaemon::_PutRoot(Root* root) +{ + if (root->ReleaseReference() == 1) { + INFORM("root at \"%s\" unregistered\n", root->Path().String()); + fRoots.RemoveItem(root, true); + // deletes the object + } +} + + +Volume* +PackageDaemon::_FindVolume(dev_t deviceID) const +{ + for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) { + if (Volume* volume = root->FindVolume(deviceID)) + return volume; + } + + return NULL; +} + + +void +PackageDaemon::_HandleVolumeMounted(const BMessage* message) +{ + int32 device; + if (message->FindInt32("new device", &device) != B_OK) + return; + + // _RegisterVolume() also checks whether it is a package FS volume, so we + // don't need to bother. + _RegisterVolume(device); +} + + +void +PackageDaemon::_HandleVolumeUnmounted(const BMessage* message) +{ + int32 device; + if (message->FindInt32("device", &device) != B_OK) + return; + + if (Volume* volume = _FindVolume(device)) + _UnregisterVolume(volume); +} + + +// #pragma mark - + + +int +main(int argc, const char* const* argv) +{ + status_t error; + PackageDaemon daemon(&error); + if (error == B_OK) + error = daemon.Init(); + if (error != B_OK) { + FATAL("failed to init server application: %s\n", strerror(error)); + return 1; + } + + daemon.Run(); + return 0; +} diff --git a/src/servers/package/PackageDaemon.h b/src/servers/package/PackageDaemon.h new file mode 100644 index 0000000..86c6f4c --- /dev/null +++ b/src/servers/package/PackageDaemon.h @@ -0,0 +1,57 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ +#ifndef PACKAGE_DAEMON_H +#define PACKAGE_DAEMON_H + + +#include <fs_info.h> +#include <ObjectList.h> +#include <VolumeRoster.h> + +#include <Server.h> + + +class Root; +class Volume; + + +class PackageDaemon : public BServer { +public: + PackageDaemon(status_t* _error); + virtual ~PackageDaemon(); + + status_t Init(); + + virtual void MessageReceived(BMessage* message); + +private: + typedef BObjectList<Root> RootList; + +private: + status_t _RegisterVolume(dev_t device); + void _UnregisterVolume(Volume* volume); + + status_t _GetOrCreateRoot(dev_t deviceID, ino_t nodeID, + Root*& _root); + Root* _FindRoot(dev_t deviceID, ino_t nodeID) const; + void _PutRoot(Root* root); + + Volume* _FindVolume(dev_t deviceID) const; + + void _HandleVolumeMounted(const BMessage* message); + void _HandleVolumeUnmounted(const BMessage* message); + +private: + Root* fSystemRoot; + RootList fRoots; + BVolumeRoster fVolumeWatcher; +}; + + + +#endif // PACKAGE_DAEMON_H diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp new file mode 100644 index 0000000..bf7fec9 --- /dev/null +++ b/src/servers/package/Root.cpp @@ -0,0 +1,145 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ + + +#include "Root.h" + +#include <Directory.h> +#include <Entry.h> +#include <Path.h> + +#include "DebugSupport.h" +#include "Volume.h" + + +Root::Root() + : + fDeviceID(-1), + fNodeID(-1), + fPath(), + fSystemVolume(NULL), + fCommonVolume(NULL), + fHomeVolume(NULL) +{ +} + + +Root::~Root() +{ +} + + +status_t +Root::Init(dev_t deviceID, ino_t nodeID) +{ + fDeviceID = deviceID; + fNodeID = nodeID; + + // get the path + node_ref nodeRef; + nodeRef.device = fDeviceID; + nodeRef.node = fNodeID; + BDirectory directory; + status_t error = directory.SetTo(&nodeRef); + if (error != B_OK) { + ERROR("Root::Init(): failed to open directory: %s\n", strerror(error)); + return error; + } + + BEntry entry; + error = directory.GetEntry(&entry); + + BPath path; + if (error == B_OK) + error = entry.GetPath(&path); + + if (error != B_OK) { + ERROR("Root::Init(): failed to get directory path: %s\n", + strerror(error)); + RETURN_ERROR(error); + } + + fPath = path.Path(); + if (fPath.IsEmpty()) + RETURN_ERROR(B_NO_MEMORY); + + return B_OK; +} + + +status_t +Root::RegisterVolume(Volume* volume) +{ + Volume** volumeToSet = _GetVolume(volume->MountType()); + if (volumeToSet == NULL) + return B_BAD_VALUE; + + if (*volumeToSet != NULL) { + ERROR("Root::RegisterVolume(): can't register volume at \"%s\", since " + "there's already volume at \"%s\" with the same type.\n", + volume->Path().String(), (*volumeToSet)->Path().String()); + return B_BAD_VALUE; + } + + *volumeToSet = volume; + volume->SetRoot(this); + + return B_OK; +} + + +void +Root::UnregisterVolume(Volume* volume) +{ + Volume** volumeToSet = _GetVolume(volume->MountType()); + if (volumeToSet == NULL || *volumeToSet != volume) { + ERROR("Root::UnregisterVolume(): can't unregister unknown volume at " + "\"%s.\n", volume->Path().String()); + return; + } + + *volumeToSet = NULL; + volume->SetRoot(NULL); +} + + +Volume* +Root::FindVolume(dev_t deviceID) const +{ + Volume* volumes[] = { fSystemVolume, fCommonVolume, fHomeVolume }; + for (size_t i = 0; i < sizeof(volumes) / sizeof(volumes[0]); i++) { + Volume* volume = volumes[i]; + if (volume != NULL && volume->DeviceID() == deviceID) + return volume; + } + + return NULL; +} + + +void +Root::LastReferenceReleased() +{ +} + + +Volume** +Root::_GetVolume(PackageFSMountType mountType) +{ + switch (mountType) { + case PACKAGE_FS_MOUNT_TYPE_SYSTEM: + return &fSystemVolume; + case PACKAGE_FS_MOUNT_TYPE_COMMON: + return &fCommonVolume; + case PACKAGE_FS_MOUNT_TYPE_HOME: + return &fHomeVolume; + case PACKAGE_FS_MOUNT_TYPE_CUSTOM: + default: + return NULL; + } +} diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h new file mode 100644 index 0000000..940f99c --- /dev/null +++ b/src/servers/package/Root.h @@ -0,0 +1,56 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ +#ifndef ROOT_H +#define ROOT_H + + +#include <fs_info.h> +#include <String.h> + +#include <Referenceable.h> + +#include <packagefs.h> + + +class Volume; + + +class Root : public BReferenceable { +public: + Root(); + virtual ~Root(); + + status_t Init(dev_t deviceID, ino_t nodeID); + + dev_t DeviceID() const { return fDeviceID; } + ino_t NodeID() const { return fNodeID; } + const BString& Path() const + { return fPath; } + + status_t RegisterVolume(Volume* volume); + void UnregisterVolume(Volume* volume); + + Volume* FindVolume(dev_t deviceID) const; + +protected: + virtual void LastReferenceReleased(); + +private: + Volume** _GetVolume(PackageFSMountType mountType); + +private: + dev_t fDeviceID; + ino_t fNodeID; + BString fPath; + Volume* fSystemVolume; + Volume* fCommonVolume; + Volume* fHomeVolume; +}; + + +#endif // ROOT_H diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp new file mode 100644 index 0000000..4d17279 --- /dev/null +++ b/src/servers/package/Volume.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ + + +#include "Volume.h" + +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <Directory.h> +#include <Entry.h> +#include <Path.h> + +#include "DebugSupport.h" + + +Volume::Volume() + : + fPath(), + fMountType(PACKAGE_FS_MOUNT_TYPE_CUSTOM), + fDeviceID(-1), + fRootDirectoryID(1), + fRoot(NULL) +{ +} + + +Volume::~Volume() +{ +} + + +status_t +Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID) +{ + // get the directory path + BEntry entry; + status_t error = directory.GetEntry(&entry); + + BPath path; + if (error == B_OK) + error = entry.GetPath(&path); + + if (error != B_OK) { + ERROR("Volume::Init(): failed to get root directory path: %s\n", + strerror(error)); + RETURN_ERROR(error); + } + + fPath = path.Path(); + if (fPath.IsEmpty()) + RETURN_ERROR(B_NO_MEMORY); + + // stat() the directory + struct stat st; + error = directory.GetStat(&st); + if (error != B_OK) { + ERROR("Volume::Init(): failed to stat root directory: %s\n", + strerror(error)); + RETURN_ERROR(error); + } + + fDeviceID = st.st_dev; + fRootDirectoryID = st.st_ino; + + // get a volume info from the FS + int fd = directory.Dup(); + if (fd < 0) { + ERROR("Volume::Init(): failed to get root directory FD: %s\n", + strerror(fd)); + RETURN_ERROR(fd); + } + + PackageFSVolumeInfo info; + if (ioctl(fd, PACKAGE_FS_OPERATION_GET_VOLUME_INFO, &info, sizeof(info)) + != 0) { + error = errno; + close(fd); + if (error != B_OK) { + ERROR("Volume::Init(): failed to get volume info: %s\n", + strerror(error)); + RETURN_ERROR(error); + } + } + + close(fd); + + fMountType = info.mountType; + _rootDeviceID = info.rootDeviceID; + _rootNodeID = info.rootDirectoryID; + + return B_OK; +} diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h new file mode 100644 index 0000000..aa90a29 --- /dev/null +++ b/src/servers/package/Volume.h @@ -0,0 +1,55 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold <ingo_weinhold@xxxxxx> + */ +#ifndef VOLUME_H +#define VOLUME_H + + +#include <fs_info.h> +#include <String.h> + +#include <packagefs.h> + + +class BDirectory; + +class Root; + + +class Volume { +public: + Volume(); + ~Volume(); + + status_t Init(BDirectory& directory, + dev_t& _rootDeviceID, ino_t& _rootNodeID); + + const BString& Path() const + { return fPath; } + PackageFSMountType MountType() const + { return fMountType; } + dev_t DeviceID() const + { return fDeviceID; } + ino_t RootDirectoryID() const + { return fRootDirectoryID; } + + Root* GetRoot() const + { return fRoot; } + void SetRoot(Root* root) + { fRoot = root; } + +private: + BString fPath; + PackageFSMountType fMountType; + dev_t fDeviceID; + ino_t fRootDirectoryID; + Root* fRoot; +}; + + + +#endif // VOLUME_H diff --git a/src/servers/package/package_daemon.rdef b/src/servers/package/package_daemon.rdef new file mode 100644 index 0000000..ad88e3c --- /dev/null +++ b/src/servers/package/package_daemon.rdef @@ -0,0 +1,15 @@ +resource app_signature "application/x-vnd.haiku-package_daemon"; + +resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "package_daemon", + long_info = "package_daemon ©2013 Haiku, Inc." +};