QR Code Business Card

noctus.net

ねぇ、今日はどこに行こうかな?

Archiv für den Tag ‘Code’

Wie wahr, wie wahr …

keine Kommentare

Eine passendere Maßeinheit gibt es kaum

Geschrieben von Mathias

14. Juli 2012 um 02:17

Initscript mit Tiny Tiny RSS 1.5.10

8 Kommentare

Mit der Veröffentlichung der Version 1.5.10 des webbasierten Feed-Aggregators Tiny Tiny RSS fiel mir auf, dass das sich das optional beziehbare Initscript nicht mehr zum Starten des Update-Daemons nutzen lies. Beim Ausführen des Startkommandos geschah schlichtweg gar nichts.

Erste Versuche, das betreffende PHP-Script händisch zu starten schlugen weitestgehend fehl. Das Daemon-Script fror ständig ein, nachdem ich die SSH-Verbindung trennte, mit der ich meinen Server administriere. Folgende Fehlermeldung wies mich darauf hin:

Der Aktualisierungs Daemon braucht zu lange um eine Aktualisierung durchzuführen. Dies könnte auf ein Problem wie einen Absturz oder eine Blockierung hinweisen. Bitte überprüfen Sie den Prozess des Daemons oder benachrichtigen Sie den Besitzer des Instanz.

Und tatsächlich konnte das Update durch Töten des Prozesses und Löschen der lock-Dateien zeitweise wiederbeleben. Eine dauerhafte Lösung konnte dies aber nicht sein.

Also befasste ich mich erneut mit dem Initscript, welches das Hilfsprogramm start-stop-daemon zum Starten des Update-Daemons nutzt. Nach genauer Betrachtung fiel mir auf, dass nirgends ein Wechsel zu einem unprivilegierten Nutzer stattfand, der Daemon lief daher bisher immer mit Superuser-Rechten. Dass aus dies aus Sicherheitsgründen eine schlechte Idee ist dürfte ersichtlich sein.

Jedenfalls wurde diesem Verfahren mit der neuesten Version von Tiny Tiny RSS ein Riegel vorgeschoben, der im Änderungsprotokoll nicht aufgeführt aber durchaus im Versionierungsprotokoll durch diese Änderung ersichtlich ist. Der Versuch wird nun entsprechend quittiert:

[sanity_check] Please don’t run this script as root.

Mit diesem Wissen erweiterte ich das Initscript und seine Datei für Standardeinstellungen um eine neue Variable, welcher ein Nutzername oder eine -ID zugewiesen werden kann. Der Update-Daemon wird nun mit diesem Nutzer (www-data hier) ausgeführt und verfügt nicht mehr über systemweite Rechte. Es folgen die aktualisierten Dateien.

Die Einstellungsdatei /etc/default/tt-rss

## Defaults for Tiny Tiny RSS update daemon init.d script
 
# Set DISABLED to 1 to prevent the daemon from starting.
DISABLED=0
 
# Emplacement of your Tiny Tiny RSS installation.
TTRSS_PATH="/var/www/feeds"
 
# Set FORKING to 1 to use the forking daemon (update_daemon2.php) in stead of
# the standard one.
# This option is only available for Tiny Tiny RSS 1.2.20 and over.
FORKING=1
 
# Set USER to the user/uid to run the daemon as
USER=www-data

Das Initscript /etc/init.d/tt-rss

#! /bin/sh
### BEGIN INIT INFO
# Provides:          ttrss-DOMAIN
# Required-Start:    $local_fs $remote_fs networking
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Tiny Tiny RSS update daemon for DOMAIN
# Description:       Update the Tiny Tiny RSS subscribed syndication feeds.
### END INIT INFO
 
# Author: Pierre-Yves Landuré 
 
# Do NOT "set -e"
 
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Tiny Tiny RSS update daemon"
NAME=$(command basename "${0}")
DISABLED=0
FORKING=0
USER=$(id --user)
 
# Read configuration variable file if it is present
[ -r "/etc/default/${NAME}" ] && . "/etc/default/${NAME}"
 
