TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

process.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /* vi: ts=8 sts=4 sw=4
  2. *
  3. * $Id$
  4. *
  5. * This file is part of the KDE project, module kdesu.
  6. * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
  7. *
  8. * This file contains code from TEShell.C of the KDE konsole.
  9. * Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
  10. *
  11. * This is free software; you can use this library under the GNU Library
  12. * General Public License, version 2. See the file "COPYING.LIB" for the
  13. * exact licensing terms.
  14. *
  15. * process.cpp: Functionality to build a front end to password asking
  16. * terminal programs.
  17. */
  18. #include <config.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <fcntl.h>
  23. #include <signal.h>
  24. #include <errno.h>
  25. #include <string.h>
  26. #include <termios.h>
  27. #include <signal.h>
  28. #include <sys/types.h>
  29. #include <sys/wait.h>
  30. #include <sys/stat.h>
  31. #include <sys/time.h>
  32. #include <sys/resource.h>
  33. #include <sys/ioctl.h>
  34. #if defined(__SVR4) && defined(sun)
  35. #include <stropts.h>
  36. #include <sys/stream.h>
  37. #endif
  38. #ifdef HAVE_SYS_SELECT_H
  39. #include <sys/select.h> // Needed on some systems.
  40. #endif
  41. #include <tqglobal.h>
  42. #include <tqcstring.h>
  43. #include <tqfile.h>
  44. #include <kconfig.h>
  45. #include <kdebug.h>
  46. #include <kstandarddirs.h>
  47. #include "process.h"
  48. #include "kdesu_pty.h"
  49. #include "kcookie.h"
  50. int PtyProcess::waitMS(int fd,int ms)
  51. {
  52. struct timeval tv;
  53. tv.tv_sec = 0;
  54. tv.tv_usec = 1000*ms;
  55. fd_set fds;
  56. FD_ZERO(&fds);
  57. FD_SET(fd,&fds);
  58. return select(fd+1, &fds, 0L, 0L, &tv);
  59. }
  60. /*
  61. ** Basic check for the existence of @p pid.
  62. ** Returns true iff @p pid is an extant process.
  63. */
  64. bool PtyProcess::checkPid(pid_t pid)
  65. {
  66. KConfig* config = KGlobal::config();
  67. config->setGroup("super-user-command");
  68. TQString superUserCommand = config->readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
  69. //sudo does not accept signals from user so we except it
  70. if (superUserCommand == "sudo") {
  71. return true;
  72. } else {
  73. return kill(pid,0) == 0;
  74. }
  75. }
  76. /*
  77. ** Check process exit status for process @p pid.
  78. ** On error (no child, no exit), return Error (-1).
  79. ** If child @p pid has exited, return its exit status,
  80. ** (which may be zero).
  81. ** If child @p has not exited, return NotExited (-2).
  82. */
  83. int PtyProcess::checkPidExited(pid_t pid)
  84. {
  85. int state, ret;
  86. ret = waitpid(pid, &state, WNOHANG);
  87. if (ret < 0)
  88. {
  89. kdError(900) << k_lineinfo << "waitpid(): " << perror << "\n";
  90. return Error;
  91. }
  92. if (ret == pid)
  93. {
  94. if (WIFEXITED(state))
  95. return WEXITSTATUS(state);
  96. return Killed;
  97. }
  98. return NotExited;
  99. }
  100. class PtyProcess::PtyProcessPrivate
  101. {
  102. public:
  103. QCStringList env;
  104. };
  105. PtyProcess::PtyProcess()
  106. {
  107. m_bTerminal = false;
  108. m_bErase = false;
  109. m_pPTY = 0L;
  110. d = new PtyProcessPrivate;
  111. }
  112. int PtyProcess::init()
  113. {
  114. delete m_pPTY;
  115. m_pPTY = new PTY();
  116. m_Fd = m_pPTY->getpt();
  117. if (m_Fd < 0)
  118. return -1;
  119. if ((m_pPTY->grantpt() < 0) || (m_pPTY->unlockpt() < 0))
  120. {
  121. kdError(900) << k_lineinfo << "Master setup failed.\n";
  122. m_Fd = -1;
  123. return -1;
  124. }
  125. m_TTY = m_pPTY->ptsname();
  126. m_Inbuf.resize(0);
  127. return 0;
  128. }
  129. PtyProcess::~PtyProcess()
  130. {
  131. delete m_pPTY;
  132. delete d;
  133. }
  134. /** Set additinal environment variables. */
  135. void PtyProcess::setEnvironment( const QCStringList &env )
  136. {
  137. d->env = env;
  138. }
  139. const QCStringList& PtyProcess::environment() const
  140. {
  141. return d->env;
  142. }
  143. /*
  144. * Read one line of input. The terminal is in canonical mode, so you always
  145. * read a line at at time, but it's possible to receive multiple lines in
  146. * one time.
  147. */
  148. TQCString PtyProcess::readLine(bool block)
  149. {
  150. int pos;
  151. TQCString ret;
  152. if (!m_Inbuf.isEmpty())
  153. {
  154. pos = m_Inbuf.find('\n');
  155. if (pos == -1)
  156. {
  157. ret = m_Inbuf;
  158. m_Inbuf.resize(0);
  159. } else
  160. {
  161. ret = m_Inbuf.left(pos);
  162. m_Inbuf = m_Inbuf.mid(pos+1);
  163. }
  164. return ret;
  165. }
  166. int flags = fcntl(m_Fd, F_GETFL);
  167. if (flags < 0)
  168. {
  169. kdError(900) << k_lineinfo << "fcntl(F_GETFL): " << perror << "\n";
  170. return ret;
  171. }
  172. int oflags = flags;
  173. if (block)
  174. flags &= ~O_NONBLOCK;
  175. else
  176. flags |= O_NONBLOCK;
  177. if ((flags != oflags) && (fcntl(m_Fd, F_SETFL, flags) < 0))
  178. {
  179. // We get an error here when the child process has closed
  180. // the file descriptor already.
  181. return ret;
  182. }
  183. int nbytes;
  184. char buf[256];
  185. while (1)
  186. {
  187. nbytes = read(m_Fd, buf, 255);
  188. if (nbytes == -1)
  189. {
  190. if (errno == EINTR)
  191. continue;
  192. else break;
  193. }
  194. if (nbytes == 0)
  195. break; // eof
  196. buf[nbytes] = '\000';
  197. m_Inbuf += buf;
  198. pos = m_Inbuf.find('\n');
  199. if (pos == -1)
  200. {
  201. ret = m_Inbuf;
  202. m_Inbuf.resize(0);
  203. } else
  204. {
  205. ret = m_Inbuf.left(pos);
  206. m_Inbuf = m_Inbuf.mid(pos+1);
  207. }
  208. break;
  209. }
  210. return ret;
  211. }
  212. TQCString PtyProcess::readAll(bool block)
  213. {
  214. TQCString ret;
  215. if (!m_Inbuf.isEmpty())
  216. {
  217. // if there is still something in the buffer, we need not block.
  218. // we should still try to read any further output, from the fd, though.
  219. block = false;
  220. ret = m_Inbuf;
  221. m_Inbuf.resize(0);
  222. }
  223. int flags = fcntl(m_Fd, F_GETFL);
  224. if (flags < 0)
  225. {
  226. kdError(900) << k_lineinfo << "fcntl(F_GETFL): " << perror << "\n";
  227. return ret;
  228. }
  229. int oflags = flags;
  230. if (block)
  231. flags &= ~O_NONBLOCK;
  232. else
  233. flags |= O_NONBLOCK;
  234. if ((flags != oflags) && (fcntl(m_Fd, F_SETFL, flags) < 0))
  235. {
  236. // We get an error here when the child process has closed
  237. // the file descriptor already.
  238. return ret;
  239. }
  240. int nbytes;
  241. char buf[256];
  242. while (1)
  243. {
  244. nbytes = read(m_Fd, buf, 255);
  245. if (nbytes == -1)
  246. {
  247. if (errno == EINTR)
  248. continue;
  249. else break;
  250. }
  251. if (nbytes == 0)
  252. break; // eof
  253. buf[nbytes] = '\000';
  254. ret += buf;
  255. break;
  256. }
  257. return ret;
  258. }
  259. void PtyProcess::writeLine(const TQCString &line, bool addnl)
  260. {
  261. if (!line.isEmpty())
  262. write(m_Fd, line, line.length());
  263. if (addnl)
  264. write(m_Fd, "\n", 1);
  265. }
  266. void PtyProcess::unreadLine(const TQCString &line, bool addnl)
  267. {
  268. TQCString tmp = line;
  269. if (addnl)
  270. tmp += '\n';
  271. if (!tmp.isEmpty())
  272. m_Inbuf.prepend(tmp);
  273. }
  274. /*
  275. * Fork and execute the command. This returns in the parent.
  276. */
  277. int PtyProcess::exec(const TQCString &command, const QCStringList &args)
  278. {
  279. kdDebug(900) << k_lineinfo << "Running `" << command << "'\n";
  280. if (init() < 0)
  281. return -1;
  282. // Open the pty slave before forking. See SetupTTY()
  283. int slave = open(m_TTY, O_RDWR);
  284. if (slave < 0)
  285. {
  286. kdError(900) << k_lineinfo << "Could not open slave pty.\n";
  287. return -1;
  288. }
  289. if ((m_Pid = fork()) == -1)
  290. {
  291. kdError(900) << k_lineinfo << "fork(): " << perror << "\n";
  292. return -1;
  293. }
  294. // Parent
  295. if (m_Pid)
  296. {
  297. close(slave);
  298. return 0;
  299. }
  300. // Child
  301. if (SetupTTY(slave) < 0)
  302. _exit(1);
  303. for(QCStringList::ConstIterator it = d->env.begin();
  304. it != d->env.end(); it++)
  305. {
  306. putenv(const_cast<TQCString&>(*it).data());
  307. }
  308. unsetenv("TDE_FULL_SESSION");
  309. // set temporarily LC_ALL to C, for su (to be able to parse "Password:")
  310. const char* old_lc_all = getenv( "LC_ALL" );
  311. if( old_lc_all != NULL )
  312. setenv( "KDESU_LC_ALL", old_lc_all, 1 );
  313. else
  314. unsetenv( "KDESU_LC_ALL" );
  315. setenv("LC_ALL", "C", 1);
  316. // From now on, terminal output goes through the tty.
  317. TQCString path;
  318. if (command.contains('/'))
  319. path = command;
  320. else
  321. {
  322. TQString file = KStandardDirs::findExe(command);
  323. if (file.isEmpty())
  324. {
  325. kdError(900) << k_lineinfo << command << " not found\n";
  326. _exit(1);
  327. }
  328. path = TQFile::encodeName(file);
  329. }
  330. const char **argp = (const char **)malloc((args.count()+2)*sizeof(char *));
  331. int i = 0;
  332. argp[i++] = path;
  333. for (QCStringList::ConstIterator it=args.begin(); it!=args.end(); ++it)
  334. argp[i++] = *it;
  335. argp[i] = 0L;
  336. execv(path, (char * const *)argp);
  337. kdError(900) << k_lineinfo << "execv(\"" << path << "\"): " << perror << "\n";
  338. _exit(1);
  339. return -1; // Shut up compiler. Never reached.
  340. }
  341. /*
  342. * Wait until the terminal is set into no echo mode. At least one su
  343. * (RH6 w/ Linux-PAM patches) sets noecho mode AFTER writing the Password:
  344. * prompt, using TCSAFLUSH. This flushes the terminal I/O queues, possibly
  345. * taking the password with it. So we wait until no echo mode is set
  346. * before writing the password.
  347. * Note that this is done on the slave fd. While Linux allows tcgetattr() on
  348. * the master side, Solaris doesn't.
  349. */
  350. int PtyProcess::WaitSlave()
  351. {
  352. int slave = open(m_TTY, O_RDWR);
  353. if (slave < 0)
  354. {
  355. kdError(900) << k_lineinfo << "Could not open slave tty.\n";
  356. return -1;
  357. }
  358. kdDebug(900) << k_lineinfo << "Child pid " << m_Pid << endl;
  359. struct termios tio;
  360. while (1)
  361. {
  362. if (!checkPid(m_Pid))
  363. {
  364. close(slave);
  365. return -1;
  366. }
  367. if (tcgetattr(slave, &tio) < 0)
  368. {
  369. kdError(900) << k_lineinfo << "tcgetattr(): " << perror << "\n";
  370. close(slave);
  371. return -1;
  372. }
  373. if (tio.c_lflag & ECHO)
  374. {
  375. kdDebug(900) << k_lineinfo << "Echo mode still on.\n";
  376. waitMS(slave,100);
  377. continue;
  378. }
  379. break;
  380. }
  381. close(slave);
  382. return 0;
  383. }
  384. int PtyProcess::enableLocalEcho(bool enable)
  385. {
  386. int slave = open(m_TTY, O_RDWR);
  387. if (slave < 0)
  388. {
  389. kdError(900) << k_lineinfo << "Could not open slave tty.\n";
  390. return -1;
  391. }
  392. struct termios tio;
  393. if (tcgetattr(slave, &tio) < 0)
  394. {
  395. kdError(900) << k_lineinfo << "tcgetattr(): " << perror << "\n";
  396. close(slave); return -1;
  397. }
  398. if (enable)
  399. tio.c_lflag |= ECHO;
  400. else
  401. tio.c_lflag &= ~ECHO;
  402. if (tcsetattr(slave, TCSANOW, &tio) < 0)
  403. {
  404. kdError(900) << k_lineinfo << "tcsetattr(): " << perror << "\n";
  405. close(slave); return -1;
  406. }
  407. close(slave);
  408. return 0;
  409. }
  410. /*
  411. * Copy output to stdout until the child process exists, or a line of output
  412. * matches `m_Exit'.
  413. * We have to use waitpid() to test for exit. Merely waiting for EOF on the
  414. * pty does not work, because the target process may have children still
  415. * attached to the terminal.
  416. */
  417. int PtyProcess::waitForChild()
  418. {
  419. int retval = 1;
  420. fd_set fds;
  421. FD_ZERO(&fds);
  422. while (1)
  423. {
  424. FD_SET(m_Fd, &fds);
  425. int ret = select(m_Fd+1, &fds, 0L, 0L, 0L);
  426. if (ret == -1)
  427. {
  428. if (errno != EINTR)
  429. {
  430. kdError(900) << k_lineinfo << "select(): " << perror << "\n";
  431. return -1;
  432. }
  433. ret = 0;
  434. }
  435. if (ret)
  436. {
  437. TQCString output = readAll(false);
  438. bool lineStart = true;
  439. while (!output.isNull())
  440. {
  441. if (!m_Exit.isEmpty())
  442. {
  443. // match exit string only at line starts
  444. int pos = output.find(m_Exit.data());
  445. if ((pos >= 0) && ((pos == 0 && lineStart) || (output.at (pos - 1) == '\n')))
  446. {
  447. kill(m_Pid, SIGTERM);
  448. }
  449. }
  450. if (m_bTerminal)
  451. {
  452. fputs(output, stdout);
  453. fflush(stdout);
  454. }
  455. lineStart = output.tqat( output.length() - 1 ) == '\n';
  456. output = readAll(false);
  457. }
  458. }
  459. ret = checkPidExited(m_Pid);
  460. if (ret == Error)
  461. {
  462. if (errno == ECHILD) retval = 0;
  463. else retval = 1;
  464. break;
  465. }
  466. else if (ret == Killed)
  467. {
  468. retval = 0;
  469. break;
  470. }
  471. else if (ret == NotExited)
  472. {
  473. // keep checking
  474. }
  475. else
  476. {
  477. retval = ret;
  478. break;
  479. }
  480. }
  481. return retval;
  482. }
  483. /*
  484. * SetupTTY: Creates a new session. The filedescriptor "fd" should be
  485. * connected to the tty. It is closed after the tty is reopened to make it
  486. * our controlling terminal. This way the tty is always opened at least once
  487. * so we'll never get EIO when reading from it.
  488. */
  489. int PtyProcess::SetupTTY(int fd)
  490. {
  491. // Reset signal handlers
  492. for (int sig = 1; sig < NSIG; sig++)
  493. signal(sig, SIG_DFL);
  494. signal(SIGHUP, SIG_IGN);
  495. // Close all file handles
  496. struct rlimit rlp;
  497. getrlimit(RLIMIT_NOFILE, &rlp);
  498. for (int i = 0; i < (int)rlp.rlim_cur; i++)
  499. if (i != fd) close(i);
  500. // Create a new session.
  501. setsid();
  502. // Open slave. This will make it our controlling terminal
  503. int slave = open(m_TTY, O_RDWR);
  504. if (slave < 0)
  505. {
  506. kdError(900) << k_lineinfo << "Could not open slave side: " << perror << "\n";
  507. return -1;
  508. }
  509. close(fd);
  510. #if defined(__SVR4) && defined(sun)
  511. // Solaris STREAMS environment.
  512. // Push these modules to make the stream look like a terminal.
  513. ioctl(slave, I_PUSH, "ptem");
  514. ioctl(slave, I_PUSH, "ldterm");
  515. #endif
  516. #ifdef TIOCSCTTY
  517. ioctl(slave, TIOCSCTTY, NULL);
  518. #endif
  519. // Connect stdin, stdout and stderr
  520. dup2(slave, 0); dup2(slave, 1); dup2(slave, 2);
  521. if (slave > 2)
  522. close(slave);
  523. // Disable OPOST processing. Otherwise, '\n' are (on Linux at least)
  524. // translated to '\r\n'.
  525. struct termios tio;
  526. if (tcgetattr(0, &tio) < 0)
  527. {
  528. kdError(900) << k_lineinfo << "tcgetattr(): " << perror << "\n";
  529. return -1;
  530. }
  531. tio.c_oflag &= ~OPOST;
  532. if (tcsetattr(0, TCSANOW, &tio) < 0)
  533. {
  534. kdError(900) << k_lineinfo << "tcsetattr(): " << perror << "\n";
  535. return -1;
  536. }
  537. return 0;
  538. }
  539. void PtyProcess::virtual_hook( int, void* )
  540. { /*BASE::virtual_hook( id, data );*/ }