155a5a6bdSJérôme Duval /*****************************************************************************/ 255a5a6bdSJérôme Duval // Expander 355a5a6bdSJérôme Duval // Written by Jérôme Duval 455a5a6bdSJérôme Duval // 555a5a6bdSJérôme Duval // ExpanderThread.cpp 655a5a6bdSJérôme Duval // 755a5a6bdSJérôme Duval // Copyright (c) 2004 OpenBeOS Project 855a5a6bdSJérôme Duval // 955a5a6bdSJérôme Duval // Original code from ZipOMatic by jonas.sundstrom@kirilla.com 1055a5a6bdSJérôme Duval // 1155a5a6bdSJérôme Duval // Permission is hereby granted, free of charge, to any person obtaining a 1255a5a6bdSJérôme Duval // copy of this software and associated documentation files (the "Software"), 1355a5a6bdSJérôme Duval // to deal in the Software without restriction, including without limitation 1455a5a6bdSJérôme Duval // the rights to use, copy, modify, merge, publish, distribute, sublicense, 1555a5a6bdSJérôme Duval // and/or sell copies of the Software, and to permit persons to whom the 1655a5a6bdSJérôme Duval // Software is furnished to do so, subject to the following conditions: 1755a5a6bdSJérôme Duval // 1855a5a6bdSJérôme Duval // The above copyright notice and this permission notice shall be included 1955a5a6bdSJérôme Duval // in all copies or substantial portions of the Software. 2055a5a6bdSJérôme Duval // 2155a5a6bdSJérôme Duval // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 2255a5a6bdSJérôme Duval // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2355a5a6bdSJérôme Duval // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2455a5a6bdSJérôme Duval // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2555a5a6bdSJérôme Duval // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2655a5a6bdSJérôme Duval // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2755a5a6bdSJérôme Duval // DEALINGS IN THE SOFTWARE. 2855a5a6bdSJérôme Duval /*****************************************************************************/ 2955a5a6bdSJérôme Duval #include <Path.h> 3055a5a6bdSJérôme Duval #include <ExpanderThread.h> 3155a5a6bdSJérôme Duval #include <image.h> 3255a5a6bdSJérôme Duval #include <signal.h> 3355a5a6bdSJérôme Duval #include <unistd.h> 3455a5a6bdSJérôme Duval #include <errno.h> 3555a5a6bdSJérôme Duval 3655a5a6bdSJérôme Duval const char * ExpanderThreadName = "ExpanderThread"; 3755a5a6bdSJérôme Duval 3855a5a6bdSJérôme Duval ExpanderThread::ExpanderThread (BMessage * refs_message, BMessenger * messenger) 3955a5a6bdSJérôme Duval : GenericThread(ExpanderThreadName, B_NORMAL_PRIORITY, refs_message), 4055a5a6bdSJérôme Duval fWindowMessenger(messenger), 4155a5a6bdSJérôme Duval fThreadId(-1), 4255a5a6bdSJérôme Duval fStdIn(-1), 4355a5a6bdSJérôme Duval fStdOut(-1), 4455a5a6bdSJérôme Duval fStdErr(-1), 4555a5a6bdSJérôme Duval fExpanderOutput(NULL), 4655a5a6bdSJérôme Duval fExpanderOutputString(), 4755a5a6bdSJérôme Duval fExpanderOutputBuffer(new char [4096]) 4855a5a6bdSJérôme Duval { 4955a5a6bdSJérôme Duval SetDataStore(new BMessage (* refs_message)); // leak? 5055a5a6bdSJérôme Duval // prevents bug with B_SIMPLE_DATA 5155a5a6bdSJérôme Duval // (drag&drop messages) 5255a5a6bdSJérôme Duval } 5355a5a6bdSJérôme Duval 5455a5a6bdSJérôme Duval ExpanderThread::~ExpanderThread() 5555a5a6bdSJérôme Duval { 5655a5a6bdSJérôme Duval delete fWindowMessenger; 5755a5a6bdSJérôme Duval delete [] fExpanderOutputBuffer; 5855a5a6bdSJérôme Duval } 5955a5a6bdSJérôme Duval 6055a5a6bdSJérôme Duval status_t 6155a5a6bdSJérôme Duval ExpanderThread::ThreadStartup() 6255a5a6bdSJérôme Duval { 6355a5a6bdSJérôme Duval status_t status = B_OK; 6455a5a6bdSJérôme Duval entry_ref srcRef, destRef; 6555a5a6bdSJérôme Duval BString cmd; 6655a5a6bdSJérôme Duval 6755a5a6bdSJérôme Duval if ((status = GetDataStore()->FindRef("srcRef", &srcRef))!=B_OK) 6855a5a6bdSJérôme Duval return status; 69*91d1efffSJérôme Duval if ((status = GetDataStore()->FindRef("destRef", &destRef))==B_OK) { 70*91d1efffSJérôme Duval BPath path(&destRef); 71*91d1efffSJérôme Duval chdir(path.Path()); 72*91d1efffSJérôme Duval } 7355a5a6bdSJérôme Duval if ((status = GetDataStore()->FindString("cmd", &cmd))!=B_OK) 7455a5a6bdSJérôme Duval return status; 7555a5a6bdSJérôme Duval 7655a5a6bdSJérôme Duval BPath path(&srcRef); 7755a5a6bdSJérôme Duval BString pathString(path.Path()); 7855a5a6bdSJérôme Duval pathString.CharacterEscape("\"$`", '\\'); 7955a5a6bdSJérôme Duval pathString.Prepend("\""); 8055a5a6bdSJérôme Duval pathString.Append("\""); 8155a5a6bdSJérôme Duval cmd.ReplaceAll("%s", pathString.String()); 8255a5a6bdSJérôme Duval 8355a5a6bdSJérôme Duval int32 argc = 3; 8455a5a6bdSJérôme Duval const char ** argv = new const char * [argc + 1]; 8555a5a6bdSJérôme Duval 8655a5a6bdSJérôme Duval argv[0] = strdup("/bin/sh"); 8755a5a6bdSJérôme Duval argv[1] = strdup("-c"); 8855a5a6bdSJérôme Duval argv[2] = strdup(cmd.String()); 8955a5a6bdSJérôme Duval argv[argc] = NULL; 9055a5a6bdSJérôme Duval 9155a5a6bdSJérôme Duval fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr); 9255a5a6bdSJérôme Duval 9355a5a6bdSJérôme Duval delete [] argv; 9455a5a6bdSJérôme Duval 9555a5a6bdSJérôme Duval if (fThreadId < 0) 9655a5a6bdSJérôme Duval return fThreadId; 9755a5a6bdSJérôme Duval 9855a5a6bdSJérôme Duval resume_thread(fThreadId); 9955a5a6bdSJérôme Duval 10055a5a6bdSJérôme Duval fExpanderOutput = fdopen(fStdOut, "r"); 10155a5a6bdSJérôme Duval 10255a5a6bdSJérôme Duval return B_OK; 10355a5a6bdSJérôme Duval } 10455a5a6bdSJérôme Duval 10555a5a6bdSJérôme Duval status_t 10655a5a6bdSJérôme Duval ExpanderThread::ExecuteUnit (void) 10755a5a6bdSJérôme Duval { 10855a5a6bdSJérôme Duval // read output from command 10955a5a6bdSJérôme Duval // send it to window 11055a5a6bdSJérôme Duval 11155a5a6bdSJérôme Duval char * output_string; 11255a5a6bdSJérôme Duval output_string = fgets(fExpanderOutputBuffer , 4096-1, fExpanderOutput); 11355a5a6bdSJérôme Duval 11455a5a6bdSJérôme Duval if (output_string == NULL) 11555a5a6bdSJérôme Duval return EOF; 11655a5a6bdSJérôme Duval 11755a5a6bdSJérôme Duval BMessage message('outp'); 11855a5a6bdSJérôme Duval message.AddString("output", output_string); 11955a5a6bdSJérôme Duval for (int32 i=0; i<5; i++) { 12055a5a6bdSJérôme Duval output_string = fgets(fExpanderOutputBuffer , 4096-1, fExpanderOutput); 12155a5a6bdSJérôme Duval if(!output_string) 12255a5a6bdSJérôme Duval break; 12355a5a6bdSJérôme Duval message.AddString("output", output_string); 12455a5a6bdSJérôme Duval } 12555a5a6bdSJérôme Duval fWindowMessenger->SendMessage(&message); 12655a5a6bdSJérôme Duval 12755a5a6bdSJérôme Duval return B_OK; 12855a5a6bdSJérôme Duval } 12955a5a6bdSJérôme Duval 13055a5a6bdSJérôme Duval status_t 13155a5a6bdSJérôme Duval ExpanderThread::ThreadShutdown(void) 13255a5a6bdSJérôme Duval { 13355a5a6bdSJérôme Duval close(fStdIn); 13455a5a6bdSJérôme Duval close(fStdOut); 13555a5a6bdSJérôme Duval close(fStdErr); 13655a5a6bdSJérôme Duval 13755a5a6bdSJérôme Duval return B_OK; 13855a5a6bdSJérôme Duval } 13955a5a6bdSJérôme Duval 14055a5a6bdSJérôme Duval void 14155a5a6bdSJérôme Duval ExpanderThread::ThreadStartupFailed(status_t status) 14255a5a6bdSJérôme Duval { 14355a5a6bdSJérôme Duval fprintf(stderr, "ExpanderThread::ThreadStartupFailed() : %s\n", strerror(status)); 14455a5a6bdSJérôme Duval 14555a5a6bdSJérôme Duval Quit(); 14655a5a6bdSJérôme Duval } 14755a5a6bdSJérôme Duval 14855a5a6bdSJérôme Duval void 14955a5a6bdSJérôme Duval ExpanderThread::ExecuteUnitFailed(status_t status) 15055a5a6bdSJérôme Duval { 15155a5a6bdSJérôme Duval if (status == EOF) { 15255a5a6bdSJérôme Duval // thread has finished, been quit or killed, we don't know 15355a5a6bdSJérôme Duval fWindowMessenger->SendMessage(new BMessage('exit')); 15455a5a6bdSJérôme Duval } else { 15555a5a6bdSJérôme Duval // explicit error - communicate error to Window 15655a5a6bdSJérôme Duval fWindowMessenger->SendMessage(new BMessage('exrr')); 15755a5a6bdSJérôme Duval } 15855a5a6bdSJérôme Duval 15955a5a6bdSJérôme Duval Quit(); 16055a5a6bdSJérôme Duval } 16155a5a6bdSJérôme Duval 16255a5a6bdSJérôme Duval void 16355a5a6bdSJérôme Duval ExpanderThread::ThreadShutdownFailed(status_t status) 16455a5a6bdSJérôme Duval { 16555a5a6bdSJérôme Duval fprintf(stderr, "ExpanderThread::ThreadShutdownFailed() %s\n", strerror(status)); 16655a5a6bdSJérôme Duval } 16755a5a6bdSJérôme Duval 16855a5a6bdSJérôme Duval 16955a5a6bdSJérôme Duval status_t 17055a5a6bdSJérôme Duval ExpanderThread::ProcessRefs(BMessage *msg) 17155a5a6bdSJérôme Duval { 17255a5a6bdSJérôme Duval return B_OK; 17355a5a6bdSJérôme Duval } 17455a5a6bdSJérôme Duval 17555a5a6bdSJérôme Duval thread_id 17655a5a6bdSJérôme Duval ExpanderThread::PipeCommand(int argc, const char **argv, int &in, int &out, int &err, const char **envp) 17755a5a6bdSJérôme Duval { 17855a5a6bdSJérôme Duval // This function written by Peter Folk <pfolk@uni.uiuc.edu> 17955a5a6bdSJérôme Duval // and published in the BeDevTalk FAQ 18055a5a6bdSJérôme Duval // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 18155a5a6bdSJérôme Duval 18255a5a6bdSJérôme Duval // Save current FDs 18355a5a6bdSJérôme Duval int old_in = dup(0); 18455a5a6bdSJérôme Duval int old_out = dup(1); 18555a5a6bdSJérôme Duval int old_err = dup(2); 18655a5a6bdSJérôme Duval 18755a5a6bdSJérôme Duval int filedes[2]; 18855a5a6bdSJérôme Duval 18955a5a6bdSJérôme Duval /* Create new pipe FDs as stdin, stdout, stderr */ 19055a5a6bdSJérôme Duval pipe(filedes); dup2(filedes[0],0); close(filedes[0]); 19155a5a6bdSJérôme Duval in=filedes[1]; // Write to in, appears on cmd's stdin 19255a5a6bdSJérôme Duval pipe(filedes); dup2(filedes[1],1); close(filedes[1]); 19355a5a6bdSJérôme Duval out=filedes[0]; // Read from out, taken from cmd's stdout 19455a5a6bdSJérôme Duval pipe(filedes); dup2(filedes[1],2); close(filedes[1]); 19555a5a6bdSJérôme Duval err=filedes[0]; // Read from err, taken from cmd's stderr 19655a5a6bdSJérôme Duval 19755a5a6bdSJérôme Duval // "load" command. 19855a5a6bdSJérôme Duval thread_id ret = load_image(argc, argv, envp); 19955a5a6bdSJérôme Duval 20055a5a6bdSJérôme Duval if (ret < B_OK) 20155a5a6bdSJérôme Duval return ret; 20255a5a6bdSJérôme Duval 20355a5a6bdSJérôme Duval // thread ret is now suspended. 20455a5a6bdSJérôme Duval 20555a5a6bdSJérôme Duval setpgid(ret, ret); 20655a5a6bdSJérôme Duval 20755a5a6bdSJérôme Duval // Restore old FDs 20855a5a6bdSJérôme Duval close(0); dup(old_in); close(old_in); 20955a5a6bdSJérôme Duval close(1); dup(old_out); close(old_out); 21055a5a6bdSJérôme Duval close(2); dup(old_err); close(old_err); 21155a5a6bdSJérôme Duval 21255a5a6bdSJérôme Duval /* Theoretically I should do loads of error checking, but 21355a5a6bdSJérôme Duval the calls aren't very likely to fail, and that would 21455a5a6bdSJérôme Duval muddy up the example quite a bit. YMMV. */ 21555a5a6bdSJérôme Duval 21655a5a6bdSJérôme Duval return ret; 21755a5a6bdSJérôme Duval } 21855a5a6bdSJérôme Duval 21955a5a6bdSJérôme Duval 22055a5a6bdSJérôme Duval status_t 22155a5a6bdSJérôme Duval ExpanderThread::SuspendExternalExpander() 22255a5a6bdSJérôme Duval { 22355a5a6bdSJérôme Duval status_t status; 22455a5a6bdSJérôme Duval thread_info thread_info; 22555a5a6bdSJérôme Duval status = get_thread_info(fThreadId, &thread_info); 22655a5a6bdSJérôme Duval BString thread_name = thread_info.name; 22755a5a6bdSJérôme Duval 22855a5a6bdSJérôme Duval if (status == B_OK) 22955a5a6bdSJérôme Duval return send_signal(-fThreadId, SIGSTOP); 23055a5a6bdSJérôme Duval else 23155a5a6bdSJérôme Duval return status; 23255a5a6bdSJérôme Duval } 23355a5a6bdSJérôme Duval 23455a5a6bdSJérôme Duval status_t 23555a5a6bdSJérôme Duval ExpanderThread::ResumeExternalExpander() 23655a5a6bdSJérôme Duval { 23755a5a6bdSJérôme Duval status_t status = B_OK; 23855a5a6bdSJérôme Duval thread_info thread_info; 23955a5a6bdSJérôme Duval status = get_thread_info(fThreadId, &thread_info); 24055a5a6bdSJérôme Duval BString thread_name = thread_info.name; 24155a5a6bdSJérôme Duval 24255a5a6bdSJérôme Duval if (status == B_OK) 24355a5a6bdSJérôme Duval return send_signal(-fThreadId, SIGCONT); 24455a5a6bdSJérôme Duval else 24555a5a6bdSJérôme Duval return status; 24655a5a6bdSJérôme Duval } 24755a5a6bdSJérôme Duval 24855a5a6bdSJérôme Duval status_t 24955a5a6bdSJérôme Duval ExpanderThread::InterruptExternalExpander() 25055a5a6bdSJérôme Duval { 25155a5a6bdSJérôme Duval status_t status = B_OK; 25255a5a6bdSJérôme Duval thread_info thread_info; 25355a5a6bdSJérôme Duval status = get_thread_info (fThreadId, &thread_info); 25455a5a6bdSJérôme Duval BString thread_name = thread_info.name; 25555a5a6bdSJérôme Duval 25655a5a6bdSJérôme Duval if (status == B_OK) { 25755a5a6bdSJérôme Duval status = send_signal(-fThreadId, SIGINT); 25855a5a6bdSJérôme Duval WaitOnExternalExpander(); 25955a5a6bdSJérôme Duval } 26055a5a6bdSJérôme Duval return status; 26155a5a6bdSJérôme Duval } 26255a5a6bdSJérôme Duval 26355a5a6bdSJérôme Duval status_t 26455a5a6bdSJérôme Duval ExpanderThread::WaitOnExternalExpander() 26555a5a6bdSJérôme Duval { 26655a5a6bdSJérôme Duval status_t status; 26755a5a6bdSJérôme Duval thread_info thread_info; 26855a5a6bdSJérôme Duval status = get_thread_info(fThreadId, &thread_info); 26955a5a6bdSJérôme Duval BString thread_name = thread_info.name; 27055a5a6bdSJérôme Duval 27155a5a6bdSJérôme Duval if (status == B_OK) 27255a5a6bdSJérôme Duval return wait_for_thread(fThreadId, &status); 27355a5a6bdSJérôme Duval else 27455a5a6bdSJérôme Duval return status; 27555a5a6bdSJérôme Duval } 276