Segmentation Fault bei strcat?

daboss

daboss

Kaiser
Heyho,

Ich habe folgendes Progrämmchen versucht, zu schreiben. (Was es machen soll, steht weiter unten ;) ).
Code:
/*
 * filewatch.c
 *
 *  Created on: 27.11.2008
 *      Author: alex
 */
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char* argv[]){
    //Parametercheck:
    if(argc != 5){
        printf("AnzParam: %i\n", argc);
        printf("Aufruf: filewatch -d directory -f file\n");
        return 1;

    //Debugausgabe:
    }else{
        int i;
        for(i = 0;i<5;++i){
            printf("arg %i: %s\n", i, argv[i]);
        }
    }

    //Falls die richtigen Parameter uebergeben
    //wurden, diese Uebernehmen:
    int iD, iF = 1;
    char *cD = "\0";
    char *cF = "\0";
    if(strcmp("-d", argv[1])){
        printf("Dir an 1\n");

        iD = 0;
        cD = (char*) calloc(strlen(argv[2]), sizeof(char));
        if(cD == NULL){
            printf("Kein Platz fuer die Parameteruebergabe!");
            return 1;
        }else{
            cD = argv[2];
        }
    }
    if(strcmp("-d", argv[3])){
        printf("Dir an 3\n");
        printf("argv[3] [%s], argv[4] [%s]\n", argv[3], argv[4]);

        iD = 0;
        cD = (char*) calloc(strlen(argv[4]), sizeof(char));
        if(cD == NULL){
            printf("Kein Platz fuer die Parameteruebergabe!");
            return 1;
        }else{
            cD = argv[4];
        }
    }
    if(strcmp("-f", argv[1])){
        printf("File an 1\n");

        iF = 0;
        cF = (char*) calloc(strlen(argv[2]), sizeof(char));
        if(cF == NULL){
            printf("Kein Platz fuer die Parameteruebergabe!");
            return 1;
        }else{
            cF = argv[2];
        }
    }
    if(strcmp("-f", argv[3])){
        printf("File an 3\n");

        iF = 0;
        cF = (char*) calloc(strlen(argv[2]), sizeof(char));
        if(cF == NULL){
            printf("Kein Platz fuer die Parameteruebergabe!");
            return 1;
        }else{
            cF = argv[4];
        }
    }
    //Falsche Parameter -> Abbruch:
    if(iF == 1 || iD == 1){
        printf("Aufruf: filewatch -d directory -f file\n");
        return 1;
    }

    printf("Dir %s\n", cD);
    printf("File %s\n", cF);

    //Pfad zur Datei basteln:
    char *caPfad = strcat(cF, "/");
    caPfad = strcat(cF, cD);
    printf("Pfad: %s\n", caPfad);

    //Datei oeffnen und entsprechend reagieren:
    int iFDesc = (-1);
    while(iFDesc == (-1)){

        //Crtl-C abfangen
        if(sigaction(SIGINT, NULL, NULL)){
            printf("Vom Benutzer abgebrochen.\n");
            return 0;
        }
        //kill abfangen
        if(sigaction(SIGKILL, NULL, NULL)){
            printf("Via kill beendet.\n");
            return 0;
        }
        int iFDesc = open(caPfad, O_RDONLY);
        if(iFDesc == -1){
            printf("Datei nicht vorhanden!\n");
            sleep(60);
        }else{
            printf("Datei vorhanden!\n");
            unlink(caPfad);
            printf("Datei geloescht.\nInhalt des Verzeichnisses:\n");

            char *caBefehl = (char*) calloc(strlen(cD) + 10, sizeof(char));
            if(caBefehl == NULL){
                printf("Kein Platz fuer den Befehl...\n");
                return 1;
            }
            caBefehl = strcat("/bin/ls", cD);
            printf("Befehl: %s\n", caBefehl);
    //        execl(caBefehl, "", NULL);

            return 0;
        }
    }

    return 1;
}
Damit habe ich aber (mind.) 2 Probleme:

Zum einen funktioniert die Parameterübergabe offensichtlich nicht so, wie ich mir das Vorstelle. Die Stelle
Code:
if([B]strcmp("[U]-d[/U]", argv[3][/B])){
        printf("Dir an 3\n");
        printf("argv[3] [%s], argv[4] [%s]\n", argv[3], argv[4]);

        iD = 0;
        cD = (char*) calloc(strlen(argv[4]), sizeof(char));
        if(cD == NULL){
            printf("Kein Platz fuer die Parameteruebergabe!");
            return 1;
        }else{
            cD = argv[4];
        }
    }
führt zu
alex@asterix:~$ workspace/UNP.FU.03Filewatch/Release/UNP.FU.03Filewatch -d /opt -f test
arg 0: workspace/UNP.FU.03Filewatch/Release/UNP.FU.03Filewatch
arg 1: -d
arg 2: /opt

arg 3: -f
arg 4: test
Dir an 3
argv[3] [-f], argv[4] [test]

File an 1

Dir test
File /opt

(...)
.

