Added emountd, a simple daemon that uses HAL to monitor when

devices get mounted or unmounted; reports will be send via dbus.

Updated docs for dbus usage.

Removed obsolete parts from jambuild.txt.

Small tunings in asciidoc's xhtml11.conf.

econtrol now can run program applets.
This commit is contained in:
Sanel Zukan 2008-08-05 14:26:38 +00:00
parent aebae643bd
commit 545bbbb330
10 changed files with 644 additions and 118 deletions

View File

@ -11,6 +11,7 @@
SubDir TOP ; SubDir TOP ;
EdeManual HACKING.txt ; EdeManual HACKING.txt ;
Clean distclean : $(JCACHEFILE) $(HCACHEFILE) ; Clean distclean : $(JCACHEFILE) $(HCACHEFILE) ;
# SubInclude goes after local rules # SubInclude goes after local rules
@ -24,6 +25,7 @@ SubInclude TOP efiler ;
SubInclude TOP eiconman ; SubInclude TOP eiconman ;
SubInclude TOP eimage ; SubInclude TOP eimage ;
SubInclude TOP elma ; SubInclude TOP elma ;
SubInclude TOP emountd ;
SubInclude TOP etimedate ; SubInclude TOP etimedate ;
SubInclude TOP etip ; SubInclude TOP etip ;
SubInclude TOP evoke ; SubInclude TOP evoke ;

View File

@ -10,4 +10,5 @@
SubDir TOP docs ; SubDir TOP docs ;
EdeManual index.txt introduction.txt jambuild.txt dbus-usage.txt ; EdeManual index.txt introduction.txt jambuild.txt ;
EdeManualWithToc dbus-usage.txt ;

View File

@ -426,7 +426,7 @@ Version {revision}<br />
Last updated {localdate} {localtime} Last updated {localdate} {localtime}
</div> </div>
<div id="footer-badges"> <div id="footer-badges">
{edeversion} {edeversion} manual
</div> </div>
ifdef::badges[] ifdef::badges[]
<div id="footer-badges"> <div id="footer-badges">

View File

