Bug Summary

File:/rootdir/_build/../src/btepty.cc
Warning:line 134, column 1
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name btepty.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I src/libbte-2.91.so.0.6500.0.p -I src -I ../src -I . -I .. -I src/bte -I ../src/bte -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/uuid -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/p11-kit-1 -I /usr/include/ctk-3.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D _FILE_OFFSET_BITS=64 -D G_LOG_DOMAIN="BTE" -D LOCALEDIR="/usr/local/share/locale" -D BTE_DISABLE_DEPRECATION_WARNINGS -D BTE_COMPILATION -U PARSER_INCLUDE_NOP -D CDK_VERSION_MIN_REQUIRED=(G_ENCODE_VERSION(3,18)) -D CDK_VERSION_MAX_ALLOWED=(G_ENCODE_VERSION(3,20)) -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-address-of-packed-member -Wno-missing-field-initializers -Wno-packed -Wno-switch-enum -Wno-unused-parameter -Wwrite-strings -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/rootdir/_build -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2022-12-31-022803-10898-1 -x c++ ../src/btepty.cc
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
56typedef struct _BtePtyPrivate BtePtyPrivate;
57
58typedef struct {
59 GSpawnChildSetupFunc extra_child_setup;
60 gpointer extra_child_setup_data;
61} BtePtyChildSetupData;
62
63/**
64 * BtePty:
65 */
66struct _BtePty {
67 GObject parent_instance;
68
69 /* <private> */
70 BtePtyPrivate *priv;
71};
72
73struct _BtePtyPrivate {
74 bte::base::Pty* pty; /* owned */
75 int foreign_fd; /* foreign FD if != -1 */
76 BtePtyFlags flags;
77};
78
79struct _BtePtyClass {
80 GObjectClass parent_class;
81};
82
83bte::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 */
132void
133bte_pty_child_setup (BtePty *pty) noexcept
134try
This statement is never executed
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}
142catch (...)
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 */
161gboolean
162bte_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
173bool
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
180try
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}
197catch (...)
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 */
216gboolean
217bte_pty_get_size(BtePty *pty,
218 int *rows,
219 int *columns,
220 GError **error) noexcept
221try
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}
237catch (...)
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 */
254gboolean
255bte_pty_set_utf8(BtePty *pty,
256 gboolean utf8,
257 GError **error) noexcept
258try
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}
272catch (...)
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 */
285void
286bte_pty_close (BtePty *pty) noexcept
287{
288 /* impl->close(); */
289}
290
291/* BTE PTY class */
292
293enum {
294 PROP_0,
295 PROP_FLAGS,
296 PROP_FD,
297};
298
299/* GInitable impl */
300
301static gboolean
302bte_pty_initable_init (GInitable *initable,
303 GCancellable *cancellable,
304 GError **error) noexcept
305try
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}
326catch (...)
327{
328 return bte::glib::set_error_from_exception(error);
329}
330
331static void
332bte_pty_initable_iface_init (GInitableIface *iface)
333{
334 iface->init = bte_pty_initable_init;
335}
336
337/* GObjectClass impl */
338
339G_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
343static void
344bte_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
355static void
356bte_pty_finalize (GObject *object) noexcept
357try
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}
366catch (...)
367{
368 bte::log_exception();
369}
370
371static void
372bte_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
394static void
395bte_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
417static void
418bte_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 */
466GQuark
467bte_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 */
512BtePty *
513bte_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 */
539BtePty *
540bte_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 */
561int
562bte_pty_get_fd (BtePty *pty) noexcept
563try
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}
568catch (...)
569{
570 bte::log_exception();
571 return -1;
572}
573
574static constexpr inline auto
575all_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
591static constexpr inline auto
592forbidden_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
600static constexpr inline auto
601ignored_spawn_flags() noexcept
602{
603 return GSpawnFlags(G_SPAWN_CLOEXEC_PIPES |
604 G_SPAWN_DO_NOT_REAP_CHILD);
605}
606
607static bte::base::SpawnContext
608spawn_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
651bool
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
664try
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}
693catch (...)
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 */
704bool
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 */
777void
778bte_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
794try
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}
835catch (...)
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 */
866void
867bte_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 */
899gboolean
900bte_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}