<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[FAQ - Linux&#x2F;Unix]]></title><description><![CDATA[Archiv von häufig vorkommenden Fragen aus dem Linux&#x2F;Unix-Board. ]]></description><link>https://www.c-plusplus.net/forum/category/64</link><generator>RSS for Node</generator><lastBuildDate>Mon, 09 Mar 2026 02:50:16 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/category/64.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 30 Oct 2004 13:36:37 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Port auch nach Absturz besetzt]]></title><description><![CDATA[Hast Du denn nun mal ein kleines Testprogramm mit den paar Codezeilen von mir geschrieben?
Es empfiehlt sich nicht immer, an einem größeren Programm eine Korrektur vorzunehmen und dann wenn es immer noch nicht funktioniert zu glauben, dass das es das es noch eine andere Lösung geben muss, denn eigentlich ist es die beschriebene Lösung. In C/C++ können manchmal durch verbogene Zeiger, bereits gelöschte Objekte etc. Probleme an Stellen auftreten, an die man in den kühnsten Träumen nicht zu denken mag.
Schreib mal das Testprogramm, &quot;kill&quot; es dann und vergleich das Verhalten mit mit Deinem ursprünglichen Progamm (z.B. auch mal killen).
SO_REUSEPORT habe ich übrigens bei mir in der socket.h gefunden, allerdings auskommentiert:
/* To add :#define SO_REUSEPORT 15 */
Kannst es damit ja auch nochmal testen, indem Du einfach den Wert 15 nimmst.
]]></description><link>https://www.c-plusplus.net/forum/topic/90356/port-auch-nach-absturz-besetzt</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/90356/port-auch-nach-absturz-besetzt</guid><dc:creator><![CDATA[wischmop2]]></dc:creator><pubDate>Sat, 30 Oct 2004 13:36:37 GMT</pubDate></item><item><title><![CDATA[POSIX Api Dokumentation]]></title><description><![CDATA[Danke!
Genau so etwas habe ich gesucht...
Gruss
]]></description><link>https://www.c-plusplus.net/forum/topic/73911/posix-api-dokumentation</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/73911/posix-api-dokumentation</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Sat, 15 May 2004 10:09:57 GMT</pubDate></item><item><title><![CDATA[Unterschied Linux&#x2F;Unix]]></title><description><![CDATA[Es sind 2 verschiedene Betriebssysteme, wobei Linux den Kernel bezeichnet, und nur durch die dazugehörigen Tools kann man es als Betriebssystem bezeichnen. Deswegen findest du auch oft die Bezeichnung GNU/Linux.
Linux ist ein UNIX-Derivat. Das bedeutet, es erfüllt bestimmte Standards (z. B. POSIX, was auf der gleiche Seiten erklärt wird). Andere UNIX-Derivate sind z. B. BSD oder Solaris. Naja, lange Rede kurzer Sinn, auf der o. a. Seite finden sich noch allerhand Infos dazu, ich denke dass sollte erstmal ausführlich genug sein. 
Einen ausführlichen Stammbaum gibts hier:
http://www.levenez.com/unix/history.html
Siehe auch http://de.wikipedia.org/wiki/Unix#Linux
]]></description><link>https://www.c-plusplus.net/forum/topic/62626/unterschied-linux-unix</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/62626/unterschied-linux-unix</guid><dc:creator><![CDATA[CarstenJ]]></dc:creator><pubDate>Sun, 25 Jan 2004 14:15:43 GMT</pubDate></item><item><title><![CDATA[Den Bildschirm leeren&#x2F;löschen]]></title><description><![CDATA[Um den Bildschirm zu leeren gibt es sehr viele verschiedene Methoden. Generell sollte man aber bedenken, ob man den Bildschirm wirklich löschen will, da so die Fähigkeit das Programm `Unix`-typisch zu benutzen, in dem man es zu anderen Anwendungen piped verloren geht (Wenn es sich eh um ein UI handelt, ist das natürlich egal)!
1. (n)curses - clear
/*Compile: gcc -lncurses clr.c*/
#include &lt;curses.h&gt;

int main(void)
{
  initscr(); /*init ncurses*/
  cbreak();
  noecho();

  printw(&quot;Text ...\n&quot;);
  getch(); /*wait for key*/
  clear();
  printw(&quot;Wie sauber\n&quot;);
  getch();
  endwin();
  return 0;
}

2. (n)curses - termios (danke an virtual)
/*Compile: gcc -lncurses clr.c*/
#include &lt;stdio.h&gt; 
#include &lt;term.h&gt; 

int main(void) 
{ 
  printf(&quot;Text ...\n&quot;);
  getchar();
  setupterm(NULL, 1, NULL); 
  putp(clear_screen); 
  printf(&quot;Wie sauber\n&quot;);
  return 0; 
}

3. ANSI Escape Sequenzen
( geht nur auf Terminals, wo die ANSI Escape Sequenzen aktiviert sind)
/*Compile: gcc clr.c*/
#include &lt;stdio.h&gt;

void clear() {
  printf(&quot;\033[2J\033[1;1H\033[m&quot;);
}

int main() {
  printf(&quot;Text ...\n&quot;);
  getchar();
  clear();
  printf(&quot;Wie sauber\n&quot;);
}

Die &quot;Lösung&quot; mit man: system(3) und man: clear(1) habe ich weggelassen, da diese die langsamsten und schlechtesten sind!
(Der Beitrag ist aus 2 älteren Threads zusammen gestellt worden
http://www.c-plusplus.net/forum/viewtopic.php?t=39521
http://www.c-plusplus.net/forum/viewtopic.php?t=39522)
Danke an Pretty für die Korrektur eines Fehlers.
]]></description><link>https://www.c-plusplus.net/forum/topic/62523/den-bildschirm-leeren-löschen</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/62523/den-bildschirm-leeren-löschen</guid><dc:creator><![CDATA[rüdiger]]></dc:creator><pubDate>Sat, 24 Jan 2004 12:04:16 GMT</pubDate></item><item><title><![CDATA[pthread_create mit C++]]></title><description><![CDATA[pasti schrieb:

Ist es auch möglich Memberfunktionen einer Klasse int pthread_create zu verwenden?

nur statische. Mit dem extra-Parameter an pthread_create kannst du aber das Objekt mitgeben:
class Thread
{
public:
  Thread()
  {
    pthread_create(..., _thread, this);
  }

  void* thread()
  {
    ...
  }

private:
  static void* _thread(void* This) { return ((Thread*)This)-&gt;thread(); }
};

]]></description><link>https://www.c-plusplus.net/forum/topic/48278/pthread_create-mit-c</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/48278/pthread_create-mit-c</guid><dc:creator><![CDATA[DrGreenthumb]]></dc:creator><pubDate>Tue, 09 Sep 2003 19:37:01 GMT</pubDate></item><item><title><![CDATA[eigene IP herausfinden]]></title><description><![CDATA[Hab hier mal was in einer Newsgroup aufgeschnappt. Geht wohl nur für Linux:
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/ioctl.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;net/if.h&gt;
#include &lt;arpa/inet.h&gt;

int main(int c, char **v) {

  struct ifreq ifa;
  struct sockaddr_in *i;
  int fd;

  if(c != 2) {
    fprintf(stderr, &quot;Usage: %s &lt;iface&gt;\n&quot;, v[0]);
    exit(EXIT_FAILURE);
  }

  if (strlen (v[1]) &gt;= sizeof ifa.ifr_name) {
    fprintf (stderr, &quot;%s is to long\n&quot;, v[1]);
    exit (EXIT_FAILURE);
  }

  strcpy (ifa.ifr_name, v[1]);

  if((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    perror (&quot;socket&quot;);
    exit (EXIT_FAILURE);
  }

  if(ioctl(fd, SIOCGIFADDR, &amp;ifa)) {
    perror (&quot;ioctl&quot;);
    exit (EXIT_FAILURE);
  }

  i = (struct sockaddr_in*)&amp;ifa.ifr_addr;
  puts (inet_ntoa(i-&gt;sin_addr));

  return 0;
}

]]></description><link>https://www.c-plusplus.net/forum/topic/43703/eigene-ip-herausfinden</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/43703/eigene-ip-herausfinden</guid><dc:creator><![CDATA[DrGreenthumb]]></dc:creator><pubDate>Thu, 24 Jul 2003 13:09:48 GMT</pubDate></item><item><title><![CDATA[&amp;quot;Programmieren unter Unix&amp;quot; Links]]></title><description><![CDATA[da wohl niemand mehr einen Link hat, pack ich das mal in die FAQ
]]></description><link>https://www.c-plusplus.net/forum/topic/39511/quot-programmieren-unter-unix-quot-links</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39511/quot-programmieren-unter-unix-quot-links</guid><dc:creator><![CDATA[rüdiger]]></dc:creator><pubDate>Sun, 01 Jun 2003 19:48:00 GMT</pubDate></item><item><title><![CDATA[GUI Programmierung (X, KDE&#x2F;QT, GNOME&#x2F;GTK)]]></title><description><![CDATA[Du musst dich erst einmal entscheiden, mit welcher Programmiersprache du Programme erstellen möchtest:
C oder C++ ?
Die GTK Bibltiohek und die darauf aufbauenden GNOME Bibliotheken kannst du von C aus verwenden. Für C++ existiert mit GTK-- allerdings ein Wrapper.
Die Qt Bibliothek und die darauf aufbauenden KDE Bibliotheken kannst du von C++ aus verwenden. Es existiert keine Möglichkeit, diese Bibliotheken von reinem C aus direkt zu verwenden.
Zur Entscheidung KDE oder GNOME:
KDE Programme integrieren sich sehr gut in den KDE Desktop (Theme Einstellungen, etc.) und GNOME Programme integrieren sich sehr gut in den GNOME Desktop.
Sofern du die notwendigen KDE Bibiotheken installierst, kannst du natürlich auch KDE Applikationen unter GNOME ablaufen lassen. Dito für GNOME Applikationen unter KDE. Allerdings ist dann die Integration in den Desktop nicht gegeben, d.h. es wird z.B. dein GNOME Theme oder deine Desktop Farbeinstellungen nicht auf die KDE Applikation angewendet.
Die Qt Bibliothek wird von TrollTech bereits mit vollständiger Dokumentation und mit Tutorial ausgeliefert. Online verfügbar unter http://doc.trolltech.com/3.1/index.html .
Für KDE wirst du bei http://developer.kde.org/ fündig werden und für GNOME schaust du bei http://developer.gnome.org/ .
Wenn du eher einen toten Baum bevorzugst:
GNOME 2.0. Das Entwickler- Handbuch.
Gnome 2.0 | ISBN: 3898421821
KDE- und Qt-Programmierung. GUI-Entwicklung für Linux
KDE- und Qt-Programmierung | ISBN: 3827314771
Das QT-Buch. Portable GUI Programmierung unter Linux/UNIX und Windows
Das Qt-Buch | ISBN: 3934678769
]]></description><link>https://www.c-plusplus.net/forum/topic/39515/gui-programmierung-x-kde-qt-gnome-gtk</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39515/gui-programmierung-x-kde-qt-gnome-gtk</guid><dc:creator><![CDATA[Descartes]]></dc:creator><pubDate>Sat, 17 May 2003 16:08:00 GMT</pubDate></item><item><title><![CDATA[random device]]></title><description><![CDATA[
Original erstellt von fsd:
**Hi!
Ist das random-device auf allen Un*ces /dev/random bzw. /dev/urandom? Wie siehts auf FreeBSD aus? Und auf GNU/Hurd?
Gibt es vielleicht irgendwo eine Tabelle?
Danke!
MFG fsd.**

