1 | /* |
2 | This file is part of the KDE project, module kdesu. |
3 | SPDX-FileCopyrightText: 1999, 2000 Geert Jansen <jansen@kde.org> |
4 | |
5 | SPDX-License-Identifier: GPL-2.0-only |
6 | */ |
7 | |
8 | #ifndef KDESUPTYPROCESS_H |
9 | #define KDESUPTYPROCESS_H |
10 | |
11 | #include <memory> |
12 | #include <sys/types.h> |
13 | |
14 | #include <QByteArray> |
15 | #include <QList> |
16 | #include <QString> |
17 | #include <QStringList> |
18 | |
19 | #include <kdesu/kdesu_export.h> |
20 | |
21 | #include <KPty> |
22 | |
23 | namespace KDESu |
24 | { |
25 | class PtyProcessPrivate; |
26 | |
27 | /*! |
28 | * \class KDESu::PtyProcess |
29 | * \inmodule KDESu |
30 | * \inheaderfile KDESu/PtyProcess |
31 | * |
32 | * \brief Synchronous communication with tty programs. |
33 | * |
34 | * PtyProcess provides synchronous communication with tty based programs. |
35 | * The communications channel used is a pseudo tty (as opposed to a pipe) |
36 | * This means that programs which require a terminal will work. |
37 | */ |
38 | class KDESU_EXPORT PtyProcess |
39 | { |
40 | public: |
41 | /*! |
42 | * Error return values for checkPidExited() |
43 | * |
44 | * \value Error No child |
45 | * \value NotExited Child hasn't exited |
46 | * \value Killed Child terminated by signal |
47 | */ |
48 | enum checkPidStatus { |
49 | Error = -1, |
50 | NotExited = -2, |
51 | Killed = -3, |
52 | }; |
53 | |
54 | PtyProcess(); |
55 | virtual ~PtyProcess(); |
56 | |
57 | /*! |
58 | * Forks off and execute a command. |
59 | * |
60 | * The command's standard in and output |
61 | * are connected to the pseudo tty. They are accessible with readLine |
62 | * and writeLine. |
63 | * |
64 | * \a command The command to execute. |
65 | * |
66 | * \a args The arguments to the command. |
67 | * |
68 | * Returns 0 on success, -1 on error. errno might give more information then. |
69 | */ |
70 | int exec(const QByteArray &command, const QList<QByteArray> &args); |
71 | |
72 | /*! |
73 | * Reads a line from the program's standard out. Depending on the \a block |
74 | * parameter, this call blocks until something was read. |
75 | * |
76 | * Note that in some situations this function will return less than a full |
77 | * line of output, but never more. Newline characters are stripped. |
78 | * |
79 | * \a block Block until a full line is read? |
80 | * |
81 | * Returns the output string. |
82 | */ |
83 | QByteArray readLine(bool block = true); |
84 | |
85 | /*! |
86 | * Read all available output from the program's standard out. |
87 | * |
88 | * \a block If no output is in the buffer, should the function block |
89 | * (else it will return an empty QByteArray)? |
90 | * |
91 | * Returns the output. |
92 | */ |
93 | QByteArray readAll(bool block = true); |
94 | |
95 | /*! |
96 | * Writes a line of text to the program's standard in. |
97 | * |
98 | * \a line The text to write. |
99 | * |
100 | * \a addNewline Adds a '\n' to the line. |
101 | */ |
102 | void writeLine(const QByteArray &line, bool addNewline = true); |
103 | |
104 | /*! |
105 | * Puts back a line of input. |
106 | * |
107 | * \a line The line to put back. |
108 | * |
109 | * \a addNewline Adds a '\n' to the line. |
110 | */ |
111 | void unreadLine(const QByteArray &line, bool addNewline = true); |
112 | |
113 | /*! |
114 | * Sets the exit string. If a line of program output matches this, |
115 | * waitForChild() will terminate the program and return. |
116 | */ |
117 | void setExitString(const QByteArray &exit); |
118 | |
119 | /*! |
120 | * Waits for the child to exit. See also setExitString. |
121 | */ |
122 | int waitForChild(); |
123 | |
124 | /*! |
125 | * Waits until the pty has cleared the ECHO flag. This is useful |
126 | * when programs write a password prompt before they disable ECHO. |
127 | * Disabling it might flush any input that was written. |
128 | */ |
129 | int waitSlave(); |
130 | |
131 | /*! |
132 | * Enables/disables local echo on the pseudo tty. |
133 | */ |
134 | int enableLocalEcho(bool enable = true); |
135 | |
136 | /*! |
137 | * Enables/disables terminal output. Relevant only to some subclasses. |
138 | */ |
139 | void setTerminal(bool terminal); |
140 | |
141 | /*! |
142 | * Overwrites the password as soon as it is used. Relevant only to |
143 | * some subclasses. |
144 | */ |
145 | void setErase(bool erase); |
146 | |
147 | /*! |
148 | * Set additinal environment variables. |
149 | */ |
150 | void setEnvironment(const QList<QByteArray> &env); |
151 | |
152 | /*! |
153 | * Returns the filedescriptor of the process. |
154 | */ |
155 | int fd() const; |
156 | |
157 | /*! |
158 | * Returns the pid of the process. |
159 | */ |
160 | int pid() const; |
161 | |
162 | /* |
163 | * This is a collection of static functions that can be |
164 | * used for process control inside kdesu. I'd suggest |
165 | * against using this publicly. There are probably |
166 | * nicer Qt based ways to do what you want. |
167 | */ |
168 | |
169 | /*! |
170 | * Wait \a ms milliseconds (ie. 1/10th of a second is 100ms), |
171 | * using \a fd as a filedescriptor to wait on. |
172 | * |
173 | * Returns |
174 | * select(2)'s result, which is -1 on error, 0 on timeout, |
175 | * or positive if there is data on one of the selected fd's. |
176 | * |
177 | * \a ms must be in the range 0..999 (i.e. the maximum wait |
178 | * duration is 999ms, almost one second). |
179 | */ |
180 | static int waitMS(int fd, int ms); |
181 | |
182 | /*! |
183 | * Basic check for the existence of \a pid. |
184 | * |
185 | * Returns true iff \a pid is an extant process, |
186 | * (one you could kill - see man kill(2) for signal 0). |
187 | */ |
188 | static bool checkPid(pid_t pid); |
189 | |
190 | /*! |
191 | * Check process exit status for process \a pid. |
192 | * |
193 | * If child \a pid has exited, return its exit status, |
194 | * (which may be zero). |
195 | * |
196 | * On error (no child, no exit), return -1. |
197 | * |
198 | * If child \a has not exited, return -2. |
199 | */ |
200 | static int checkPidExited(pid_t pid); |
201 | |
202 | protected: |
203 | KDESU_NO_EXPORT explicit PtyProcess(PtyProcessPrivate &dd); |
204 | |
205 | /* Standard hack to add virtual methods in a BC way. Unused. */ |
206 | virtual void virtual_hook(int id, void *data); |
207 | QList<QByteArray> environment() const; |
208 | |
209 | // KF6 TODO: move to PtyProcessPrivate |
210 | bool m_erase; |
211 | bool m_terminal; /* Indicates running in a terminal, causes additional |
212 | newlines to be printed after output. Set to @c false |
213 | in constructors */ |
214 | int m_pid; /* PID of child process */ |
215 | QByteArray m_command; /* Unused */ |
216 | QByteArray m_exitString; /* String to scan for in output that indicates child has exited. */ |
217 | |
218 | private: |
219 | KDESU_NO_EXPORT int init(); |
220 | KDESU_NO_EXPORT int setupTTY(); |
221 | |
222 | protected: |
223 | std::unique_ptr<PtyProcessPrivate> const d_ptr; |
224 | |
225 | private: |
226 | Q_DECLARE_PRIVATE(PtyProcess) |
227 | }; |
228 | |
229 | } |
230 | |
231 | #endif // KDESUPTYPROCESS_H |
232 | |