execl mehrere Parameter übergeben



  • Hallo,
    ich möchte einen Hintergrundprozess starten, aktuell verwende ich noch system().

    den hintergundprozess selbst erstellen ist ja recht einfach:

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
      if (fork()==0)
      {
        //int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
        execl("/bin/ls","ls","param1","param2",NULL);
      }
      return 0;
    }
    

    mein Problem: ich habe die Parameter (mehrere) als string vorliegen...

    also z.b.
    Programm "vlc"
    Parameter "-f --play-and-exit --key-quit=esc --volume=256"

    wie übergebe ich das am sinnvollsten an die exec-funktion?
    ich weis, es gibt auch exec-varianten (execv*), die ein array aufnehmen, aber wie erstelle ich ein dynamisches array of char*? außerdem müsste ich den string dann aufsplitten (evtl probleme mit leerzeichen etc, die ich umgehen möchte).

    weiterhin benötigt exec ja den kompletten Pfad zum Programm...wie bekomme ich den, wenn ich nur den Programmname habe? also so eine art "which"

    //edit:
    aktuell realisiere ich es so:

    execl("/bin/sh","sh","-c","ls /media /dev",NULL);
    

    ist sicher nicht die eleganteste Art und ich möchte ungern eine shell hochziehen

    Gruß Frank



  • char params[] = "vlc -f --play-and-exit --key-quit=esc --volume=256"; // wichtig! Erster Parameter ist argv[0]!
    
      size_t number_of_params = 1;
      for(char *p = params; *p; ++p) {
        if(*p == ' ') {
          ++number_of_params;
        }
      }
    
      char **args = malloc( (number_of_params+1) * sizeof(*args));
      if(!args) {
        perror("malloc");
        _Exit(1);
      }
    
      size_t i = 1;
      args[0] = params;
      for(char *p = params; *p; ++p) {
        if(*p == ' ') {
          assert(i < number_of_params);
          args[i++] = p+1;
          *p = '\0';
        }
      }
      args[number_of_params] = NULL;
    
      if(execvp("vlc", args) == -1) {
        perror("execvp");
        _Exit(1);
      }
    

    weiterhin benötigt exec ja den kompletten Pfad zum Programm...wie bekomme ich den, wenn ich nur den Programmname habe? also so eine art "which"

    Die *p-Varianten benötigen nicht den kompletten Pfad. Genau wie die Shell werten die die Umgebungsvariable PATH aus und schauen in den entsprechenden Verzeichnissen.



  • einfacher geht es so:

    char params[] = "vlc -f --play-and-exit --key-quit=esc --volume=256";
    
    ...
    
    execlp("sh", "sh", "-c", params, NULL);
    


  • supertux schrieb:

    einfacher geht es so:

    char params[] = "vlc -f --play-and-exit --key-quit=esc --volume=256";
    
    ...
    
    execlp("sh", "sh", "-c", params, NULL);
    

    Das hat er ja schon. Aber will es nicht so.



  • der andere Weg mit der Umwandlung in ein char*-Array hat den nachteil, dass er Probleme mit Leerzeichen hat, da er die als Trennzeichen (Ersetzung durch \0) nimmt.
    Ich möchte dem Player ja eine Datei mitgeben, und diese kann Leerzeichen im Pfad enthalten.

    hat da vllt. auch jemand eine Idee?

    ich bin mit der speicher-allokierung nicht ganz so vertraut. evtl. könnte ich das array eins (1*sizeof(*args)) größer machen und ins letzte Element einen Pointer auf das Datei-Char* (bzw. string.c_str()) reinschreiben...

    vorher müsste ich aber meinen command noch vorne an meine Parameter ranbasteln
    mit der Konvertierung nach String ist das aber kein Problem denke ich 🙂

    Als Hintergrundinfo...meine Ursprungsfunktion sieht so aus:

    void RunViewer(const char *player, const char *options, const char *file)
    {
      string command=string(player)+" "+string(options)+" \""+string(file)+"\""; 
      if (FileExists(file))
      {
        Last_Viewed.SetValue(file,GetTimeString());
        system(command.c_str());
      } else
        g_print("error opening file...\n");
    }
    

    ich möchte nur das System ersetzen um den Player in den Hintergrund zu schieben...



  • rüdiger schrieb:

    supertux schrieb:

    einfacher geht es so:

    char params[] = "vlc -f --play-and-exit --key-quit=esc --volume=256";
    
    ...
    
    execlp("sh", "sh", "-c", params, NULL);
    

    Das hat er ja schon. Aber will es nicht so.

    Ohh, das habe ich glatt übersehen. Wie dem auch sie, wieso einfacher, wenn es doch immer schwerer geht 😕



  • frank schrieb:

    ich bin mit der speicher-allokierung nicht ganz so vertraut. evtl. könnte ich das array eins (1*sizeof(*args)) größer machen und ins letzte Element einen Pointer auf das Datei-Char* (bzw. string.c_str()) reinschreiben...

    Ja natürlich. Du könntest den Rest der Optionen idealerweise auch gleich in einem besseren Format speichern.



  • rüdiger schrieb:

    Du könntest den Rest der Optionen idealerweise auch gleich in einem besseren Format speichern.

    wie meinst du das? will die Funktion selbst auf std::string umbauen (nach außen)

    dann müsste ich das eigentlich einmal (mit arg0 zusammen) in ein char[] kopieren, oder? sonst klappt das ja nicht mit dem Umbau auf das Array



  • Naja bekommst du die Optionen und den Dateinamen vom User oder sind die Optionen fix bzw. von deinem Programm generiert? Wenn sie von deinem Programm sind, dann könntest du sie natürlich gleich so speichern, dass du sie an execvp weitergeben kannst.



  • das programm und die optionen werden aus einer textdatei ausgelesen und im Programm in einer map<string,string> gespeichert.

    es gibt aktuell 4 Paare dieser Konfiguration (programm, optionen), daher wäre es schon sinnvoll das array dynamisch aus dem string zu erzeugen.

    der Dateiname kommt vom Benutzer (wird vorher auch als string zusammengebaut).



  • also ich habs jetzt so:

    bool Exec(string command,string parameters,string file)
    {
      pid_t pid=fork();
      if (pid==0)//child-process
      {
        //char params[] = "vlc -f --play-and-exit --key-quit=esc --volume=256"; // wichtig! Erster Parameter ist argv[0]!
        char params[command.size()+1+parameters.size()+1];
        char file_char[file.size()];
    
        strcpy(params,command.c_str());
        strcat(params," ");
        strcat(params,parameters.c_str());
        //g_print("Params: %s\n",params);
    
        strcpy(file_char,file.c_str());
    
        size_t number_of_params = 1;
        for(char *p = params; *p; ++p) {
          if(*p == ' ') {
            ++number_of_params;
          }
        }
        number_of_params++;//increase Param-count to hold file
        //g_print("Parameter-Anzahl: %d\n",number_of_params);
        char **args = (char**)malloc( (number_of_params+1) * sizeof(*args));
        if(!args) {
          perror("malloc");
          return false;
        }
    
        size_t i = 1;
        args[0] = params;
        for(char *p = params; *p; ++p) {
          if(*p == ' ') {
            assert(i < number_of_params);
            args[i++] = p+1;
            *p = '\0';
          }
        }
        args[number_of_params-1] = file_char;
        args[number_of_params] = NULL;
    
        if(execvp(command.c_str(), args) == -1) 
        {
          return false;
        } else return true;
      } else if (pid==-1)
        return false; //problem while forking
      else return true;//parent process
    }
    

    funktioniert soweit alles~~, und keine Abstürze ;)~~
    denke mal, die speicherallokierung stimmt so, musste nur die strings kopieren, da "string.c_str()" ein "sonst char*" ist und in dem array aber normale char* sein müssen...

    EDIT: wenn das programm nicht existiert, stürzt das Programm ab 😢 kann mir jemand sagen, warum?
    und wie kann man dem vorbeugen?

    Error: Wiedergabeprogramm konnte nicht gestartet werden!
    mediaselector: Fatal IO error 2 (No such file or directory) on X server :0.0.
    mediaselector: ../../src/xcb_io.c:249: process_responses: Assertion `(((long) (dpy->last_request_read) - (long) (dpy->request)) <= 0)' failed.
    Aborted

    die erste Zeile ist eine ausgabe von mir wo der rückgabewert meiner exec-funktion ausgewertet wird, gleichzeitig versuche ich ein GTK-Control zu modifizieren (Anzeige der gleichen Fehlermeldung in einer InfoBar)...ich denke mal, da knallts.
    mit dem Handling

    perror("execvp");
          _Exit(1);
    

    wenn die execvp nicht fehlschlägt, stürzt das Programm auch nicht ab.
    Aber ich habe keine Rückmeldung, an der ich feststellen kann, ob der prozess korrekt gestartet werden konnte.
    Ich gebe doch mit _Exit(...) den errorcode mit, den muss ich doch irgendwie vom parent auslesen können...
    wie kann ich dem parent sagen, dass der Child-prozess fehlgeschlagen ist?

    Gruß Frank



  • Hi,
    hat jemand eine idee (siehe vorheriger Post)?

    außerdem hab ich festgestellt, dass nach der benutzung von execvp ein zombo-prozess zurückbleibt. wie kann ich das verhindern? muss ich das fork aufheben?

    Gruß Frank


Anmelden zum Antworten