Inhalt und Aufbau der beiden Verzeichnisse /dev und /proc sind sehr stark vom jeweils verwendeten Unix Betriebssystem abhängig.
GNU/Linux:
Auszug aus der Manpage random(4):
&quot;The character special files /dev/random and /dev/urandom (present since Linux 1.3.30) provide an interface to the kernel's random number generator. File /dev/random has major device number 1 and minor device number 8. File /dev/urandom has major device number 1 and minor device number 9.&quot;
GNU/Hurd:
&quot;This is a port of the Linux /dev/{,u}random device driver, it is still
incomplete (lacks the in-kernel entropy gathering), atm. it only
generates randomness of the same order as /dev/random under Linux, when
the entropy pool is empty.&quot;
Quelle: http://mel.interspace.dk/~sune/hurd/entropy.html
FreeBSD/NetBSD/OpenBSD:
&quot;The *BSD's (Net/Free/Open) support both /dev/random and
/dev/urandom.&quot;
&quot;In NetBSD, these devices aren't provided in the default (generic) kernel. You
have to compile a kernel with the &quot;pseudo-device rnd&quot; turned on, then
boot with that kernel, and as root do a &quot;MAKEDEV urandom&quot; in the /dev
directory.&quot;
Sun Solaris:
Quelle: http://sunsolve.sun.com/pub-cgi/retrieve.pl?doc=fsrdb/27606
&quot;Solaris [TM] Operating Environment releases before Solaris 9 come unbundled with support for a /dev/random device. Starting with Solaris 9 the /dev/random feature has been integrated.
Update for Solaris 8:
On march, 28th 2002 SUN has released the feature patch 112438-01 which includes /dev/random support for Solaris 8. This patch is available from SunSolve.
&quot;
HP-UX:
&quot;Neither /dev/random nor /dev/urandom exist on HP-UX. Actually, the only
platform which seems to provide them are Linux systems. The stating about
the POSIX-conformity turned out to be wrong. /dev/random conforms to RFC
1750, which is of memo status.&quot;
IBM AIX:
&quot;I am using IBM AIX System and DO NOT have /dev/random device.&quot;
Digital Tru64:
&quot;... doesn't have a /dev/random device.&quot;
VMS:
&quot;We have no /dev/random to get strong random numbers on VMS.&quot;
BeOS:
dev-random-wise: A /dev/random driver for BeOS.
http://www.bebits.com/app/2740
Apple Mac OS X:
&quot;10.1 (Codename &quot;Puma&quot;) finally has /dev/random and /dev/urandom.&quot;
Plan9 + Ultrix:
Anscheinend existieren die Devices /dev/{,u}random
Auszug aus einem OpenSSH Readme:
&quot;If you are building OpenSSH on a Unix which lacks a kernel random
number pool (/dev/random), you will need to install EGD ( http://egd.sourceforge.net/ ).&quot;
OpenSSH 情報
http://www.unixuser.org/%7Eharuyama/security/openssh/index.html
A Solaris kernel module to emulate /dev/random and /dev/urandom known from Linux in Solaris.
http://www.cosy.sbg.ac.at/~andi/SUNrand/
]]></description><link>https://www.c-plusplus.net/forum/topic/39507/random-device</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39507/random-device</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Sun, 27 Apr 2003 18:38:00 GMT</pubDate></item><item><title><![CDATA[Wo finde ich Software XYZ oder ein Software Tool XYZ?]]></title><description><![CDATA[freshmeat.net - die Unix Software Suchmaschine
FSF/UNESCO Free Software Directory
Tuxfinder - Packet suchmaschine
RPMfind - Suchmaschine für RPM Packete
apt-get.org - Suchmaschine für Debian Packete (auch auf alternativen apt-get-Quellen)
http://www.google.de (ich weiss ist ein dummer Link, aber viele User benutzen ihn nicht :o )
SourceForge - die größte OpenSource Software Platform
]]></description><link>https://www.c-plusplus.net/forum/topic/39500/wo-finde-ich-software-xyz-oder-ein-software-tool-xyz</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39500/wo-finde-ich-software-xyz-oder-ein-software-tool-xyz</guid><dc:creator><![CDATA[rüdiger]]></dc:creator><pubDate>Thu, 29 Aug 2002 19:18:00 GMT</pubDate></item><item><title><![CDATA[Lokale Benutzerdatenbank unter Unix &#x2F; Linux]]></title><description><![CDATA[Thema: Wie mache ich mir die lokale Benutzerdatenbank unter Unix / Linux zunutze?
Für ein größeres, systemnahes Projekt unter Linux benötigte ich eine Benutzerdatenbank. Da es aber
weit aus mehr Administrationsaufwand macht, die eigene Datenbank synchron mit der lokalen Userdatenbank
unter Unix / Linux zu halten, habe ich mich entschlossen, eine Klasse zu schreiben, die mir einfachen
und sicheren Zugriff auf das Benutzersystem gibt. Im folgenden setze ich gewisse Übung mit dem Umgang
mit Unix / Linux voraus.
In diesem FAQ Beitrag geht es um:

Wie ist das Benutzersystem von Unix / Linux aufgebaut?
Wie werte ich die Informationen aus?
Die Klasse FUnixpasswords
Was noch zu tun ist
Beispiele
Anhang (Vollst. Implementierung der Klasse)

