void cockpit_set_journal_logging (const gchar *stderr_domain, gboolean only) { int fd; old_handler = g_log_set_default_handler (cockpit_journal_log_handler, NULL); /* SELinux won't let us always open the sd_journal_stream_fd * so just check that the main journal socket exists */ have_journal = g_file_test ("/run/systemd/journal/socket", G_FILE_TEST_EXISTS); if (only) old_handler = NULL; if (only && stderr_domain) { fd = sd_journal_stream_fd (stderr_domain, LOG_WARNING, 0); if (fd < 0) { if (-fd == ENOENT) g_debug ("no journal present to stream stderr"); else g_warning ("couldn't open journal stream for stderr: %s", g_strerror (-fd)); } else { if (dup2 (fd, 2) < 0) { g_warning ("couldn't replace journal stream for stderr: %s", g_strerror (errno)); close (fd); } } } }
static int run(int argc, char *argv[]) { _cleanup_close_ int fd = -1, saved_stderr = -1; int r; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) return r; fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); if (fd < 0) return log_error_errno(fd, "Failed to create stream fd: %m"); saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); r = rearrange_stdio(STDIN_FILENO, fd, fd); /* Invalidates fd on succcess + error! */ TAKE_FD(fd); if (r < 0) return log_error_errno(r, "Failed to rearrange stdout/stderr: %m"); if (argc <= optind) (void) execl("/bin/cat", "/bin/cat", NULL); else (void) execvp(argv[optind], argv + optind); r = -errno; /* Let's try to restore a working stderr, so we can print the error message */ if (saved_stderr >= 0) (void) dup3(saved_stderr, STDERR_FILENO, 0); return log_error_errno(r, "Failed to execute process: %m"); }
int main(int argc, char *argv[]) { int r, fd = -1, saved_stderr = -1; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); if (fd < 0) { log_error("Failed to create stream fd: %s", strerror(-fd)); r = fd; goto finish; } saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); if (dup3(fd, STDOUT_FILENO, 0) < 0 || dup3(fd, STDERR_FILENO, 0) < 0) { log_error("Failed to duplicate fd: %m"); r = -errno; goto finish; } if (fd >= 3) close_nointr_nofail(fd); fd = -1; if (argc <= optind) execl("/bin/cat", "/bin/cat", NULL); else execvp(argv[optind], argv + optind); r = -errno; /* Let's try to restore a working stderr, so we can print the error message */ if (saved_stderr >= 0) dup3(saved_stderr, STDERR_FILENO, 0); log_error("Failed to execute process: %s", strerror(-r)); finish: if (fd >= 0) close_nointr_nofail(fd); if (saved_stderr >= 0) close_nointr_nofail(saved_stderr); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int stream_fd (lua_State *L) { int fd; const char *identifier = luaL_checkstring(L, 1); int priority = luaL_checkinteger(L, 2); int level_prefix = lua_toboolean(L, 3); /* Optional arg, defaults to false */ luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream)); p->closef = NULL; /* create a `closed' file handle before opening file, in case of errors */ luaL_setmetatable(L, LUA_FILEHANDLE); fd = sd_journal_stream_fd(identifier, priority, level_prefix); if (fd < 0) return handle_error(L, -fd); p->f = fdopen(fd, "w"); if (!p->f) return handle_error(L, errno); p->closef = &io_fclose; return 1; }
static PyObject* journal_stream_fd(PyObject *self, PyObject *args) { const char* identifier; int priority, level_prefix; int fd; if (!PyArg_ParseTuple(args, "sii:stream_fd", &identifier, &priority, &level_prefix)) return NULL; fd = sd_journal_stream_fd(identifier, priority, level_prefix); if (fd < 0) { errno = -fd; return PyErr_SetFromErrno(PyExc_IOError); } return PyLong_FromLong(fd); }
/** * Spawns a new process. * * On Unix platforms, the child_setup function is passed the given * user_data and is run in the child after fork() but before calling exec(). * This can be used to change uid, resource limits and so on. * On Windows, this functionality does not fit the multi-processing model * (Windows does the equivalent of fork() and exec() in a single API call), * and the child_setup function and its user_data are ignored. * * Also creates a "babysitter" which tracks the status of the * child process, advising the parent if the child exits. * If the spawn fails, no babysitter is created. * If sitter_p is #NULL, no babysitter is kept. * * @param sitter_p return location for babysitter or #NULL * @param log_name the name under which to log messages about this process being spawned * @param argv the executable and arguments * @param env the environment, or #NULL to copy the parent's * @param child_setup function to call in child pre-exec() * @param user_data user data for setup function * @param error error object to be filled in if function fails * @returns #TRUE on success, #FALSE if error is filled in */ dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, const char *log_name, char * const *argv, char **env, DBusSpawnFlags flags, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { DBusBabysitter *sitter; int child_err_report_pipe[2] = { -1, -1 }; DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT }; pid_t pid; #ifdef HAVE_SYSTEMD int fd_out = -1; int fd_err = -1; #endif _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (argv[0] != NULL); if (sitter_p != NULL) *sitter_p = NULL; sitter = NULL; sitter = _dbus_babysitter_new (); if (sitter == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } sitter->log_name = _dbus_strdup (log_name); if (sitter->log_name == NULL && log_name != NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (sitter->log_name == NULL) sitter->log_name = _dbus_strdup (argv[0]); if (sitter->log_name == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) goto cleanup_and_fail; /* Setting up the babysitter is only useful in the parent, * but we don't want to run out of memory and fail * after we've already forked, since then we'd leak * child processes everywhere. */ sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->error_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd, DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->sitter_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); #ifdef HAVE_SYSTEMD if (flags & DBUS_SPAWN_REDIRECT_OUTPUT) { /* This may fail, but it's not critical. * In particular, if we were compiled with journald support but are now * running on a non-systemd system, this is going to fail, so we * have to cope gracefully. */ fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE); fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE); } #endif pid = fork (); if (pid < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FORK_FAILED, "Failed to fork (%s)", _dbus_strerror (errno)); goto cleanup_and_fail; } else if (pid == 0) { /* Immediate child, this is the babysitter process. */ int grandchild_pid; /* Be sure we crash if the parent exits * and we write to the err_report_pipe */ signal (SIGPIPE, SIG_DFL); /* Close the parent's end of the pipes. */ close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&babysitter_pipe[0].fd); /* Create the child that will exec () */ grandchild_pid = fork (); if (grandchild_pid < 0) { write_err_and_exit (babysitter_pipe[1].fd, CHILD_FORK_FAILED); _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); } else if (grandchild_pid == 0) { #ifdef __linux__ int fd = -1; #ifdef O_CLOEXEC fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); #endif if (fd < 0) { fd = open ("/proc/self/oom_score_adj", O_WRONLY); _dbus_fd_set_close_on_exec (fd); } if (fd >= 0) { if (write (fd, "0", sizeof (char)) < 0) _dbus_warn ("writing oom_score_adj error: %s", strerror (errno)); _dbus_close (fd, NULL); } #endif /* Go back to ignoring SIGPIPE, since it's evil */ signal (SIGPIPE, SIG_IGN); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD /* log to systemd journal if possible */ if (fd_out >= 0) dup2 (fd_out, STDOUT_FILENO); if (fd_err >= 0) dup2 (fd_err, STDERR_FILENO); close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif do_exec (child_err_report_pipe[WRITE_END], argv, env, child_setup, user_data); _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); } else { close_and_invalidate (&child_err_report_pipe[WRITE_END]); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif babysit (grandchild_pid, babysitter_pipe[1].fd); _dbus_assert_not_reached ("Got to code after babysit()"); } } else { /* Close the uncared-about ends of the pipes */ close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif sitter->socket_to_babysitter = babysitter_pipe[0]; babysitter_pipe[0].fd = -1; sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; child_err_report_pipe[READ_END] = -1; sitter->sitter_pid = pid; if (sitter_p != NULL) *sitter_p = sitter; else _dbus_babysitter_unref (sitter); dbus_free_string_array (env); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; } cleanup_and_fail: _DBUS_ASSERT_ERROR_IS_SET (error); close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[0].fd); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif if (sitter != NULL) _dbus_babysitter_unref (sitter); return FALSE; }
int main (int argc, char **argv) { GError *error = NULL; static char **override_autostart_dirs = NULL; static char *opt_session_name = NULL; const char *debug_string = NULL; gboolean gl_failed = FALSE; guint name_owner_id; GOptionContext *options; static GOptionEntry entries[] = { { "autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), N_("AUTOSTART_DIR") }, { "session", 0, 0, G_OPTION_ARG_STRING, &opt_session_name, N_("Session to use"), N_("SESSION_NAME") }, { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL }, { "failsafe", 'f', 0, G_OPTION_ARG_NONE, &failsafe, N_("Do not load user-specified applications"), NULL }, { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL }, /* Translators: the 'fail whale' is the black dialog we show when something goes seriously wrong */ { "whale", 0, 0, G_OPTION_ARG_NONE, &please_fail, N_("Show the fail whale dialog for testing"), NULL }, { "disable-acceleration-check", 0, 0, G_OPTION_ARG_NONE, &disable_acceleration_check, N_("Disable hardware acceleration check"), NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; /* Make sure that we have a session bus */ if (!require_dbus_session (argc, argv, &error)) { gsm_util_init_error (TRUE, "%s", error->message); } /* From 3.14 GDM sets XDG_CURRENT_DESKTOP. For compatibility with * older versions of GDM, other display managers, and startx, * set a fallback value if we don't find it set. */ if (g_getenv ("XDG_CURRENT_DESKTOP") == NULL) { g_setenv("XDG_CURRENT_DESKTOP", "GNOME", TRUE); gsm_util_setenv ("XDG_CURRENT_DESKTOP", "GNOME"); } /* Make sure we initialize gio in a way that does not autostart any daemon */ initialize_gio (); setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); debug_string = g_getenv ("GNOME_SESSION_DEBUG"); if (debug_string != NULL) { debug = rpmatch (debug_string) == TRUE || atoi (debug_string) == 1; } error = NULL; options = g_option_context_new (_(" - the GNOME session manager")); g_option_context_add_main_entries (options, entries, GETTEXT_PACKAGE); g_option_context_parse (options, &argc, &argv, &error); if (error != NULL) { g_warning ("%s", error->message); exit (1); } g_option_context_free (options); /* Rebind stdout/stderr to the journal explicitly, so that * journald picks ups the nicer "gnome-session" as the program * name instead of whatever shell script GDM happened to use. */ #ifdef HAVE_SYSTEMD if (!debug) { int journalfd; journalfd = sd_journal_stream_fd (PACKAGE, LOG_INFO, 0); if (journalfd >= 0) { dup2(journalfd, 1); dup2(journalfd, 2); } } #endif gdm_log_init (); gdm_log_set_debug (debug); if (disable_acceleration_check) { g_debug ("hardware acceleration check is disabled"); } else { /* Check GL, if it doesn't work out then force software fallback */ if (!check_gl (&error)) { gl_failed = TRUE; g_debug ("hardware acceleration check failed: %s", error? error->message : ""); g_clear_error (&error); if (g_getenv ("LIBGL_ALWAYS_SOFTWARE") == NULL) { g_setenv ("LIBGL_ALWAYS_SOFTWARE", "1", TRUE); if (!check_gl (&error)) { g_warning ("software acceleration check failed: %s", error? error->message : ""); g_clear_error (&error); } else { gl_failed = FALSE; } } } } if (show_version) { g_print ("%s %s\n", argv [0], VERSION); exit (0); } if (gl_failed) { gsm_fail_whale_dialog_we_failed (FALSE, TRUE, NULL); gsm_main (); exit (1); } if (please_fail) { gsm_fail_whale_dialog_we_failed (TRUE, TRUE, NULL); gsm_main (); exit (1); } { gchar *ibus_path; ibus_path = g_find_program_in_path("ibus-daemon"); if (ibus_path) { const gchar *p; p = g_getenv ("QT_IM_MODULE"); if (!p || !*p) p = "ibus"; gsm_util_setenv ("QT_IM_MODULE", p); p = g_getenv ("XMODIFIERS"); if (!p || !*p) p = "@im=ibus"; gsm_util_setenv ("XMODIFIERS", p); } g_free (ibus_path); } /* Some third-party programs rely on GNOME_DESKTOP_SESSION_ID to * detect if GNOME is running. We keep this for compatibility reasons. */ gsm_util_setenv ("GNOME_DESKTOP_SESSION_ID", "this-is-deprecated"); /* We want to use the GNOME menus which has the designed categories. */ gsm_util_setenv ("XDG_MENU_PREFIX", "gnome-"); /* hack to fix keyring until we can reorder things in 3.20 * https://bugzilla.gnome.org/show_bug.cgi?id=738205 */ if (g_strcmp0 (g_getenv ("XDG_SESSION_TYPE"), "wayland") == 0 && g_getenv ("GSM_SKIP_SSH_AGENT_WORKAROUND") == NULL) { char *ssh_socket; ssh_socket = g_build_filename (g_get_user_runtime_dir (), "keyring", "ssh", NULL); gsm_util_setenv ("SSH_AUTH_SOCK", ssh_socket); g_free (ssh_socket); } gsm_util_set_autostart_dirs (override_autostart_dirs); session_name = opt_session_name; /* Talk to logind before acquiring a name, since it does synchronous * calls at initialization time that invoke a main loop and if we * already owned a name, then we would service too early during * that main loop. */ g_object_unref (gsm_get_system ()); name_owner_id = acquire_name (); gsm_main (); g_clear_object (&manager); g_free (gl_renderer); g_bus_unown_name (name_owner_id); gdm_log_shutdown (); return 0; }