diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch) | |
tree | 67208f7c145782a7e90b123b982ca78d88cc2c87 /kalarm/lib/shellprocess.cpp | |
download | tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kalarm/lib/shellprocess.cpp')
-rw-r--r-- | kalarm/lib/shellprocess.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/kalarm/lib/shellprocess.cpp b/kalarm/lib/shellprocess.cpp new file mode 100644 index 000000000..1e37d2e74 --- /dev/null +++ b/kalarm/lib/shellprocess.cpp @@ -0,0 +1,208 @@ +/* + * shellprocess.cpp - execute a shell process + * Program: kalarm + * Copyright (c) 2004, 2005 by David Jarvie <software@astrojar.org.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <sys/stat.h> +#include <kapplication.h> +#include <klocale.h> +#include <kdebug.h> + +#include "shellprocess.moc" + + +QCString ShellProcess::mShellName; +QCString ShellProcess::mShellPath; +bool ShellProcess::mInitialised = false; +bool ShellProcess::mAuthorised = false; + + +ShellProcess::ShellProcess(const QString& command) + : KShellProcess(shellName()), + mCommand(command), + mStatus(INACTIVE), + mStdinExit(false) +{ +} + +/****************************************************************************** +* Execute a command. +*/ +bool ShellProcess::start(Communication comm) +{ + if (!authorised()) + { + mStatus = UNAUTHORISED; + return false; + } + KShellProcess::operator<<(mCommand); + connect(this, SIGNAL(wroteStdin(KProcess*)), SLOT(writtenStdin(KProcess*))); + connect(this, SIGNAL(processExited(KProcess*)), SLOT(slotExited(KProcess*))); + if (!KShellProcess::start(KProcess::NotifyOnExit, comm)) + { + mStatus = START_FAIL; + return false; + } + mStatus = RUNNING; + return true; +} + +/****************************************************************************** +* Called when a shell process execution completes. +* Interprets the exit status according to which shell was called, and emits +* a shellExited() signal. +*/ +void ShellProcess::slotExited(KProcess* proc) +{ + kdDebug(5950) << "ShellProcess::slotExited()\n"; + mStdinQueue.clear(); + mStatus = SUCCESS; + if (!proc->normalExit()) + { + kdWarning(5950) << "ShellProcess::slotExited(" << mCommand << ") " << mShellName << ": died/killed\n"; + mStatus = DIED; + } + else + { + // Some shells report if the command couldn't be found, or is not executable + int status = proc->exitStatus(); + if (mShellName == "bash" && (status == 126 || status == 127) + || mShellName == "ksh" && status == 127) + { + kdWarning(5950) << "ShellProcess::slotExited(" << mCommand << ") " << mShellName << ": not found or not executable\n"; + mStatus = NOT_FOUND; + } + } + emit shellExited(this); +} + +/****************************************************************************** +* Write a string to STDIN. +*/ +void ShellProcess::writeStdin(const char* buffer, int bufflen) +{ + QCString scopy(buffer, bufflen+1); // construct a deep copy + bool write = mStdinQueue.isEmpty(); + mStdinQueue.append(scopy); + if (write) + KProcess::writeStdin(mStdinQueue.first(), mStdinQueue.first().length()); +} + +/****************************************************************************** +* Called when output to STDIN completes. +* Send the next queued output, if any. +* Note that buffers written to STDIN must not be freed until the writtenStdin() +* signal has been processed. +*/ +void ShellProcess::writtenStdin(KProcess* proc) +{ + mStdinQueue.pop_front(); // free the buffer which has now been written + if (!mStdinQueue.isEmpty()) + proc->writeStdin(mStdinQueue.first(), mStdinQueue.first().length()); + else if (mStdinExit) + kill(); +} + +/****************************************************************************** +* Tell the process to exit once all STDIN strings have been written. +*/ +void ShellProcess::stdinExit() +{ + if (mStdinQueue.isEmpty()) + kill(); + else + mStdinExit = true; +} + +/****************************************************************************** +* Return the error message corresponding to the command exit status. +* Reply = null string if not yet exited, or if command successful. +*/ +QString ShellProcess::errorMessage() const +{ + switch (mStatus) + { + case UNAUTHORISED: + return i18n("Failed to execute command (shell access not authorized):"); + case START_FAIL: + case NOT_FOUND: + return i18n("Failed to execute command:"); + case DIED: + return i18n("Command execution error:"); + case INACTIVE: + case RUNNING: + case SUCCESS: + default: + return QString::null; + } +} + +/****************************************************************************** +* Determine which shell to use. +* This is a duplication of what KShellProcess does, but we need to know +* which shell is used in order to decide what its exit code means. +*/ +const QCString& ShellProcess::shellPath() +{ + if (mShellPath.isEmpty()) + { + // Get the path to the shell + mShellPath = "/bin/sh"; + QCString envshell = QCString(getenv("SHELL")).stripWhiteSpace(); + if (!envshell.isEmpty()) + { + struct stat fileinfo; + if (stat(envshell.data(), &fileinfo) != -1 // ensure file exists + && !S_ISDIR(fileinfo.st_mode) // and it's not a directory + && !S_ISCHR(fileinfo.st_mode) // and it's not a character device + && !S_ISBLK(fileinfo.st_mode) // and it's not a block device +#ifdef S_ISSOCK + && !S_ISSOCK(fileinfo.st_mode) // and it's not a socket +#endif + && !S_ISFIFO(fileinfo.st_mode) // and it's not a fifo + && !access(envshell.data(), X_OK)) // and it's executable + mShellPath = envshell; + } + + // Get the shell filename with the path stripped off + int i = mShellPath.findRev('/'); + if (i >= 0) + mShellName = mShellPath.mid(i + 1); + else + mShellName = mShellPath; + } + return mShellPath; +} + +/****************************************************************************** +* Check whether shell commands are allowed at all. +*/ +bool ShellProcess::authorised() +{ + if (!mInitialised) + { + mAuthorised = kapp->authorize("shell_access"); + mInitialised = true; + } + return mAuthorised; +} |