1) Wie ist das Benutzersystem von Unix / Linux aufgebaut?
Die Benutzer werden unter Unix / Linux (ich werde im folgenden nur noch von Linux sprechen) mit
sehr detaillierten Informationen gespeichert. Die wichtigsten Merkmale sind: Name, Passwort,
UID (Benutzernummer, einmalig auf dem System), GID (Nummer der Gruppe, der er angehört),
Heimatverzeichnis und Shell (oder ein anderes Programm. Dieses wird aufgerufen, wenn sich der
Benutzer einloggt). Diese und weitere Informationen werden in 2 Dateien gespeichert, die
üblicherweise einen festen Platz im System haben: /etc/passwd und /etc/shadow. Des weiteren
finden wir noch die Datei /etc/group.
Die /etc/passwd ist aus Zeilen aufgebaut, die vom Gerüst so aussehen:
BenutzernameUID:GID:Kommentar:Heimatverzeichnis:Programm
Korbinian500Korbinians Account:/home/korbinian:/bin/bash
An der Stelle, an der x steht, kann auch nichts stehen. Dann hat der Benutzer kein Passwort (selten, da sehr unsicher). Steht ein 'x', so wird das Passwort
in der /etc/shadow gespeichert.
Die /etc/shadow besteht aus solchen Zeilen:
Benutzername:VerschlüsseltesPasswort:LetzteÄnderung:MinGültigkeit:MaxGültigkeit:Vorwarnung:Verfall:UnbenutztesFlag
Wichtig hierbei ist, dass der Name der selbe ist, wie in der /etc/passwd. Die letzte
Änderung wird in Tagen seit dem 01.01.1970 (offizieller Entstehungstag von Unix) gezählt.
Min- und MaxGültigkeit werden in Tagen angegeben. Damit kann man kontrollieren, dass kein
Account länger besteht als erlaubt (oft wichtig für Netzwerkanwendungen). Vorwarnzeit
(in Tagen) gibt die Zeitspanne an, in der der Benutzer ermahnt wird, sein Passwort zu ändern. Nach dem
Ablauf des bei Verfall angegebenen Datums ist der Account verloren, der Sysadmin muss ihn wieder
herstellen. Die letzte Flag ist noch unbenutzt.
Die /etc/group enthält eine Zuordnungstabelle der Gruppen.
Gruppenname:GruppenPasswort:NumerischeID:Liste_der_Benutzer
users100:korbinian, sebastian, barbara
Das Passwort ist unbenutzt (habe noch kein System gesehen, wo es verwendet wird, drum lass
ich es außer acht). Wenn sich jetzt ein Benutzer anmeldet (login), dann macht das Programm folgendes:
Es sucht erst nach einem Eintrag in der /etc/passwd, in dem der eingegebene Name steht, und dann
nach der entsprechenden Zeile in /etc/shadow. Nun wird das eingegebene Passwort verschlüsselt
(dazu später mehr) und mit dem aus /etc/shadow verglichen. Stimmen sie überein, wird der Anmeldevorgang
fortgesetzt, andernfalls der Zugriff verweigert. Anschließend wird das Programm ausgeführt, dass in
/etc/passwd spezifiziert worden ist (meist /bin/bash).
2) Wie werte ich die Informationen aus?
Nachdem wir jetzt einen Überblick über die Funktion der Benutzerverwaltung von Linux haben,
können wir daran gehen, diese Dateien auszuwerten. Das grobe Prinzip ist einfach: Zeilenweises
Auslesen der 3 Dateien und sichern der Informationen im Speicher. Dann kann man sich User zeigen
lassen, bearbeiten und neu erstellen. Anschließend müssen diese 3 Dateien wieder neu geschrieben
werden, damit die Änderungen wirksam werden.
VORSICHT: Obwohl die Funktionsweise, die ich hier vorstelle, einwandfrei funktioniert,
gebe ich keine Garantie dafür ab, dass sie auf anderen Systemen nicht funktioniert. Leichtsinnige
Änderungen in den Dateien (z.B.: User root löschen) sind dringendst zu vermeiden!
3) Die Klasse FUnixpasswords
Diese Klasse bringt nun alles (Auslesen, Speichern, Bearbeite/Lösche/Neuanlegen,
Zurückschreiben) unter einen Hut. Sie ist getestet und funktioniert. Ich will im Folgenden die
Schritte erläutern, wie ich zu diesem Ergebnis gekommen bin. Dazu erst mal einige theoretische
Überlegungen (sollte man übrigens immer erst machen 
Was muss unsere Klasse können, wenn sie fertig ist?
- Schneller, sicherer Zugriff auf vorhandene Benutzer
- Leichtes ändern von Benutzerdaten
- Debug Möglichkeiten
Wie realisiert man einen schnellen Zugriff? Genau, man speichert einfach die ganzen Daten im RAM.
Soweit so gut. Wäre da nicht das Problem: Was ist, wenn jemand parallel zu uns in den Dateien
arbeitet? Dann machen wir alles kaputt. Ergo: wir bauen eine Kontrollfunktion ein, die
überprüft, ob die Datei geändert worden ist. Diese wird dann vor jeder Aktion aufgerufen,
die z.B.: Benutzerinformationen haben will, und lädt, falls erforderlich, die Dateien neu
in den Speicher.
Sicherer Zugriff? Ganz einfach: Idiotensicher programmieren. Will heißen dass sämtliche
Änderungen an Benutzerdatem im Speicher über Set Methoden gemacht werden, das verschafft
Kontrolle über Usereingaben. Debug Möglichkeiten baut man am besten mit Include Guards (DEBUG) ein.
Die kann man dann ganz locker dem g++ mit der Option -DDEGBUG übergeben.
Ein letzter Schritt Theorie noch: Die Benutzerdaten speichert man am besten in einer
separaten Klasse, welche die einzelnen Felder aus den Dateien (Name, Passwort, etc) speichert.
Um einen schnellen Zugriff zu bekommen, werden die Instanzen dieser Klassen in einer Map gespeichert,
die dann über den Namen des Users als Key (wer die map nicht kennt, www.cppreference.com)) schnell den zugehörigen User liefert.
Jetzt aber mal etwas Code!
funixpasswords.h:
/******************************************************************************/
/* Library: FUnixpasswords                                                    */
/* -------------------------------------------------------------------------  */
/* Description: This library gives access to the unix user files to           */
/* have an easy and secure port for administrating the                        */
/* system. It is designed for the use with GUIs and programs                  */
/* the require the authentification system of a local unix                    */
/* system.                                                                    */
/* -------------------------------------------------------------------------  */
/* Files: funixpasswords.h (this one), funixpasswords.cpp                     */
/* Version: 0.8                                                               */
/* Author: Korbinian Riedhammer                                               */
/* email: faulerhund@faulerhund.net                                           */
/* www: http://www.faulerhund.net                                              */
/* License: GPL                                                               */
/******************************************************************************/
#ifndef __FUNIXPASSWORDS__    
#define __FUNIXPASSWORDS__
#include &lt;map&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;fstream&gt;
#include &lt;sys/types.h&gt;    // Brauchen wir für die Überprüfung
#include &lt;sys/stat.h&gt;     // des letzten Schreibzugriffs
#include &lt;sys/time.h&gt;
#include &lt;time.h&gt;
#ifdef DEBUG              // Zum Debuggen brauchen wir Ausgabe!
#include &lt;iostream&gt;
#endif
class FUserentry {  // Diese Klasse speichert alle Informationen über einen user
    public:        
        FUserentry(std::string passwdline, std::string shadowline);
        bool validatepasswd(std::string plaintext);
        // Set/Get Methoden
        std::string get_passwdline() const; // Zum Neuschreiben der passwd
        std::string get_shadowline() const; // Zum Neuschreiben der shadow
        std::string get_name() const { return m_name; }
        std::string get_cryptedpasswd() const { return m_crypted_passwd; }
        std::string get_uid() const { return m_uid; }
        std::string get_gid() const { return m_gid; }
        std::string get_comment() const { return m_comment; }
        std::string get_homedir() const { return m_homedir; }
        std::string get_shell() const { return m_shell; }
        void set_passwd(std::string plaintextpasswd);
        void set_uid(std::string uid) { m_uid = uid; }
        void set_gid(std::string gid) { m_gid = gid; }
        void set_comment(std::string comment) { m_comment = comment; }
        void set_homedir(std::string homedir) { m_homedir = homedir; }
        void set_shell(std::string shell) { m_shell = shell; }
        void mark_deleted() { is_deleted = true; }
    private:
        // Userdaten
        FUserentry() {}    // Verhindert ein &quot;normales&quot; erstellen
        std::string m_name; // Benutzername
        std::string m_passwd; // Passwort, unverschlüsselt (meist 'x')
        std::string m_crypted_passwd; // Passwort, verschlüsselt
        std::string m_uid; // User ID, numerischer Wert
        std::string m_gid; // Gruppen ID, numerischer Wert
        std::string m_comment; // Kommentar
        std::string m_homedir; // Heimatverzeichnis
        std::string m_shell; // Shell
        // Weitere Einträge in shadow, jedoch noch nicht bearbeitbar in dieser Klasse
        std::string m_lastchange;
        std::string m_min;
        std::string m_max;
        std::string m_warn;
        std::string m_inactive;
        std::string m_expire;
        std::string m_flag;
        // Weitere Flags/Variablen/Funktionen
        bool is_deleted; // Soll der User gelöscht werden?
        void newencrypt(std::string &amp;plaintext);  // soll ein neues Passwort erstellt werden?
        void oldencrypt(std::string &amp;plaintext);  // soll ein altes überprüft werden?
        int getrnd(int x, int y);                 // erstellt eine Zufallszahl (für Verschlüsseung)
}; 

typedef map &lt; std::string, FUserentry &gt; UserMap;
typedef map &lt; std::string, std::string &gt; GroupMap;

class FUnixpasswords { // Kontrollstruktur
    public:
        FUnixpasswords();
        FUnixpasswords(std::string passwd, std::string group, std::string shadow);
        bool validate_user(std::string name, std::string passwd);
        FUserentry &amp;get_user(std::string name, bool &amp;flag);
        int applychanges();
        #ifdef DEBUG
        void displaymap();
        #endif
        std::string gid2group(std::string gid) { return groups[gid]; }
    private:
        std::string m_file_passwd;
        std::string m_file_group;
        std::string m_file_shadow;
        int refresh();
        bool is_refresh_needed();
        void setlastwrite();
        time_t m_lastwrite_passwd;
        time_t m_lastwrite_shadow;
        time_t m_lastwrite_group;

        UserMap users; 
        GroupMap groups; // groups[&quot;gid&quot;] == &quot;name&quot;, z.B.: groups[&quot;0&quot;] == &quot;root&quot;
};
#endif

