3 * This file is part of the KDE project, module kdesu.
4 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
6 * This file contains code from TEShell.C of the KDE konsole.
7 * Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
9 * This is free software; you can use this library under the GNU Library
10 * General Public License, version 2. See the file "COPYING.LIB" for the
11 * exact licensing terms.
13 * process.cpp: Functionality to build a front end to password asking
31 #include <sys/types.h>
35 #include <sys/resource.h>
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h> // Needed on some systems.
41 #include <QtCore/QBool>
42 #include <QtCore/QFile>
44 #include <ksharedconfig.h>
45 #include <kconfiggroup.h>
47 #include <kstandarddirs.h>
53 using namespace KDESuPrivate
;
56 ** Wait for @p ms miliseconds
57 ** @param fd file descriptor
58 ** @param ms time to wait in miliseconds
61 int PtyProcess::waitMS(int fd
,int ms
)
70 return select(fd
+1, &fds
, 0L, 0L, &tv
);
73 // XXX this function is nonsense:
74 // - for our child, we could use waitpid().
75 // - the configurability at this place it *complete* braindamage
77 ** Basic check for the existence of @p pid.
78 ** Returns true iff @p pid is an extant process.
80 bool PtyProcess::checkPid(pid_t pid
)
82 KSharedConfig::Ptr config
= KGlobal::config();
83 KConfigGroup
cg(config
, "super-user-command");
84 QString superUserCommand
= cg
.readEntry("super-user-command", "sudo");
85 //sudo does not accept signals from user so we except it
86 if (superUserCommand
== "sudo") {
89 return kill(pid
, 0) == 0;
94 ** Check process exit status for process @p pid.
95 ** On error (no child, no exit), return Error (-1).
96 ** If child @p pid has exited, return its exit status,
97 ** (which may be zero).
98 ** If child @p has not exited, return NotExited (-2).
101 int PtyProcess::checkPidExited(pid_t pid
)
104 ret
= waitpid(pid
, &state
, WNOHANG
);
108 kError(900) << k_lineinfo
<< "waitpid(): " << perror
<< "\n";
113 if (WIFEXITED(state
))
114 return WEXITSTATUS(state
);
122 class PtyProcess::PtyProcessPrivate
125 PtyProcessPrivate() : m_pPTY(0L) {}
130 QList
<QByteArray
> env
;
136 PtyProcess::PtyProcess()
137 :d(new PtyProcessPrivate
)
144 int PtyProcess::init()
147 d
->m_pPTY
= new KPty();
148 if (!d
->m_pPTY
->open())
150 kError(900) << k_lineinfo
<< "Failed to open PTY.\n";
153 d
->m_Inbuf
.resize(0);
158 PtyProcess::~PtyProcess()
163 /** Set additional environment variables. */
164 void PtyProcess::setEnvironment( const QList
<QByteArray
> &env
)
169 int PtyProcess::fd() const
171 return d
->m_pPTY
? d
->m_pPTY
->masterFd() : -1;
174 int PtyProcess::pid() const
179 /** Returns the additional environment variables set by setEnvironment() */
180 QList
<QByteArray
> PtyProcess::environment() const
186 QByteArray
PtyProcess::readAll(bool block
)
189 if (!d
->m_Inbuf
.isEmpty())
191 // if there is still something in the buffer, we need not block.
192 // we should still try to read any further output, from the fd, though.
195 d
->m_Inbuf
.resize(0);
198 int flags
= fcntl(fd(), F_GETFL
);
201 kError(900) << k_lineinfo
<< "fcntl(F_GETFL): " << perror
<< "\n";
206 flags
&= ~O_NONBLOCK
;
210 if ((flags
!= oflags
) && (fcntl(fd(), F_SETFL
, flags
) < 0))
212 // We get an error here when the child process has closed
213 // the file descriptor already.
221 nbytes
= read(fd(), buf
, 255);
229 break; // nothing available / eof
231 buf
[nbytes
] = '\000';
240 QByteArray
PtyProcess::readLine(bool block
)
242 d
->m_Inbuf
= readAll(block
);
246 if (!d
->m_Inbuf
.isEmpty())
248 pos
= d
->m_Inbuf
.indexOf('\n');
251 // NOTE: this means we return something even if there in no full line!
253 d
->m_Inbuf
.resize(0);
256 ret
= d
->m_Inbuf
.left(pos
);
257 d
->m_Inbuf
= d
->m_Inbuf
.mid(pos
+1);
265 void PtyProcess::writeLine(const QByteArray
&line
, bool addnl
)
268 write(fd(), line
, line
.length());
270 write(fd(), "\n", 1);
274 void PtyProcess::unreadLine(const QByteArray
&line
, bool addnl
)
276 QByteArray tmp
= line
;
280 d
->m_Inbuf
.prepend(tmp
);
283 void PtyProcess::setExitString(const QByteArray
&exit
)
289 * Fork and execute the command. This returns in the parent.
292 int PtyProcess::exec(const QByteArray
&command
, const QList
<QByteArray
> &args
)
294 kDebug(900) << k_lineinfo
<< "Running `" << command
<< "'\n";
300 if ((m_Pid
= fork()) == -1)
302 kError(900) << k_lineinfo
<< "fork(): " << perror
<< "\n";
309 d
->m_pPTY
->closeSlave();
317 for (i
= 0; i
< d
->env
.count(); ++i
)
319 putenv(const_cast<char *>(d
->env
.at(i
).constData()));
321 unsetenv("KDE_FULL_SESSION");
322 // for : Qt: Session management error
323 unsetenv("SESSION_MANAGER");
324 // QMutex::lock , deadlocks without that.
325 // <thiago> you cannot connect to the user's session bus from another UID
326 unsetenv("DBUS_SESSION_BUS_ADDRESS");
328 // set temporarily LC_ALL to C, for su (to be able to parse "Password:")
329 const QByteArray old_lc_all
= qgetenv( "LC_ALL" );
330 if( !old_lc_all
.isEmpty() )
331 qputenv( "KDESU_LC_ALL", old_lc_all
);
333 unsetenv( "KDESU_LC_ALL" );
334 qputenv("LC_ALL", "C");
336 // From now on, terminal output goes through the tty.
339 if (command
.contains('/'))
343 QString file
= KStandardDirs::findExe(command
);
346 kError(900) << k_lineinfo
<< command
<< " not found\n";
349 path
= QFile::encodeName(file
);
352 const char **argp
= (const char **)malloc((args
.count()+2)*sizeof(char *));
356 for (QList
<QByteArray
>::ConstIterator it
=args
.begin(); it
!=args
.end(); ++it
, ++i
)
361 execv(path
, const_cast<char **>(argp
));
362 kError(900) << k_lineinfo
<< "execv(\"" << path
<< "\"): " << perror
<< "\n";
364 return -1; // Shut up compiler. Never reached.
369 * Wait until the terminal is set into no echo mode. At least one su
370 * (RH6 w/ Linux-PAM patches) sets noecho mode AFTER writing the Password:
371 * prompt, using TCSAFLUSH. This flushes the terminal I/O queues, possibly
372 * taking the password with it. So we wait until no echo mode is set
373 * before writing the password.
374 * Note that this is done on the slave fd. While Linux allows tcgetattr() on
375 * the master side, Solaris doesn't.
378 int PtyProcess::WaitSlave()
380 kDebug(900) << k_lineinfo
<< "Child pid " << m_Pid
;
385 if (!checkPid(m_Pid
))
389 if (!d
->m_pPTY
->tcGetAttr(&tio
))
391 kError(900) << k_lineinfo
<< "tcgetattr(): " << perror
<< "\n";
394 if (tio
.c_lflag
& ECHO
)
396 kDebug(900) << k_lineinfo
<< "Echo mode still on.\n";
406 int PtyProcess::enableLocalEcho(bool enable
)
408 return d
->m_pPTY
->setEcho(enable
) ? 0 : -1;
412 void PtyProcess::setTerminal(bool terminal
)
414 m_bTerminal
= terminal
;
417 void PtyProcess::setErase(bool erase
)
423 * Copy output to stdout until the child process exists, or a line of output
425 * We have to use waitpid() to test for exit. Merely waiting for EOF on the
426 * pty does not work, because the target process may have children still
427 * attached to the terminal.
430 int PtyProcess::waitForChild()
439 // specify timeout to make sure select() does not block, even if the
440 // process is dead / non-responsive. It does not matter if we abort too
441 // early. In that case 0 is returned, and we'll try again in the next
442 // iteration. (As long as we don't consitently time out in each iteration)
445 timeout
.tv_usec
= 100000;
446 int ret
= select(fd()+1, &fds
, 0L, 0L, &timeout
);
451 kError(900) << k_lineinfo
<< "select(): " << perror
<< "\n";
459 QByteArray output
= readAll(false);
460 bool lineStart
= true;
461 while (!output
.isNull())
463 if (!m_Exit
.isEmpty())
465 // match exit string only at line starts
466 int pos
= output
.indexOf(m_Exit
);
467 if ((pos
>= 0) && ((pos
== 0 && lineStart
) || (output
.at (pos
- 1) == '\n')))
469 kill(m_Pid
, SIGTERM
);
474 fputs(output
, stdout
);
477 lineStart
= output
.endsWith( '\n' );
478 output
= readAll(false);
482 ret
= checkPidExited(m_Pid
);
485 if (errno
== ECHILD
) return 0;
488 else if (ret
== Killed
)
492 else if (ret
== NotExited
)
504 * SetupTTY: Creates a new session. The filedescriptor "fd" should be
505 * connected to the tty. It is closed after the tty is reopened to make it
506 * our controlling terminal. This way the tty is always opened at least once
507 * so we'll never get EIO when reading from it.
510 int PtyProcess::setupTTY()
512 // Reset signal handlers
513 for (int sig
= 1; sig
< NSIG
; sig
++)
514 KDE_signal(sig
, SIG_DFL
);
515 KDE_signal(SIGHUP
, SIG_IGN
);
517 d
->m_pPTY
->setCTty();
519 // Connect stdin, stdout and stderr
520 int slave
= d
->m_pPTY
->slaveFd();
521 dup2(slave
, 0); dup2(slave
, 1); dup2(slave
, 2);
523 // Close all file handles
524 // XXX this caused problems in KProcess - not sure why anymore. -- ???
525 // Because it will close the start notification pipe. -- ossi
527 getrlimit(RLIMIT_NOFILE
, &rlp
);
528 for (int i
= 3; i
< (int)rlp
.rlim_cur
; i
++)
531 // Disable OPOST processing. Otherwise, '\n' are (on Linux at least)
532 // translated to '\r\n'.
533 struct ::termios tio
;
534 if (tcgetattr(0, &tio
) < 0)
536 kError(900) << k_lineinfo
<< "tcgetattr(): " << perror
<< "\n";
539 tio
.c_oflag
&= ~OPOST
;
540 if (tcsetattr(0, TCSANOW
, &tio
) < 0)
542 kError(900) << k_lineinfo
<< "tcsetattr(): " << perror
<< "\n";
549 void PtyProcess::virtual_hook( int, void* )
550 { /*BASE::virtual_hook( id, data );*/ }