Automatisches einbinden von Datenträgern

Ich binde nun nicht jeden Tag irgendwelche Laufwerke in mein System ein. Von daher kann ich nicht genau sagen, bei welchem Update da nun dieses Problem Einzug in Arch gehalten hat.

Es geht darum, dass man einen Datenträger einsteckt, zum Beispiel einen USB-Stick, eine CD-ROM, oder eine DVD und man bekommt die Meldung, dass man zum einbinden nicht berechtigt ist.

Not authorized to perform operation

Das ist ärgerlich! Ein versierter Nutzer hat damit nur bedingt Schwierigkeiten. Der bindet den Datenträger einfach von Hand ein, was so aussieht:

udisksctl mount -b /dev/sr0

Um das CD-ROM/DVD/Blueray-Laufwerk einzubinden.

Wer mit seinem System aber nur arbeitet und nicht einmal weiss, dass man Befehle auch von Hand in einen Terminal tippen kann, der ist schlagartig aller externen Datenträger beraubt.

Abhilfe ist jedoch recht schnell geschaffen.

  1. Wir legen eine Regel für Polkit fest
  2. Wir fügen den Benutzer der Gruppe storage hinzu

1. Regel für Polkit

In einem Terminal legen wir eine neue Regel für Polkit an:

sudo nano /etc/polkit-1/rules.d/50-udiskie.rules

Die ist aller Wahrscheinlichkeit nach leer, sonst würde das einbinden ja funktionieren. Da muss nun also folgendes rein:

polkit.addRule(function(action, subject) {
  var YES = polkit.Result.YES;
  // NOTE: there must be a comma at the end of each line except for the last:
  var permission = {
    // required for udisks1:
    "org.freedesktop.udisks.filesystem-mount": YES,
    "org.freedesktop.udisks.luks-unlock": YES,
    "org.freedesktop.udisks.drive-eject": YES,
    "org.freedesktop.udisks.drive-detach": YES,
    // required for udisks2:
    "org.freedesktop.udisks2.filesystem-mount": YES,
    "org.freedesktop.udisks2.encrypted-unlock": YES,
    "org.freedesktop.udisks2.eject-media": YES,
    "org.freedesktop.udisks2.power-off-drive": YES,
    // required for udisks2 if using udiskie from another seat (e.g. systemd):
    "org.freedesktop.udisks2.filesystem-mount-other-seat": YES,
    "org.freedesktop.udisks2.filesystem-unmount-others": YES,
    "org.freedesktop.udisks2.encrypted-unlock-other-seat": YES,
    "org.freedesktop.udisks2.eject-media-other-seat": YES,
    "org.freedesktop.udisks2.power-off-drive-other-seat": YES
  };
  if (subject.isInGroup("storage")) {
    return permission[action.id];
  }
});

Einfach den ganzen Kasten hier kopieren und im Terminal einfügen. Speichern (Strg+X -> j -> Enter), fertig.

2. Benutzer zur Gruppe “storage” hinzufügen

sudo gpasswd -a <user> storage

Wobei <user> durch den eigenen Benutzernamen ersetzt werden muss. In meinem Fall also diabolus.

sudo gpasswd -a diabolus storage

Okay. Nachdem der Benutzer neu angemeldet, oder die Kiste neu gestartet wurde, sollte nun das automatische einbinden von Datenträger wieder funktionieren.

Das MUI Grundgerüst

In diesem Artikel geht es um das Grundgerüst eines MUI-Programms. Dieses wird nicht mehr tun, als ein Fenster zu öffnen, darin einen Text auszugeben und beim beenden eine Abfrage durchzuführen.

Auch wenn ich sehr gerne C++ eingesetzt hätte, es kommt immer wieder zu Problemen, die ich nicht lösen konnte. Also, zurück zu C. Auch keine Dramatik, früher habe ich nur in C auf dem Amiga programmiert. Da gehen dann zwar ein paar Bequemlichkeiten flöten, damit kann ich aber leben.

Einrichtung

Wir brauchen ein paar Dinge, um ein MUI-Programm in C auf dem AmigaOS 3.x schreiben zu können. Ich habe mich für folgende Kombination entschieden:

  • ADE (für GCC)
  • MUI (um MUI-Programme ausführen und compilieren zu können)
  • Redit (als Editor)

Ich bin etwas betrübt, dass GoldED mittlerweile kommerziell vertrieben wird. Er war früher mein Standard-Editor und ich hätte ihn auch gerne wieder eingesetzt. Da ich leider auch nicht mehr auf StormC zurückgreifen kann, muss für den Anfang eben ein alternativer Editor her und hier habe ich mich derzeit für Redit entschieden.

Das Ganze hat aber auch etwas Gutes. Ich habe ein Projekt, welches ich in Angriff nehmen kann und muss mir nicht erst etwas aus den Fingern ziehen. Ich schreibe eine IDE in MUI! Kostenlos, quelloffen, so dass auch andere Entwickler sich bei Interesse daran beteiligen können.

ADE

Zuerst installieren wir ADE, um GCC nutzen zu können. ADE findet man im Aminet. Wo auch sonst? So ein bisschen erinnert das Aminet an die Paketquellen unter Linux. Es müsste nur noch einen entsprechenden Paketmanager dafür geben. Na, mal schauen, ob sich da nicht irgendwann was schreiben lässt!

Ist das Archiv runtergeladen und entpackt, hat man den Ordner ADE. Diesen kopiert man einfach dorthin, wo man ihn gerne haben würde. Ich habe ihn direkt auf DH0: liegen, die bei mir HD0 heisst.

Hat man das gemacht, muss man noch folgende Zeilen in die User-Startup eintragen:

;BEGIN ADE
Execute HD0:ADE/ADE-Startup DIR HD0:ADE
assign AmiTCP: ADE:
;END ADE

Anstelle von HD0:ADE/ muss der Ort angegeben werden, wo man das ADE Verzeichnis hinkopiert hat.

Die Zeile

assign AmiTCP: ADE:

steht so nicht in der Beschreibung im Aminet. Ich habe sie hinzugefügt, weil jeder Aufruf von gcc oder g++ immer wieder die Fehlermeldung produziert, dass AmiTCP: nicht gefunden wurde. Warum genau diese überhaupt gesucht wird, ist mir überhaupt nicht klar. Was will denn der Compiler im Internet? Egal. In der Emulation kann mein AmigaOS ohnehin nicht ins Internet, von daher tue ich ihm einfach den Gefallen.

Anmerkung:

gcc/g++ sucht die Datei "usergroup.library" und zwar im Verzeichnis "AmiTCP:libs/". Diese findet sich auch in "ADE:libs/". Deshalb setze ich "AmiTCP:" auf "ADE:"

MUI

Für MUI brauchen wir zwei Archive. Beide finden sich im Aminet.

Nach dem entpacken von mui38usr.lha findet man im Ordner MUI eine Installationsdatei. Die einfach ausführen, die entsprechenden Schritte abarbeiten und fertig.

Nach dem entpacken von mui38dev.lha hat man den Ordner Developer. Darin findet sich der Ordner C und darin der Ordner Include. Also:

MUI/Developer/C/Include

Den kompletten Inhalt kopieren wir nach ADE:include.

Fertig.

Redit

Auch Redit findet sich natürlich im Aminet. Zu installieren gibt es da nicht viel. Ich habe die Datei Redit einfach nach C: kopiert, damit sie von überall aufgerufen werden kann.

Das Grundgerüst

Hat alles geklappt, können wir mit dem programmieren anfangen.

Hier soll nun ein Grundgerüst aufgebaut werden, auf welchem spätere Anwendungen basieren können.

default.h

Wir beginnen mit der Header-Datei. Die kann man eigentlich nach belieben benennen, solange ein .h dahinter steht. Ich habe mich für default.h entschieden. Warum? Na, weil es eben so etwas wie der Standard sein soll, auf dem zukünftige Anwendungen beruhen.

Wir fangen an, indem wir die benötigten Dateien includieren:

#include <libraries/mui.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/muimaster.h>
#include <libraries/gadtools.h>
#include <libraries/iffparse.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

Da ist schon viel Zeug dabei, was man in diesem Grundgerüst eigentlich nicht braucht. Da wir aber später noch komplexere Anwendungen schreiben wollen, bauen wir das einfach direkt mit ein.

Nun definieren wir MAKE_ID, um den Fenstern später IDs zuweisen zu können. MUI benötigt das, also spendieren wir es ihm:

#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))

MAKE_ID wird uns später noch in der default.c begegnen.

Da wir auch noch ein paar Libaries benötigen, deklatieren wir die entsprechenden Zeiger:

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *MUIMasterBase;

Für das Grundgerüst würde auch nur MUIMasterBase ausreichen, doch wie oben schon geschrieben, es soll ja auch mal komplexer werden!

Da wir aber die Libraries brauchen und nicht nur eine Deklaration, schreiben wir uns jetzt noch eine Funktion, die wir dann später einfach aufrufen können und die für das öffnen der Libraries sorgt:

BOOL openLibs()
{
.
.
.
}

Darin öffnen wir jetzt eine Library nach der anderen und prüfen dabei, ob auch alles geklappt hat:

if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 39))) return FALSE;

Wir öffnen also die intuition.library und prüfen, ob sie auch geöffnet werden konnte. Wenn ja, geht es weiter in der Funktion. Wenn nicht, wird die Funktion mit FALSE beendet.

  if(!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0)))
  {
    CloseLibrary((struct Library *)IntuitionBase);
    return FALSE;
  }

Das gleiche Spiel mit graphics.library. Wurde sie erfolgreich geöffnet, geht es weiter. Wenn nicht, dann wir die intuition.library wieder geschlossen und wieder die Funktion mit FALSE beendet.

  if(!(MUIMasterBase=OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
  {
    CloseLibrary((struct Library *)GfxBase);
    CloseLibrary((struct Library *)IntuitionBase);
    return FALSE;
  }

Und weiter geht es mit der muimaster.library. Klappt das, geht es weiter. Wenn nicht, werden die geöffneten Libraries geschlossen und die Funktion mit FALSE beendet. Wer hätte es gedacht?

return TRUE;

Wenn bis hierhin alles geklappt hat, kann die Funktion mit TRUE beendet werden. Komplett sieht das dann so aus:

BOOL openLibs()
{
  if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 39))) return FALSE;

  if(!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0)))
  {
    CloseLibrary((struct Library *)IntuitionBase);
    return FALSE;
  }

  if(!(MUIMasterBase=OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
  {
    CloseLibrary((struct Library *)GfxBase);
    CloseLibrary((struct Library *)IntuitionBase);
    return FALSE;
  }
  
  return TRUE;
}

Wir sind ja anständige Programmierer und wenn wir Libraries öffnen, dann schliessen wir sie auch wieder, wenn wir sie nicht mehr brauchen. Dafür basteln wir uns erneut eine Funktion:

void closeLibs()
{
  if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);

  if(GfxBase) CloseLibrary((struct Library *)GfxBase);

  if(MUIMasterBase) CloseLibrary(MUIMasterBase);
}

Damit wäre die Header-Datei auch schon fertig!

default.c

Hier wird das Programm starten. Das heisst, hier drin befindet sich die main() Funktion. Aber zuerst wieder includieren!

#include <stdio.h>

#include "default.h"

Die Datei stdio.h brauchen wir für Funktionen wie printf() zum Beispiel. Ich denke aber, wer sich an die Programmierung mit MUI wagt, der weiss das schon. Da gehe ich also nicht wirklich drauf ein.

Für einen ungeübten Entwickler hier schnell die Anmerkung, die default.h wird nicht mit <> eingebunden! Warum nicht? Weil sie nicht im Include-Verzeichnis liegt, sondern in dem selben Ordner, wie default.c! Die spitzen Klammern sagen also: “Such im Include-Verzeichnis!”. Während die Anführungsstriche sagen: “Such dort, wo die Datei liegt, von der du aufgerufen wurdest!”.

Und schon kommt die main() Funktion!

int main(int argc, char *argv[])
{
.
.
.
}

Das sollte eigentlich immer so aussehen. Man gibt dem Betriebssystem nach dem beenden einen Wert zurück und kann beim Aufruf des Programms Parameter angeben. Sollte bekannt sein.