Jetzt langsam. Ich geh jetzt nur auf die wichtigsten Funktionen und Abläufe ein. Freaks können
sich dann unten die ganze Implementation anschauen (ist aber nicht so gut kommentiert  An die
Kritiker, die mosern, dass Weder CpyCtor noch Zuweisungsop fehlen: Da brauchts keinen speziellen 
Die Klasse FUserentry ist weitgehend selbsterklärend. Hier werden einfach alle Infos über diesen
User zusammengetragen und gespeichert (wie bei der Stasi ;).Im Konstruktor wird ordentlich
geparst (siehe Implementation) und Anschließend gespeichert. Wichtig: Der Defaultkonstruktor wurde
unterbunden. Nur wer über (gültige!) Zeilen aus /etc/passwd und /etc/shadow verfügt,
darf auch erstellen. Das aber macht Kontrollstruktur FUnixpasswords. Die Sicherungsfunktionen bei
FUserentry sind noch nicht eingebaut, da das nicht so wichtig ist, dort zu kontrollieren,
weil die Informationen eigentlich nur von FUnixpasswords kommen , und damit korrekt sein sollten.
[cpp]bool validatepasswd(std::string passwd); [/code]
Diese Funktion übernimmt für uns das überprüfen der Benutzerdaten. Sie nimmt das im Plaintext
vorliegende Passwort, verschlüsselt es, und überprüft es mit dem Vorhandenen.
Bei Übereinstimmung true, sonst false.
[cpp]void mark_deleted();[/code]
Einmal aufgerufen, setzt sie das Lösch-Flag auf true, und der User wird nicht wieder in die
Datenbank zurückgeschrieben. Damit wird er gelöscht.
[cpp]
void newencrypt(std::string &amp;plaintext);
void oldencrypt(std::string &amp;plaintext);[/code]
Diese Funktionen übernehmen die Verschlüsselung von Plaintext. Sie benutzen den Unix Befehl
char *crypt(const char*, char *); siehe [man]crypt(3)[/man]
Die Klasse FUnixpasswords ist die Kontrollstruktur. Sie erhält über den Konstruktor die
Positionen der Dateien passwd, shadow und group (Default: /etc/passwd, /etc/shadow, /etc/group).
Sie liest dann die Dateien aus, ordnet nach Namen zu, und füllt damit die Map auf.
Wichtig: solange man nur Lesezugriff macht (also nicht applychanges aufruft)
passiert diesen Dateien nichts.
Die Funktion validate_user übernimmt das schnelle Überprüfen von Benutzerdaten. Über get_user
bekommt man eine Referenz auf den angegebenen User. Falls dieses fehlschlägt (der Benutzer
also nicht vorhanden ist) ist die übergebene Flag false (SEHR wichtig, wg Speicherfehlern...).
Wie das Funktioniert, sieht man am besten im Beispiel unten.
Die Funktion applychanges
speichert die aktuellen Daten in die Dateien zurück.
displaymap ist für Debug Zwecke, und zeigt den kompletten Inhalt der Map, also
damit alle user auf dem System an.
4) Was noch zu tun ist
Es fehlt noch ne ganze Menge in der Klasse:
- Auflistungssystem aller User (über const_iteratoren)
- Gruppenadminsystem
- Neuerstellen der User, Defaultparameter (sind nämlich ganz schön viele 
- Sicherungsfunktionen, die vor Speicherlecks und Fehlinputs schützen
- z.B. Implementation von [man]getpwnam(3)[/man]
5) Beispiele
Ein Login Klon:
[cpp]
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &quot;funixpasswords.h&quot;
using namespace std;
int main(int argc, char **argv)
{
FUnixpasswords pwds(&quot;/etc/passwd.old&quot;, &quot;/etc/group.old&quot;, &quot;/etc/shadow.old&quot;);
// Zur Sicherheit nur die Backupdateien!
string name, pwd;
cout &lt;&lt; &quot;Geben Sie ihren Loginnamen an: &quot;;
cin &gt;&gt; name;
cout &lt;&lt; &quot;Geben Sie ihr Passwort ein: &quot;;
cin &gt;&gt; pwd;
if ( !pwds.validate_user(name, pwd) )
{
cout &lt;&lt; &quot;Falsche Daten.&quot; &lt;&lt; endl;
return 0;
}
cout &lt;&lt; &quot;OK&quot; &lt;&lt; endl;
// Hier müsste man noch die Shell ausführen, das spar ich mir 
return 1;
}[/cpp]
Ein passwd Klon:
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &quot;funixpasswords.h&quot;
using namespace std;

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        cout &lt;&lt; &quot;usage: &quot; &lt;&lt; argv[0] &lt;&lt; &quot; username&quot; &lt;&lt; endl;
        return 0;
    }
    FUnixpasswords pwds(&quot;/etc/passwd.old&quot;, &quot;/etc/group.old&quot;, &quot;/etc/shadow.old&quot;);
    // Zur Sicherheit nur die Backupdateien!
    string pwd_old, pwd_new1, pwd_new2;
    cout &lt;&lt; &quot;Altes Passwort eingeben: &quot;;
    cin &gt;&gt; pwd_old;
    cout &lt;&lt; &quot;Neues Passwort eingeben: &quot;;
    cin &gt;&gt; pwd_new1;
    cout &lt;&lt; &quot;Passwort eingeben (nochmal): &quot;;
    cin &gt;&gt; pwd_new2;
    if (pwd_new1 != pwd_new2)
    {
        cout &lt;&lt; &quot;Passwörter stimmen nicht überein&quot; &lt;&lt; endl;
        return 0;
    }
    if ( !pwds.validate_user(argv[1], pwd_old) )
    {
        cout &lt;&lt; &quot;Falsche Daten.&quot; &lt;&lt; endl;
        return 0;
    }
    bool flag;
    FUserentry &amp;user = pwds.get_user(argv[1], flag);
    if (!flag)
    {
        cout &lt;&lt; &quot;Unbekannter Benutzer&quot; &lt;&lt; endl;
        return 0;
    }
    user.setpwd(pwd_new1);
    pwds.applychanges();
    cout &lt;&lt; &quot;Passwort geändert&quot; &lt;&lt; endl;
    return 1;
}

Welche Benutzer sind auf dem System? (kompilieren mit -DDEBUG, spuckt ausserdem noch die Arbeitsgänge beim Parsen aus)
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &quot;funixpasswords.h&quot;
using namespace std;

int main(int argc, char **argv)
{
    FUnixpasswords pwds; // Hier kann man bedenkenlos die echten Dateien nehmen, es wird nicht geschrieben.
    pwds.displaymap();
    return 1;
}