DAEMON_SCRIPT="update.php --daemon"
 
if [ "$FORKING" != "0" ]; then
  DAEMON_SCRIPT="update_daemon2.php"
fi
 
DAEMON=/usr/bin/php
DAEMON_ARGS="${TTRSS_PATH}/${DAEMON_SCRIPT}"
DAEMON_DIR="${TTRSS_PATH}"
PIDFILE="/var/run/${NAME}.pid"
SCRIPTNAME="/etc/init.d/${NAME}"
 
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
 
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
 
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
 
if [ "$DISABLED" != "0" -a "$1" != "stop" ]; then
  log_warning_msg "Not starting $DESC - edit /etc/default/tt-rss-DOMAIN and change DISABLED to be 0.";
  exit 0;
fi
 
#
# Function that starts the daemon/service
#
do_start()
{
  # Return
  #   0 if daemon has been started
  #   1 if daemon was already running
  #   2 if daemon could not be started
  start-stop-daemon --start --make-pidfile --background --quiet --chdir "$DAEMON_DIR" --pidfile "$PIDFILE" --chuid "$USER" --exec "$DAEMON" --test > /dev/null \
    || return 1
 
  start-stop-daemon --start --make-pidfile --background --quiet --chdir "$DAEMON_DIR" --pidfile "$PIDFILE" --chuid "$USER" --exec "$DAEMON" -- \
    $DAEMON_ARGS \
    || return 2
  # Add code here, if necessary, that waits for the process to be ready
  # to handle requests from services started subsequently which depend
  # on this one.  As a last resort, sleep for some time.
}
 
#
# Function that stops the daemon/service
#
do_stop()
{
  # Return
  #   0 if daemon has been stopped
  #   1 if daemon was already stopped
  #   2 if daemon could not be stopped
  #   other if a failure occurred
  start-stop-daemon --stop --make-pidfile --quiet --retry=TERM/1/KILL/5 --pidfile $PIDFILE --name $NAME
  RETVAL="$?"
  [ "$RETVAL" = 2 ] && return 2
  # Wait for children to finish too if this is a daemon that forks
  # and if the daemon is only ever run from this initscript.
  # If the above conditions are not satisfied then add some other code
  # that waits for the process to drop all resources that could be
  # needed by services started subsequently.  A last resort is to
  # sleep for some time.
  start-stop-daemon --stop --quiet --oknodo --retry=0/1/KILL/5 --exec $DAEMON
  [ "$?" = 2 ] && return 2
  # Many daemons don't delete their pidfiles when they exit.
  rm -f $PIDFILE
  return "$RETVAL"
}
 
case "$1" in
  start)
  [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
  do_start
  case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  esac
  ;;
  stop)
  [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
  do_stop
  case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  esac
  ;;
  restart|force-reload)
  #
  # If the "reload" option is implemented then remove the
  # 'force-reload' alias
  #
  log_daemon_msg "Restarting $DESC" "$NAME"
  do_stop
  case "$?" in
    0|1)
    do_start
    case "$?" in
      0) log_end_msg 0 ;;
      1) log_end_msg 1 ;; # Old process is still running
      *) log_end_msg 1 ;; # Failed to start
    esac
    ;;
    *)
      # Failed to stop
    log_end_msg 1
    ;;
  esac
  ;;
  *)
  echo "Usage: ${SCRIPTNAME} {start|stop|restart|force-reload}" >&2
  exit 3
  ;;
esac
 
:

Geschrieben von Mathias

29. Februar 2012 um 20:14

Tags: ,

Let’s bring the magic to Extbase

1 Kommentar

Beim Durchstöbern der Meldungen des Extension-Builder bin ich eher zufällig auf etwas gestoßen, was die Entwicklung von TYPO3-Erweiterungen mit Extbase revolutionieren könnte:

Workpaper: Magic for Domain Models
– A Plan for the Future of Models in Extbase