Gut. Lasset uns deklarieren!

	Object *app, *win1;
	ULONG signals;
	BOOL running = TRUE;

Zuerst brauchen wir Objekte. Eines für das Programm selbst app und eines für das Fenster win1. Die Variablen kann man beliebig benennen, seit kreativ! Oder belasst es einfach so.

Signale sind sehr wichtig! Ohne sie hätte man zwar ein Fenster, es würde aber auf nichts reagieren. Also ULONG signals;.

Anders als Kommandozeilen-Programme, läuft ein MUI-Programm in einer Schleife. Das heisst, dass Programm erreicht nicht einen bestimmten Punkt und wartet dort auf eine Eingabe. Wäre auch ziemlich unsinnig. Sagen wir, wir haben da ein komplexes Programm mit diversen Strings, Buttons und was weiss ich. Da wäre es ja unsinnig, wenn man immer darauf warten würde, dass ein bestimmter Button gedrückt wird. Das Programm wäre ziemlich nutzlos. Also läuft hier eine Schleife, die wartet auf ein Signal und die will man ja irgendwann auch beenden können. Deshalb deklarieren wir die Variable running und setzen sie auf TRUE. Sprich, ja, dass Programm läuft!

	if(!openLibs())
	{
		printf("Cannot open libs\n");
		return FALSE;
	}

Okay. Nun öffnen wir die Libraries. Dafür haben wir uns ja die Funktion openLibs() gebaut und die rufen wir jetzt auf. Natürlich prüfen wir, was da zurück kommt. Ist es TRUE, dann kann es weitergehen. Wenn nicht geben wir in der Kommandozeile aus, dass wir die Libraries nicht öffnen können und beenden das Programm.

	app = ApplicationObject,

Nun füllen wir die Variable app. Hier geht es eigentlich erst los mit MUI. Die Variable soll also ein ApplicationObject sein. MUI will so etwas haben, also sind wir so gnädig.

		MUIA_Application_Title,       "Default",
		MUIA_Application_Version,     "$VER: Default X.X (XX.XX.XX)",
		MUIA_Application_Copyright,   " ",
		MUIA_Application_Author,      " ",
		MUIA_Application_Description, " ",
		MUIA_Application_Base,        " ",

Dann möchte MUI gerne ein paar Informationen haben. Titel, Version usw. Bei Version sollte man $VER: voranstellen. Dann kann man später in der Kommandozeile die Version des Programms abrufen.

Was man hier jetzt aber überall einträgt, kann man sich quasi würfeln. Es empfiehlt sich jedoch, die entsprechenden Werte sinnvoll zu setzen!

Jetzt kommt der spannende Teil:

		MUIA_Application_Window, win1 = WindowObject,
			MUIA_Window_Title, "Window Title",
			MUIA_Window_ID,    MAKE_ID('D','E','F','A'),
			WindowContents, VGroup,
				Child, MUI_MakeObject(MUIO_Label, "Default MUI Application", NULL),
			End,
		End,

Wir erstellen das Fenster! Dieses ist ein MUIA_Application_Window und das hätte gerne ein paar Informationen. Ausserdem soll es in der Variable win1 gespeichert werden. Man weiss ja nie, ob man es irgendwann vielleicht mal schliessen und wieder öffnen will? Zugegeben, beim Hauptfenster wird das weniger passieren, aber trotzdem gehört es in eine Variable.

Titel sollte klar sein. Da kommt das rein, was später in der Titelleiste stehen soll.

Bei der ID kommt dann die definierte Funktion MAKE_ID zum Einsatz. Hier kann man im Prinzip seine Buchstaben auch würfeln. Wichtig ist nur, man sollte nicht zwei Fenster die gleiche ID zuweisen!

WindowContents ist dann der richtig spannende Teil. Denn hier baut man alles das ein, was später mal im Fenster erscheinen soll. Buttons, Listen, Strings usw.

MUI organisiert seine Child in Gruppen. HGroup und VGroup zum Beispiel. Also horizontale Gruppen, in welchen die darin befindlichen Childs in einer Reihe angeordnet werden, während sie in vertikalen Gruppen untereinander erscheinen. Soweit ist das ja logisch.

Da wir kein leeres Fenster wollen, basteln wir hier einfach ein MUIO_Label rein. Also nichts anderes, wie eine Beschriftung, ein kleiner Text. Was da drin stehen soll, kommt dahinter in die Anführungszeichen.

Nun heisst es noch, mit End, erst den WindowContents beenden und mit dem nächsten End, MUI_Application_Window.

End;

Mit End; beenden wir dann auch noch das ApplicationObject und das Fenster ist fertig definiert. Feuern wir es ab!

	if(!app)
	{
		printf("Cannot create application.\n");

                closeLibs();

		return FALSE;
	}

Wir wollen also jetzt, dass das Fenster auch angezeigt wird. Sollte dabei irgendetwas schiefgehen, geben wir wieder eine Fehlermeldung aus und beenden das Programm! Da wir ja ordentlich sind, schliessen wir auch die Libraries dabei wieder.

	DoMethod(win1, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
		app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

Das Programm soll aber auch bitte über den Quit-Button beendet werden können. Dafür müssen wir mit DoMethod() angeben, dass beim drücken des Buttons etwas passiert. Es soll MUIV_Application_ReturnID_Quit zurückgegeben werden.

	set(win1, MUIA_Window_Open, TRUE);

So. Das Programm ist gestartet, jetzt wollen wir auch das Fenster sehen. Das ist ja in win1 gespeichert und wir öffnen es jetzt, indem wir MUIA_Window_Open auf TRUE setzen. Ich sagte ja, es ist durchaus sinnvoll, sein Fenster in einer Variable zu speichern ;).

while(running)
{
    ULONG id = DoMethod(app, MUIM_Application_Input, &signals);

    switch(id)
    {
            case MUIV_Application_ReturnID_Quit:
                if((MUI_RequestA(app, 0, 0, "Quit?", "_Yes|_No", "\33cAre you sure?", 0)) == 1)
                    running = FALSE;
            break;
    }
    if(running && signals) Wait(signals);
}

