File: | /rootdir/_build/../src/btepty.cc |
Warning: | line 357, column 1 This statement is never executed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (C) 2001,2002 Red Hat, Inc. |
3 | * Copyright © 2009, 2010, 2019 Christian Persch |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 3 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ |
19 | |
20 | /** |
21 | * SECTION: bte-pty |
22 | * @short_description: Functions for starting a new process on a new pseudo-terminal and for |
23 | * manipulating pseudo-terminals |
24 | * |
25 | * The terminal widget uses these functions to start commands with new controlling |
26 | * pseudo-terminals and to resize pseudo-terminals. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | |
31 | #include <exception> |
32 | |
33 | #include <bte/bte.h> |
34 | |
35 | #include <errno(*__errno_location ()).h> |
36 | #include <glib.h> |
37 | #include <gio/gio.h> |
38 | #include "debug.h" |
39 | |
40 | #include <glib/gi18n-lib.h> |
41 | |
42 | #include "cxx-utils.hh" |
43 | #include "libc-glue.hh" |
44 | #include "pty.hh" |
45 | #include "refptr.hh" |
46 | #include "spawn.hh" |
47 | |
48 | #include "bteptyinternal.hh" |
49 | |
50 | #if !GLIB_CHECK_VERSION(2, 42, 0)(2 > (2) || (2 == (2) && 74 > (42)) || (2 == (2 ) && 74 == (42) && 4 >= (0))) |
51 | #define G_PARAM_EXPLICIT_NOTIFY 0 |
52 | #endif |
53 | |
54 | #define I_(string)(g_intern_static_string(string)) (g_intern_static_string(string)) |
55 | |
56 | typedef struct _BtePtyPrivate BtePtyPrivate; |
57 | |
58 | typedef struct { |
59 | GSpawnChildSetupFunc extra_child_setup; |
60 | gpointer extra_child_setup_data; |
61 | } BtePtyChildSetupData; |
62 | |
63 | /** |
64 | * BtePty: |
65 | */ |
66 | struct _BtePty { |
67 | GObject parent_instance; |
68 | |
69 | /* <private> */ |
70 | BtePtyPrivate *priv; |
71 | }; |
72 | |
73 | struct _BtePtyPrivate { |
74 | bte::base::Pty* pty; /* owned */ |
75 | int foreign_fd; /* foreign FD if != -1 */ |
76 | BtePtyFlags flags; |
77 | }; |
78 | |
79 | struct _BtePtyClass { |
80 | GObjectClass parent_class; |
81 | }; |
82 | |
83 | bte::base::Pty* |
84 | _bte_pty_get_impl(BtePty* pty) |
85 | { |
86 | return pty->priv->pty; |
87 | } |
88 | |
89 | #define IMPL(wrapper)(_bte_pty_get_impl(wrapper)) (_bte_pty_get_impl(wrapper)) |
90 | |
91 | /** |
92 | * BTE_SPAWN_NO_PARENT_ENVV: |
93 | * |
94 | * Use this as a spawn flag (together with flags from #GSpawnFlags) in |
95 | * bte_pty_spawn_async(). |
96 | * |
97 | * Normally, the spawned process inherits the environment from the parent |
98 | * process; when this flag is used, only the environment variables passed |
99 | * to bte_pty_spawn_async() etc. are passed to the child process. |
100 | */ |
101 | |
102 | /** |
103 | * BTE_SPAWN_NO_SYSTEMD_SCOPE: |
104 | * |
105 | * Use this as a spawn flag (together with flags from #GSpawnFlags) in |
106 | * bte_pty_spawn_async(). |
107 | * |
108 | * Prevents bte_pty_spawn_async() etc. from moving the newly created child |
109 | * process to a systemd user scope. |
110 | * |
111 | * Since: 0.60 |
112 | */ |
113 | |
114 | /** |
115 | * BTE_SPAWN_REQUIRE_SYSTEMD_SCOPE |
116 | * |
117 | * Use this as a spawn flag (together with flags from #GSpawnFlags) in |
118 | * bte_pty_spawn_async(). |
119 | * |
120 | * Requires bte_pty_spawn_async() etc. to move the newly created child |
121 | * process to a systemd user scope; if that fails, the whole spawn fails. |
122 | * |
123 | * This is supported on Linux only. |
124 | * |
125 | * Since: 0.60 |
126 | */ |
127 | |
128 | /** |
129 | * bte_pty_child_setup: |
130 | * @pty: a #BtePty |
131 | */ |
132 | void |
133 | bte_pty_child_setup (BtePty *pty) noexcept |
134 | try |
135 | { |
136 | g_return_if_fail(pty != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (pty != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "pty != nullptr" ); return; } } while (0); |
137 | auto impl = IMPL(pty)(_bte_pty_get_impl(pty)); |
138 | g_return_if_fail(impl != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (impl != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "impl != nullptr" ); return; } } while (0); |
139 | |
140 | impl->child_setup(); |
141 | } |
142 | catch (...) |
143 | { |
144 | bte::log_exception(); |
145 | } |
146 | |
147 | /** |
148 | * bte_pty_set_size: |
149 | * @pty: a #BtePty |
150 | * @rows: the desired number of rows |
151 | * @columns: the desired number of columns |
152 | * @error: (allow-none): return location to store a #GError, or %NULL |
153 | * |
154 | * Attempts to resize the pseudo terminal's window size. If successful, the |
155 | * OS kernel will send #SIGWINCH to the child process group. |
156 | * |
157 | * If setting the window size failed, @error will be set to a #GIOError. |
158 | * |
159 | * Returns: %TRUE on success, %FALSE on failure with @error filled in |
160 | */ |
161 | gboolean |
162 | bte_pty_set_size(BtePty *pty, |
163 | int rows, |
164 | int columns, |
165 | GError **error) noexcept |
166 | { |
167 | /* No way to determine the pixel size; set it to (0, 0), meaning |
168 | * "undefined". |
169 | */ |
170 | return _bte_pty_set_size(pty, rows, columns, 0, 0, error); |
171 | } |
172 | |
173 | bool |
174 | _bte_pty_set_size(BtePty *pty, |
175 | int rows, |
176 | int columns, |
177 | int cell_height_px, |
178 | int cell_width_px, |
179 | GError **error) noexcept |
180 | try |
181 | { |
182 | g_return_val_if_fail(BTE_IS_PTY(pty), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((pty)); GType __t = ((bte_pty_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "BTE_IS_PTY(pty)"); return ((0)); } } while (0); |
183 | auto impl = IMPL(pty)(_bte_pty_get_impl(pty)); |
184 | g_return_val_if_fail(impl != nullptr, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (impl != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "impl != nullptr" ); return ((0)); } } while (0); |
185 | |
186 | if (impl->set_size(rows, columns, cell_height_px, cell_width_px)) |
187 | return true; |
188 | |
189 | auto errsv = bte::libc::ErrnoSaver{}; |
190 | g_set_error(error, G_IO_ERRORg_io_error_quark(), |
191 | g_io_error_from_errno(errsv), |
192 | "Failed to set window size: %s", |
193 | g_strerror(errsv)); |
194 | |
195 | return false; |
196 | } |
197 | catch (...) |
198 | { |
199 | return bte::glib::set_error_from_exception(error); |
200 | } |
201 | |
202 | |
203 | /** |
204 | * bte_pty_get_size: |
205 | * @pty: a #BtePty |
206 | * @rows: (out) (allow-none): a location to store the number of rows, or %NULL |
207 | * @columns: (out) (allow-none): a location to store the number of columns, or %NULL |
208 | * @error: return location to store a #GError, or %NULL |
209 | * |
210 | * Reads the pseudo terminal's window size. |
211 | * |
212 | * If getting the window size failed, @error will be set to a #GIOError. |
213 | * |
214 | * Returns: %TRUE on success, %FALSE on failure with @error filled in |
215 | */ |
216 | gboolean |
217 | bte_pty_get_size(BtePty *pty, |
218 | int *rows, |
219 | int *columns, |
220 | GError **error) noexcept |
221 | try |
222 | { |
223 | g_return_val_if_fail(BTE_IS_PTY(pty), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((pty)); GType __t = ((bte_pty_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "BTE_IS_PTY(pty)"); return ((0)); } } while (0); |
224 | auto impl = IMPL(pty)(_bte_pty_get_impl(pty)); |
225 | g_return_val_if_fail(impl != nullptr, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (impl != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "impl != nullptr" ); return ((0)); } } while (0); |
226 | |
227 | if (impl->get_size(rows, columns)) |
228 | return true; |
229 | |
230 | auto errsv = bte::libc::ErrnoSaver{}; |
231 | g_set_error(error, G_IO_ERRORg_io_error_quark(), |
232 | g_io_error_from_errno(errsv), |
233 | "Failed to get window size: %s", |
234 | g_strerror(errsv)); |
235 | return false; |
236 | } |
237 | catch (...) |
238 | { |
239 | return bte::glib::set_error_from_exception(error); |
240 | } |
241 | |
242 | /** |
243 | * bte_pty_set_utf8: |
244 | * @pty: a #BtePty |
245 | * @utf8: whether or not the pty is in UTF-8 mode |
246 | * @error: (allow-none): return location to store a #GError, or %NULL |
247 | * |
248 | * Tells the kernel whether the terminal is UTF-8 or not, in case it can make |
249 | * use of the info. Linux 2.6.5 or so defines IUTF8 to make the line |
250 | * discipline do multibyte backspace correctly. |
251 | * |
252 | * Returns: %TRUE on success, %FALSE on failure with @error filled in |
253 | */ |
254 | gboolean |
255 | bte_pty_set_utf8(BtePty *pty, |
256 | gboolean utf8, |
257 | GError **error) noexcept |
258 | try |
259 | { |
260 | g_return_val_if_fail(BTE_IS_PTY(pty), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((pty)); GType __t = ((bte_pty_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "BTE_IS_PTY(pty)"); return ((0)); } } while (0); |
261 | auto impl = IMPL(pty)(_bte_pty_get_impl(pty)); |
262 | g_return_val_if_fail(impl != nullptr, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (impl != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "impl != nullptr" ); return ((0)); } } while (0); |
263 | |
264 | if (impl->set_utf8(utf8)) |
265 | return true; |
266 | |
267 | auto errsv = bte::libc::ErrnoSaver{}; |
268 | g_set_error(error, G_IO_ERRORg_io_error_quark(), g_io_error_from_errno(errsv), |
269 | "%s failed: %s", "tc[sg]etattr", g_strerror(errsv)); |
270 | return false; |
271 | } |
272 | catch (...) |
273 | { |
274 | return bte::glib::set_error_from_exception(error); |
275 | } |
276 | |
277 | /** |
278 | * bte_pty_close: |
279 | * @pty: a #BtePty |
280 | * |
281 | * Since 0.42 this is a no-op. |
282 | * |
283 | * Deprecated: 0.42 |
284 | */ |
285 | void |
286 | bte_pty_close (BtePty *pty) noexcept |
287 | { |
288 | /* impl->close(); */ |
289 | } |
290 | |
291 | /* BTE PTY class */ |
292 | |
293 | enum { |
294 | PROP_0, |
295 | PROP_FLAGS, |
296 | PROP_FD, |
297 | }; |
298 | |
299 | /* GInitable impl */ |
300 | |
301 | static gboolean |
302 | bte_pty_initable_init (GInitable *initable, |
303 | GCancellable *cancellable, |
304 | GError **error) noexcept |
305 | try |
306 | { |
307 | BtePty *pty = BTE_PTY (initable)((((BtePty*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((initable)), ((bte_pty_get_type())))))); |
308 | BtePtyPrivate *priv = pty->priv; |
309 | |
310 | if (priv->foreign_fd != -1) { |
311 | priv->pty = bte::base::Pty::create_foreign(priv->foreign_fd, priv->flags); |
312 | priv->foreign_fd = -1; |
313 | } else { |
314 | priv->pty = bte::base::Pty::create(priv->flags); |
315 | } |
316 | |
317 | if (priv->pty == nullptr) { |
318 | auto errsv = bte::libc::ErrnoSaver{}; |
319 | g_set_error(error, G_IO_ERRORg_io_error_quark(), g_io_error_from_errno(errsv), |
320 | "Failed to open PTY: %s", g_strerror(errsv)); |
321 | return FALSE(0); |
322 | } |
323 | |
324 | return !g_cancellable_set_error_if_cancelled(cancellable, error); |
325 | } |
326 | catch (...) |
327 | { |
328 | return bte::glib::set_error_from_exception(error); |
329 | } |
330 | |
331 | static void |
332 | bte_pty_initable_iface_init (GInitableIface *iface) |
333 | { |
334 | iface->init = bte_pty_initable_init; |
335 | } |
336 | |
337 | /* GObjectClass impl */ |
338 | |
339 | G_DEFINE_TYPE_WITH_CODE (BtePty, bte_pty, G_TYPE_OBJECT,static void bte_pty_init (BtePty *self); static void bte_pty_class_init (BtePtyClass *klass); static GType bte_pty_get_type_once (void ); static gpointer bte_pty_parent_class = __null; static gint BtePty_private_offset; static void bte_pty_class_intern_init (gpointer klass) { bte_pty_parent_class = g_type_class_peek_parent (klass); if (BtePty_private_offset != 0) g_type_class_adjust_private_offset (klass, &BtePty_private_offset); bte_pty_class_init ((BtePtyClass *) klass); } __attribute__ ((__unused__)) static inline gpointer bte_pty_get_instance_private (BtePty *self) { return (((gpointer ) ((guint8*) (self) + (glong) (BtePty_private_offset)))); } GType bte_pty_get_type (void) { static gsize static_g_define_type_id = 0; if ((__extension__ ({ static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&static_g_define_type_id) : __null); ( !(__extension__ ({ static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer *)( &static_g_define_type_id); __atomic_load (gapg_temp_atomic , &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id)); }))) { GType g_define_type_id = bte_pty_get_type_once (); (__extension__ ( { static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*( &static_g_define_type_id) = (g_define_type_id)) : (void) 0 ; g_once_init_leave ((&static_g_define_type_id), (gsize) ( g_define_type_id)); })); } return static_g_define_type_id; } [ [gnu::noinline]] static GType bte_pty_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple (((GType) ( (20) << (2))), g_intern_static_string ("BtePty"), sizeof (BtePtyClass), (GClassInitFunc)(void (*)(void)) bte_pty_class_intern_init , sizeof (BtePty), (GInstanceInitFunc)(void (*)(void)) bte_pty_init , (GTypeFlags) 0); { {{ BtePty_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (BtePtyPrivate)); } { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc)(void (*) (void)) bte_pty_initable_iface_init, __null, __null }; g_type_add_interface_static (g_define_type_id, (g_initable_get_type ()), &g_implement_interface_info ); };} } return g_define_type_id; } |
340 | G_ADD_PRIVATE (BtePty)static void bte_pty_init (BtePty *self); static void bte_pty_class_init (BtePtyClass *klass); static GType bte_pty_get_type_once (void ); static gpointer bte_pty_parent_class = __null; static gint BtePty_private_offset; static void bte_pty_class_intern_init (gpointer klass) { bte_pty_parent_class = g_type_class_peek_parent (klass); if (BtePty_private_offset != 0) g_type_class_adjust_private_offset (klass, &BtePty_private_offset); bte_pty_class_init ((BtePtyClass *) klass); } __attribute__ ((__unused__)) static inline gpointer bte_pty_get_instance_private (BtePty *self) { return (((gpointer ) ((guint8*) (self) + (glong) (BtePty_private_offset)))); } GType bte_pty_get_type (void) { static gsize static_g_define_type_id = 0; if ((__extension__ ({ static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&static_g_define_type_id) : __null); ( !(__extension__ ({ static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer *)( &static_g_define_type_id); __atomic_load (gapg_temp_atomic , &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id)); }))) { GType g_define_type_id = bte_pty_get_type_once (); (__extension__ ( { static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*( &static_g_define_type_id) = (g_define_type_id)) : (void) 0 ; g_once_init_leave ((&static_g_define_type_id), (gsize) ( g_define_type_id)); })); } return static_g_define_type_id; } [ [gnu::noinline]] static GType bte_pty_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple (((GType) ( (20) << (2))), g_intern_static_string ("BtePty"), sizeof (BtePtyClass), (GClassInitFunc)(void (*)(void)) bte_pty_class_intern_init , sizeof (BtePty), (GInstanceInitFunc)(void (*)(void)) bte_pty_init , (GTypeFlags) 0); { {{ BtePty_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (BtePtyPrivate)); } { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc)(void (*) (void)) bte_pty_initable_iface_init, __null, __null }; g_type_add_interface_static (g_define_type_id, (g_initable_get_type ()), &g_implement_interface_info ); };} } return g_define_type_id; } |
341 | G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, bte_pty_initable_iface_init))static void bte_pty_init (BtePty *self); static void bte_pty_class_init (BtePtyClass *klass); static GType bte_pty_get_type_once (void ); static gpointer bte_pty_parent_class = __null; static gint BtePty_private_offset; static void bte_pty_class_intern_init (gpointer klass) { bte_pty_parent_class = g_type_class_peek_parent (klass); if (BtePty_private_offset != 0) g_type_class_adjust_private_offset (klass, &BtePty_private_offset); bte_pty_class_init ((BtePtyClass *) klass); } __attribute__ ((__unused__)) static inline gpointer bte_pty_get_instance_private (BtePty *self) { return (((gpointer ) ((guint8*) (self) + (glong) (BtePty_private_offset)))); } GType bte_pty_get_type (void) { static gsize static_g_define_type_id = 0; if ((__extension__ ({ static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&static_g_define_type_id) : __null); ( !(__extension__ ({ static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); gpointer gapg_temp_newval; gpointer *gapg_temp_atomic = (gpointer *)( &static_g_define_type_id); __atomic_load (gapg_temp_atomic , &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id)); }))) { GType g_define_type_id = bte_pty_get_type_once (); (__extension__ ( { static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*( &static_g_define_type_id) = (g_define_type_id)) : (void) 0 ; g_once_init_leave ((&static_g_define_type_id), (gsize) ( g_define_type_id)); })); } return static_g_define_type_id; } [ [gnu::noinline]] static GType bte_pty_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple (((GType) ( (20) << (2))), g_intern_static_string ("BtePty"), sizeof (BtePtyClass), (GClassInitFunc)(void (*)(void)) bte_pty_class_intern_init , sizeof (BtePty), (GInstanceInitFunc)(void (*)(void)) bte_pty_init , (GTypeFlags) 0); { {{ BtePty_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (BtePtyPrivate)); } { const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc)(void (*) (void)) bte_pty_initable_iface_init, __null, __null }; g_type_add_interface_static (g_define_type_id, (g_initable_get_type ()), &g_implement_interface_info ); };} } return g_define_type_id; } |
342 | |
343 | static void |
344 | bte_pty_init (BtePty *pty) |
345 | { |
346 | BtePtyPrivate *priv; |
347 | |
348 | priv = pty->priv = (BtePtyPrivate *)bte_pty_get_instance_private (pty); |
349 | |
350 | priv->pty = nullptr; |
351 | priv->foreign_fd = -1; |
352 | priv->flags = BTE_PTY_DEFAULT; |
353 | } |
354 | |
355 | static void |
356 | bte_pty_finalize (GObject *object) noexcept |
357 | try |
This statement is never executed | |
358 | { |
359 | BtePty *pty = BTE_PTY (object)((((BtePty*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((bte_pty_get_type())))))); |
360 | BtePtyPrivate *priv = pty->priv; |
361 | |
362 | auto implptr = bte::base::RefPtr<bte::base::Pty>{priv->pty}; // moved |
363 | |
364 | G_OBJECT_CLASS (bte_pty_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((bte_pty_parent_class)), (((GType) ((20) << (2))))) )))->finalize (object); |
365 | } |
366 | catch (...) |
367 | { |
368 | bte::log_exception(); |
369 | } |
370 | |
371 | static void |
372 | bte_pty_get_property (GObject *object, |
373 | guint property_id, |
374 | GValue *value, |
375 | GParamSpec *pspec) |
376 | { |
377 | BtePty *pty = BTE_PTY (object)((((BtePty*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((bte_pty_get_type())))))); |
378 | BtePtyPrivate *priv = pty->priv; |
379 | |
380 | switch (property_id) { |
381 | case PROP_FLAGS: |
382 | g_value_set_flags(value, priv->flags); |
383 | break; |
384 | |
385 | case PROP_FD: |
386 | g_value_set_int(value, bte_pty_get_fd(pty)); |
387 | break; |
388 | |
389 | default: |
390 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((property_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "../src/btepty.cc", 390, ("property"), _glib__property_id, _glib__pspec ->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) ( _glib__pspec))->g_class))->g_type)))), (g_type_name ((( (((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
391 | } |
392 | } |
393 | |
394 | static void |
395 | bte_pty_set_property (GObject *object, |
396 | guint property_id, |
397 | const GValue *value, |
398 | GParamSpec *pspec) |
399 | { |
400 | BtePty *pty = BTE_PTY (object)((((BtePty*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((bte_pty_get_type())))))); |
401 | BtePtyPrivate *priv = pty->priv; |
402 | |
403 | switch (property_id) { |
404 | case PROP_FLAGS: |
405 | priv->flags = (BtePtyFlags) g_value_get_flags(value); |
406 | break; |
407 | |
408 | case PROP_FD: |
409 | priv->foreign_fd = g_value_get_int(value); |
410 | break; |
411 | |
412 | default: |
413 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((property_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "../src/btepty.cc", 413, ("property"), _glib__property_id, _glib__pspec ->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) ( _glib__pspec))->g_class))->g_type)))), (g_type_name ((( (((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
414 | } |
415 | } |
416 | |
417 | static void |
418 | bte_pty_class_init (BtePtyClass *klass) |
419 | { |
420 | GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); |
421 | |
422 | object_class->set_property = bte_pty_set_property; |
423 | object_class->get_property = bte_pty_get_property; |
424 | object_class->finalize = bte_pty_finalize; |
425 | |
426 | /** |
427 | * BtePty:flags: |
428 | * |
429 | * Flags. |
430 | */ |
431 | g_object_class_install_property |
432 | (object_class, |
433 | PROP_FLAGS, |
434 | g_param_spec_flags ("flags", NULL__null, NULL__null, |
435 | BTE_TYPE_PTY_FLAGS(bte_pty_flags_get_type ()), |
436 | BTE_PTY_DEFAULT, |
437 | (GParamFlags) (G_PARAM_READWRITE | |
438 | G_PARAM_CONSTRUCT_ONLY | |
439 | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_EXPLICIT_NOTIFY))); |
440 | |
441 | /** |
442 | * BtePty:fd: |
443 | * |
444 | * The file descriptor of the PTY master. |
445 | */ |
446 | g_object_class_install_property |
447 | (object_class, |
448 | PROP_FD, |
449 | g_param_spec_int ("fd", NULL__null, NULL__null, |
450 | -1, G_MAXINT2147483647, -1, |
451 | (GParamFlags) (G_PARAM_READWRITE | |
452 | G_PARAM_CONSTRUCT_ONLY | |
453 | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_EXPLICIT_NOTIFY))); |
454 | } |
455 | |
456 | /* public API */ |
457 | |
458 | /** |
459 | * bte_pty_error_quark: |
460 | * |
461 | * Error domain for BTE PTY errors. Errors in this domain will be from the #BtePtyError |
462 | * enumeration. See #GError for more information on error domains. |
463 | * |
464 | * Returns: the error domain for BTE PTY errors |
465 | */ |
466 | GQuark |
467 | bte_pty_error_quark(void) noexcept |
468 | { |
469 | static GQuark quark = 0; |
470 | |
471 | if (G_UNLIKELY (quark == 0)(__builtin_expect (__extension__ ({ int _g_boolean_var_; if ( quark == 0) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 0))) |
472 | quark = g_quark_from_static_string("bte-pty-error"); |
473 | |
474 | return quark; |
475 | } |
476 | |
477 | /** |
478 | * bte_pty_new_sync: (constructor) |
479 | * @flags: flags from #BtePtyFlags |
480 | * @cancellable: (allow-none): a #GCancellable, or %NULL |
481 | * @error: (allow-none): return location for a #GError, or %NULL |
482 | * |
483 | * Allocates a new pseudo-terminal. |
484 | * |
485 | * You can later use fork() or the g_spawn_async() family of functions |
486 | * to start a process on the PTY. |
487 | * |
488 | * If using fork(), you MUST call bte_pty_child_setup() in the child. |
489 | * |
490 | * If using g_spawn_async() and friends, you MUST either use |
491 | * bte_pty_child_setup() directly as the child setup function, or call |
492 | * bte_pty_child_setup() from your own child setup function supplied. |
493 | * |
494 | * When using bte_terminal_spawn_sync() with a custom child setup |
495 | * function, bte_pty_child_setup() will be called before the supplied |
496 | * function; you must not call it again. |
497 | * |
498 | * Also, you MUST pass the %G_SPAWN_DO_NOT_REAP_CHILD flag. |
499 | * |
500 | * Note also that %G_SPAWN_STDOUT_TO_DEV_NULL, %G_SPAWN_STDERR_TO_DEV_NULL, |
501 | * and %G_SPAWN_CHILD_INHERITS_STDIN are not supported, since stdin, stdout |
502 | * and stderr of the child process will always be connected to the PTY. |
503 | * |
504 | * Note that you should set the PTY's size using bte_pty_set_size() before |
505 | * spawning the child process, so that the child process has the correct |
506 | * size from the start instead of starting with a default size and then |
507 | * shortly afterwards receiving a SIGWINCH signal. You should prefer |
508 | * using bte_terminal_pty_new_sync() which does this automatically. |
509 | * |
510 | * Returns: (transfer full): a new #BtePty, or %NULL on error with @error filled in |
511 | */ |
512 | BtePty * |
513 | bte_pty_new_sync (BtePtyFlags flags, |
514 | GCancellable *cancellable, |
515 | GError **error) noexcept |
516 | { |
517 | return (BtePty *) g_initable_new (BTE_TYPE_PTY(bte_pty_get_type()), |
518 | cancellable, |
519 | error, |
520 | "flags", flags, |
521 | NULL__null); |
522 | } |
523 | |
524 | /** |
525 | * bte_pty_new_foreign_sync: (constructor) |
526 | * @fd: a file descriptor to the PTY |
527 | * @cancellable: (allow-none): a #GCancellable, or %NULL |
528 | * @error: (allow-none): return location for a #GError, or %NULL |
529 | * |
530 | * Creates a new #BtePty for the PTY master @fd. |
531 | * |
532 | * No entry will be made in the lastlog, utmp or wtmp system files. |
533 | * |
534 | * Note that the newly created #BtePty will take ownership of @fd |
535 | * and close it on finalize. |
536 | * |
537 | * Returns: (transfer full): a new #BtePty for @fd, or %NULL on error with @error filled in |
538 | */ |
539 | BtePty * |
540 | bte_pty_new_foreign_sync (int fd, |
541 | GCancellable *cancellable, |
542 | GError **error) noexcept |
543 | { |
544 | g_return_val_if_fail(fd != -1, nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (fd != -1) _g_boolean_var_ = 1; else _g_boolean_var_ = 0 ; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "fd != -1"); return (nullptr); } } while (0); |
545 | |
546 | return (BtePty *) g_initable_new (BTE_TYPE_PTY(bte_pty_get_type()), |
547 | cancellable, |
548 | error, |
549 | "fd", fd, |
550 | NULL__null); |
551 | } |
552 | |
553 | /** |
554 | * bte_pty_get_fd: |
555 | * @pty: a #BtePty |
556 | * |
557 | * Returns: the file descriptor of the PTY master in @pty. The |
558 | * file descriptor belongs to @pty and must not be closed or have |
559 | * its flags changed |
560 | */ |
561 | int |
562 | bte_pty_get_fd (BtePty *pty) noexcept |
563 | try |
564 | { |
565 | g_return_val_if_fail(BTE_IS_PTY(pty), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((pty)); GType __t = ((bte_pty_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "BTE_IS_PTY(pty)"); return ((0)); } } while (0); |
566 | return IMPL(pty)(_bte_pty_get_impl(pty))->fd(); |
567 | } |
568 | catch (...) |
569 | { |
570 | bte::log_exception(); |
571 | return -1; |
572 | } |
573 | |
574 | static constexpr inline auto |
575 | all_spawn_flags() noexcept |
576 | { |
577 | return GSpawnFlags(G_SPAWN_LEAVE_DESCRIPTORS_OPEN | |
578 | G_SPAWN_DO_NOT_REAP_CHILD | |
579 | G_SPAWN_SEARCH_PATH | |
580 | G_SPAWN_STDOUT_TO_DEV_NULL | |
581 | G_SPAWN_STDERR_TO_DEV_NULL | |
582 | G_SPAWN_CHILD_INHERITS_STDIN | |
583 | G_SPAWN_FILE_AND_ARGV_ZERO | |
584 | G_SPAWN_SEARCH_PATH_FROM_ENVP | |
585 | G_SPAWN_CLOEXEC_PIPES | |
586 | BTE_SPAWN_NO_PARENT_ENVV(1 << 25) | |
587 | BTE_SPAWN_NO_SYSTEMD_SCOPE(1 << 26) | |
588 | BTE_SPAWN_REQUIRE_SYSTEMD_SCOPE(1 << 27)); |
589 | } |
590 | |
591 | static constexpr inline auto |
592 | forbidden_spawn_flags() noexcept |
593 | { |
594 | return GSpawnFlags(G_SPAWN_LEAVE_DESCRIPTORS_OPEN | |
595 | G_SPAWN_STDOUT_TO_DEV_NULL | |
596 | G_SPAWN_STDERR_TO_DEV_NULL | |
597 | G_SPAWN_CHILD_INHERITS_STDIN); |
598 | } |
599 | |
600 | static constexpr inline auto |
601 | ignored_spawn_flags() noexcept |
602 | { |
603 | return GSpawnFlags(G_SPAWN_CLOEXEC_PIPES | |
604 | G_SPAWN_DO_NOT_REAP_CHILD); |
605 | } |
606 | |
607 | static bte::base::SpawnContext |
608 | spawn_context_from_args(BtePty* pty, |
609 | char const* working_directory, |
610 | char const* const* argv, |
611 | char const* const* envv, |
612 | int const* fds, |
613 | int n_fds, |
614 | int const* fd_map_to, |
615 | int n_fd_map_to, |
616 | GSpawnFlags spawn_flags, |
617 | GSpawnChildSetupFunc child_setup, |
618 | void* child_setup_data, |
619 | GDestroyNotify child_setup_data_destroy) |
620 | { |
621 | auto context = bte::base::SpawnContext{}; |
622 | context.set_pty(bte::glib::make_ref(pty)); |
623 | context.set_cwd(working_directory); |
624 | context.set_fallback_cwd(g_get_home_dir()); |
625 | context.set_child_setup(child_setup, child_setup_data, child_setup_data_destroy); |
626 | |
627 | if ((spawn_flags & G_SPAWN_SEARCH_PATH_FROM_ENVP) || |
628 | (spawn_flags & G_SPAWN_SEARCH_PATH)) |
629 | context.set_search_path(); |
630 | |
631 | if (spawn_flags & G_SPAWN_FILE_AND_ARGV_ZERO) |
632 | context.set_argv(argv[0], argv + 1); |
633 | else |
634 | context.set_argv(argv[0], argv); |
635 | |
636 | context.set_environ(envv); |
637 | if (spawn_flags & BTE_SPAWN_NO_PARENT_ENVV(1 << 25)) |
638 | context.set_no_inherit_environ(); |
639 | |
640 | if (spawn_flags & BTE_SPAWN_NO_SYSTEMD_SCOPE(1 << 26)) |
641 | context.set_no_systemd_scope(); |
642 | if (spawn_flags & BTE_SPAWN_REQUIRE_SYSTEMD_SCOPE(1 << 27)) |
643 | context.set_require_systemd_scope(); |
644 | |
645 | context.add_fds(fds, n_fds); |
646 | context.add_map_fds(fds, n_fds, fd_map_to, n_fd_map_to); |
647 | |
648 | return context; |
649 | } |
650 | |
651 | bool |
652 | _bte_pty_spawn_sync(BtePty* pty, |
653 | char const* working_directory, |
654 | char const* const* argv, |
655 | char const* const* envv, |
656 | GSpawnFlags spawn_flags, |
657 | GSpawnChildSetupFunc child_setup, |
658 | gpointer child_setup_data, |
659 | GDestroyNotify child_setup_data_destroy, |
660 | GPid* child_pid /* out */, |
661 | int timeout, |
662 | GCancellable* cancellable, |
663 | GError** error) noexcept |
664 | try |
665 | { |
666 | /* These are ignored or need not be passed since the behaviour is the default */ |
667 | g_warn_if_fail((spawn_flags & ignored_spawn_flags()) == 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((spawn_flags & ignored_spawn_flags()) == 0) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_warn_message ("BTE", "../src/btepty.cc", 667, ((const char *) (__PRETTY_FUNCTION__)), "(spawn_flags & ignored_spawn_flags()) == 0" ); } while (0); |
668 | |
669 | /* This may be upgraded to a g_return_if_fail in the future */ |
670 | g_warn_if_fail((spawn_flags & forbidden_spawn_flags()) == 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((spawn_flags & forbidden_spawn_flags()) == 0) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_warn_message ("BTE", "../src/btepty.cc", 670, ((const char *) (__PRETTY_FUNCTION__)), "(spawn_flags & forbidden_spawn_flags()) == 0" ); } while (0); |
671 | spawn_flags = GSpawnFlags(spawn_flags & ~forbidden_spawn_flags()); |
672 | |
673 | auto op = bte::base::SpawnOperation{spawn_context_from_args(pty, |
674 | working_directory, |
675 | argv, |
676 | envv, |
677 | nullptr, 0, |
678 | nullptr, 0, |
679 | spawn_flags, |
680 | child_setup, |
681 | child_setup_data, |
682 | child_setup_data_destroy), |
683 | timeout, |
684 | cancellable}; |
685 | |
686 | auto err = bte::glib::Error{}; |
687 | auto rv = op.run_sync(child_pid, err); |
688 | if (!rv) |
689 | err.propagate(error); |
690 | |
691 | return rv; |
692 | } |
693 | catch (...) |
694 | { |
695 | return bte::glib::set_error_from_exception(error); |
696 | } |
697 | |
698 | /* |
699 | * _bte_pty_check_envv: |
700 | * @strv: |
701 | * |
702 | * Validates that each element is of the form 'KEY=VALUE'. |
703 | */ |
704 | bool |
705 | _bte_pty_check_envv(char const* const* strv) noexcept |
706 | { |
707 | if (!strv) |
708 | return true; |
709 | |
710 | for (int i = 0; strv[i]; ++i) { |
711 | const char *str = strv[i]; |
712 | const char *equal = strchr(str, '='); |
713 | if (equal == nullptr || equal == str) |
714 | return false; |
715 | } |
716 | |
717 | return true; |
718 | } |
719 | |
720 | /** |
721 | * bte_pty_spawn_with_fds_async: |
722 | * @pty: a #BtePty |
723 | * @working_directory: (allow-none): the name of a directory the command should start |
724 | * in, or %NULL to use the current working directory |
725 | * @argv: (array zero-terminated=1) (element-type filename): child's argument vector |
726 | * @envv: (allow-none) (array zero-terminated=1) (element-type filename): a list of environment |
727 | * variables to be added to the environment before starting the process, or %NULL |
728 | * @fds: (nullable) (array length=n_fds) (transfer none) (scope call): an array of file descriptors, or %NULL |
729 | * @n_fds: the number of file descriptors in @fds, or 0 if @fds is %NULL |
730 | * @map_fds: (nullable) (array length=n_map_fds) (transfer none) (scope call): an array of integers, or %NULL |
731 | * @n_map_fds: the number of elements in @map_fds, or 0 if @map_fds is %NULL |
732 | * @spawn_flags: flags from #GSpawnFlags |
733 | * @child_setup: (allow-none) (scope async): an extra child setup function to run in the child just before exec(), or %NULL |
734 | * @child_setup_data: (nullable) (closure child_setup): user data for @child_setup, or %NULL |
735 | * @child_setup_data_destroy: (nullable) (destroy child_setup_data): a #GDestroyNotify for @child_setup_data, or %NULL |
736 | * @timeout: a timeout value in ms, -1 for the default timeout, or G_MAXINT to wait indefinitely |
737 | * @cancellable: (allow-none): a #GCancellable, or %NULL |
738 | * @callback: (nullable) (scope async): a #GAsyncReadyCallback, or %NULL |
739 | * @user_data: (closure callback): user data for @callback |
740 | * |
741 | * Starts the specified command under the pseudo-terminal @pty. |
742 | * The @argv and @envv lists should be %NULL-terminated. |
743 | * The "TERM" environment variable is automatically set to a default value, |
744 | * but can be overridden from @envv. |
745 | * @pty_flags controls logging the session to the specified system log files. |
746 | * |
747 | * Note also that %G_SPAWN_STDOUT_TO_DEV_NULL, %G_SPAWN_STDERR_TO_DEV_NULL, |
748 | * and %G_SPAWN_CHILD_INHERITS_STDIN are not supported in @spawn_flags, since |
749 | * stdin, stdout and stderr of the child process will always be connected to |
750 | * the PTY. Also %G_SPAWN_LEAVE_DESCRIPTORS_OPEN is not supported; and |
751 | * %G_SPAWN_DO_NOT_REAP_CHILD will always be added to @spawn_flags. |
752 | * |
753 | * If @fds is not %NULL, the child process will map the file descriptors from |
754 | * @fds according to @map_fds; @n_map_fds must be less or equal to @n_fds. |
755 | * This function will take ownership of the file descriptors in @fds; |
756 | * you must not use or close them after this call. All file descriptors in @fds |
757 | * must have the FD_CLOEXEC flag set on them; it will be unset in the child process |
758 | * before calling exec. |
759 | * |
760 | * Note that all open file descriptors apart from those mapped as above |
761 | * will be closed in the child. (If you want to keep some other file descriptor |
762 | * open for use in the child process, you need to use a child setup function |
763 | * that unsets the FD_CLOEXEC flag on that file descriptor manually.) |
764 | * |
765 | * Beginning with 0.60, and on linux only, and unless %BTE_SPAWN_NO_SYSTEMD_SCOPE is |
766 | * passed in @spawn_flags, the newly created child process will be moved to its own |
767 | * systemd user scope; and if %BTE_SPAWN_REQUIRE_SYSTEMD_SCOPE is passed, and creation |
768 | * of the systemd user scope fails, the whole spawn will fail. |
769 | * You can override the options used for the systemd user scope by |
770 | * providing a systemd override file for 'bte-spawn-.scope' unit. See man:systemd.unit(5) |
771 | * for further information. |
772 | * |
773 | * See bte_pty_new(), and bte_terminal_watch_child() for more information. |
774 | * |
775 | * Since: 0.62 |
776 | */ |
777 | void |
778 | bte_pty_spawn_with_fds_async(BtePty *pty, |
779 | char const* working_directory, |
780 | char const* const* argv, |
781 | char const* const* envv, |
782 | int const* fds, |
783 | int n_fds, |
784 | int const* fd_map_to, |
785 | int n_fd_map_to, |
786 | GSpawnFlags spawn_flags, |
787 | GSpawnChildSetupFunc child_setup, |
788 | gpointer child_setup_data, |
789 | GDestroyNotify child_setup_data_destroy, |
790 | int timeout, |
791 | GCancellable *cancellable, |
792 | GAsyncReadyCallback callback, |
793 | gpointer user_data) noexcept |
794 | try |
795 | { |
796 | g_return_if_fail(argv != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (argv != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "argv != nullptr" ); return; } } while (0); |
797 | g_return_if_fail(argv[0] != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (argv[0] != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "argv[0] != nullptr" ); return; } } while (0); |
798 | g_return_if_fail(envv == nullptr || _bte_pty_check_envv(envv))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (envv == nullptr || _bte_pty_check_envv(envv)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "envv == nullptr || _bte_pty_check_envv(envv)"); return; } } while (0); |
799 | g_return_if_fail(n_fds == 0 || fds != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (n_fds == 0 || fds != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "n_fds == 0 || fds != nullptr" ); return; } } while (0); |
800 | for (auto i = int{0}; i < n_fds; ++i) |
801 | g_return_if_fail(bte::libc::fd_get_cloexec(fds[i]))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (bte::libc::fd_get_cloexec(fds[i])) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "bte::libc::fd_get_cloexec(fds[i])"); return; } } while ( 0); |
802 | g_return_if_fail(n_fd_map_to == 0 || fd_map_to != nullptr)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (n_fd_map_to == 0 || fd_map_to != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "n_fd_map_to == 0 || fd_map_to != nullptr"); return; } } while (0); |
803 | g_return_if_fail(n_fds >= n_fd_map_to)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (n_fds >= n_fd_map_to) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "n_fds >= n_fd_map_to" ); return; } } while (0); |
804 | g_return_if_fail((spawn_flags & ~all_spawn_flags()) == 0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((spawn_flags & ~all_spawn_flags()) == 0) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "(spawn_flags & ~all_spawn_flags()) == 0"); return; } } while (0); |
805 | g_return_if_fail(!child_setup_data || child_setup)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (!child_setup_data || child_setup) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "!child_setup_data || child_setup" ); return; } } while (0); |
806 | g_return_if_fail(!child_setup_data_destroy || child_setup_data)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (!child_setup_data_destroy || child_setup_data) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "!child_setup_data_destroy || child_setup_data"); return; } } while (0); |
807 | g_return_if_fail(timeout >= -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (timeout >= -1) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "timeout >= -1" ); return; } } while (0); |
808 | g_return_if_fail(cancellable == nullptr || G_IS_CANCELLABLE (cancellable))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (cancellable == nullptr || (((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ((cancellable)); GType __t = ((g_cancellable_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "cancellable == nullptr || G_IS_CANCELLABLE (cancellable)" ); return; } } while (0); |
809 | |
810 | /* These are ignored or need not be passed since the behaviour is the default */ |
811 | g_warn_if_fail((spawn_flags & ignored_spawn_flags()) == 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((spawn_flags & ignored_spawn_flags()) == 0) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_warn_message ("BTE", "../src/btepty.cc", 811, ((const char *) (__PRETTY_FUNCTION__)), "(spawn_flags & ignored_spawn_flags()) == 0" ); } while (0); |
812 | |
813 | /* This may be upgraded to a g_return_if_fail in the future */ |
814 | g_warn_if_fail((spawn_flags & forbidden_spawn_flags()) == 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((spawn_flags & forbidden_spawn_flags()) == 0) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_warn_message ("BTE", "../src/btepty.cc", 814, ((const char *) (__PRETTY_FUNCTION__)), "(spawn_flags & forbidden_spawn_flags()) == 0" ); } while (0); |
815 | spawn_flags = GSpawnFlags(spawn_flags & ~forbidden_spawn_flags()); |
816 | |
817 | auto op = new bte::base::SpawnOperation{spawn_context_from_args(pty, |
818 | working_directory, |
819 | argv, |
820 | envv, |
821 | fds, n_fds, |
822 | fd_map_to, n_fd_map_to, |
823 | spawn_flags, |
824 | child_setup, |
825 | child_setup_data, |
826 | child_setup_data_destroy), |
827 | timeout, |
828 | cancellable}; |
829 | |
830 | /* takes ownership of @op */ |
831 | op->run_async((void*)bte_pty_spawn_async, /* tag */ |
832 | callback, |
833 | user_data); |
834 | } |
835 | catch (...) |
836 | { |
837 | // FIXME: make the function above exception safe. It needs to guarantee |
838 | // that the callback will be invoked regardless of when the throw occurred. |
839 | |
840 | bte::log_exception(); |
841 | } |
842 | |
843 | /** |
844 | * bte_pty_spawn_async: |
845 | * @pty: a #BtePty |
846 | * @working_directory: (allow-none): the name of a directory the command should start |
847 | * in, or %NULL to use the current working directory |
848 | * @argv: (array zero-terminated=1) (element-type filename): child's argument vector |
849 | * @envv: (allow-none) (array zero-terminated=1) (element-type filename): a list of environment |
850 | * variables to be added to the environment before starting the process, or %NULL |
851 | * @spawn_flags: flags from #GSpawnFlags |
852 | * @child_setup: (allow-none) (scope async): an extra child setup function to run in the child just before exec(), or %NULL |
853 | * @child_setup_data: (nullable) (closure child_setup): user data for @child_setup, or %NULL |
854 | * @child_setup_data_destroy: (nullable) (destroy child_setup_data): a #GDestroyNotify for @child_setup_data, or %NULL |
855 | * @timeout: a timeout value in ms, -1 for the default timeout, or G_MAXINT to wait indefinitely |
856 | * @cancellable: (allow-none): a #GCancellable, or %NULL |
857 | * @callback: (nullable) (scope async): a #GAsyncReadyCallback, or %NULL |
858 | * @user_data: (closure callback): user data for @callback |
859 | * |
860 | * Like bte_pty_spawn_with_fds_async(), except that this function does not |
861 | * allow passing file descriptors to the child process. See bte_pty_spawn_with_fds_async() |
862 | * for more information. |
863 | * |
864 | * Since: 0.48 |
865 | */ |
866 | void |
867 | bte_pty_spawn_async(BtePty *pty, |
868 | const char *working_directory, |
869 | char **argv, |
870 | char **envv, |
871 | GSpawnFlags spawn_flags, |
872 | GSpawnChildSetupFunc child_setup, |
873 | gpointer child_setup_data, |
874 | GDestroyNotify child_setup_data_destroy, |
875 | int timeout, |
876 | GCancellable *cancellable, |
877 | GAsyncReadyCallback callback, |
878 | gpointer user_data) noexcept |
879 | { |
880 | bte_pty_spawn_with_fds_async(pty, working_directory, argv, envv, |
881 | nullptr, 0, nullptr, 0, |
882 | spawn_flags, |
883 | child_setup, child_setup_data, child_setup_data_destroy, |
884 | timeout, cancellable, |
885 | callback, user_data); |
886 | } |
887 | |
888 | /** |
889 | * bte_pty_spawn_finish: |
890 | * @pty: a #BtePty |
891 | * @result: a #GAsyncResult |
892 | * @child_pid: (out) (allow-none) (transfer full): a location to store the child PID, or %NULL |
893 | * @error: (allow-none): return location for a #GError, or %NULL |
894 | * |
895 | * Returns: %TRUE on success, or %FALSE on error with @error filled in |
896 | * |
897 | * Since: 0.48 |
898 | */ |
899 | gboolean |
900 | bte_pty_spawn_finish(BtePty* pty, |
901 | GAsyncResult* result, |
902 | GPid* child_pid /* out */, |
903 | GError** error) noexcept |
904 | { |
905 | g_return_val_if_fail (BTE_IS_PTY(pty), false)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((pty)); GType __t = ((bte_pty_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "BTE_IS_PTY(pty)"); return (false); } } while (0); |
906 | g_return_val_if_fail (G_IS_TASK(result), false)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((result)); GType __t = ((g_task_get_type ())); gboolean __r ; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "G_IS_TASK(result)"); return (false); } } while (0); |
907 | g_return_val_if_fail (g_task_get_source_tag(G_TASK (result)) == bte_pty_spawn_async, false)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (g_task_get_source_tag(((((GTask*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((result)), ((g_task_get_type ()))))))) == bte_pty_spawn_async) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__)), "g_task_get_source_tag(G_TASK (result)) == bte_pty_spawn_async" ); return (false); } } while (0); |
908 | g_return_val_if_fail(error == nullptr || *error == nullptr, false)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (error == nullptr || *error == nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("BTE", ((const char*) (__PRETTY_FUNCTION__ )), "error == nullptr || *error == nullptr"); return (false); } } while (0); |
909 | |
910 | auto pid = g_task_propagate_int(G_TASK(result)((((GTask*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((result)), ((g_task_get_type ())))))), error); |
911 | if (child_pid) |
912 | *child_pid = pid; |
913 | |
914 | return pid != -1; |
915 | } |