Um die Idee hinter dem Vorhaben zu verstehen, hier einmal eine kurze Auflistung der zum Hinzufügen eines einzelnen Felds zu einer einzigen Tabelle typischerweise notwendigen Schritte:

  1. Definition des Datenbank-Feldes (plus einer weiteren Tabelle bei MM-Beziehungen) in der ext_tables.sql,
  2. Hinzufügen der Eigenschaft nebst Getter und Setter zum betreffenden Model (plus ggf. Methoden zum Hinzufügen oder Entfernen von Elementen bei MM-Beziehungen),
  3. Hinzufügen des Felds zum TYPO3-Backend durch Anpassung der TCA-Definition der Tabelle,
  4. Ergänzen der notwendigen Übersetzungen (locallang_db.xml) und ggf. Beschreibungen/Hilfetexte (locallang_csh_*.xml)

Weitere Schritte ergeben sich, wenn z.B. MM-Beziehungen auch auf der Gegenseite bearbeitet/abgerufen werden können sollen. Insgesamt also eine Menge Schritte für eine eigentlich lapidare Erweiterung. Zudem verteilen sich die Schritte über mehrere Dateien deren Zusammenhang nicht unbedingt direkt ersichtlich ist. All dies zentral und mit minimalen Anpassungen vornehmen zu können würde Zeit und Aufwand sparen sowie mögliche Fehlerquellen reduzieren. Genau dies stellt das Projekt „Magic for Domain Models“ in Aussicht:

The core purpose is to make extension development, particularly modelling, more centralized and less prone to errors – and as a side bonus making it dynamic if so requested.

Erreicht werden soll dies um stark erweiterte Kennzeichnungen in den Kommentaren für Domain-Model und dessen Eigenschaften, was sich stark an die Möglichkeiten in FLOW3 anlehnt. Eine Beispiel-Konfiguration von der Projekt-Seite:

/**
 * Refrigerator Model
 *
 * (description and model annotiations ... )
 */
class Tx_Fedexample_Domain_Model_Refrigerator extends Tx_Extbase_DomainObject_AbstractEntity {
 
 // Other properties ...
 
 /**
 * Food content
 *
 * The parameters given to the "OneToMany" annotation are the default values which
 * will be used if not overridden - so they are shown for illustration only. You
 * can leave them out (just use @Magic\OneToMany) to use the table name in the relation
 * (tx_fedexample_domain_model_fooditem because Tx_FedExample_Domain_Model_FoodItem
 * is the type of relation. And the target field name from this Model (refrigerator).
 *
 * Note that a @Magic\Database annotations is not required here, it is automatically
 * applied based on the relation type. Although we use @Magic\Inline here there are
 * other options - like @Magic\Select and @Magic\Group, each with their own options.
 *
 * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Fedexample_Domain_Model_FoodItem>
 * @Magic\Field(type="relation")
 * @Magic\OneToMany(foreignTable="tx_fedexample_domain_model_fooditem", foreignField="refrigerator")
 * @Magic\Inline(maxItems="1000")
 * @Magic\Column(provider="Tx_Magic_Provider_Column_InlineProvider", dynamic="TRUE")
 */
 protected $food;
 
}

Aus diesen Angaben kann automatisch geschlussfolgert werden, dass für die Datenbank-Tabelle tx_fedexample_domain_model_refrigerator ein Feld namens food definiert, als MM-Beziehung gekennzeichnet und im TYPO3-Backend via IRRE bearbeitet werden soll.

Darüber hinaus soll es aber auch möglich sein, das Bearbeiten von Feldern im TYPO3-Backend durch neue und benutzerdefinierte Widgets zu verbessern. Im Endeffekt sollen Datenbank-Definition, TCA-Konfiguration und Backend-Bearbeitungsmöglichkeiten an einer einzigen zentralen Stelle zusammengeführt werden: dem Model. Alle dafür von TYPO3 benötigten Angaben sollen automatisch und dynamisch generiert werden. All dies soll gänzlich optional sein, wobei nach einer gewissen Reifephase sicher nichts dagegen spricht, dies zum Standardverhalten zu machen. Wer spart sich nicht gerne Arbeit und Zeit. ;-)

