Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright 2025 GNOME Foundation, Inc.
4 : : *
5 : : * SPDX-License-Identifier: GPL-2.0-or-later
6 : : *
7 : : * This program is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This program is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Authors:
21 : : * - Philip Withnall <pwithnall@gnome.org>
22 : : */
23 : :
24 : : #include "config.h"
25 : :
26 : : #include <gio/gio.h>
27 : : #include <glib.h>
28 : : #include <glib/gi18n.h>
29 : : #include <glib/gstdio.h>
30 : : #include <glib-unix.h>
31 : : #include <locale.h>
32 : : #include <signal.h>
33 : : #include <sysexits.h>
34 : :
35 : :
36 : : typedef unsigned int SourceHandle;
37 : :
38 : : static void
39 : 2 : source_handle_clear (SourceHandle *handle)
40 : : {
41 [ + - ]: 2 : g_clear_handle_id (handle, g_source_remove);
42 : 2 : }
43 : :
44 : 2 : G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (SourceHandle, source_handle_clear)
45 : :
46 : : const char *error_file = "/var/lib/malcontent-webd/update-error";
47 : : const char *error_file_group = "Web Filter Update Error";
48 : :
49 : : /* Writes out a file like the following, containing error information if the
50 : : * malcontent-webd process failed. This can then be reported to the parent when
51 : : * they next log in or check web filtering settings.
52 : : *
53 : : * ```
54 : : * [Web Filter Update Error]
55 : : * ErrorCode=org.freedesktop.MalcontentWeb1.Filtering.Error.Downloading
56 : : * ErrorMessage[en_GB]=There was an error downloading foo from blah.
57 : : * ```
58 : : *
59 : : * Returns an exit status.
60 : : */
61 : : static int
62 : 1 : report_error (const GError *error)
63 : : {
64 : 1 : g_autoptr(GKeyFile) key_file = NULL;
65 : 1 : g_autoptr(GError) local_error = NULL;
66 : 1 : const char *current_locale = setlocale (LC_ALL, NULL);
67 : 1 : g_autoptr(GError) stripped_error = NULL;
68 : 2 : g_autofree char *error_code = g_dbus_error_get_remote_error (error);
69 : 1 : g_autofree char *key_file_data = NULL;
70 : 1 : size_t key_file_data_length = 0;
71 : :
72 : : /* Output a copy of the error to the journal. */
73 : 1 : stripped_error = g_error_copy (error);
74 : 1 : g_dbus_error_strip_remote_error (stripped_error);
75 : :
76 : 1 : g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
77 : : "CODE_FILE", __FILE__,
78 : : "CODE_LINE", G_STRINGIFY (__LINE__),
79 : : "CODE_FUNC", G_STRFUNC,
80 : : "SYSLOG_IDENTIFIER", g_get_prgname (),
81 : 1 : "ERROR_CODE", (error_code != NULL) ? error_code : "",
82 : : "MESSAGE_ID", "e91b59b0c8e24b9b99a15e0004c2f1d0",
83 [ + - ]: 1 : "MESSAGE", "%s", stripped_error->message);
84 : :
85 : : /* If we were cancelled, just ignore everything. */
86 [ - + ]: 1 : if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
87 : 0 : return EX_TEMPFAIL;
88 : :
89 : 1 : key_file = g_key_file_new ();
90 : :
91 [ + - ]: 1 : if (error_code != NULL)
92 : 1 : g_key_file_set_string (key_file, error_file_group, "ErrorCode", error_code);
93 : 1 : g_key_file_set_locale_string (key_file, error_file_group, "ErrorMessage", current_locale, stripped_error->message);
94 : :
95 : : /* Save it using g_file_set_contents_full() so we can set the permissions so
96 : : * all users can read. */
97 : 1 : key_file_data = g_key_file_to_data (key_file, &key_file_data_length, &local_error);
98 [ + - + - ]: 2 : if (key_file_data == NULL ||
99 : 1 : !g_file_set_contents_full (error_file, key_file_data, key_file_data_length,
100 : : G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_DURABLE,
101 : : 0644, &local_error))
102 : : {
103 : 1 : g_warning (_("Error updating error file ‘%s’: %s"), error_file, local_error->message);
104 : : }
105 : :
106 : 1 : return EX_UNAVAILABLE;
107 : : }
108 : :
109 : : static void
110 : 1 : clear_error (void)
111 : : {
112 : 1 : g_unlink (error_file);
113 : 1 : }
114 : :
115 : : static gboolean
116 : 0 : sigint_cb (void *user_data)
117 : : {
118 : 0 : GCancellable *cancellable = G_CANCELLABLE (user_data);
119 : :
120 : 0 : g_cancellable_cancel (cancellable);
121 : :
122 : 0 : return G_SOURCE_CONTINUE;
123 : : }
124 : :
125 : : int
126 : 2 : main (int argc,
127 : : char *argv[])
128 : : {
129 : 2 : g_autoptr(GOptionContext) context = NULL;
130 : 2 : g_autoptr(GCancellable) cancellable = NULL;
131 : 2 : g_auto(SourceHandle) sigint_id = 0;
132 : 2 : g_autoptr(GDBusConnection) connection = NULL;
133 : 2 : g_autoptr(GVariant) reply = NULL;
134 : 2 : g_autoptr(GError) local_error = NULL;
135 : :
136 : 2 : setlocale (LC_ALL, "");
137 : :
138 : : /* --help handling */
139 : 2 : context = g_option_context_new (_("- trigger a web filter update"));
140 [ - + ]: 2 : if (!g_option_context_parse (context, &argc, &argv, &local_error))
141 : : {
142 : 0 : g_warning ("%s", local_error->message);
143 : 0 : return EX_USAGE;
144 : : }
145 : :
146 : : /* Handle cancellation, since everything here runs sync. */
147 : 2 : cancellable = g_cancellable_new ();
148 : 2 : sigint_id = g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGINT, sigint_cb,
149 : : g_object_ref (cancellable), g_object_unref);
150 : :
151 : : /* Call the malcontent-webd daemon via D-Bus and get it to update all the
152 : : * users’ web filters. */
153 : 2 : connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
154 : :
155 [ - + ]: 2 : if (connection == NULL)
156 : 0 : return report_error (local_error);
157 : :
158 : 2 : reply = g_dbus_connection_call_sync (connection,
159 : : "org.freedesktop.MalcontentWeb1",
160 : : "/org/freedesktop/MalcontentWeb1",
161 : : "org.freedesktop.MalcontentWeb1.Filtering",
162 : : "UpdateFilters",
163 : : g_variant_new ("(u)", 0), /* zero means ‘all users’ */
164 : : NULL,
165 : : G_DBUS_CALL_FLAGS_NONE,
166 : : -1, /* timeout */
167 : : cancellable,
168 : : &local_error);
169 : :
170 [ + + ]: 2 : if (reply == NULL)
171 : 1 : return report_error (local_error);
172 : :
173 : 1 : clear_error ();
174 : :
175 : 1 : return 0;
176 : : }
177 : :
|