6) Anhang (Vollst. Implementierung der Klasse)
/******************************************************************************/
/*  Library:        FUnixpasswords                                            */
/*  ------------------------------------------------------------------------- */
/*  Description:    This library gives access to the unix user files to       */
/*                  have an easy and secure port for administrating the       */
/*                  system. It is designed for the use with GUIs and programs */
/*                  the require the authentification system of a local unix   */
/*                  system.                                                   */
/*  ------------------------------------------------------------------------- */
/*  Files:          funixpasswords.h, funixpasswords.cpp (this one)           */
/*  Version:        0.8                                                       */
/*  Author:         Korbinian Riedhammer                                      */
/*                  email: faulerhund@faulerhund.net                          */
/*                  www:   http://www.faulerhund.net                           */
/*  License:        GPL                                                       */
/******************************************************************************/
#include &quot;funixpasswords.h&quot;
#include &lt;map&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;fstream&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;unistd.h&gt;
#include &lt;crypt.h&gt;
#ifdef DEBUG
#include &lt;iostream&gt;
#endif
using namespace std;
FUnixpasswords::FUnixpasswords() 
 : m_file_passwd(&quot;/etc/passwd&quot;), m_file_group(&quot;/etc/group&quot;), m_file_shadow(&quot;/etc/shadow&quot;)
{
    setlastwrite();
    refresh();
    srand((unsigned)time(NULL));
}
FUnixpasswords::FUnixpasswords(string passwd, string group, string shadow) 
 : m_file_passwd(passwd), m_file_group(group), m_file_shadow(shadow)
{
    setlastwrite();
    refresh();
}
bool FUnixpasswords::is_refresh_needed()
{
    struct stat stat_passwd, stat_shadow, stat_group;
    stat(m_file_passwd.c_str(), &amp;stat_passwd);
    stat(m_file_shadow.c_str(), &amp;stat_shadow);
    stat(m_file_group.c_str(), &amp;stat_group);
    if (m_lastwrite_passwd != stat_passwd.st_mtime)   return true;
    if (m_lastwrite_shadow != stat_shadow.st_mtime)   return true;
    if (m_lastwrite_group != stat_group.st_mtime)     return true;
    return false;
}
void FUnixpasswords::setlastwrite()
{
    struct stat stat_passwd, stat_shadow, stat_group;
    stat(m_file_passwd.c_str(), &amp;stat_passwd);
    stat(m_file_shadow.c_str(), &amp;stat_shadow);
    stat(m_file_group.c_str(), &amp;stat_group);
    m_lastwrite_passwd = stat_passwd.st_mtime;
    m_lastwrite_shadow = stat_shadow.st_mtime;
    m_lastwrite_group = stat_group.st_mtime;
}
bool FUnixpasswords::validate_user(string name, string passwd)
{
    if (is_refresh_needed())    refresh();
    if (users.find(name) == users.end())    return false;
    return users[name].validatepasswd(passwd);
}
FUserentry &amp;FUnixpasswords::get_user(string name, bool &amp;flag)
{
    if (is_refresh_needed())
    {
        #ifdef DEBUG
        cout &lt;&lt; &quot;Refresh erforderlich&quot; &lt;&lt; endl;
        #endif
        refresh();
    }
    flag = (users.find(name) != users.end());
    return users[name];
}
bool FUnixpasswords::updateuser(std::string name, FUserentry &amp;user)
{
    if (name != user.get_name())    return false;
    if (users.find(name) == users.end())    return false;
    users[name] = user;
    return true;
}
int FUnixpasswords::applychanges()
{
    ofstream fpasswd(m_file_passwd.c_str()), fshadow(m_file_shadow.c_str());
    if (!fpasswd.is_open() ||!fshadow.is_open())    return -1;
    for (UserMap::const_iterator iter = users.begin(); iter != users.end(); iter++)
    {
        fpasswd &lt;&lt; iter-&gt;second.get_passwdline() &lt;&lt; endl;
        fshadow &lt;&lt; iter-&gt;second.get_shadowline() &lt;&lt; endl;
    }
    fpasswd.close();
    fshadow.close();
}
int FUnixpasswords::refresh()
{
    users.clear();
    groups.clear();
    map &lt; string , string &gt; passwdlines, shadowlines;
    vector &lt; string &gt; names;
    ifstream fshadow(m_file_shadow.c_str()), fpasswd(m_file_passwd.c_str()), fgroup(m_file_group.c_str());
    if (!fshadow.is_open() ||!fpasswd.is_open() || !fgroup.is_open())   return 0;
    #ifdef DEBUG
    int zeilencounter = 0;
    cout &lt;&lt; &quot;DEBUG: Lese &quot; &lt;&lt; m_file_passwd &lt;&lt; &quot; aus...&quot; &lt;&lt; endl;
    #endif
    while (!fpasswd.eof())
    {
        #ifdef DEBUG
        zeilencounter++;
        #endif
        string zeile, name;
        getline(fpasswd, zeile);
        if (zeile.length() &lt; 1) continue;
        for (int i = 0; i &lt; zeile.length(); i++)
        {
            if (zeile[i] == ':')    break;
            name += zeile[i];
        }
        names.push_back(name);
        passwdlines[name] = zeile;
        #ifdef DEBUG
        cout &lt;&lt; &quot;DEBUG: &quot; &lt;&lt; m_file_passwd &lt;&lt; &quot;, Zeile &quot; &lt;&lt; zeilencounter &lt;&lt; &quot;: Name: &quot; &lt;&lt; name 
        &lt;&lt; &quot; Zeile: &quot; &lt;&lt; zeile &lt;&lt; endl;
        cout &lt;&lt; &quot;DEBUG: passwdlines[&quot; &lt;&lt; name &lt;&lt; &quot;] == &quot; &lt;&lt; passwdlines[name] &lt;&lt; endl;
        #endif
    }
    #ifdef DEBUG
    cout &lt;&lt; &quot;DEBUT: ...fertig&quot; &lt;&lt; endl;
    zeilencounter = 0;
    cout &lt;&lt; &quot;DEBUG: Lese &quot; &lt;&lt; m_file_shadow &lt;&lt; &quot; aus...&quot; &lt;&lt; endl;
    #endif
    while (!fshadow.eof())
    {
        #ifdef DEBUG
        zeilencounter++;
        #endif
        string zeile, name;
        getline(fshadow, zeile);
        if (zeile.length() &lt; 1) continue;
        for (int i = 0; i &lt; zeile.length(); i++)
        {
            if (zeile[i] == ':')    break;
            name += zeile[i];
        }
        shadowlines[name] = zeile;
        #ifdef DEBUG
        cout &lt;&lt; &quot;DEBUG: &quot; &lt;&lt; m_file_shadow &lt;&lt; &quot;, Zeile &quot; &lt;&lt; zeilencounter &lt;&lt; &quot;: Name: &quot; &lt;&lt; name 
        &lt;&lt; &quot; Zeile: &quot; &lt;&lt; zeile &lt;&lt; endl;
        cout &lt;&lt; &quot;DEBUG: shadowlines[&quot; &lt;&lt; name &lt;&lt; &quot;] == &quot; &lt;&lt; shadowlines[name] &lt;&lt; endl;
        #endif
    }
    #ifdef DEBUG
    cout &lt;&lt; &quot;DEBUG: ...fertig&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;DEBUG: Lese &quot; &lt;&lt; m_file_group &lt;&lt; &quot; aus...&quot; &lt;&lt; endl;
    #endif
    while (!fgroup.eof())
    {
        string zeile, name, gid;
        getline(fgroup, zeile);
        if (zeile.length() &lt; 1) continue;
        int i;
        for (i = 0; i &lt; zeile.length(); i++)
        {
            if (zeile[i] == ':')    break;
            name += zeile[i];
        }
        ++i;
        for (; i &lt; zeile.length(); i++) if (zeile[i] == ':')    break;
        ++i;
        for (; i &lt; zeile.length(); i++)
        {
            if (zeile[i] == ':')    break;
            gid += zeile[i];
        }
        groups[gid] = name;
        #ifdef DEBUG
        cout &lt;&lt; &quot;DEBUG: name: &quot; &lt;&lt; name &lt;&lt; &quot; gid: &quot; &lt;&lt; gid &lt;&lt; endl;
        #endif
    }
    #ifdef DEBUG
    cout &lt;&lt; &quot;DEBUG: ...fertig&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;DEBUG: Namensliste start&quot; &lt;&lt; endl;
    for (int i = 0; i &lt; names.size(); i++)
        cout &lt;&lt; &quot;DEBUG: *** &quot; &lt;&lt; names[i] &lt;&lt; endl;
    cout &lt;&lt; &quot;DEBUG: Namensliste ende&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;DEBUG: Speichere in Klassenweiter Map...&quot; &lt;&lt; endl;
    #endif
    for (int i = 0; i &lt; names.size(); i++)
    {
        FUserentry tmp(passwdlines[names[i&rsqb;&rsqb;, shadowlines[names[i&rsqb;&rsqb;);
        users[names[i&rsqb;&rsqb; = tmp;
    }
    #ifdef DEBUG
    cout &lt;&lt; &quot;DEBUG: ...fertig&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;DEBUG: Ausgabe der eingelesenen User...&quot; &lt;&lt; endl;
    displaymap();
    cout &lt;&lt; &quot;DEBUG: ...fertig&quot; &lt;&lt; endl;
    #endif
    return 1;
}
#ifdef DEBUG
void FUnixpasswords::displaymap()
{
    cout &lt;&lt; &quot;DEBUG: Beginn Inhalt der Map users&quot; &lt;&lt; endl;
    for (UserMap::const_iterator iter = users.begin(); iter != users.end(); iter++)
    {
         string name = iter-&gt;first;
         FUserentry tmp = iter-&gt;second;
         cout &lt;&lt; &quot;DEBUG: user &quot; &lt;&lt; name &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** name: &quot; &lt;&lt; tmp.get_name() &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** crypted pwd: &quot; 
              &lt;&lt; tmp.get_cryptedpasswd() &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** uid: &quot; &lt;&lt; tmp.get_uid() &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** gid: &quot; &lt;&lt; tmp.get_gid() &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** comment: &quot; &lt;&lt; tmp.get_comment() &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** homedir: &quot; &lt;&lt; tmp.get_homedir() &lt;&lt; endl;
         cout &lt;&lt; &quot;DEBUG: ** shell: &quot; &lt;&lt; tmp.get_shell() &lt;&lt; endl;
    }
    cout &lt;&lt; &quot;DEBUG: Ende Inhalt der Map users&quot; &lt;&lt; endl;
}
#endif
FUserentry::FUserentry(string passwdline, string shadowline)
{
    // Zeile aus passwd parsen -&gt; name, uid, gid, comment, homedir, shell
    int i = 0;
    for (;; i++)
    {
        if (passwdline[i] == ':')   { ++i; break; }
        m_name += passwdline[i];
    }
    for (;; i++)
    {
        if (passwdline[i] == ':')   { ++i; break; }
        m_passwd += passwdline[i];
    }
    for (;; i++)
    {
        if (passwdline[i] == ':')   { ++i; break; }
        m_uid += passwdline[i];
    }
    for (;; i++)
    {
        if (passwdline[i] == ':')   { ++i; break; }
        m_gid += passwdline[i];
    }
    for (;; i++)
    {
        if (passwdline[i] == ':')   { ++i; break; }
        m_comment += passwdline[i];
    }
    for (;; i++)
    {
        if (passwdline[i] == ':')   { ++i; break; }
        m_homedir += passwdline[i];
    }
    for (;i &lt; passwdline.length(); i++)
    {
        m_shell += passwdline[i];
    }
    // Zeile aus shadow parsen
    i = 0;
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; } // Benutzer interessiert nicht
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_crypted_passwd += shadowline[i];
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_lastchange += shadowline[i];
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_min += shadowline[i];
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_max += shadowline[i];
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_warn += shadowline[i];
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_inactive += shadowline[i];
    }
    for (;; i++)
    {
        if (shadowline[i] == ':')   { ++i; break; }
        m_expire += shadowline[i];
    }
    for (;i &lt; shadowline.length(); i++)
    {
        m_flag += shadowline[i];
    }
}
string FUserentry::get_passwdline() const
{
    string zeile = m_name;
    zeile += ':';
    zeile += m_passwd;
    zeile += ':';
    zeile += m_uid;
    zeile += ':';
    zeile += m_gid;
    zeile += ':';
    zeile += m_comment;
    zeile += ':';
    zeile += m_homedir;
    zeile += ':';
    zeile += m_shell;
    return zeile;
}
string FUserentry::get_shadowline() const
{
    string zeile = m_name;
    zeile += ':';
    zeile += m_crypted_passwd;
    zeile += ':';
    zeile += m_lastchange;
    zeile += ':';
    zeile += m_min;
    zeile += ':';
    zeile += m_max;
    zeile += ':';
    zeile += m_warn;
    zeile += ':';
    zeile += m_inactive;
    zeile += ':';
    zeile += m_expire;
    zeile += ':';
    zeile += m_flag;
    return zeile;
}
bool FUserentry::validatepasswd(string plaintext)
{
    oldencrypt(plaintext);
    return (plaintext == m_crypted_passwd);
}
void FUserentry::set_passwd(string plaintext)
{
    newencrypt(plaintext);
    m_crypted_passwd = plaintext;
}
void FUserentry::newencrypt(string &amp;plaintext)
{
    string set = &quot;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./&quot;;
    string plain = plaintext;
    char seed[] = {set[getrnd(0, (set.length()-1))], set[getrnd(0, (set.length()-1))] };
    char *pwd = crypt(plaintext.c_str(), seed);
    plaintext = pwd;
}
void FUserentry::oldencrypt(string &amp;plaintext)
{
    string plain = plaintext;
    char seed[] = {m_crypted_passwd[0], m_crypted_passwd[1]};
    char *pwd = crypt(plaintext.c_str(), seed);
    plaintext = pwd;
}
int FUserentry::getrnd(int x, int y)
{
    if (x &gt; y)
    {
        int tmp = y;
        y = x;
        x = tmp;
    }
    y += 1;
    return ((rand() % (y - x)) + x);
}

]]></description><link>https://www.c-plusplus.net/forum/topic/39518/lokale-benutzerdatenbank-unter-unix-linux</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39518/lokale-benutzerdatenbank-unter-unix-linux</guid><dc:creator><![CDATA[Korbinian]]></dc:creator><pubDate>Mon, 22 Jul 2002 13:26:00 GMT</pubDate></item><item><title><![CDATA[kein echo bei eingabe]]></title><description><![CDATA[Hier ist die konkrete Lösung:
/*
    password.c - Passwortabfrage ohne Echo
*/

# include &lt;stdio.h&gt;
# include &lt;unistd.h&gt;
# include &lt;fcntl.h&gt;
# include &lt;termios.h&gt;

int main()
 {
  int old_flags;
  char password[16];
  struct termios term_attr;

  if (tcgetattr(STDIN_FILENO, &amp;term_attr) != 0)
   {
    perror(&quot;password: tcgetattr() failed&quot;);
    return(1);
   }             /* alte Einst. sichern */
  old_flags = term_attr.c_lflag;
  term_attr.c_lflag &amp;= ~ECHO;
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &amp;term_attr) != 0)
    perror(&quot;password: tcsetattr() failed&quot;);

  printf(&quot;password: &quot;);
  scanf(&quot;%15s&quot;, password);
            /* Std.-Eingabe wie vorher */
  term_attr.c_lflag = old_flags;
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &amp;term_attr) != 0)
    perror(&quot;password: tcsetattr() failed&quot;);

  if (strcmp(password, &quot;secret&quot;) == 0)
    printf(&quot;\npassword accepted.\n&quot;);
  else
    printf(&quot;\nwrong password.\n&quot;);

  return(0);
 }