Um das ganze performant zu halten, soll das Ergebnis der automatischen Code-Generierung natürlich Cache-fähig sein, was eingeplant, aber momentan noch ein offener Punkt ist. Der aktuelle Entwicklungsverlauf kann im TYPO3-Git-Repository der Magic-Erweiterung verfolgt werden. Initiiert und voran getrieben wird die Entwicklung von keinem geringeren als Claus Due, dem Kopf hinter den unschätzbar hilfreichen fed- und flux-Erweiterungen. Die Wahrscheinlichkeit, dass dieses Projekt also Realität wird ist sehr hoch. Hilfe in jeder Form ist allerdings sehr willkommen.

So muss Magie der Neuzeit aussehen.

Geschrieben von Mathias

26. Februar 2012 um 15:03

Tags: , ,

Extbase: Model-Zugriff in Validatoren

keine Kommentare

Für den Fall, dass die Standard-Validatoren von Extbase oder benutzerdefinierte Validatoren für einzelne Eigenschaften eines Models nicht genügen, gibt es noch die Option eines benutzerdefinierten Validators mit vollem Zugriff auf die neue Instanz eines Models.

Dafür kann man sich eine gänzlich undokumentierte Feinheit des Extbase-Frameworks zunutze machen: standardmäßig wird in einem Standardpfad versucht, einen passenden Validator passend zu einem Model zu finden. Wieder ein Beispiel für „Konvention über Konfiguration“, worauf in Extbase und FLOW3 Wert gelegt wird.

Der besagte Validator wird standardmäßig unter Classes/Domain/Validator/ModelNameValidator.php gesucht. Wie bei allen Extbase-Validatoren üblich ist zur Erfüllung der Schnittstelle Tx_Extbase_Validation_Validator_ValidatorInterface (OOP-Konvention wäre hier eigentlich IValidator) eine Ableitung von Tx_Extbase_Validation_Validator_AbstractValidator empfehlenswert. Dessen isValid-Methode erhält als einziges Argument die betreffende Instanz des Models, womit dann beliebige Überprüfungen vorgenommen werden können. Da hier ein uneingeschränkter Zugriff auf alle Eigenschaften des Models gegeben ist, können so auch komplexe Validierungen mit Abhängigkeiten zwischen Eigenschaften und dergleichen vorgenommen werden.

Der Validator sollte zu guter Letzt wie immer true oder false zurückgeben um über das Ergebnis der Validierung zu informieren und im Fehlerfall zuvor noch eine aussagekräftige Fehlermeldung vermerken. Dies kann entweder über die addError-Methode oder direkt per Manipulation der errors-Eigenschaft geschehen:

// 1) addError()
$this->addError('Descriptive error message', 0000000000); // Hier sollte 0000000000 eine eindeutige Nummer sein
 
// 2) errors
$this->errors[] = new Tx_Extbase_Validation_Error('Descriptive error message', 0000000000); // Siehe oben

Letztere Variante bietet die Möglichkeit, manuell Instanzen von Tx_Extbase_Validation_PropertyError einzufügen. Dadurch können bestehende, auf Model-Eigenschaften optimierte, Partials für die Ausgabe von Validierungsfehlern ohne Anpassung verwendet werden. Dazu hängt man die eigentlichen Fehlermeldungen an eine Fake-Eigenschaft:

// Container für gruppierte Fehlermeldungen über eine Fake-Eigenschaft anlegen
if (!isset($this->errors['fakeProperty']) {
 
  $this->errors['fakeProperty'] = new Tx_Extbase_Validation_PropertyError('fakeProperty');
}
 
// Eigentliche Fehlermeldungen an den Container anhängen
$this->errors['fakeProperty']->addErrors(array(
  new Tx_Extbase_Validation_Error('Descriptive error message', 0000000000); // See above
));

Da dieser Validator allgemein für das Model gilt, wird er immer dann zur Rate gezogen, wenn eine neue Instanz des Models im Zuge einer Aktion angelegt werden soll. Wahlweise kann man dies allerdings auch manuell für die gewünschten Aktionen eines Controllers über die  @validate …Validator.php DocComment-Notation erfolgen. Allerdings sollte man dann darauf achten, dass der Validator nicht der oben beschriebenen Pfad-Konvention folgt. Andernfalls wird der Validator wie gehabt immer aufgerufen, @dontvalidate einmal ausgenommen. Auf diese Weise können der Zielaktion auch beliebige weitere Validatoren hinzugefügt werden, welche jeweils den gleichen Zugriff auf das Model haben.

Geschrieben von Mathias

16. Mai 2011 um 21:31

Tags: , , ,

Mingetty und systemd

keine Kommentare

Das von systemd standardmäßig für das Öffnen virtueller Terminals genutzte agetty verfügt verglichen mit mingetty nur über einen sehr beschränkten Funktionsumfang. So ist gerade die Option --autologin von mingetty interessant, wenn man beim Start des Systems automatisch einen Nutzer ohne manuelle Eingaben anmelden möchte. Unter SysVinit ist hierfür folgender Eintrag in der /etc/inittab erforderlich:

1:2345:respawn:/sbin/mingetty --autologin USER tty1

Die Konfiguration unter systemd gestaltet sich dagegen komplett anders, ermöglicht aber eine nicht minder flexible Anpassung:

  1. Die Datei /lib/systemd/system/getty@.service nach /etc/systemd/system kopieren
  2. Die Datei /etc/systemd/system/getty@.service editieren und in der Sektion [Service] die Option ExecStartwie folgt ändern:
    ExecStart=-/sbin/mingetty --autologin USER %I
  3. Ändern des Standard-Symlinks für die Startdefinition des getty-Dienstes auf tty1 (analog für die anderen virtuellen Terminals):
    ln -sf /etc/systemd/system/getty@.service \
    /etc/systemd/system/getty.target.wants/getty@tty1.service

    Dieses Kommando muss auch nach jedem Update von systemd ausgeführt werden, da dies die Dateien in /etc/systemd neu generiert.

Hiernach kann der Dienst neu gestartet werden. Eine laufende X-Sitzung wird damit allerings auch beendet:

systemctl restart getty@tty1.service

Ab diesem Zeitpunkt wird bei jedem Systemstart der per USER spezifierte Nutzer automatisch angemeldet. Als kleiner Bonus noch eine mögliche Vorgehensweise, um dabei auch automatisch den X-Server zu starten:

if [ -z "$DISPLAY" -a $(tty) = /dev/tty1 ]; then
  startx
fi

Hier wird geprüft, ob noch kein X-Server gestartet wurde (die Umgebungsvariable $DISPLAY ist andernfalls gesetzt) und ob wir uns gerade auf tty1 befinden, von wo aus üblicherweise der erste X-Server gestartet wird. Einzutragen ist das ganze in die ~/.bash_profile, nicht in die ~/.bashrc.

Geschrieben von Mathias

13. Mai 2011 um 22:58

Tags: ,

Shell-Autovervollständigung

keine Kommentare

Um den Umgang mit der Shell zu vereinfachen, habe ich schon seit geraumer Zeit die sofortige Anzeige aller Optionen bei einer mehrdeutigen Autovervollständigung aktiviert. Hierzu genügt folgender Eintrag in der ~/.inputrc:

# If you have this in your /etc/inputrc or ~/.inputrc, you will no longer
# have to hit the <Tab> key twice to produce a list of all possible
# completions.
# A single <Tab>  will suffice.
set show-all-if-ambiguous on

Dazu gesellte sich auch immer gleich die Festlegung der Autovervollständigung auf die Tab-Taste:

TAB:menu-complete

Nun bin ich auch endlich auf einen Hinweis gestoßen, wie man das Gegenstück, das rückwärtige Durchlaufen der Optionen, mittels Shift-Tab erreichen kann:

"\e[Z":menu-complete-backward

Die geliebten Einzeiler präsentieren sich wieder einmal in ganzer Pracht.

Geschrieben von Mathias

18. April 2011 um 23:07

Tags: , ,

Mehr Liebe für Exaile

keine Kommentare

Das ständige Aufrufen meines Last.fm-Profils im Browser um ein Stück meinen Lieblingen hinzuzufügen nervte mich schon lange und eine Integration dieser Funktion in Exaile lag auf der Hand. Geplant hatte ich dies schon seit langer Zeit und vergangenes Wochenende befasste ich mich nun damit. Heraus kam das Plugin Last.fm Lieblinge:

Exaile-Wiedergabeliste mit Plugin-Integration als Spalte und im Kontextmenü

Integration in Exailes Wiedergabelisten

Durch die hervorragende Dokumentation der Last.fm-API waren mir bereits die API-Aufrufe track.love und track.unlove bekannt. Allerdings grübelte ich lange darüber nach, wie ich den derzeitigen Lieblings-Status eines Stücks abfragen könnte. Aus früheren Experimenten meinte ich mich zu erinnern, dass track.getInfo unter anderem einen Eintrag dafür lieferte. Dem ist allerdings nicht so und nach einem kurzen Besuch in #audioscrobbler wurde mir nahe gelegt, den Aufruf user.getLovedTracks zu nutzen. Eingangs scheute ich noch die Iteration über alle Stücke in dieser Liste, da die lokalen Tag-Informationen ja durchaus von denen auf Last.fm aufgrund automatischer Korrekturen abweichen können. Schnell wurde jedoch klar, dass dies der einzig gangbare Weg ist, da es 1. sowieso keine andere Möglichkeit gibt, den Status abzufragen und 2. ein einmaliges Abrufen aller Lieblings-Stücke deutlich weniger Datenverkehr verursacht als eine ständige Abfrage pro Stück.

Nachdem dies geklärt war ging es an den zweiten wichtigen Aspekt: Schreibzugriffe auf Profile. Die Aufrufe track.love und track.unlove erfordern wie zu erwarten ist Schreibzugriff auf das Profil des jeweiligen Nutzers. Ein Einbetten meines persönlichen API-Schlüssels und Geheimnisses stand außer Frage; hierdurch hätte  jeder Schreibrechte auf die Profile aller Nutzer, die diesen Zugriff auf ihr Profil erlaubt hätten. Mehr als ein Kopieren des API-Schlüssels und Geheimnisses aus dem Quellcode des Plugins wäre hierfür nicht notwendig gewesen.

Aus diesem Grund entschied ich mich für das einzig Logische: jeder Nutzer müsste dem Plugin zur Nutzung seinen ganz persönlichen  API-Schlüssel und das zugehörige Geheimnis mitteilen. Damit obliegt dem Nutzer weiterhin die Entscheidung, ob Exaile auf sein Profil zugreifen darf und die erforderlichen Authentifizierungsdaten bleiben privat. Grafisch sieht das ganze daher nun so aus:

Dialog mit Einstellungen des Plugins Last.fm Lieblinge

Einstellungsdialog

Ein Klick auf die Schaltfläche „Zugriffsgenehmigung anfragen“ öffnet die Seite zum Verbinden von Apps auf Last.fm im Browser.

Bei der Umsetzung habe ich besonders Wert auf Multithreading gelegt, denn nichts nervt mehr als eine Anwendung, die nicht mehr reagiert, weil sie irgendetwas Aufwändiges im Hintergrund macht. Die Integration in Exailes grafische Oberfläche gestaltete sich dank des bereits vorhandenen Providers-Frameworks simpel. Der zum Umschalten des Lieblings-Status verwendete CellRendererToggleImage ist gekapselt und andernorts uneingeschränkt nutzbar. Die Kommunikation mit Last.fm (und in Zukunft auch Libre.fm, sollte dieser Dienst die AudioScrobbler 2.0 API implementieren) findet durch die wunderbare pylast-Bibliothek statt. Praktisch alle API-Aufrufe werden von dieser gekapselt und komfortabel zur Verfügung gestellt. Lediglich den track.unlove-Aufruf musste ich manuell hinzufügen.

Nunmehr genügt ein einzelner Klick auf das Herz-Symbol in der durch das Plugin hinzugefügten Spalte für Wiedergabelisten oder wahlweise der passende Eintrag im Kontextmenü von Stücken um diese als Lieblinge zu markieren oder diese Markierung zu entfernen. Für Letzteres hatte ich bisher allerdings noch keinen Bedarf. ;-)

