Shellskript aus einem C++ Programm starten
-
Ich gebe in der Eingabeaufforderung folgendes ein:
Telnet UNIX [Enter]
dann kommt die Ausgabe:
HP-UX UNIX B.11.11 U 9000/800 (tm)login: user [Enter]
Password: pw [Enter]login und Password ist eine Ausgabe vom System, ich gebe nur den
Benutzer "user" und das Passwort "pw" ein.
-
Bis Fritzi so in die Puschen kommt (;)) zeige ich mal eine Indy-Variante.
//--------------------------------------------------------------------------- bool logged_in = false; String strLogin = "jansen"; String strPass = "pass"; String strCommand = "touch test.dat;ls -l test.dat;rm test.dat"; String strResponse = "-rw-r--r-- 1 jansen users"; String strText = ""; void __fastcall TForm1::TN1DataAvailable(TIdTelnet *Sender, const AnsiString Buffer) { if (Buffer != "") { if (!logged_in) { // Loginprompt erreicht if (UpperCase(Buffer).Pos("LOGIN: ") == Buffer.Length() - 6) strText = strLogin; // Passwortprompt erreicht else if (UpperCase(Buffer).Pos("PASSWORD: ") == Buffer.Length() - 9) strText = strPass; // Eingabeprompt erreicht, Kommando abschicken else if (UpperCase(Buffer).Pos(UpperCase("jansen@suse82:~> ")) > 0) { logged_in = true; strText = strCommand; } } // Ausgabe enthält erwartetes Resultat des Kommandos, Verbindung beenden else if (UpperCase(Buffer).Pos(UpperCase(strResponse)) > 0) strText = "exit &"; if (strText != "") { // das eigentliche Versenden for (int i = 1; i <= strText.Length(); i++) TN1->SendCh(strText[i]); TN1->SendCh(VK_RETURN); strText = ""; } // Kontrollausgabe Memo1->Lines->Add(Buffer); } } //---------------------------------------------------------------------------
TN1 ist die Indy-Komponente, Connect und Disconnect erfolgen im Formkonstruktor/-destruktor.
-
Wie bau ich die Verbindung auf? So was wie Active oder open hab ich nicht gefunden.
-
Jansen schrieb:
... Connect und Disconnect ...
Wie könnten entsprechende Methoden wohl heissen?
-
Hab ich dann auch gemerkt
*schäm*
Noch mal eine Frage zu deinem Beispiel.
Ich hab alles so gemacht wie du, funktioniert auch wunderbar.
Mein Unix sieht ein bisschen anders aus als deins, wie kann ich bei mir prüfen in was für einem Verzeichnis ich mich befinde?user@UNIX [/user/dwhst/]
$Bei dem $ Zeichen kann ich meinen Code eingeben. Hab dein Skript schon so abgeändert, das ich in das () Verzeichnis wechseln kann.
Wie kann ich aber abfragen ob ich wirklich in diesem Verzeichnis bin?
-
Du musst halt immer den letzten Output auswerten (die Buffer-Variable). Da steht das drin, was du auch nach einer Eingabe an der Konsole sehen würdest.
-
Bountblasher schrieb:
Ich gebe in der Eingabeaufforderung folgendes ein:
Telnet UNIX [Enter]
dann kommt die Ausgabe:
HP-UX UNIX B.11.11 U 9000/800 (tm)login: user [Enter]
Password: pw [Enter]login und Password ist eine Ausgabe vom System, ich gebe nur den
Benutzer "user" und das Passwort "pw" ein.Wenn du das gleich so gesagt hättest, dann hätte ich dir sofort diesen Code geben können:
#include <windows.h> #include <winsock2.h> //--------------------------------------------------------------------------- VOID ErrorMsg(HWND hwnd, LPCTSTR lpszErr) { MessageBox(hwnd, TEXT(lpszErr), TEXT("ERROR"), MB_OK | MB_ICONERROR); } //--------------------------------------------------------------------------- VOID ShowLastSockError(HWND hwnd) { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL); MessageBox(hwnd, (LPCTSTR)lpMsgBuf, TEXT("ERROR"), MB_OK | MB_ICONERROR); LocalFree(lpMsgBuf); } //--------------------------------------------------------------------------- BOOL StartWinsock2() { WSADATA wsa; int retVal = WSAStartup(MAKEWORD(2,0), &wsa); if(retVal == 0) return TRUE; else { switch(retVal) { case WSASYSNOTREADY: ErrorMsg(NULL, "The underlying network subsystem is not ready for network communication"); case WSAVERNOTSUPPORTED: ErrorMsg(NULL, "The version of Windows Sockets support requested (2.0) is not provided by this particular Windows Sockets implementation."); case WSAEINPROGRESS: ErrorMsg(NULL, "A blocking Windows Sockets 1.1 operation is in progress"); case WSAEPROCLIM: ErrorMsg(NULL, "Limit on the number of tasks supported by the Windows Sockets implementation has been reached"); case WSAEFAULT: ErrorMsg(NULL, "Implementation Error"); } return FALSE; } } //--------------------------------------------------------------------------- BOOL EndWinsock2() { if( WSACleanup() == 0 ) return TRUE; else { ShowLastSockError(NULL); return FALSE; } } //--------------------------------------------------------------------------- SOCKET SetupSocket() { SOCKET retVal = socket(AF_INET, SOCK_STREAM, 0); if(retVal != INVALID_SOCKET) return retVal; else { ShowLastSockError(NULL); return NULL; } } //--------------------------------------------------------------------------- BOOL CloseSocket(SOCKET s) { if( closesocket(s) == 0 ) return TRUE; else { ShowLastSockError(NULL); return FALSE; } } //--------------------------------------------------------------------------- ULONG GetIPFromString(LPTSTR hostnameOrIp) { ULONG retVal; HOSTENT* he; // Is there an IP in hostnameOrIp? retVal = inet_addr(hostnameOrIp); if(retVal == INADDR_NONE) // NO { he = gethostbyname(hostnameOrIp); if(he == NULL) // An error occured { ShowLastSockError(NULL); return 0; } else // everything's fine // Copy the first 4 bytes from he->h_addr_list to ip CopyMemory((PVOID)&retVal, he->h_addr_list[0], 4*sizeof(BYTE)); } return retVal; } //--------------------------------------------------------------------------- BOOL Connect(SOCKET s, USHORT port, LPCTSTR lpszCompName) { SOCKADDR_IN addr; int rc; ZeroMemory((PVOID)&addr, sizeof(SOCKADDR_IN)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = GetIPFromString((LPTSTR)lpszCompName); rc = connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR)); if(rc == 0) return TRUE; else { ShowLastSockError(NULL); return FALSE; } } //--------------------------------------------------------------------------- BOOL Send(SOCKET s, char* buf, int len) { int bytes_sent; bytes_sent = send(s, buf, len, 0); if(bytes_sent != SOCKET_ERROR) return TRUE; else { ShowLastSockError(NULL); return FALSE; } } //--------------------------------------------------------------------------- BOOL Receive(SOCKET s, char* buf, int len) { int bytes_received; bytes_received = recv(s, buf, len, 0); if(bytes_received != SOCKET_ERROR) return TRUE; else { ShowLastSockError(NULL); return FALSE; } } //--------------------------------------------------------------------------- #pragma argsused WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { SOCKET s; char buf[4096]; if( !StartWinsock2() ) return 0; s = SetupSocket(); if(s == NULL) { EndWinsock2(); return 0; } if( !Connect(s, 23, "UNIX") ) { CloseSocket(s); EndWinsock2(); return 0; } Receive(s, buf, 4096); Send(s, "Username\r\n", 10); Receive(s, buf, 4096); Send(s, "Pass\r\n", 6); Receive(s, buf, 4096); Send(s, "cd Skripte\r\n", 12); Receive(s, buf, 4096); Send(s, "dvl_bk.sh\r\n", 11); Receive(s, buf, 4096); Send(s, "quit\r\n", 6); Receive(s, buf, 4096); if( !CloseSocket(s) ) { EndWinsock2(); return 0; } if( !EndWinsock2() ) return 0; return 1; } //---------------------------------------------------------------------------
Der Code ist nicht getestet, da ich keinen Server kenne, bei dem man Benutzername und Pass eingeben muss. Ich hoffe, du kannst auch damit ein wenig was anfangen.
-
äh ja, schön, Fritzi... nur sind wir hier im VCL Forum und haben glücklicherweise den TClientSocket, welcher uns n Haufen von dem WinAPI-Gewusel da abnimmt und die Verwendung von Sockets erheblich erleichtert (o;
-junix
-
junix schrieb:
äh ja, schön, Fritzi... nur sind wir hier im VCL Forum und haben glücklicherweise den TClientSocket, welcher uns n Haufen von dem WinAPI-Gewusel da abnimmt und die Verwendung von Sockets erheblich erleichtert (o;
Ja schön, junix. Aber du hast wohl mitbekommen, dass Bountblasher mich darum gebeten hatte, ihm etwas Code zu geben. Wenn nicht, dann lies den Thread nochmal durch. Tut dir gut! Ich habe somit lediglich mein Versprechen eingelöst. Ganz davon abgesehen arbeitet deine tolle Klasse sicher auch mit genau den Funktionen, mit denen ich arbeite. Warum sollte Bountblasher nicht wissen, was wirklich dahinter steckt. Und nochmal außerdem: ich habe diese Klasse nicht, denn ich hab den BCB3.
-
WebFritzi schrieb:
Aber du hast wohl mitbekommen, dass Bountblasher mich darum gebeten hatte, ihm etwas Code zu geben. Wenn nicht, dann lies den Thread nochmal durch. Tut dir gut!
danke, brauche keine Leseübungen und ich wüsste nicht wieso sonst mir das gut tun sollte. (:
WebFritzi schrieb:
Ganz davon abgesehen arbeitet deine tolle Klasse sicher auch mit genau den Funktionen, mit denen ich arbeite.
Ich glaube du solltest mein Posting nochmals lesen statt gleich rot zu sehen, nur weil man eine kritische Äusserung macht... täte dir wohl ganz gut.... Ich sagte ausdrücklich dass sie komfortabler im Handling sei. Zu deinem Funktionsset bräuchte man noch einen Thread der die IO-Aufgaben übernimmt um sie effizient einsetzen zu können.
WebFritzi schrieb:
Warum sollte Bountblasher nicht wissen, was wirklich dahinter steckt.
Wer sagt denn sowas? Es geht nur darum, dass in der ersten Phase die Erfolgschancen höher und das Verständnis leichter ist als wenn man gleich aus dem Vollen schöpft... vor Allem dann, wenn man sich auf absolutem neuland bewegt...
WebFritzi schrieb:
Und nochmal außerdem: ich habe diese Klasse nicht, denn ich hab den BCB3.
Tja... Für leute mit dem BCB < 5 (oder 4?) haben wir ja auch noch die Indy-Library die dir auch nicht unbekannt sein dürfte....
Also spiel hier nicht gleich den beleidigten Webfritzen. War ja kein persönlicher Angriff sondern nur ein Hinweis am Rande...
-junix
-
junix schrieb:
Für leute mit dem BCB < 5 (oder 4?) haben wir ja auch noch die Indy-Library die dir auch nicht unbekannt sein dürfte....
Ne, isse nich. Aber die ist nicht für den BCB3 gedacht, soweit ich mich erinnern kann.
junix schrieb:
Also spiel hier nicht gleich den beleidigten Webfritzen. War ja kein persönlicher Angriff sondern nur ein Hinweis am Rande...
Auch wenn es nicht wie ein "Hinweis am Rande" daherkam... Ich bin nicht beleidigt. Ich habe lediglich meinen Post gerechtfertigt.
Zum Thread: Wieso? Meinst du nicht, einer reicht? Ich hatte eben an ein Programm für ihn gedacht, dessen Symbol er nur anzuklicken braucht, und schon ist das Skript gestartet. Da braucht's kein Input.
-
WebFritzi schrieb:
junix schrieb:
Für leute mit dem BCB < 5 (oder 4?) haben wir ja auch noch die Indy-Library die dir auch nicht unbekannt sein dürfte....
Ne, isse nich. Aber die ist nicht für den BCB3 gedacht, soweit ich mich erinnern kann.
Äh die älteren Versionen... (damals hiess sie glaube ich WinShoes...) würden da helfen...
WebFritzi schrieb:
Zum Thread: Wieso? Meinst du nicht, einer reicht? Ich hatte eben an ein Programm für ihn gedacht, dessen Symbol er nur anzuklicken braucht, und schon ist das Skript gestartet. Da braucht's kein Input.
Jo, dann gehts... trotzdem wäre ein Thread eleganter um das UI zu entkoppeln...
-junix
-
Ich bedank mich für eure Hilfe.
Es ist immer besser mehrere Möglichkeiten zu kennen...Danke!!!
-
Junix ich hab noch mal kurz eine Frage.
Was bedeudet die Zahl, die man beim connect mit übergeben muss?
TN1->Connect(1);
-
Falls du mich meinst: bei meiner Indy-Version (9.00.14) erwartet Connect keinen Parameter. Und auch bei der beim BCB6 mitgelieferten Version (ca. 8.0) wird kein Parameter benötigt, wenn ich die entsprechende Hilfedatei richtig lese.
-
Hallo Jansen,
hab noch mal eine Frage.
Wie muss ich das machen, das sich mein Programm mit der Unix Maschine verbindet und dann nur den Befehl () ausführt und danach die Verbindung gleich trennt?
Weil so wie ich es gemacht hab (siehe unten) startet er mein Shellskript 2 mal.
Kannst du mir bitte Helfen..void __fastcall TForm1::TN1DataAvailable(TIdTelnet *Sender, const AnsiString Buffer) { bool logged_in = false; bool bEnde = false; String strLogin = "user"; String strPass = "pw"; String strCommand = "nohup bin/dvl_bk.sh > log/dvl_bk.log &"; String strResponse = ""; String strText = ""; if (Buffer != "") { if (!logged_in) { ShowMessage("Ja"); // Loginprompt erreicht if (UpperCase(Buffer).Pos("LOGIN: ") == Buffer.Length() - 6) strText = strLogin; // Passwortprompt erreicht else if (UpperCase(Buffer).Pos("PASSWORD: ") == Buffer.Length() - 9) strText = strPass; // Eingabeprompt erreicht, Kommando abschicken else if (UpperCase(Buffer).Pos(UpperCase("$ ")) > 0) { logged_in = true; strText = strCommand; } if (UpperCase(Buffer).Pos(UpperCase("Controlling.sh")) > 0) { strText = "exit"; } } ShowMessage("Befehl: " + strText); if (strText != "") { // das eigentliche Versenden for (int i = 1; i <= strText.Length(); i++) TN1->SendCh(strText[i]); TN1->SendCh(VK_RETURN); strText = ""; } // Kontrollausgabe Memo1->Lines->Add(Buffer); } }
Edit:
Bitte die Code-Tags benutzen. Danke!
-
Ist die Kontrolle auf den String "Controlling.sh" die Prüfung auf den korrekten Start des Skripts?
Wenn ja, dann darf die natürlich nicht innerhalb der if (!logged_in)-Klammern stehen, da sie ja nach erfolgreichem Login nie ausgeführt wird.
-
Mir ist aufgefallen, dass mein Programm die bool Variable nicht setzt.
Hab sie jetzt mal global gemacht, jetzt funktioniert es.
Mir ist aufgefallen, das nach jeder Eingabe über Telnet mein Programm wider zum Connect zurückspringt. An was kann das liegen?Ich hab die Inidi 9.. und Borland 5 und bei mir benötigt mein Connect eine const int.