Das Beispiel stammt aus meinem Buch &quot;C und Linux&quot; http://home.t-online.de/home/AuM.Graefe/c_und_linux.html
]]></description><link>https://www.c-plusplus.net/forum/topic/39512/kein-echo-bei-eingabe</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39512/kein-echo-bei-eingabe</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Sun, 21 Jul 2002 19:15:00 GMT</pubDate></item><item><title><![CDATA[wie bekomm ich mein prog dazu das es als daemon läuft]]></title><description><![CDATA[@bash. Die kannte ich auch noch nicht ;), danke
]]></description><link>https://www.c-plusplus.net/forum/topic/39501/wie-bekomm-ich-mein-prog-dazu-das-es-als-daemon-läuft</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39501/wie-bekomm-ich-mein-prog-dazu-das-es-als-daemon-läuft</guid><dc:creator><![CDATA[virtual]]></dc:creator><pubDate>Tue, 16 Jul 2002 13:27:00 GMT</pubDate></item><item><title><![CDATA[Serielle Schnittstelle ansprechen]]></title><description><![CDATA[libserial - eine fertige Bibliothek für die Serielleschnittstelle
Serial Programming HOWTO
IO Port Programming HOWTO
Serial HOWTO
Serial Programming Guide for POSIX Compliant Operating Systems
Beispiel: (25.7.2002)
Ein Code von &lt;Martin&gt; aus seinem Buch &quot;C und Linux&quot;
C und Linux | ISBN: 3446224270
/*
    terminal.c - Ein- und Ausgabe ueber die serielle
                 Schnittstelle
*/

# include &lt;stdio.h&gt;
# include &lt;unistd.h&gt;
# include &lt;fcntl.h&gt;
# include &lt;termios.h&gt;

# define TERM_DEVICE &quot;/dev/ttyS0&quot;   /* = COM1 */
# define TERM_SPEED B19200      /* Bit/Sek */

int main()
 {
  int fd, old_flags;
  ssize_t length;
  char buffer[16];
  struct termios term_attr;
  fd_set input_fdset;

  if ((fd = open(TERM_DEVICE, O_RDWR)) == -1)
   {
    perror(&quot;terminal: Can't open device &quot; TERM_DEVICE);
    return(1);
   }
            /* RS232 konfigurieren */
  if (tcgetattr(fd, &amp;term_attr) != 0)
   {
    perror(&quot;terminal: tcgetattr() failed&quot;);
    return(1);
   }
  term_attr.c_cflag = TERM_SPEED | CS8 | CRTSCTS | CLOCAL;
  term_attr.c_iflag = 0;
  term_attr.c_oflag = OPOST | ONLCR;
  term_attr.c_lflag = 0;
  if (tcsetattr(fd, TCSAFLUSH, &amp;term_attr) != 0)
    perror(&quot;terminal: tcsetattr() failed&quot;);

            /* Std.-Eingabe anpassen */
  if (tcgetattr(STDIN_FILENO, &amp;term_attr) != 0)
   {
    perror(&quot;terminal: tcgetattr() failed&quot;);
    return(1);
   }
            /* alte Einst. sichern */
  old_flags = term_attr.c_lflag;
  term_attr.c_lflag &amp;= ~(ICANON | ECHO);
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &amp;term_attr) != 0)
    perror(&quot;terminal: tcsetattr() failed&quot;);

  while (1)
   {
    FD_ZERO(&amp;input_fdset);
    FD_SET(STDIN_FILENO, &amp;input_fdset);
    FD_SET(fd, &amp;input_fdset);
    if (select(fd+1, &amp;input_fdset, NULL, NULL, NULL) == -1)
      perror(&quot;terminal: select() failed&quot;);
    if (FD_ISSET(STDIN_FILENO, &amp;input_fdset))
     {
      if ((length = read(STDIN_FILENO, buffer, 16)) == -1)
        perror(&quot;terminal: read() failed&quot;);
      else
        if (buffer[0] == '\33')  /* Abbruch mit ESC */
      break;
    else
          write(fd, buffer, length);
     }
    if (FD_ISSET(fd, &amp;input_fdset))
     {
      if ((length = read(fd, buffer, 16)) == -1)
        perror(&quot;terminal: read() failed&quot;);
      else
        write(STDOUT_FILENO, buffer, length);
     }
   }
            /* Std.-Eingabe wie vorher */
  term_attr.c_lflag = old_flags;
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &amp;term_attr) != 0)
    perror(&quot;terminal: tcsetattr() failed&quot;);

  printf(&quot;Aborted.\n&quot;);
  close(fd);
  return(0);
 }

]]></description><link>https://www.c-plusplus.net/forum/topic/39504/serielle-schnittstelle-ansprechen</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39504/serielle-schnittstelle-ansprechen</guid><dc:creator><![CDATA[rüdiger]]></dc:creator><pubDate>Thu, 06 Jun 2002 19:34:00 GMT</pubDate></item><item><title><![CDATA[Bewegen in Verzeichnissen unter Unix]]></title><description><![CDATA[Thema: Bewegen in Verzeichnissen unter Linux/Unix
Was benoetigt man?
Nun grundsaetzlich kann ich nicht sagen, was du benötigst,
da es immer davon abhängt, was genau man programmieren will. Aber
ich denke, dass ich die wichtigsten Dinge zusammentragen kann.
Ich werde ein paar Funktionen vorstellen und das ganze anhand eines
Beispieles (Ein Directory kopieren) mehr erklären. Sollte ich Fehler
machen, bitte ich natürlich um Korrektur!
Okay, also was benätige ich?
Zu erst einmal muss ich feststellen können, ob es sich bei einer
Dateiart um ein Directory, eine Normale Datei (regular file) oder
eine spezielle Art einer Datei (special file) handelt.
Zu diesem Zweck gibt es drei Funktionen:
int stat ( const char *PathName, struct stat *Buffer ); [man: stat(2)]
*int fstat ( int FD, struct stat Buffer ); [man: fstat(2)]
int lstat ( const char *PathName, struct stat *Buffer ); [man: lstat(2)]
Diese Funktionen sind in der Headerdatei &lt;sys/stat.h&gt;
definiert. Ebenfalls wird die Headerdatei &lt;sys/types.h&gt;
benoetigt.
Wer ein Unixsystem nutzt, sollte darauf Acht geben, wie
die Headerdateien includiert werden, da bei manchen Unixsystemen
keine Rekursive Includierung der Headerdateien untereinander vor-
handen ist. Im o. Fall saehe eine Includierung so aus:
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;