Hier ist jetzt die erwähnte Schleife. Solange also running auf TRUE gesetzt ist, wird diese Schleife immer wieder abgerufen. Dabei wird in der neu deklarierten Variable id der entsprechende Wert des Signals gespeichert. Dafür haben wir schliesslich auch signals deklariert!

Nun werten wir das eintreffende Signal aus. Kommt MUIV_Application_ReturnID_Quit an, starten wir eine kleine Abfrage, ob wir auch sicher sind, dass Programm beenden zu wollen. Klickt man hier auf Yes, wird 1 zurückgegeben. Kommt hier also eine 1, wird running auf FALSE gesetzt und nach Durchlauf der Schleife die Schleife verlassen.

Am Ende der Schleife checken wir dann, ob running und signals noch TRUE sind. Ist dem so, so warten wir genau an dieser Stelle auf das nächste Signal.

	set(win1, MUIA_Window_Open, FALSE);

Wenn die Schleife verlassen wurde, soll ja auch das ganze Programm beendet werden. Also soll auch das Fenster verschwinden. Deshalb setzen wir es auf FALSE. Ja, wenn das Programm beendet wurde, würde auch das Fenster von selbst verschwinden. Wir sind aber anständige Programmierer!

  if(app) MUI_DisposeObject(app);

Okay. Wenn in app irgendetwas drin steht, soll MUI das jetzt entfernen. Deshalb MUI_DisposeObject();.

	closeLibs();

Was macht der brave Programmierer am Ende seines Programms? Richtig! Er schliesst, was er vorher geöffnet hat. Also closeLibs();.

	exit(TRUE);

Alles geschlossen, gelöscht und sauber? Dann beenden wir das Programm mit exit(TRUE);. Weil hat ja alles prima geklappt.

Komplett sieht das dann so aus:

#include <stdio.h>

#include "default.h"