Die Integration der Lieblingsstücke als benutzerdefinierte oder dynamische Wiedergabeliste ist schon vorgesehen. Langfristig ist übrigens auch geplant, dieses und alle anderen AudioScrobbler-bezogenen Plugins zu vereinen. Bis dahin gibt es noch viele interessante Funktionen, die es zu integrieren heißt.

Geschrieben von Mathias

25. März 2011 um 00:44

Tags: , , ,

Geliebte Einzeiler

keine Kommentare

Da mich das lautstarke Knarzen meiner Logitech MX518 beim Scrollen schon lange störte und auch die Oberfläche dieser nicht mehr wirklich angenehm war, gönnte ich mir nach langer Zeit einmal etwas Neues. Nach kurzer Suche fiel meine Wahl auf die Logitech M500:

Damit kann ich nun endlich laut- und scheinbar endlos scrollen. Die Kippfunktion des Mausrads ist allerdings nicht ganz glücklich geraten; bei einem Mittelklick löst man viel zu leicht die Vor/Zurück-Funktionalität aus. Das fehlen der Tasten zum Umstellen der Auflösung im Vergleich zur MX518 kann ich verschmerzen, da ich diese sowieso nie wirklich genutzt habe. Nichtsdestotrotz wünschte ich mir bei meiner neuen Maus eine höhere Auflösung; die augenscheinlich standardmäßigen 400 CPI sind mir zu wenig.