Kurze Erlaeuterung der Funktionen:
int stat ( const char *PathName, struct stat *Buffer );
Schreibt die Attribute der Datei, die in 'PathName' spezifiziert ist,
in die Strukturvariable 'Buffer'. Handelt es sich bei der unter
'PathName' spezifizierten Datei um einen symbolischen Link, so werden
die Attribute der Datei, auf die der symbolische Link zeigt, in die
Strukturvariable 'Buffer' geschrieben.
(siehe man: stat(2))
*int fstat ( int FD, struct stat Buffer );
Schreibt die Attribute der schon geoeffneten Datei mit dem Datei-
descriptor 'FD' in die Strukturvariable 'Buffer'
(siehe man: fstat(2))
int lstat ( const char *PathName, struct stat *Buffer );
Verhaelt sich wie die stat-Funktion, mit dem Unterschied, dass, wenn
es sich bei der unter 'PathName' spezifizierten Datei um einen
symbolischen Link, so werden die Attribute dieses symbolischen Links
selbst in die Strukturvariable 'Buffer' geschrieben.
(siehe man: lstat(2))
Aufbau der Struktur 'stat'
Die Struktur kann sich in den einzelnen Unix-Distributionen etwas
unterscheiden, sie sollte allerdings so aussehen:
Alle drei Funktionen geben zurueck: 0 bei Erfolg; -1 bei Fehler
struct stat
{
    mode_t  st_mode;      //Dateiart und Zugriffsrechte
    ino_t   st_ino;       //i-node Nummer
    dev_t   st_dev;       //Geraetenummer (Dateisystem)
    dev_t   st_rdev;      //Geraetenummer fuer Geraetedatei
    nlink_t st_nlink;     //Anzahl der Links auf die Datei
    uid_t   st_uid;       //User-ID des Eigentuemers
    gid_t   st_gid;       //Group-ID des Eigentuemers
    off_t   st_size;      //Groeße in Byte fuer normale Dateien
    time_t  st_atime;     //Zeit d. letzten Zugriffs (access time)
    time_t  st_mtime;     /*Zeit d. letzten Aenderung in der Datei
                            (modification time)*/
    time_t  st_ctime;     //Zeit der letzten Aenderung der i-node
    long    st_blksize;   //voreingestellte Blockgroeße
    long    st_blocks;    //Anzahl der benoetigten 512-Byte-Bloecke
};

Alle Elemente, bis auf st_rdev, st_blksize und
st_blocks, sind von POSIX.1 vorgeschrieben und sind auf allen
Systemen vorhanden.
Ihr koennt die Funktionsweise von der stat-Funktion ja einmal aus-
probieren, indem ihr ein kleines Programm schreibt. Das koennte dann
ungefaehr so aussehen:
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;

int main() {
    char PathName[30];
    struct stat FileInfo;
    printf(&quot;Pfad + Dateiname:  &quot;);
    scanf(&quot;%s&quot;,PathName);
    if (stat(PathName,&amp;FileInfo) == -1) {
      perror(&quot;stat()&quot;);
      return EXIT_FAILURE;
    }
    if (S_ISREG(FileInfo.st_mode))
      puts(&quot;Normale Datei&quot;);
    else
      puts(&quot;Spezielle Datei&quot;);
    return EXIT_SUCCESS;
}

In diesem Code taucht ein Makro auf: S_ISREG()
Es gibt eine Reihe von Makros, die Auskunft darueber geben, um was
es sich bei einer Datei handelt. Ich werde hier alle vom POSIX.1
vorgeschriebenen Makros kurz beschreiben. Die Makros werden immer
auf das Element st_mode einer Stat-Strukturvariablen
angewandt.
S_ISREG()
Liefert einen Wert ungleich 0, wenn es sich um eine regulaere Datei
handelt
S_ISDIR()
Liefert einen Wert ungleich 0, wenn es sich um ein Directory handelt
S_ISCHR()
Liefert einen Wert ungleich 0, wenn es sich um ein zeichenorientiertes
Geraet handelt
S_ISBLK()
Liefert einen Wert ungleich 0, wenn es sich um ein blockorientiertes
Geraet handelt
S_ISFIFO()
Liefert einen Wert ungleich 0, wenn es sich um eine Pipe oder FIFO
handelt
Ihr koennt ja mit diesen Makros ein wenig experimentieren.
Kommen wir nun zu den Funktionen, die wir benoetigen um uns unter
Linux/Unix in Diretorys fortzubewegen.
DIR *opendir ( const char *Path ); [man: opendir(3)]
-&gt; Rueckgabe: DIR-Zeiger bei Erfolg; NULL bei Fehler
struct dirent *readdir ( DIR *Ptr ); [man: readdir(3)]
-&gt; Rueckgabe: dirent-Zeiger bei Erfolg; NULL bei Fehler
*void rewinddir ( DIR Ptr ); [man: rewinddir(3)]
*int closedir ( DIR Ptr ); [man: closedir(3)]
-&gt; Rueckgabe: 0 bei Erfolg; -1 bei Fehler
Wie man sieht, benoetigt man noch mehr. Naemlich die Struktur
DIR und dirent.
Die Struktur DIR ist eine Systeminterne Struktur, die Infor-
mationen ueber das zu lesende Directory speichert.
dirent ist eine Struktur, die laut POSIX.1 mindestens den
Dateinamen enthalten muss. Sie kann auch noch die i-node-Nummer
enthalten.
Diese Struktur ist wie folgt definiert:
struct dirent
{
    char   d_name[NAME_MAX + 1];  //Dateiname mit '\0'
    ino_t  d_ino;                 //i-node-Nummer
};

Die Strukturen und die o. g. Funktionen sind in der Headerdatei
&lt;dirent.h&gt; definiert.
Kurze Erlaeuterung der Funktionen:
DIR *opendir ( const char *Path );
Oeffnen des Directory 'Path'
(siehe man: opendir(3))
struct dirent *readdir ( DIR *Ptr );
Mit 'readdir' ließt man schrittweiße die Eintraete in einem Directory
Der erste Aufruf liefert die erste Datei in einem Directory, jeder
weitere Aufruf die naechste Datei. Dabei muessten die Dateien nicht
in der Reihenfolge gelesen werden, wie es ein 'ls -l'-Befehl anzeigt
(siehe man: readdir(3))
*void rewinddir ( DIR Ptr );
Setzt den Lesezeiger zurueck auf den Anfang der Namesliste des
Directorys
(siehe man: rewinddir(3))
*int closedir ( DIR Ptr );
Schließt ein Directory wieder (wer haetts gedacht  )
(siehe man: closedir(3))
Das ist eigentlich schon alles. Ich werde die Rechte eines Directorys
jetzt mal nicht beachten. Dafuer muesste ich fuer die Rechte etwas
mehr ausholen. Das kann ich ja dann machen, wenn mir wiedermal
langweilig ist  .
Machen wir mal ein kleines Beispiel. Einfach ein Programm, welches
den Inhalt eines Directorys ausließt und ausgibt, ob es sich um
eine regulaere Datei handelt oder nicht.
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;dirent.h&gt;

int main () {
    struct stat FileInfo;
    struct dirent *CurrentFile;
    DIR *Directory;
    char Path[30];
    if ( (Directory = opendir(&quot;/tmp&quot;)) == NULL) {
      perror(&quot;opendir()&quot;);
      return EXIT_FAILURE;
    }
    while ( (CurrentFile = readdir(Directory)) != NULL) {
      if (strcmp(CurrentFile-&gt;d_name,&quot;.&quot;) &amp;&amp;
             strcmp(CurrentFile-&gt;d_name,&quot;..&quot;))
      {
        strcpy(Path,&quot;/tmp/&quot;);
        strcat(Path,CurrentFile-&gt;d_name);
        printf (&quot;%s \t:&quot;,Path);
        if (stat(Path,&amp;FileInfo) == -1) {
          perror(&quot;stat()&quot;);
          closedir(Directory);
          return EXIT_FAILURE;
        }
        if (S_ISREG(FileInfo.st_mode))
          puts(&quot;Regulaere Datei&quot;);
        else if (S_ISDIR(FileInfo.st_mode))
          puts(&quot;Directory&quot;);
        else
          puts(&quot;Spezielle Datei&quot;);
      }
    } //end while
    closedir(Directory);
    return EXIT_SUCCESS;
} //end main

Erklärung zum Code:
Zunaechst einmal legen wir ein paar Variablen an. Die ersten drei
dürften jetzt klar sein. Die vierte ist dafür da, den aktuellen
Pfadname + Dateiname zu speichern, damit wir die stat-Funktion
ordnungsgemäß aufrufen können.
Als nächstes öffnen wir das Directory '/tmp'.
Danach lesen wir solange aus dem Directory, bis wir an das Ende
angelangen. Die 'Directorys' &quot;.&quot; und &quot;..&quot; (Current Directory und
Parent Directory) muessen abgefangen werden. Wuerde man immer &quot;.&quot;
lesen, waere es Fatal und man haette eine Endlosschleife. Das selbe
mit &quot;..&quot;.
Danach kopieren wir in die Variable 'Path' den Pfad + Dateinamen, so
dass wir so ein Format bekommen: '/PathName/FileName'.
Nun holen wir uns die Informationen ueber diese Datei, werten diese
aus und geben die entsprechende Message aus. Sind wir am Ende des
Directorys angelangt, schließen wir das Directory und das Programm
ist beendet.
War ja gar nicht so schwer *g*.
Okay. Dann koennen wir ja jetzt unser Programm schreiben, mit dem
wir ein Directory rekursiv kopieren koennen. Das Programm wird
sicherlich nicht PERFEKT sein. Ich werde auch keine Prüfung von
Rechten hineinbringen oder sowas. Aber das hab ich ja bereits gesagt.
Was wir benötigen, ist eine Funktion, die ein Directory durchläuft
und eine Funktion, die Dateien ins neue Directory kopiert.
symbolische Links werde ich abfangen und nicht mitkopieren.
Nennen wir die Funktionen Copy und ReadSrcDir (ja, ja, es gibt
bestimmt bessere Namen, aber mir fallen grad keine ein :p ).
Die main-Funktion werd ich mir sparen, die kann dann jeder grad
selbst schreiben und die Funktionen mit den noetigen Parametern
aufrufen.
Fangen wir mit der Copy-Funktion an. Was muss sie können? Sie muss
eine Datei von einem Directory in das andere kopieren.
void Copy(const char *Src,const char *Dst) {
     size_t ReadBytes;
     const int Max = 255;
     char Buffer[Max];
     FILE *FileIn;
     FILE *FileOut;
     if ( (FileIn = fopen(Src,&quot;r&quot;)) == NULL)
       return;
     if ( (FileOut = fopen(Dst,&quot;w&quot;) ) == NULL) {
       fclose(FileIn);
       return;
     }

     printf(&quot;Kopiere %s nach %s...\n&quot;,Src,Dst);

     //Solange aus Datei gelesen wird
     while ( (ReadBytes = fread(Buffer,1,Max,FileIn)) &gt; 0)
       //wird auch in Datei geschrieben
       if (fwrite(Buffer,1,ReadBytes,FileOut) != ReadBytes) {
         fclose(FileIn);
         fclose(FileOut);
         return;
       }

     puts(&quot;Fertig!&quot;);

     fclose(FileIn);
     fclose(FileOut);
}