int main(int argc, char *argv[])
{
	Object *app, *win1;
	ULONG signals;
	BOOL running = TRUE;

	if(!openLibs())
	{
		printf("Cannot open libs\n");
		return FALSE;
	}

	app = ApplicationObject,
		MUIA_Application_Title,       "Default",
		MUIA_Application_Version,     "$VER: Default X.X (XX.XX.XX)",
		MUIA_Application_Copyright,   " ",
		MUIA_Application_Author,      " ",
		MUIA_Application_Description, " ",
		MUIA_Application_Base,        " ",

		MUIA_Application_Window, win1 = WindowObject,
			MUIA_Window_Title, "Window Title",
			MUIA_Window_ID,    MAKE_ID('D','E','F','A'),
			WindowContents, VGroup,
				Child, MUI_MakeObject(MUIO_Label, "Default MUI Application", NULL),
			End,
		End,
	End;

	if(!app)
	{
		printf("Cannot create application.\n");

		closeLibs();

		return FALSE;
	}

	DoMethod(win1, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
		app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

	set(win1, MUIA_Window_Open, TRUE);

	while(running)
	{
		ULONG id = DoMethod(app, MUIM_Application_Input, &signals);

		switch(id)
		{
				case MUIV_Application_ReturnID_Quit:
					if((MUI_RequestA(app, 0, 0, "Quit?", "_Yes|_No", "\33cAre you sure?", 0)) == 1)
						running = FALSE;
				break;
		}
		if(running && signals) Wait(signals);
	}

	set(win1, MUIA_Window_Open, FALSE);

  if(app) MUI_DisposeObject(app);

	closeLibs();

	exit(TRUE);
}

Das war es auch schon!

makefile

Das ist eigentlich optional. Aber will man wirklich jedes Mal gcc mit den ganzen Parametern starten? Nö! Also basteln wir uns ein Makefile.

Zuerst setzen wir ein paar Variablen:

objects = default.o
appname = Default
option = -O3 -m68000 -noixemul

Mit objects geben wir an, wie die Objekt-Datei heissen soll. Unser Programm heisst default, also nennen wir das auch default.o. Bei anderen Programmen, die andere Namen tragen, steht dann hier irgendwas.o. Ganz klar.

Da unser Programm compiliert nicht a.out heissen soll, taufen wir es und setzen deshalb appname auf Default.

Wie schon gesagt, gcc hat ganz gerne Parameter. Die setzen wir unter option.

-03 heisst in dem Fall, er soll optimieren. Den Wert kann man auch höher setzen, oder weglassen. Aber -03 ist eigentlich immer ein ganz guter Wert.

-m68000 sagt, es soll für den 68000 Prozessor optimiert werden. Hier könnte man zum Beispiel auch -m68030 reinschreiben. Dann kann es aber sein, dass es unterhalb eines 68030 nicht mehr läuft!

-noixemul heisst eigentlich nur, dass ixemul nicht eingebunden werden soll. Das dient dazu, Programme aus zum Beispiel der Linux-Welt besser portieren zu können. Brauchen wir nicht, als lassen wir es auch weg.

default:	$(objects)
	gcc -o $(appname) $(objects) $(option)

Jetzt geht die Linkerei los. Wie man es sich fast schon denken kann, default: ist wieder der Name unseres Programms. $(objects) gibt nun das an, was wir unter objects angegeben haben, genauso wie $(option).

Jetzt kommt auch gcc ins Spiel. Der Parameter -o gibt an, wie dass compilierte Programm heissen soll.

default.o:	default.c default.h
	gcc -c default.c $(option)

Ich denke, dazu ist nicht mehr viel zu sagen. Lediglich sollte klar sein, dass man hier die .c Datei angeben muss, in der sich main() befindet.

clean:
	rm $(objects) $(appname)

Schliesslich wollen wir auch aufräumen können. Beispielsweise, um das Programm erneut zu compilieren. Findet gcc die default.o Datei kann es nämlich gut sein, dass behauptet wird, alles wäre “up-to-date”. Dann wird nichts compiliert!

Komplett sieht das dann so aus:

# 
# Target OS: Amiga OS3.X
# Compiler : GCC
#

objects = default.o
appname = Default
option = -O3 -m68000 -noixemul

default:	$(objects)
	gcc -o $(appname) $(objects) $(option)
	
default.o:	default.c default.h
	gcc -c default.c $(option)
	
clean:
	rm $(objects) $(appname)
	

Fertig.

Finale

Wir haben jetzt alles zusammen. Das heisst, wir können unser Programm compilieren!

Dazu starten wir eine Shell, wechseln in das Verzeichnis, indem wir die Dateien gespeichert haben und dann geben wir make ein!

Na da schau her! Erst hat gcc das Programm compiliert und dann auch noch gelinkt! Heisst das etwa, es hat funktioniert? Es gibt nur einen Weg, um es herauszufinden! Wir tippen default ein und schauen was passiert.

Klasse! Es hat geklappt! Das Programm wird gestartet, dass Fenster geöffnet und wenn wir auf den Button drücken, kommt die Abfrage! Noch ein Klick auf Yes und das Programm wird brav wieder beendet. Wir sind am Ziel!

Beschreibung

Das AmigaOS hat mich wieder!

Wahrscheinlich fragt sich jetzt der Eine oder Andere, ob mit mir alles in Ordnung ist. Auf der einen Seite erzähle ich da immer etwas von Linux und jetzt komme ich mit dem AmigaOS?

Richtig. Tue ich! Das mag daran liegen, ich komme ganz ursprünglich vom C64. Von da ging mein Weg dann direkt zum Amiga 500. Es folgte ein Amiga 1200 und am Ende ein DraCo. Dieser war schliesslich bis 2004 auch im aktiven Einsatz. Doch leider, leider, immer aktiver wurde das Internet und die Browser auf dem Amiga waren einfach irgendwie nicht mehr zeitgemäss. Ausserdem krankte die Hardware zunehmends und während ich bei der Anschaffung des DraCos noch keine Probleme mit dem schnöden Mammon hatte, war es an dessen Ende dann doch eher so, dass die Kohle immer knapper wurde. Dann etwa zwei oder drei Jahre Windows XP und schliesslich ganz schnell zu Linux. Aber, mein Herz gehört immer noch dem AmigaOS.

Warum jetzt wieder AmigaOS?

Nun ja, es ist jetzt nicht so, dass ich das AmigaOS gänzlich aus meinen Gedanken vertrieben hätte. Beim besten Willen nicht. Immer mal wieder hatte ich da so Anflüge, wie ich alles mal wieder etwas beleben könnte. Doch das waren echt nur Anflüge. Wer diesen Blog kennt weiss, ich habe immer und dauernd Projekte im Kopf stecken und immer fehlt es irgendwo an Zeit, oder eben das Geld.

Eigentlich habe ich im Moment auch keine Zeit. Neben meiner Arbeit entwickle ich ja zur Zeit (Stand: April 2021) eine App für die Wifesharing-Community und da ist ja auch noch die Sache mit der Familie. Alles kostet Zeit und davon hat man einfach nicht unbegrenzt. Dann verlangt der Körper auch noch nach so etwas dämlichen wie Schlaf, ach, es ist ein Drama.

Dann kam Youtube. Viele finden es ja gar nicht toll, wenn man auf der Startseite von Youtube einfach so Videos vorgeschlagen bekommt. Bevormundung, wird es oft genannt. Ich mag es aber. Man glaubt es kaum, aber wirklich oft tauchen da wirklich Videos auf, die mich wirklich interessieren! Ich bin aber durchaus noch selbst dazu in der Lage, mir meinen Content zu suchen.

Auf jeden Fall, da wurde mir ein Video vorgeschlagen, wo sich jemand seinen eigenen, fast nagelneuen Amiga 500+ zusammen lötet. Das musste ich natürlich anschauen und ich war begeistert. Neue Amiga-Hardware? Also neu im Sinne von, nicht schon vor 30 Jahren zusammengebaut. Also musste ich mir diesen Kanal genauer anschauen.

Dabei handelt es sich um Virtual Dimension. Da geht es in der Hauptsache um Retro. Also Retro-Computer, Retro-Zeitschriften, aber auch Retro-Spiele. Quasi Lets Plays von Spielen die älter sind, als viele Youtuber, welche solche Videos von aktuellen Spielen publizieren.

Ach, was wurden da für Emotionen wach. Nicht nur, dass ich die Meisten der Spiele selbst früher gespielt habe, nein. Die beiden RetroPlayer, die Meistens zu sehen sind, unterhalten sich dabei auch oft über die Vergangenheit und mir kommt da einfach so unglaublich viel bekannt vor. Auch die Art, wie die Videos aufgezogen werden. Historyline zum Beispiel. Das wurde glaube ich 2014 gestartet und läuft aktuell (Stand: April 2021) nach über 200 Folgen immer noch. Es ist dabei gar nicht immer das Spiel, weshalb ich die Videos schaue, sondern die beiden Jungs, die es spielen. Da werden dann mal Modellflugzeuge geklebt, oder sie kostümieren sich, erzählen von aktuellen Themen, von damals, machen natürlich auch mal für sich Werbung und alles ist irgendwie stimmig. Ich möchte einfach das nächste Video sehen.

Was ich da aber dann immer wieder höre, AmigaOS zum Beispiel ist nicht tot! Nein, sowieso nicht, denn es gibt es ja noch und daran wird ja auch in der Version 4 gearbeitet. Ich meine aber das OS 3.1, 3.5, 3.9. Also das, womit ich damals schon gearbeitet habe. Da werden immer noch Spiele produziert und das hat mich irgendwie angespornt.

Bei meiner Recherche habe ich dann entdeckt, auch im Aminet wird nach wie vor neue Software veröffentlicht. Auch neue Hardware findet sich. Vampire sollte da ein Begriff sein. Turbokarten mit 68080 Prozessor, den es nie gegeben hat. Alles realisiert über FPGA, was ich wirklich grossartig finde. Das gibt es mittlerweile sogar Standalone, also quasi ein ganz neuer Amiga! Grossartig.

Dabei ist mir dann aber etwas aufgefallen. Es gibt ein Video, da wird dieser Vampire 4 mit dem AmigaOS auf dem Raspberry Pi 3 und 4 verglichen. Gegenüber dem 3er hat der Vampire dabei noch Leistungsvorteile. Gegen den Pi 4 sieht er aber dann doch kein Land mehr. Allerdings muss man sagen, zumindest habe ich es so verstanden, auf dem Vampire läuft das AmigaOS nativ, auf dem Pi im Emulator.

Okay. An dem Punkt würde ich dann zum Vampire 4 tendieren. Aber, hier ist dann wieder die Nummer mit dem Geld. Davon habe ich eben immer noch nicht so viel. Soll heissen, ich kann mir keinen Vampire 4 leisten. Der kostet so um die 500€. Die habe ich einfach nicht. Aber die 50-100€, je nach Ausstattung, für einen Pi 4, die kriege ich noch zusammen.

Jetzt hat es mich also voll geritten. Ich will wieder was mit dem AmigaOS machen. Aber nein, deshalb kehre ich Linux natürlich nicht den Rücken. Wieso auch? Bleiben wir mal realistisch. Vielleicht führt die Entwicklung des Vampire wirklich dazu, dass das AmigaOS wieder mehr Mainstream wird und Software darauf portiert wird, die heute eigentlich Standard ist. Dabei rede ich nicht einmal von Browsern, oder so. Wenn ich aber sehe, wie lange man suchen muss, bis man alleine was in C/C++ entwickeln kann, also da wird einem schon komisch. Klar, kommerziell gibt es da einiges, oder man könnte es auf Linux schreiben und crosscompilieren. Aber na ja, wenn ich etwas auf dem AmigsOS entwickeln will, dann will ich es auch auf dem AmigsOS programmieren.

Bedauerlich in dem Zusammenhang finde ich, ich habe noch den StormC 3 hier auf CD. Mit Serial# usw. Damit habe ich früher programmiert und war immer sehr zufrieden damit. Nur leider hat die CD die Zeit nicht überdauert. Ich komme nicht mehr an das Programm ran. Sehr schade.

Dann so Dinge wie Git, Cmake, llvm und Co. Für das AmigaOS 4 gibt es das. Dummerweise habe ich das nicht. Das sind so Punkte, weshalb es mir aktuell schwer fallen würde, von Linux weg rein wieder zum AmigaOS zu gehen. Dazu kommt noch, ich bin optisch durch die Vielfalt an Window-Manager echt verwöhnt. Da müsste beim AmigaOS auch noch stark nachgebessert werden.

Von daher. Das AmigaOS hat mich definitiv wieder! Aber, es steht hinter Linux und ich wage es derzeit stark zu bezweifeln, dass sich das ändern wird.

Zielsetzung

Sollten sich alle meine Hoffnungen bestätigen, dann wird das Ziel der Mission sein, mir meinen eigenen Amiga, den ich Diabolus nennen werde, zu konstruieren.

Grundlage bildet ein Raspberry. Welchen weiss ich aber noch nicht. Wahrscheinlich aber ein 4er. Je nachdem, wie lange alles so dauert, kann es aber auch ein Pi 5 werden, oder ein Pi 42. Wer weiss das schon.

Für diesen kleinen Kerl will ich ein Amiga 4000 Gehäuse entwerfen und drucken. Dieses werde ich dann aber so anpassen, dass der Pi das Diskettenlaufwerk ersetzt. Sprich, wo beim Amiga 4000 die Diskette rein kommt, sollen die USB-Ports und der Netzwerk-Anschluss vom Pi zu sehen sein. Das ganze Gehäuse soll also soweit verkleinert werden, damit der Pi genau dort passt. Die originalen Abmessungen habe ich derweil von Dennis Pauler von Virtual Dimension bekommen, da ich selbst kein solches Gerät besitze. Vielen dank an dieser Stelle.

Dummerweise hat der Pi, wenn man auf die USB-Ports schaut, die Anschlüsse für das Netzteil, HDMI und Sound auf der linken Seite. Also müsste ich ihn entweder auf dem Kopf einbauen, so dass die Anschlüsse dann auf der Seite des Gehäuses sitzen, oder ich muss die Anschlüsse nach hinten verlängern.

Den Pi auf den Kopf stellen hätte den Vorteil, ich müsste nur die entsprechenden Löcher ins Gehäuse setzen und könnte direkt alles anschliessen. Das wäre natürlich sehr einfach, zumindest in der Theorie.

Die Anschlüsse aber ins Innere des Gehäuses zeigen zu lassen, würde mir die Möglichkeit bieten, sie nach hinten zu führen. Dort, wo bei jedem anderen Computer eben auch die Anschlüsse sitzen. Das würde mich aber auch in die Lage versetzen, den MicroUSB Anschluss zu umgehen. So könnte ich den Pi mit einem Netzteil betreiben, welches zum Beispiel 12 Volt Spannung hat und 3-4, oder auch mehr, Ampere bereitstellt. Zwischen die Eingangsbuchse und dem MicroUSB vom Pi dann noch ein Modul geklemmt, welches genau 5 Volt liefert und der kleine Kerl müsste genug Saft bekommen, um immer einwandfrei laufen zu können. Soweit die Theorie.

Dazu bietet der Pi ja auch die GPIO-Pins. Die könnte ich doch für Erweiterungen verwenden! Klar, die müsste ich selbst bauen, aber Hey, warum gibt es denn Arduinos? Oder FPGAs? Ich habe zwar überhaupt keinen Plan, was man da als Erweiterungen bauen könnte, aber wen interessiert das? Die Möglichkeit wäre da, vielleicht findet sich ja was?

Den A4000 kann man ja mit einem echten Schlüssel absperren. Ich weiss jetzt nicht genau, ob damit der ganze Rechner, oder nur eine Festplatte abgesperrt werden, oder ob man damit irgendwelche Wechselhardware fixieren kann, aber da ist auf jeden Fall dieses Schloss. Das fällt bei mir weg, weil ich keinen Plan habe, wofür ich es nutzen sollte.

Aber, der Power-Knopf sollte vorhanden sein. Da würde sich wieder die Variante eignen, die Anschlüsse ins Innere des Gehäuses zu führen. Vielleicht damit einen Arduino-Nano steuern, der einen Taster abfragt? Ach, keine Ahnung.

Auf jeden Fall soll ein Druck auf den Power-Knopf/Taster bewirken, dass die Kiste anspringt und sofort das AmigaOS bootet. Ich will also, dass man da keinen Emulator sieht. Ob ich dafür nun ein Amibian einsetze, oder mir selbst etwas baue, weiss ich noch nicht. Derzeit spiele ich mit FS-UAE rum und habe ganz gute Resultate. Da man diesen Emulator ja auch über die Kommandozeile starten kann, sollte mein Vorhaben also funktionieren.

Aber, ich bin noch nicht fertig!

Natürlich könnte ich die Möhre dann nativ nutzen. Sprich, da ist Mouse und Tastatur dran und ein Monitor. Das verschlingt dann aber wieder Platz!

Platz ist aber auch wieder mehr oder weniger Mangelware. Klar, ich könnte das Teil hier irgendwo hinstellen. Das würde aber auch bedeuten, wann auch immer ich daran arbeite, ich muss den Platz wechseln. Nun habe ich aber meinen Arbeitsplatz so gestaltet, dass ich eben genau das nicht muss! Mein Monitor steht vor mir, darunter ein Tablet für Amazon, Netflix und Co, links mein NetBook, über welches ich verschiedene Dinge regele, wie beispielsweise meinen 3D-Drucker und Rechts von mir steht mein Laptop, den ich unter Anderem für die Arbeit brauche. Es ist also alles so eingerichtet, dass ich meinen Platz nicht verlassen muss.

Unter Linux ist das einfach. Siehe meinen Raspberry, welcher an meinen 3D-Drucker angeschlossen ist und den ich auch anderweitig immer wieder nutze. Wenn ich da drauf muss, benutze ich einfach VNC, oder SSH.

Hier sehe ich nun zwei Möglichkeiten, dass auch mit meinem Diabolus zu realisieren. Einmal kann ich ganz banal beim booten einen VNC-Server unter Linux starten. Ist echt kein Problem. Mein Raspberry demonstriert das im Moment. Das hat aber den Nebeneffekt, die Mouse ist nur ganz schwer zu steuern. Da weiss ich aber noch nicht, woran genau das liegt. Wäre aber auf jeden Fall eine Möglichkeit.

Die zweite Möglichkeit finde ich derzeit aber spannender. Denn, es gibt einen VNC-Server für das AmigaOS. Ja, in der Tat. Der scheint aber angestaubt und ich habe bislang noch keine Versuche unternommen, den zum laufen zu bringen. Sollte der aber funktionieren, dann könnte das bedeuten, ich boote den Pi, der bootet meine Workbench und die startet automatisch einen VNC-Server, auf den ich von meinem Desktop zugreifen kann. Läuft da auch die Mouse flüssig, wäre es einfach perfekt! Meinen eigenen Amiga in einem VNC-Fenster. Ich wäre glücklich!

Alternativ könnte ich auch mal schauen, ob es da nicht irgendwie einen Switch gibt, mit dem ich Mouse und Tastatur einfach umschalten kann. Mein Monitor bietet diese Möglichkeit zum Glück schon. Ich muss schauen.

Das wäre auf jeden Fall mein Ziel. Ein AmigaOS auf eigener Hardware, wenn auch im Emulator. Mit Directory Opus Magellan II als Workbench-Ersatz (sobald ich meine Original-CD finde, auch mit korrekter Registrierung), einer funktionierenden Entwicklungsumgebung für C/C++ und ähnliches. Alles zusammen in einem selbst gedruckten Gehäuse.

Warum Diabolus?

Unter Umständen kennt vielleicht jemand mein Pseudonym, unter welchem ich meine Bücher bei Amazon verlege. Sprich diabolus Umarov. Da könnte man nun annehmen, ich sei ein bisschen selbstverliebt, dass ich meinem Projekt meinen Namen gebe. Dem ist aber nicht so!

Dazu sollte ich mal erklären, wie ich überhaupt zu diesem Pseudonym gekommen bin!

Einst fragte ich meine damalige Freundin, welche mittlerweile meine Frau ist, ob sie nicht einen Spitznamen für mein Auto hätte. Ja, ich bin da eigen. Mein jetziges Auto hat zum Beispiel den Spitznamen DJ. Das ist aber eine andere Geschichte.

Sie dachte kurz nach und meinte:

Diabolus

Das mag damit zusammenhängen, dass wir in der Zeit das Hörbuch von Dan Brown gehört haben, welches eben Diabolus heisst.

So. Mein Auto von damals ist aber nicht mehr, weshalb ich mich seither bei Spielen und wo auch immer Diabolus nenne. Voll kreativ, oder?

Nun kam da etwas neues in mein Interessensfeld. SecondLife. Ich habe es irgendwo gelesen, installiert und mich registriert. Natürlich als Diabolus. Aber, was will dieses dumme Ding? Einen Nachnamen! Den konnte man damals auch nicht frei wählen, sondern musste aus einer Liste auswählen. Ich also gesucht und gesucht. Bis ich über Umarov gestolpert bin. Kein Plan was es bedeutet, aber es klang so “östlich”. Russisch vielleicht? Na, wen interessiert es? Ich habe es also gewählt.

In dieser Zeit war ich als Gerüstbauer tätig. Sprich, Morgens um sechs Uhr aus dem Haus und zu unbestimmter Zeit zurück. Zudem ist der Beruf auch noch verdammt körperlich anstrengend, woraufhin ich so gar keine Lust hatte, nach der Arbeit, oder am Wochenende, gross etwas zu unternehmen. Doch dank SecondLife hatte ich dennoch ein wirklich angenehmes Sozialleben, mit meiner Frau zusammen. Was hatten wir da nicht alles? Club, Stores, eigenes Land, eine Fussballmannschaft, ich hatte eine Rennsportszene gebaut und und und. Ausserdem war ich dort als Skripter unterwegs und habe tatsächlich echtes Geld damit verdient. Aufträge hatte ich viele und so kam es dann auch, dass wenn ich irgendwann in bestimmten Kreisen aufgetaucht bin, ich so ein wenig wie ein kleiner Star behandelt wurde.

So. Wenn man mal irgendwohin kommt und die Leute “tuscheln”:

Das ist doch Diabolus Umarov

Dann bleibt das irgendwie hängen.

Na ja. Aus diversen Gründen ist das mit SecondLife aber dann in den Keller gegangen. Schuld daran war, dass ich als Gerüstbauer aufgehört hatte und wieder Zeit für echte soziale Interaktion hatte. Der Freundeskreis wurde dadurch dünner und auch wenn SecondLife heute technisch viel krasser ist als damals, ich langweile mich dort. Ich kenne niemand, weiss nicht wohin usw. Der Name ist aber geblieben und so war es logisch, wenn ich Bücher schreibe, dann veröffentliche ich diese unter meinem Pseudonym. Man gab mir damals aber als Tipp, ich sollte ein möglichst einfaches Logo auf die Taschenbücher drucken, damit die, die mich kennen, sofort sehen, dass es ein Buch von mir ist. Da ich jedoch super unkreativ bin, habe ich einfach ein rotes Viereck genommen und DU rein geschrieben. In Courier, damit es nach Schreibmaschine aussieht. Aber DU? Hey DU? Nee. Vollster Kreativität habe ich dann entschieden, aus dem DU ein dU zu machen. Also diabolus Umarov und dabei ist es auch geblieben.

Okay. Wer das bis hierhin gelesen hat und sich fragt, warum ich das alles erzähle, ich habe keine Ahnung! Eigentlich hätte ich die ganze Story schon bei der Namensgebung für mein Auto beenden können. Denn genau aus dem Grund wird mein Computer auch Diabolus heissen. Weil der in dem Buch von Dan Brown Diabolus heisst. Das ist das ganze Geheimnis.

Und jetzt, mein lieber Leser, stell dir einmal die Frage, warum du diesen Teil dieses Artikels bis hier hin gelesen hast. In dir scheint ein kleiner Masochist zu schlummern, ja?

Warum sage ich immer AmigaOS?

Keine Panik, hier hole ich nicht so weit aus!

Die Sache ist ganz einfach. Ich bin Anhänger des AmigaOS, nicht der Hardware. Klar, die war cool und jetzt durch die Vampire-Karten und Vampire 4, oder eben auch die Hardware für das AmigaOS 4 kann man durchaus auch echte Hardware einsetzen, aber hier ist wieder die Geschichte mit dem Geld.

Dabei muss ich auch sagen, die Zeiten, wo ich mich mit meinem Computer identifiziert habe, sind lange vorbei. Es ist mir so egal, ob mein OS auf einem IBM-Kompatiblen PC läuft, oder auf Custom-Hardware. Ich bin kein Purist! Ich will mit dem OS arbeiten und was da unter der Haube ist, hinterfrage ich nicht mehr. Es muss laufen und darf gerne schnell sein.

Deshalb sage ich AmigaOS und nicht Amiga.

Aktueller Stand

Direkt ein Hinweis. Ich werde den aktuellen Stand hier nicht aktualisieren. Er spiegelt also lediglich den Stand wieder, der zum Zeitpunkt der Veröffentlichung dieses Artikels vorgeherrscht hat! Alles weitere kommt dann in den nächsten Artikeln!

Aktuell sieht die Lage also so aus:

Ich habe die Amiga Workbench mit Kickstart 3.1 (40.68 von meinem A1200) mit UAEGFX Grafikkarte und höherer Auflösung installiert.

Weiterhin habe Directory Opus Magellan II installiert, konnte aber die Registrierung noch nicht abschliessen, da ich meine CD noch nicht gefunden habe. Die ist irgendwo in einer Kiste, die ich nach dem Umzug noch nicht ausgepackt habe. Nur, wo die Kiste aktuell ist, weiss ich leider nicht. Ich muss noch suchen.

Desweiteren habe ich im Aminet ADE gefunden. Damit kann ich meine Programme mit GCC compilieren. Auch wenn die Version jetzt nicht zwingend aktuell ist.

Doch auch wenn die Version von GCC leicht angestaubt ausschaut, dass von mir benutzte Archiv ist ziemlich aktuell. Hier die Angaben aus dem Aminet:

26.03.2021. Da kümmert sich also noch jemand drum. Bin mal gespannt, ob sich da noch etwas entwickelt.

Auf jeden Fall, ich habe schon ein “Hallo Amiga!” Programm in C und C++ geschrieben, mit gcc und g++ compiliert und es funktioniert. Das ist mir erst einmal wichtig!

Getestet habe ich auch, wie sich diese Emulation nun auf dem Pi schlägt. Mit VNC natürlich. Da muss ich sagen, also na ja. Ich hab schon mehr gelacht. Es funktioniert, aber schnell ist anders! Da will ich aber meinem Pi keinen Vorwurf machen. Auf dem läuft noch einiges anderes Zeugs, der ist nicht zwingend eine adäquate Referenz. Er hat mir aber gezeigt, es funktioniert!

Derzeit bin ich auf der Suche nach einem halbwegs vernünftigen Editor zum programmieren, für den ich nicht zwingend Geld ausgeben muss. Ich bin vielleicht durch Linux da verwöhnt, aber wenn ich sehe, dass so mancher Editor in etwa das Gleiche kostet, wie ein Pi, also so dick hab ich es dann leider nicht. Wenn doch, währen auch schon andere Projekte von mir deutlich weiter!

Aber Hey, was will ich auf dem Amiga machen? Richtig, programmieren! Also wenn sich kein Editor finden sollte, dann schreibe ich einfach einen. Schliesslich habe ich *hust* vor 20 Jahren schon ein paar Dinge programmiert und die hatten auch einen Editor. MUI hat das recht einfach möglich gemacht. Also, was soll der Geiz?

Schockierender Weise habe ich gerade festgestellt, dass mein PEA zum Beispiel nach wie vor im Aminet zu finden ist. Ich bin erschüttert! Version 6.0 vom 11.11.1998! Vor 23 Jahren!

Egal. Auf jeden Fall habe ich vor, so einen Editor dann auch Online zu stellen und zur IDE auszubauen. Ja, ich habe es vor. Ob die Zeit dafür aber reicht, werden wir sehen. Ideal wäre es natürlich, wenn ich irgendwie GIT zum laufen bringen würde. Vielleicht finden sich ja auch noch andere Entwickler, die an dem Ding dann mitarbeiten wollen. Fände ich toll.

Okay. Das ist jetzt der Stand der Dinge. Wo der Weg mich hinführt, weiss ich noch nicht. Ich habe viel vor, wie viel davon aber durch meine Zeit auch möglich wird, wird eben diese zeigen.