Ausserdem bekomme ich an der Stelle
Code:
caBefehl = strcat("/bin/ls", cD);
einen
(...)Pfad: /opt/test
Datei vorhanden!
Datei geloescht.
Inhalt des Verzeichnisses:
Segmentation fault
Kann mir da bitte jemand weiterhelfen? :)

Die Aufgabe dazu:
Als Übung zur Vorlesung Unix/Linux Netzwerkprogrammierung sollen wir ein C-Programm implementieren, das ein, beim Start übergebenes, Verzeichnis alle 60 Sekunden auf die Existenz einer, beim Start übergebenen, Datei überwacht. Existiert die Datei, soll sie gelöscht, der Inhalt des obigen Verzeichnisses mit Hilfe von "ls" ausgegeben und das Programm beendet werden. Ausserdem soll sich das Ding bei Sstrg+C und kill geordnet beenden... :rtfm:
 
Zuletzt bearbeitet:
Zum ersten Problem:

ein 'if (aussage)' wird ausgefuehrt, wenn aussage != 0. strcmp gibt 0 zurueck, wenn die beiden string gleich sind, und einen Wert ungleich 0, wenn sie - wie bei Deinem Beispiel - ungleich sind. Also steht in dem 'if(...)' etwas, was korrekterweise von C als wahr interpretiert wird und somit wird der folgende Block ausgefuehrt.

Zum zweiten Problem:
In dem 'if(strcmp("-d", argv[1]))...' Block steht an einer Stelle 'cD = argv[2]'. Hier kopierst Du nichts, sondern laesst cD auf die Adresse von argv[2] zeigen. Diese Variable hat die Laenge 5 ("/opt"), waehrend das "/bin/ls" laenger ist, Du schreibst also mit strcat in einen Speicherbereich, der Dir nicht unbedingt zugaenglich ist.

Also Vorsicht mit 'char* c = some_string' Zuweisungen, denke genau darueber nach, ob es das ist, was Du willst!
 
Ohne dein Programm genauer durchgecheckt zu haben ...

Das erste Problem hat rikola ja schon geklärt.

Als Ergänzung zum zweiten: strcat legt nicht einen neuen Speicherbereich an und kopiert dann seine Argumente rein, sondern hängt einfach das zweite Argument an das erste an und gibt dann im Erfolgsfall einen Zeiger darauf zurück, sonst einen NULL-Pointer. Spätestens wenn du den dann mit "printf" auszugeben versuchst, bekommst du den SEGFAULT (wenn er nicht schon bei dem Versuch auftritt, an den String "/bin/ls" noch was dranzuhängen.)

Ich glaube, du solltest die ganze Sache mit den Pointern nochmal etwas durchdenken. Wenn du bspw. hier

Code:
        cD = (char*) calloc(strlen(argv[4]), sizeof(char));
        if(cD == NULL){
            printf("Kein Platz fuer die Parameteruebergabe!");
            return 1;
        }else{
            cD = argv[4];
        }

mit calloc() zunächst Speicher reservierst, der zwar für argv[4] gross genug ist, das abschliessende 0-Byte aber nicht mehr aufnehmen kann (!), und dann den Pointer cD auf argv[4] umbiegst, dann kopierst du nicht Daten von argv[4] nach cD, sondern du programmierst ein klassisches memory leak ...

Und ganz allgemein kannst du dir die Verarbeitung von Argumenten, die du auf der Kommandozeile übergibst, mit getopts() deutlich vereinfachen. Check einfach mal die Manual-Page ab, da gibts auch Beispiele ...

Hoffe, das hlft ein bisschen weiter; Gruss
 
Ah ok, danke. Des mit 0 und !=0 hab ich mich wohl mal wieder vertan. Dachte, ich kann "== 0" abkürzen, aber war wohl nix.

Die Zuweisungen bei den Srings hab ich mal durch strcpy erstetzt (sollte lt. "C Kompakt und komplett" eher das machen, was ich wollte :) ) und das strcat mit "/bin/ls" hab ich wohl auch bissl falsch angewendet.

Oh, grad noch floyd's Beitrag gelesen: Stimmt, strlen zählt die 0 garnicht mit^^ Hätt ich in obigem Buch einen Satz weitergelesen..... naja :).

Danke euch auf jeden Fall, jetzt funktioniert's, so wie's ausschaut :)

Werd noch bissl zu sigaction scrooglen, zweifel noch bissl dran, das da die Signalbehandlung "richtig" angewendet ist....
 
Zuletzt bearbeitet:
Ah ok, danke. Des mit 0 und !=0 hab ich mich wohl mal wieder vertan. Dachte, ich kann "== 0" abkürzen, aber war wohl nix.
Wenn Du damit meinst, dass Du
Code:
if (strcmp ("-d", argv[2]) == 0)
schreiben wolltest, so hast Du Dich damit keineswegs vertan. Das waere der weitaus elegantere und sauberere Weg, da er leichter zu lesen ist. Das sollte auch funktionieren.
 

Ähnliche Themen

Unix Webserver mit HTML Seite erstellen

Verschlüsseltes Backup-Script mit rsync

Crontab und Scripts - Problem

Port generieren, wenn nicht dann

HandbrakeCLI Shell Skript

Zurück
Oben