Von früheren Versuchen war mir noch das Werkzeug Lomoco bekannt, welches ebenso die Möglichkeit bietet, die Auflösung sowie einige anderen Parameter von Logitech-Mäusen anzupassen. Der Versuch sollte allerdings erst einmal fehlschlagen:

$ lomoco --1200
002.018: 046d:c069 Unsupported Logitech device: Unknown

Da hieß es nicht verzagen sondern Quellen laden. Die schließlich notwendige Anpassung erwies sich als einer der heißgeliebten Einzeiler:

--- src/lomoco.c    2011-03-05 22:06:12.000000000 +0100
+++ src/lomoco.c    2011-03-05 22:07:23.000000000 +0100
@@ -47,6 +47,7 @@
 {0xc025, "MX500 Optical Mouse",                        "M-BP81A",     0, 1, 1, 1, 0},
 {0xc031, "iFeel Mouse (silver)",                       "M-UT58A",     0, 1, 0, 0, 0},
 {0xc041, "G5 Laser Gaming Mouse",                      "M-UAC113",    0, 1, 0, 1, 0},
+    {0xc069, "M500 Laser Mouse",                           "M-500",       0, 1, 1, 0, 0},
 {0xc501, "Mouse Receiver",                             "C-BA4-MSE",   1, 0, 0, 0, 0},
 {0xc502, "Dual Receiver",                              "C-UA3-DUAL",  1, 0, 0, 0, 1},
 {0xc503, "Receiver for MX900 Receiver",                "C-UJ16A",     1, 0, 0, 1, 0},

Der Quellcode selbst dokumentierte in einfacher Form, wie man an die nötigen Angaben gelangen kann. (In diesem Fall der Inhalt von /proc/bus/input/devices)

Und damit kann ich nun meine neue Maus per Lomoco konfigurieren. :-) Um das ganze festzuhalten erstellte ich auch gleich einen Report für das Lomoco-Debian-Paket.

Geschrieben von Mathias

5. März 2011 um 23:55

Aktueller Befehl im Terminaltitel

keine Kommentare

Ein schönes Feature worauf ich nicht mehr verzichten möchte ist die automatische Anzeige des aktuell ausgeführten Befehls im Titel des Terminals bzw. des Tabs. Dadurch wird die Arbeit mit multiplen Fenstern bzw. Tabs ungemein einfacher. Hier die Umsetzung, einzutragen in die ~/.bashrc:

function reset_prompt_and_title() {
  # Gewünschten Standard-Prompt hier angeben
  PS1='\[\033[0;32m\]\u\[\033[00m\] \[\033[0;33m\]\w\[\033[00m\] \$ '
 
  echo -ne "\e]0;${USER}@${HOSTNAME}: ${PWD}\a"
  # Variante: Die überflüssige Angabe des Home-Verzeichnisses
  #           durch die übliche Tilde ersetzen
  #echo -ne "\e]0;${USER}@${HOSTNAME}: ${PWD/#${HOME}/~}\a"
}
 
# Nur für grafische Terminals gedacht
case "$TERM" in
  xterm*|rxvt*)
    # Eventuelle weitere Kommandos für $PROMPT_COMMAND unbedingt erst
    # nach dieser Zeile anhängen
    PROMPT_COMMAND=reset_prompt_and_title
 
    # Aktuell ausgeführten Befehl in den Terminaltitel schreiben
    trap 'echo -ne "\e]0;$BASH_COMMAND\a"' DEBUG
    ;;
esac

Geschrieben von Mathias

27. August 2010 um 00:58

Tags: ,

Zugriff auf USB-Datenträger mittels udisks

keine Kommentare

Um endlich in den Genuss eines aktuellen Thunars mit Gio-Unterstützung zu kommen begab ich mich auf eine kurze Suche und wurde im Xubuntu Developers PPA fündig. Die Aktualisierung verlief reibungslos, womit ich nun auch einmal auf entfernte Quellen zuzugreifen. So habe ich bisher auf mein Heimverzeichnis meiner Hochschule per sshfs und einem Eintrag in /etc/fstab zugegriffen. Grafisch einigermaßen komfortabel habe ich das Einhängen mit Hilfe einer benutzerdefinierten Aktion in Thunar vorgenommen.

Doch mittels Gio-Unterstützung in Thunar sollte dies der Vergangenheit angehören. Also rief ich ssh://ilux150.informatik.htw-dresden.de auf und erfreute mich der Tatsache, dass dies einfach funktionierte. Auch FTP-Zugriff funktioniert einwandfrei, auch wenn das wünschenswerte FTPES noch nicht in Gvfs implementiert wurde.

Schnell zeigte sich allerdings ein Problem: beim versuchten Zugriff auf meinen USB-Stick wurde ich nun mit einer Not Authorized Fehlermeldung abgewiesen. Nach kurzer Suche zu diesem Problem erkannte ich schnell, dass hier PolicyKit seine Finger im Spiel hat. Weiteres Suchen offenbarte mir schließlich eine Lösung, welche ich unter /etc/polkit-1/localauthority/50-local.d/plugdev.plka platzierte:

[Access to removable media for the plugdev group]
Identity=unix-group:plugdev
Action=org.freedesktop.udisks.drive-eject;org.freedesktop.udisks.filesystem-mount
ResultAny=yes

Damit allein war es jedoch noch nicht getan, da mir ck-list-sessions nach wie vor bescheinigte, dass die ConsoleKit-Sitzung nicht aktiv sei. Ohne eine aktive ConsoleKit-Sitzung könnte kein Programm unter X Dienste wie Udisks in Anspruch nehmen. Lange Rede kurzer Sinn war die Lösung schließlich, meine .xinitrc folgendermaßen zu gestalten:

exec ck-launch-session startxfce4

Hierdurch wird Xfce in einer ConsoleKit-Sitzung gestartet, womit ich nun ohne weiteres auf meine USB-Datenträger zugreifen kann. (Nachtrag: mit dem 4.7.0 Release von xfce4-session sollte dies nicht mehr erforderlich sein.) Meiner Meinung nach sollten Distributionen den hier beschriebenen Zugriff auf USB-Datenträger von Haus aus für reguläre Nutzer erlauben. Einige wie Ubuntu werden das auch sicher machen, bei Debian ist die Akzeptanz angesichts des serverlastigen Einsatzgebietes allerdings ungewiss.

Geschrieben von Mathias

24. August 2010 um 12:41

Tags: , ,