2016-05-05 6 views
0
#include <pwd.h> 
#include <stdio.h> 

struct passwd* Getpwnam_(const char* name) 
{ 
     static struct passwd* passwd; 

     while((passwd=getpwent())!=NULL)  /* get pw entry line by line */ 
     { 
       if(strcmp(passwd->pw_name, name)==0) /* find the same name */ 
         return passwd; 
     } 

     if(passwd==NULL)  /* there is no matching name */ 
       return NULL; 
} 

int 
main(void) 
{ 
     printf("%ld %ld\n", (long)(Getpwnam_("root")->pw_uid), (long)(Getpwnam_("cho")->pw_uid)); 
} 

Auf dem obigen Code, wenn ich wie Hauptfunktionen verwenden:Segmentierungsfehler, wenn statischen Variable

printf("%ld\n", (long)(Getpwnam_("root")->pw_uid)); 
printf("%ld\n", (long)(Getpwnam_("cho")->pw_uid)); 

Es ist gut bedient. Aber wenn ich einen printf() mit zwei Getpwnam_() als Argumente verwende, erhalte ich einen Segmentierungsfehler. Ich denke, es gibt kein Problem in meiner Code-Operation.

Aber warum gibt mir das einen Segmentierungsfehler ??

+0

existiert der Benutzer 'cho' auf Ihrem System? – fluter

+0

@fluter: Ja, sicher –

+0

Sind Sie sicher, dass Getpwnam_() Sie in beiden Aufrufen nicht NULL zurückgibt? Ich glaube, dass Sie NULL für das root-Passwort bekommen sollten, wenn Sie Ihr Programm als Nicht-root-Benutzer ausführen – GMichael

Antwort

2

Sie müssen die Kennwortdatenbank mit setpwent() zwischen den Aufrufen an Getpwnam_() zurückspulen.

Angenommen, Ihre Anwendung ruft zuerst auf. Wenn in der Datenbank "root" ist vor "cho", in der Suche in einem Punkt getpwent() wird "root" zurückgeben, aber Ihre Suche wird es verwerfen, da es von "cho" unterscheidet. Später wird getpwent()"cho" zurückgeben, was das gültige Ergebnis ist.

Wenn neben Ihrer Anwendung ruft Getpwnam_("root"), getpwent() startet Einträge aus dem Punkt zurückkehren, die auf dem letzten Aufruf verlassen wurde, die in der Datenbank sowohl über "root" und "cho" ist. Da "root" nicht mehr zurückgegeben wird, wird die Suche nicht das Ergebnis erhalten, und Sie erhalten einen Nullzeiger, der das Programm abstürzt.

+1

Ich fand das Problem. Der Grund warum ist das, was atturri gerade gesagt hat: Wenn der erste Aufruf von Getpwnam _ ("cho") ', geben Sie den richtigen Wert. Aber ohne' endpwent() 'oder' setpwent() '. Der zweite Aufruf von' Getpwnam _() ' Wenn NULL mit '% ld' ausgegeben wird, gibt es einen Fehler –

+0

@atturri: Warum' Getpwnam _() 'rufen Sie in jedem' printf() 'reset die Eingabe Suchzeile ?? Ich meine die beiden Aufruf von 'Getpwnam_ () 'in einem 'printf()' ist nicht zurückgesetzt Eintrag Suchzeile. Ich meine, wenn beim ersten Aufruf von' Getpwnam _ ("cho") ', wird es Wert zurückgeben. Aber, nach dem Aufruf von' Getpwnam _ ("root" ') , es wird NULL-Wert zurückgeben, da kein Eintrag für root unterhalb des "cho" vorhanden ist. Aber warum sucht jeder 'printf()' Aufruf den Eintrag nach dem ersten, der keinen Segmentierungsfehler verursacht? –

+0

@ A.Cho Tut mir leid, ich bin mir nicht sicher, ob ich das verstehe. Sie müssen die gesamte Datenbank von Anfang an in jeder Ihrer "while" -Schleifen durchsuchen, um sicherzustellen, dass der Benutzer gefunden wird. Sie können die Datenbank innerhalb von 'Getpwnam _()' oder außerhalb zurückspulen. Beachten Sie außerdem, dass die restlichen Antworten auf ein anderes Problem hinweisen, das Sie mit Ihrem Code haben. – atturri

2

Das Problem hier ist wahrscheinlich im Zusammenhang mit der Tatsache getpwent gibt einen Zeiger auf einen (möglicherweise statischen) Speicherbereich, die es verwaltet. Also im Grunde, wenn Sie den Rückgabewert erhalten, müssen Sie es verwenden, bevor Sie einen weiteren Anruf an getpwent. Da der zweite Anruf den vom vorherigen Anruf zurückgegebenen Bereich überschreiben oder sogar freigeben könnte.

Aus der Manpage:

Der Rückgabewert auf einen statischen Bereich hinweisen und kann durch nachfolgende Aufrufe überschrieben werden, um getpwent(), getpwnam (3) oder getpwuid (3). (Do nicht den zurückgegebenen Zeiger passieren zu befreien (3).)

So zwei separate Drucke arbeiten, weil Sie die erste vor dem zweiten Aufruf verwenden. Wenn beide auf denselben Ausdruck gesetzt werden, bedeutet dies, dass der zweite Aufruf den vom ersten Aufruf zurückgegebenen Zeiger ungültig macht, aber dann versucht print, beide Zeiger zu verwenden. Selbst wenn Sie keinen Seg-Fehler erhalten, würde es höchstwahrscheinlich keine korrekte Ausgabe für den ersten Benutzer erzeugen.

Stattdessen müssen Sie Ihre Getpwnam_ ändern, um die Daten, die Sie benötigen, in ein frisch zugewiesenes Objekt zu kopieren und einen Zeiger darauf zurückgeben. Hinweis: das Kopieren muss "rekursiv" sein, wenn Sie einige der Zeichenfolgen auch möchten.

3

Ein Problem ist, dass Sie versuchen, zwei Kennworteinträge zur gleichen Zeit live zu halten. Ein nachfolgender Anruf an getpwent kann die zuvor zurückgegebenen Informationen überschreiben. Daher müssen Sie die zurückgegebenen Informationen vor dem erneuten Aufruf von getpwent beenden. Erstellen Sie bei Bedarf eine Kopie der benötigten Felder.

Außerdem muss der Zeiger nicht als statisch deklariert werden, da Sie seine Adresse nicht zurückgeben.Das andere Problem wurde von atturri erwähnt, das heißt, dass Sie nicht zwischen den Aufrufen an den Anfang der Kennwörter mit setpwent zurückgespult haben. Dies wäre klarer gewesen, wenn der Code vor dem Referenzieren eine NULL Rückgabe überprüft hätte die Passwortfelder.)