@ -1,6 +1,8 @@
D-BUS usage in EDE D-BUS usage in EDE
================== ==================
Introduction
------------
This document describes link:http://freedesktop.org/wiki/Software/dbus/[D-BUS] usage in EDE applications. This document describes link:http://freedesktop.org/wiki/Software/dbus/[D-BUS] usage in EDE applications.
It is not meant to describe D-BUS protocol nor how to use it either via libdbus nor edelib, but It is not meant to describe D-BUS protocol nor how to use it either via libdbus nor edelib, but
to document and explain what programs listen or send data via D-BUS protocol. to document and explain what programs listen or send data via D-BUS protocol.
@ -14,21 +16,141 @@ EDE uses 'org.equinoxproject' as main namespace for interfaces and object paths,
/org/equinoxproject/Eiconman # eiconman object path /org/equinoxproject/Eiconman # eiconman object path
----------------------------------------------------------- -----------------------------------------------------------
Applications rest of the name will be application name and method or signal name, like:
------------
eiconman -----------------------------------------------------------
~~~~~~~~ org.equinoxproject.Eiconman.FooMethod # FooMethod belongs to eiconman
-----------------------------------------------------------
Signals Interfaces
^^^^^^^ ----------
*org.equinoxproject.Eiconman.DesktopChanged*
org.equinoxproject.Eiconman.DesktopChanged(int32 n, string name) org.equinoxproject.Eiconman
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Used by eiconman and access object is '/org/eqiunoxproject/Eiconman'. Provided
signals are:
'---------'---------'------------ DesktopChanged(int32 n, string name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[grid="all"]
`---------`---------`----------------
Name Type Description Name Type Description
------------------------------------- -------------------------------------
n int32 Desktop number n int32 Desktop number
name string Desktop name name string Desktop name
------------------------------------- -------------------------------------
Notify when desktop view was changed.
'''''
org.equinoxproject.Emountd
~~~~~~~~~~~~~~~~~~~~~~~~~~
Used by emountd and access object is '/org/equinoxproject/Emountd'. Provided
signals are:
Mounted(struct device_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
'device_info' contains the following fields:
[grid="all"]
`---------------`---------`-----------------------------------
Name Type Description
--------------------------------------------------------------
id uint32 Device ID for easier tracking
label string Device label (can be empty)
mount_point string Device mount point
device_file string Device file
drive_type int32 Drive type (see <<X1, Drive types>>)
cdrom_type int32 CDROM type, valid only if 'drive_type == DRIVE_TYPE_CDROM' (see <<X2, Volume disc types>>)
read_only bool Is device mounted read-only
--------------------------------------------------------------
Notify when storage device was mounted.
Unmounted(int32 udi)
^^^^^^^^^^^^^^^^^^^^^
[grid="all"]
`---------`---------`----------------
Name Type Description
-------------------------------------
id int32 Device ID for easier tracking
-------------------------------------
Notify when storage device was unmounted.
AudioCDAdded(struct audio_device_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'audio_device_info' contains the following fields:
[grid="all"]
`---------------`---------`-----------------------------------
Name Type Description
--------------------------------------------------------------
id uint32 Device ID for easier tracking
label string Device label (can be empty)
device_file string Device file
--------------------------------------------------------------
Notify when Audio CD was added.
AudioCDRemoved(int32 udi)
^^^^^^^^^^^^^^^^^^^^^^^^^
[grid="all"]
`---------`---------`----------------
Name Type Description
-------------------------------------
id int32 Device ID for easier tracking
-------------------------------------
Notify when Audio CD was removed.
Device enumerations directly maps to HAL ones and those values
are send in 'drive_type' and 'cdrom_type' (device_info struct).
[[X1]]
*Drive types:*
-------------------------------------------------------------
DRIVE_TYPE_REMOVABLE_DISK = 0x00
DRIVE_TYPE_DISK = 0x01
DRIVE_TYPE_CDROM = 0x02
DRIVE_TYPE_FLOPPY = 0x03
DRIVE_TYPE_TAPE = 0x04
DRIVE_TYPE_COMPACT_FLASH = 0x05
DRIVE_TYPE_MEMORY_STICK = 0x06
DRIVE_TYPE_SMART_MEDIA = 0x07
DRIVE_TYPE_SD_MMC = 0x08
DRIVE_TYPE_CAMERA = 0x09
DRIVE_TYPE_PORTABLE_AUDIO_PLAYER = 0x0a
DRIVE_TYPE_ZIP = 0x0b
DRIVE_TYPE_JAZ = 0x0c
DRIVE_TYPE_FLASHKEY = 0x0d
DRIVE_TYPE_MO = 0x0e
-------------------------------------------------------------
[[X2]]
*Volume disc types:*
-------------------------------------------------------------
VOLUME_DISC_TYPE_CDROM = 0x00
VOLUME_DISC_TYPE_CDR = 0x01
VOLUME_DISC_TYPE_CDRW = 0x02
VOLUME_DISC_TYPE_DVDROM = 0x03
VOLUME_DISC_TYPE_DVDRAM = 0x04
VOLUME_DISC_TYPE_DVDR = 0x05
VOLUME_DISC_TYPE_DVDRW = 0x06
VOLUME_DISC_TYPE_DVDPLUSR = 0x07
VOLUME_DISC_TYPE_DVDPLUSRW = 0x08
VOLUME_DISC_TYPE_DVDPLUSR_DL = 0x09
VOLUME_DISC_TYPE_BDROM = 0x0a
VOLUME_DISC_TYPE_BDR = 0x0b
VOLUME_DISC_TYPE_BDRE = 0x0c
VOLUME_DISC_TYPE_HDDVDROM = 0x0d
VOLUME_DISC_TYPE_HDDVDR = 0x0e
VOLUME_DISC_TYPE_HDDVDRW = 0x0f
VOLUME_DISC_TYPE_MO = 0x10
-------------------------------------------------------------

View File

@ -24,8 +24,9 @@
*Programs* *Programs*
- link:ecalc.html[Ecalc] - link:ecalc.html[Ecalc]
- link:evoke.html[Evoke]
- link:etip.html[Etip] - link:etip.html[Etip]
- link:evoke.html[Evoke]
- link:emountd.html[Emountd]
*Development* *Development*

View File

@ -11,7 +11,7 @@ Introduction
Why not make, you probably ask yourself, since the rest of the world Why not make, you probably ask yourself, since the rest of the world
use it? Well, make is a nice tool for small projects, or relatively use it? Well, make is a nice tool for small projects, or relatively
large one with monolithic configuration file. This means, if you have large one with monolithic configuration file. This means, if you have
1000 files and you want to build them on the same way, make can be usefull 1000 files and you want to build them on the same way, make can be useful
(sorta of). (sorta of).
On other hand, if you want some of them to have specific requirements, On other hand, if you want some of them to have specific requirements,
@ -27,22 +27,21 @@ libraries (today very often), that library 'will be tied to' that binary, even
if binary does not use any function from it. It is silly that ecalc requires, if binary does not use any function from it. It is silly that ecalc requires,
for example, libogg for startup, even if it does not use any function from it! for example, libogg for startup, even if it does not use any function from it!
In EDE 1.x we had pretty simple (and that is 'wohaaa' with arcane make syntax) In EDE 1.x we had pretty simple build system based on make (without automake stuff
build system based on make (without automake stuff because is... ah, check comments because is... ah, check comments online about it :-P) that served us very well.
online about it :-P) that served us very well.
But it had a lot of limitation. You couldn't, as sample, specify '-DSHAPE' flag But it had a lot of limitation. You couldn't, as sample, specify '-DSHAPE' flag
for a window manager without passing it to every program in the tree. The same for a window manager without passing it to every program in the tree. The same
applies for linked libraries too. applies for linked libraries too.
Jam is designed for these cases, and when they occur, it is like homeland for him. Jam is designed for these cases and when they occur, it is like homeland for him.
So, you want only 'foo.cpp' from 'baz' directory to get '-DXYZ' flag, no problem. Or you So, you want only 'foo.cpp' from 'baz' directory to get '-DXYZ' flag, no problem. Or you
want that every file in 'baz' directory (no matter is it binary or shared library) want that every file in 'baz' directory (no matter is it binary or shared library)
be linked with 'libtaz'; no problem either. be linked with 'libtaz'; no problem either.
So how it looks like So how it looks like
-------------------- --------------------
Here are few samples with syntax explaination. Here are few samples with syntax explanation.
Let say you have 'foo.cpp', a cool application and you want to create executable from Let say you have 'foo.cpp', a cool application and you want to create executable from
it. This is the way: it. This is the way:
@ -100,97 +99,3 @@ must have space before ending ';' character, like:
Well, that is a jam syntax :-) Well, that is a jam syntax :-)
=================================== ===================================
EDE build specific rules
------------------------
This is the main reason why you are reading this :-P. This is a list of rules
for easier building various pieces and short showcase how to use them.
Program rules
~~~~~~~~~~~~~
These rules are used to build binary file(s).
Program [target] : [sources] : [libraries] : [flags] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Creates [target] binary from [sources]. If libraries are given (normal way of linking
like '-lfoo', they will be used. If [flags] are given, like '-DABC' they will be
passed to compiler. Like:
-------------------------
# Compile and link with fltk libraries
SOURCE = Main.cpp SciCalc.cpp ;
Program ecalc : $(SOURCE) : -L/usr/local/share -lfltk -lX11 -lm -lstdc++ ;
# Compile and link with fltk libraries; also pass -D_DEBUG
SOURCE = Main.cpp SciCalc.cpp ;
Program ecalc : $(SOURCE) : -L/usr/local/share -lfltk -lX11 -lm -lstdc++ : -D_DEBUG ;
-------------------------
EdeProgram [target] : [sources] : [optional-libraries] : [optional-flags] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Create [target] and link it with edelib and fltk libraries. If [optional-libraries] and
[optional-flags] are given, they will be used. Like:
-------------------------
SOURCE = abc.cpp ;
EdeProgram abc : abc.cpp ;
-------------------------
EfltkProgram [target] : [sources] : [optional-libraries] : [optional-flags] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The same as EdeProgram, but will link with efltk libraries. This rule is used to compile
some programs from 1.x version, and will be removed when those programs are ported
to the edelib and fltk code.
FltkProgram [target] : [sources] : [optional-libraries] : [optional-flags] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Create [target] linking it with fltk libraries only. Also will link with images libraries.
FltkProgramBare [target] : [sources] : [optional-libraries] : [optional-flags] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Same as FltkProgram, but will *not* link with images libraries. Usefull for programs
which does not require images support.
Library rules
~~~~~~~~~~~~~
These rules are used to build either static or shared libraries.
StaticLibrary [library] : [sources] : [optional-flags] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Creates static library from [sources] files. If [optional-flags] are given, they
will be passed to the compiler. Sample:
-------------------------
# Compile each file with -D_DEBUG flag and create
# mylib.a library
StaticLibrary mylib : file1.cpp file2.cpp file3.cpp : -D_DEBUG ;
-------------------------
SharedLibrary [library] : [sources] : [optional-linklibs] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Creates a shared library from [sources] and link with [optional-linklibs]. Shared library
will, by default, have a '.so' extension, if extension in [library] was not given.
SharedLibraryVersioned [library] : [sources] : [optional-linklibs] : [optional-version] : [nolink] ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Creates a versioned shared library (like foo.so.1.2.0) and symbolic link (foo.so) to it.
If [optional-version] is given, it will be used to add version extension, if not,
this rule behaves the same as SharedLibrary (meaning symbolic link will *not* be created).
If option [nolink] was given, but [optional-version] does, symbolic link will not be created.
Here are few samples:
-------------------------
# Create foo.so.1.2.0 and symbolic link to it
SharedLibraryVersioned foo : file1.cpp file2.cpp : -L/some/path -lsomelib : 1.2.0 ;
# Create foo.so.1.2.0 without symbolic link
SharedLibraryVersioned foo : file1.cpp file2.cpp : -L/some/path -lsomelib : 1.2.0 : nolink ;
# Create foo.so.1.2.0 without linking with external libraries
SharedLibraryVersioned foo : file1.cpp file2.cpp : : 1.2.0 : nolink ;
-------------------------

View File

@ -19,6 +19,8 @@
#include <edelib/Nls.h> #include <edelib/Nls.h>
#include <edelib/Window.h> #include <edelib/Window.h>
#include <edelib/MessageBox.h> #include <edelib/MessageBox.h>
#include <edelib/Run.h>
#include <edelib/File.h>
#include <FL/Fl.h> #include <FL/Fl.h>
#include <FL/Fl_Button.h> #include <FL/Fl_Button.h>
@ -29,14 +31,25 @@
typedef edelib::list<edelib::String> StrList; typedef edelib::list<edelib::String> StrList;
typedef edelib::list<edelib::String>::iterator StrListIter; typedef edelib::list<edelib::String>::iterator StrListIter;
bool file_can_execute(const edelib::String& f) {
if(edelib::file_executable(f.c_str()))
return true;
/* find full path then */
edelib::String fp = edelib::file_path(f.c_str());
if(fp.empty())
return false;
return edelib::file_executable(fp.c_str());
}
class ControlButton : public Fl_Button { class ControlButton : public Fl_Button {
private: private:
Fl_Box* tipbox; Fl_Box* tipbox;
edelib::String tipstr; edelib::String tipstr;
edelib::String exec; edelib::String exec;
public: public:
ControlButton(Fl_Box* t, const edelib::String& ts, int x, int y, int w, int h, const char* l = 0) : ControlButton(Fl_Box* t, const edelib::String& ts, const edelib::String& e, int x, int y, int w, int h, const char* l = 0) :
Fl_Button(x, y, w, h, l), tipbox(t), tipstr(ts) { Fl_Button(x, y, w, h, l), tipbox(t), tipstr(ts), exec(e) {
box(FL_FLAT_BOX); box(FL_FLAT_BOX);
align(FL_ALIGN_WRAP); align(FL_ALIGN_WRAP);
color(FL_BACKGROUND2_COLOR); color(FL_BACKGROUND2_COLOR);
@ -58,9 +71,14 @@ int ControlButton::handle(int event) {
box(FL_DOWN_BOX); box(FL_DOWN_BOX);
redraw(); redraw();
if(Fl::event_clicks()) if(Fl::event_clicks()) {
edelib::message("Executing programs not implemented yet"); if(exec.empty())
edelib::alert(_("Unable to execute command for '%s'. Command value is not set"), label());
else if(!file_can_execute(exec.c_str()))
edelib::alert(_("Unable to run program '%s'. Program not found"), exec.c_str());
else
edelib::run_program(exec.c_str(), false);
}
return 0; return 0;
case FL_RELEASE: case FL_RELEASE:
box(FL_FLAT_BOX); box(FL_FLAT_BOX);
@ -119,7 +137,7 @@ void load_buttons(Fl_Group* g, Fl_Box* tipbox) {
if(c.get(section, "Exec", buff, sizeof(buff))) if(c.get(section, "Exec", buff, sizeof(buff)))
exec = buff; exec = buff;
ControlButton* cb = new ControlButton(tipbox, tip, 0, 0, 80, 100); ControlButton* cb = new ControlButton(tipbox, tip, exec, 0, 0, 80, 100);
cb->copy_label(name.c_str()); cb->copy_label(name.c_str());
c.get(section, "IconPathAbsolute", abspath, false); c.get(section, "IconPathAbsolute", abspath, false);

42
emountd/Jamfile Normal file
View File

@ -0,0 +1,42 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2008 EDE Authors.
#
# This program is licensed under the terms of the
# GNU General Public License version 2 or later.
# See COPYING for the details.
SubDir TOP emountd ;
rule RemoveFlag
{
local i ;
local ret ;
for i in $(>) {
if $(i) != $(<) {
ret += $(i) ;
}
}
return $(ret) ;
}
HALFLAGS = -DDBUS_API_SUBJECT_TO_CHANGE -I/usr/include/hal -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include ;
HALLIBS = -lhal-storage -lhal -ldbus-1 ;
SOURCE = emountd.cpp ;
ObjectC++Flags $(SOURCE) : -Wno-long-long
# libhal have a bug that fails on C++ with '-pedantic' flag
[ RemoveFlag -pedantic : $(GLOBALFLAGS) ]
$(EDELIBINCLUDE)
$(HALFLAGS) ;
Main emountd : $(SOURCE) ;
LinkAgainst emountd : $(EDELIBLIB) $(HALLIBS) $(STDLIB) ;
InstallEdeProgram emountd ;
EdeManual emountd.txt ;

421
emountd/emountd.cpp Normal file
View File

@ -0,0 +1,421 @@
/*
* $Id$
*
* emountd, mount/unmount notifier
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2008 Sanel Zukan <karijes@equinox-project.org>
*
* This program is licensed under the terms of the
* GNU General Public License version 2 or later.
* See COPYING for the details.
*/
/*
* A bunch of this code is inspired from Thunar (http://thunar.xfce.org)
* since HAL documentation pretty sucks.
*/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <libhal-storage.h>
#include <edelib/List.h>
/* HAL can return NULL as error message if not checked */
#define CHECK_STR(s) ((s != NULL) ? s : "<unknown>")
#define EMOUNTD_INTERFACE "org.equinoxproject.Emountd"
#define EMOUNTD_OBJECT_PATH "/org/equinoxproject/Emountd"
struct _DeviceInfo {
unsigned int udi_hash;
const char* label;
const char* mount_point;
const char* device_file;
LibHalDriveType drive_type;
LibHalVolumeDiscType cdrom_type; /* Valid only if drive_type == LIBHAL_DRIVE_TYPE_CDROM */
int read_only;
};
/* audio CD are special */
struct _DeviceAudioInfo {
unsigned int udi_hash;
const char* label;
const char* device_file;
};
typedef struct _DeviceInfo DeviceInfo;
typedef struct _DeviceAudioInfo DeviceAudioInfo;
typedef edelib::list<unsigned int> UIntList;
typedef edelib::list<unsigned int>::iterator UIntListIter;
static int quit_signaled = 0;
static DBusConnection* bus_connection = NULL;
static UIntList known_audio_udis;
void quit_signal(int sig) {
quit_signaled = 1;
}
/* A hash function from Dr.Dobbs Journal. */
unsigned int do_hash(const char* key, int keylen) {
unsigned hash ;
int i;
for (i = 0, hash = 0; i < keylen ;i++) {
hash += (long)key[i] ;
hash += (hash<<10);
hash ^= (hash>>6) ;
}
hash += (hash <<3);
hash ^= (hash >>11);
hash += (hash <<15);
return hash ;
}
void send_dbus_signal_mounted(DeviceInfo* info) {
int vi;
dbus_bool_t vb;
const char* vs;
DBusMessage* msg = dbus_message_new_signal(EMOUNTD_OBJECT_PATH, EMOUNTD_INTERFACE, "Mounted");
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
/* open sub-iterator */
DBusMessageIter sub;
dbus_message_iter_open_container(&it, DBUS_TYPE_STRUCT, NULL, &sub);
/* hash UDI is first member*/
dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &info->udi_hash);
vs = info->label;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vs = info->mount_point;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vs = info->device_file;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vb = (dbus_bool_t)info->read_only;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &vb);
vi = (int)info->drive_type;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &vi);
vi = (int)info->cdrom_type;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &vi);
/* close sub-iterator */
dbus_message_iter_close_container(&it, &sub);
dbus_uint32_t serial;
if(!dbus_connection_send(bus_connection, msg, &serial))
printf("Failed to send message (%i)\n", serial);
dbus_connection_flush(bus_connection);
dbus_message_unref(msg);
}
void send_dbus_signal_audio_cd_added(DeviceAudioInfo* info) {
const char* vs;
DBusMessage* msg = dbus_message_new_signal(EMOUNTD_OBJECT_PATH, EMOUNTD_INTERFACE, "AudioCDAdded");
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
/* open sub-iterator */
DBusMessageIter sub;
dbus_message_iter_open_container(&it, DBUS_TYPE_STRUCT, NULL, &sub);
/* hash UDI is first member*/
dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &info->udi_hash);
vs = info->label;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vs = info->device_file;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
/* close sub-iterator */
dbus_message_iter_close_container(&it, &sub);
dbus_uint32_t serial;
if(!dbus_connection_send(bus_connection, msg, &serial))
printf("Failed to send message (%i)\n", serial);
dbus_connection_flush(bus_connection);
dbus_message_unref(msg);
}
void send_dbus_signal_removed(unsigned int udi_hash, int is_audio) {
const char* sig;
if(is_audio)
sig = "AudioCDRemoved";
else
sig = "Unmounted";
DBusMessage* msg = dbus_message_new_signal(EMOUNTD_OBJECT_PATH, EMOUNTD_INTERFACE, sig);
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &udi_hash);
dbus_uint32_t serial;
if(!dbus_connection_send(bus_connection, msg, &serial))
printf("Failed to send message (%i)\n", serial);
dbus_connection_flush(bus_connection);
dbus_message_unref(msg);
}
void device_info_init(DeviceInfo* i) {
i->udi_hash = 0;
i->label = 0;
i->mount_point = 0;
i->device_file = 0;
i->drive_type = (LibHalDriveType)-1; /* 0 is LIBHAL_DRIVE_TYPE_REMOVABLE_DISK */
i->cdrom_type = (LibHalVolumeDiscType)-1;
i->read_only = 0;
}
void device_audio_info_init(DeviceAudioInfo* i) {
i->udi_hash = 0;
i->label = 0;
i->device_file = 0;
}
void device_info_send(LibHalContext* ctx, const char* udi) {
/* spec said devices with this property should be ignored */
if(libhal_device_get_property_bool(ctx, udi, "volume.ignore", 0))
return;
/* check volume */
LibHalVolume* vol = libhal_volume_from_udi(ctx, udi);
if(!vol)
return;
/* determine udi of the drive this volume belongs to */
const char* drive_udi = libhal_volume_get_storage_device_udi(vol);
if(drive_udi) {
/* determine the drive for the volume */
LibHalDrive* drive = libhal_drive_from_udi(ctx, drive_udi);
if(drive) {
const char* label = libhal_device_get_property_string(ctx, udi, "volume.label", 0);
const char* dev = libhal_drive_get_device_file(drive);
unsigned int udi_hash = do_hash(udi, strlen(udi));
/* for audio CD's we send special signals */
if(libhal_volume_disc_has_audio(vol) && !libhal_volume_disc_has_data(vol)) {
DeviceAudioInfo d;
device_audio_info_init(&d);
d.udi_hash = udi_hash;
d.label = label;
d.device_file = dev;
/*
* register hash so when Audio CD is ejected (device_removed() will be called)
* we knows should we send AudioCDRemoved signal
*/
known_audio_udis.push_back(udi_hash);
/* send signal about Audio CD */
send_dbus_signal_audio_cd_added(&d);
} else {
/*
* Check if volume is mounted, since device_info_send() is called at emountd startup
* and collects known volumes. Also, this function is called from device_property_modified()
* and that will be when device mounts/unmounts. In either case, we send unmount signal
*/
if(!libhal_device_get_property_bool(ctx, udi, "volume.is_mounted", 0)) {
send_dbus_signal_removed(udi_hash, 0); /* TODO: or to send drive_udi? */
} else {
DeviceInfo d;
device_info_init(&d);
d.udi_hash = udi_hash;
d.label = label;
d.device_file = dev;
d.mount_point = libhal_device_get_property_string(ctx, udi, "volume.mount_point", 0);
d.read_only = (int)libhal_device_get_property_bool(ctx, udi, "volume.is_mounted_read_only", 0);
d.drive_type = libhal_drive_get_type(drive);
/* determine CD type if we got it */
if(d.drive_type == LIBHAL_DRIVE_TYPE_CDROM)
d.cdrom_type = libhal_volume_get_disc_type(vol);
/* send signal about mounted device*/
send_dbus_signal_mounted(&d);
libhal_free_string((char*)d.mount_point);
}
}
libhal_free_string((char*)label);
libhal_drive_free(drive);
}
}
libhal_volume_free(vol);
}
void device_added(LibHalContext* ctx, const char* udi) {
/* only used for Audio CD's */
device_info_send(ctx, udi);
}
void device_removed(LibHalContext* ctx, const char* udi) {
unsigned int udi_hash = do_hash(udi, strlen(udi));
/* signal audio CD removal if udi match ours */
UIntListIter it = known_audio_udis.begin(), it_end = known_audio_udis.end();
for(; it != it_end; ++it) {
if((*it) == udi_hash) {
send_dbus_signal_removed(udi_hash, 1);
known_audio_udis.erase(it);
break;
}
}
}
void device_property_modified(LibHalContext* ctx, const char* udi, const char* key, dbus_bool_t is_rem, dbus_bool_t is_added) {
/*
* we watch only 'volume.mount_point' property;
* it is always set after 'volue.is_mounted' property so we can check it manualy
*/
if(strcmp(key, "volume.mount_point") == 0)
device_info_send(ctx, udi);
}
void help(void) {
puts("Usage: emountd [--no-daemon]");
puts("EDE mount/unmount notify manager");
}
int main(int argc, char** argv) {
int go_daemon = 1;
if(argc > 1) {
if(strcmp(argv[1], "--no-daemon") == 0)
go_daemon = 0;
else {
help();
return 1;
}
}
/* run in background */
if(go_daemon)
daemon(0, 0);
DBusError err;
DBusConnection* conn = NULL, *session_conn = NULL;
LibHalContext* ctx = NULL;
LibHalDrive* hd;
char** drive_udis;
int n_drive_udis;
char** udis;
int n_udis;
signal(SIGINT, quit_signal);
signal(SIGTERM, quit_signal);
signal(SIGKILL, quit_signal);
signal(SIGQUIT, quit_signal);
ctx = libhal_ctx_new();
if(!ctx) {
puts("Unable to get libhal context");
goto error;
}
dbus_error_init(&err);
/* open system bus for HAL */
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if(dbus_error_is_set(&err)) {
printf("Unable to connect to system bus %s : %s\n", err.name, err.message);
dbus_error_free(&err);
goto error;
}
/* open session bus for EDE */
session_conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if(dbus_error_is_set(&err)) {
printf("Unable to connect to session bus %s : %s\n", err.name, err.message);
dbus_error_free(&err);
goto error;
}
bus_connection = session_conn;
/* let libhal use our system bus connection */
libhal_ctx_set_dbus_connection(ctx, conn);
if(!libhal_ctx_init(ctx, &err)) {
printf("Unable to init libhal context %s : %s\n", CHECK_STR(err.name), CHECK_STR(err.message));
printf("Does hald daemon is running?\n");
dbus_error_free(&err);
goto error;
}
libhal_ctx_set_device_added(ctx, device_added);
libhal_ctx_set_device_removed(ctx, device_removed);
libhal_ctx_set_device_property_modified(ctx, device_property_modified);
/* explicitly state to watch all properties or nothing will be received */
if(!libhal_device_property_watch_all(ctx, &err)) {
printf("Unable to watch properties %s : %s\n", CHECK_STR(err.name), CHECK_STR(err.message));
dbus_error_free(&err);
goto error;
}
/* now lookup storage devices already known by HAL */
drive_udis = libhal_find_device_by_capability(ctx, "storage", &n_drive_udis, &err);
if(drive_udis) {
for(int i = 0; i < n_drive_udis; i++) {
hd = libhal_drive_from_udi(ctx, drive_udis[i]);
if(!hd)
continue;
/* check for floppy since it does not have volumes */
if(libhal_drive_get_type(hd) == LIBHAL_DRIVE_TYPE_FLOPPY) {
device_info_send(ctx, drive_udis[i]);
} else {
/* determine all volumes for the given drive */
udis = libhal_drive_find_all_volumes(ctx, hd, &n_udis);
if(udis) {
for(int j = 0; j < n_udis; j++) {
device_info_send(ctx, udis[j]);
/* HAL bug #5279 */
free(udis[j]);
}
/* HAL bug #5279 */
free(udis);
}
}
libhal_drive_free(hd);
}
libhal_free_string_array(drive_udis);
}
/* loop to receive/send messages */
while(dbus_connection_read_write_dispatch(conn, 1000) && !quit_signaled)
;
error:
if(!ctx)
libhal_ctx_free(ctx);
return 0;
}

14
emountd/emountd.txt Normal file
View File

@ -0,0 +1,14 @@
Emountd documentation
=====================
Emountd is EDE service responsible for reporting when storage
devices get mounted or unmounted. Reporting is done via D-BUS protocol and
interested applications should listen certain signals.
Specific emountd signals can be found at link:dbus-usage.html[D-BUS usage] page.
Options
-------
--no-daemon::
Do not run in background. Emountd will by default run in background.