Soweit so gut. Diese Funktion sollte die Quelldatei ins Zieldirectory
kopieren.
Kommen wir nun zur eigentlichen Funktion. Die Funktion, die das
Directory durchlaeuft.
void ReadSrcDir(const char *Src,const char *Dst) {
     /*Wir benötigen natürlich Strukturvariablen von DIR, dirent
       und stat*/
     DIR *Directory;
     struct dirent *CurrentFile;
     static struct stat FileInfo;
     /*Wir benötigen eine Variable, mit der wir einen Absoluten
      Pfadnamen + Datei speichern*/
     char PathName[255]; //Wer weiß wie tief das Directory geht?
     char PathName2[255]; //Hier solls hin gehn -:)
     //Directory öffnen
     if ( (Directory = opendir(Src)) == NULL)
       return;
     if (stat(Src,&amp;FileInfo) == -1) {
       closedir ( Directory );
       return;
     }
     /*Nun legen wir das Zieldirectory an, falls es schon
       existiert, geben wir eine entsprechende Meldung aus*/
     if (mkdir(Dst,FileInfo.st_mode) == -1) {
       /*Wir fangen nur diesen Fehler ab. Falls es einen anderen
         Fehler gibt, beenden wir das Programm. Das kann natuerlich
         so haendeln wie er will*/
       if ( errno == EEXIST )
         puts(&quot;Directory existiert bereits&quot;);
       else {
         closedir(Directory);
         return;

       }
     }
     else
       printf ( &quot;Directory %s anlegen\n&quot;, Dst );
     //Nun fangen wir an, das Directory zu lesen
     while ( (CurrentFile = readdir(Directory)) != NULL) {
       /*Prüfen, ob es sich um das Current Directory 
         (&quot;.&quot;) oder um das Parent Directory (&quot;..&quot;)
         handelt. Wenn ja, dann passiert nichts.*/
       if (strcmp(CurrentFile-&gt;d_name,&quot;.&quot;) &amp;&amp;
           strcmp(CurrentFile-&gt;d_name,&quot;..&quot;))
       {
         /*Nun bauen wir uns den Pfad zusammen, damit
           wir mit der stat-Funktion die Attribute
           erfragen können*/
         strcpy(PathName,Src);
         strcat(PathName,&quot;/&quot;);
         strcat(PathName,CurrentFile-&gt;d_name);
         if (stat(PathName,&amp;FileInfo) == -1) {
           closedir ( Directory );
           return;
         }
         /*Handelt es sich um ein Verzeichnis?*/
         if (S_ISDIR(FileInfo.st_mode)) {
           strcpy(PathName2,Dst);
           strcat(PathName2,&quot;/&quot;);
           strcat(PathName2,CurrentFile-&gt;d_name);
           ReadSrcDir(PathName,PathName2);
         }
         /*oder handelt es sich um eine regulaere Datei?*/
         else if ( S_ISREG ( FileInfo.st_mode ) ) {
           strcpy(PathName2,Dst);
           strcat(PathName2,&quot;/&quot;);
           strcat(PathName2,CurrentFile-&gt;d_name);
           Copy(PathName,PathName2);
         }
       }
    } //end while
} //end ReadSrcDir

So, das wars auch schon. Hoffe ich hab keine Fehler eingebaut, sonst
korrigiert mich einfach. Ist leider nicht sehr einfach, den Über-
blick zu behalten, da das Textfeld hier nicht so breit ist. Egal,
ich hoffe das Prinzip ist klar geworden.
mfg
v R
C++
Wer unter C++ Objekt Orientiert programmieren will und sich nicht mit der POSIX C API abmühen möchte, sollte sich folgende Librarys angucken

Boost::Filesystem - ein Teil der Boost Library (Portabel für viele Systeme)
More - more::io enthält Klassen und Funktionen zum Umgang mit Dateien (nur für POSIX Systeme)

]]></description><link>https://www.c-plusplus.net/forum/topic/39523/bewegen-in-verzeichnissen-unter-unix</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39523/bewegen-in-verzeichnissen-unter-unix</guid><dc:creator><![CDATA[virtuell Realisticer]]></dc:creator><pubDate>Sun, 05 May 2002 19:11:00 GMT</pubDate></item><item><title><![CDATA[Pendant zu getch() und kbhit() im unix bereich???]]></title><description><![CDATA[ansonsten wird man vielleicht auch mit den ncurses oder der uconio glücklich
]]></description><link>https://www.c-plusplus.net/forum/topic/39509/pendant-zu-getch-und-kbhit-im-unix-bereich</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39509/pendant-zu-getch-und-kbhit-im-unix-bereich</guid><dc:creator><![CDATA[rüdiger]]></dc:creator><pubDate>Fri, 08 Mar 2002 16:28:00 GMT</pubDate></item><item><title><![CDATA[Dynamische Librarys (*.so) erstellen]]></title><description><![CDATA[Hier ein script
#!/bin/bash

echo &quot;Gib den Programmnamen ein&quot;
read programm
echo &quot;S fuer Sharedlib,O fuer Object,A fuer Archive&quot; 
read status

if [ &quot;$programm&quot; = &quot;&quot; ];
then
echo &quot;Kein Programmname eingegeben&quot;;
exit 1
fi

g++ -fPIC -DPIC -c $programm.cpp

if [ &quot;$status&quot; = &quot;O&quot; ];
then
exit 1
fi

if [ &quot;$status&quot; = &quot;S&quot; ];
then
g++ -shared -o lib$programm.so.1.0 -W-soname $programm.o
ln -s lib$programm.so.1.0 lib$programm.so
else
ar rcs lib$programm-static.a $programm.o
fi

in ein file kopieren und das recht ausführen geben
]]></description><link>https://www.c-plusplus.net/forum/topic/39519/dynamische-librarys-so-erstellen</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39519/dynamische-librarys-so-erstellen</guid><dc:creator><![CDATA[Unix-Tom]]></dc:creator><pubDate>Fri, 08 Mar 2002 11:02:00 GMT</pubDate></item><item><title><![CDATA[pthread_create]]></title><description><![CDATA[Also das zugreifen auf Variablen des Mutterprozesses ist mittels fork nicht so einfach. Dafür sollte man die Interprocesskommuication können. (PIPE,Socket,etc)
Wenn du das jedoch mit Threads machst mußt du Threads sehr gut können da der Zugriff auf Variablen des Hauptthreads syncronisiert werden muß.Ich mache das immer so das ich mir einen Deamonserver schreibe welcher mit Sockets arbeitet.
Dh.: Eines Socket erstellen und diesen Asynch abhören. Somit kann man auch anderen Code ausführen. In diesem Process startest du mittels fork einen Childpr. welcher unabhängig vom Mutterprocess läuft.(2 Mal fork aufrufen)
Wenn der Mutterprocess dann den Inhalt der Variablen des Childprocesses braucht dann einen Socketconnect zum Mutterprocess, welcher in diesem fall nicht mehr die Mutter des Child ist, aufbauen un ihm den Inhalt per Sockets senden. Danach den Childprocess schließen.
]]></description><link>https://www.c-plusplus.net/forum/topic/39508/pthread_create</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39508/pthread_create</guid><dc:creator><![CDATA[Unix-Tom]]></dc:creator><pubDate>Wed, 24 Oct 2001 06:02:00 GMT</pubDate></item><item><title><![CDATA[Threadwechsel unterdrücken]]></title><description><![CDATA[Da weiß ich ja gleich noch, was ich mir mal genauer ansehen muß.
]]></description><link>https://www.c-plusplus.net/forum/topic/39502/threadwechsel-unterdrücken</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39502/threadwechsel-unterdrücken</guid><dc:creator><![CDATA[Joris]]></dc:creator><pubDate>Tue, 21 Aug 2001 13:00:00 GMT</pubDate></item><item><title><![CDATA[Nonblock Sockets]]></title><description><![CDATA[Ich gehe mal davon aus das dein Socket ein
int socketvar;
ist
fcntl(socketvar,F_SETFL,O_NONBLOCK);
Siehe man: fcntl(2)
]]></description><link>https://www.c-plusplus.net/forum/topic/39525/nonblock-sockets</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39525/nonblock-sockets</guid><dc:creator><![CDATA[Unix-Tom]]></dc:creator><pubDate>Sun, 19 Aug 2001 15:29:00 GMT</pubDate></item><item><title><![CDATA[Source für smtp-Protokoll]]></title><description><![CDATA[Hi,
ihr habt recht. Man hat nicht die Berechtigung um eine E-Mail zu versenden:
Host [meine IP] has not the permissiont to realy send mail.
So sieht's aus. Ich muss nochmal zu Hause in meinem Schrank nachschauen, dann kann ich dir noch ein paar andere Adressen geben.
mfg
V_R
------------------
Am 8. Tag schuf Gott Windows und vorbei war es mit dem Paradies!
]]></description><link>https://www.c-plusplus.net/forum/topic/39503/source-für-smtp-protokoll</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/topic/39503/source-für-smtp-protokoll</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Mon, 25 Jun 2001 07:40:00 GMT</pubDate></item></channel></rss>