chiark / gitweb /
util: unify code to check whether certain file names should be ignored when listing...
[elogind.git] / systemadm.vala
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 using Gtk;
21 using GLib;
22 using DBus;
23 using Pango;
24
25 public class LeftLabel : Label {
26         public LeftLabel(string? text = null) {
27                 if (text != null)
28                         set_markup("<b>%s</b>".printf(text));
29                 set_alignment(1, 0);
30                 set_padding(6, 0);
31         }
32 }
33
34 public class RightLabel : Label {
35         public RightLabel(string? text = null) {
36                 set_text_or_na(text);
37                 set_alignment(0, 1);
38                 set_ellipsize(EllipsizeMode.START);
39                 set_selectable(true);
40         }
41
42         public void set_text_or_na(string? text = null) {
43                 if (text == null || text == "")
44                         set_markup("<i>n/a</i>");
45                 else
46                         set_text(text);
47         }
48 }
49
50 public class MainWindow : Window {
51
52         private TreeView unit_view;
53         private TreeView job_view;
54
55         private ListStore unit_model;
56         private ListStore job_model;
57
58         private Button start_button;
59         private Button stop_button;
60         private Button restart_button;
61         private Button reload_button;
62         private Button cancel_button;
63
64         private Connection bus;
65         private Manager manager;
66
67         private RightLabel unit_id_label;
68         private RightLabel unit_description_label;
69         private RightLabel unit_load_state_label;
70         private RightLabel unit_active_state_label;
71         private RightLabel unit_fragment_path_label;
72         private RightLabel unit_active_enter_timestamp_label;
73         private RightLabel unit_active_exit_timestamp_label;
74         private RightLabel unit_can_start_label;
75         private RightLabel unit_can_reload_label;
76
77         private RightLabel job_id_label;
78         private RightLabel job_state_label;
79         private RightLabel job_type_label;
80
81         public MainWindow() throws DBus.Error {
82                 title = "systemdadm";
83                 position = WindowPosition.CENTER;
84                 set_default_size(1000, 700);
85                 set_border_width(12);
86                 destroy += Gtk.main_quit;
87
88                 Notebook notebook = new Notebook();
89                 add(notebook);
90
91                 Box unit_vbox = new VBox(false, 6);
92                 notebook.append_page(unit_vbox, new Label("Units"));
93                 unit_vbox.set_border_width(12);
94
95                 Box job_vbox = new VBox(false, 6);
96                 notebook.append_page(job_vbox, new Label("Jobs"));
97                 job_vbox.set_border_width(12);
98
99
100                 unit_model = new ListStore(6, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(Unit));
101                 job_model = new ListStore(5, typeof(string), typeof(string), typeof(string), typeof(string), typeof(Job));
102
103                 unit_view = new TreeView.with_model(unit_model);
104                 job_view = new TreeView.with_model(job_model);
105
106                 unit_view.cursor_changed += unit_changed;
107                 job_view.cursor_changed += job_changed;
108
109                 unit_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 0);
110                 unit_view.insert_column_with_attributes(-1, "Description", new CellRendererText(), "text", 1);
111                 unit_view.insert_column_with_attributes(-1, "Load State", new CellRendererText(), "text", 2);
112                 unit_view.insert_column_with_attributes(-1, "Active State", new CellRendererText(), "text", 3);
113                 unit_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 4);
114
115                 job_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 0);
116                 job_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 1);
117                 job_view.insert_column_with_attributes(-1, "Type", new CellRendererText(), "text", 2);
118                 job_view.insert_column_with_attributes(-1, "State", new CellRendererText(), "text", 3);
119
120                 ScrolledWindow scroll = new ScrolledWindow(null, null);
121                 scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
122                 scroll.set_shadow_type(ShadowType.IN);
123                 scroll.add(unit_view);
124                 unit_vbox.pack_start(scroll, true, true, 0);
125
126                 scroll = new ScrolledWindow(null, null);
127                 scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
128                 scroll.set_shadow_type(ShadowType.IN);
129                 scroll.add(job_view);
130                 job_vbox.pack_start(scroll, true, true, 0);
131
132                 unit_id_label = new RightLabel();
133                 unit_description_label = new RightLabel();
134                 unit_load_state_label = new RightLabel();
135                 unit_active_state_label = new RightLabel();
136                 unit_fragment_path_label = new RightLabel();
137                 unit_active_enter_timestamp_label = new RightLabel();
138                 unit_active_exit_timestamp_label = new RightLabel();
139                 unit_can_start_label = new RightLabel();
140                 unit_can_reload_label = new RightLabel();
141
142                 job_id_label = new RightLabel();
143                 job_state_label = new RightLabel();
144                 job_type_label = new RightLabel();
145
146                 Table unit_table = new Table(9, 2, false);
147                 unit_table.set_row_spacings(6);
148                 unit_table.set_border_width(12);
149                 unit_vbox.pack_start(unit_table, false, true, 0);
150
151                 Table job_table = new Table(2, 2, false);
152                 job_table.set_row_spacings(6);
153                 job_table.set_border_width(12);
154                 job_vbox.pack_start(job_table, false, true, 0);
155
156                 unit_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
157                 unit_table.attach(unit_id_label, 1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
158                 unit_table.attach(new LeftLabel("Description:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
159                 unit_table.attach(unit_description_label, 1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
160                 unit_table.attach(new LeftLabel("Load State:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
161                 unit_table.attach(unit_load_state_label, 1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
162                 unit_table.attach(new LeftLabel("Active State:"), 0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
163                 unit_table.attach(unit_active_state_label, 1, 2, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
164                 unit_table.attach(new LeftLabel("Fragment Path:"), 0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
165                 unit_table.attach(unit_fragment_path_label, 1, 2, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
166                 unit_table.attach(new LeftLabel("Active Enter Timestamp:"), 0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
167                 unit_table.attach(unit_active_enter_timestamp_label, 1, 2, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
168                 unit_table.attach(new LeftLabel("Active Exit Timestamp:"), 0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
169                 unit_table.attach(unit_active_exit_timestamp_label, 1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
170                 unit_table.attach(new LeftLabel("Can Start/Stop:"), 0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
171                 unit_table.attach(unit_can_start_label, 1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
172                 unit_table.attach(new LeftLabel("Can Reload:"), 0, 1, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
173                 unit_table.attach(unit_can_reload_label, 1, 2, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
174
175                 job_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
176                 job_table.attach(job_id_label, 1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
177                 job_table.attach(new LeftLabel("State:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
178                 job_table.attach(job_state_label, 1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
179                 job_table.attach(new LeftLabel("Type:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
180                 job_table.attach(job_type_label, 1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0);
181
182                 ButtonBox bbox = new HButtonBox();
183                 bbox.set_layout(ButtonBoxStyle.START);
184                 bbox.set_spacing(6);
185                 unit_vbox.pack_start(bbox, false, true, 0);
186
187                 start_button = new Button.with_mnemonic("_Start");
188                 stop_button = new Button.with_mnemonic("Sto_p");
189                 reload_button = new Button.with_mnemonic("_Reload");
190                 restart_button = new Button.with_mnemonic("Res_tart");
191
192                 start_button.clicked += on_start;
193                 stop_button.clicked += on_stop;
194                 reload_button.clicked += on_reload;
195                 restart_button.clicked += on_restart;
196
197                 bbox.pack_start(start_button, false, true, 0);
198                 bbox.pack_start(stop_button, false, true, 0);
199                 bbox.pack_start(restart_button, false, true, 0);
200                 bbox.pack_start(reload_button, false, true, 0);
201
202                 bbox = new HButtonBox();
203                 bbox.set_layout(ButtonBoxStyle.START);
204                 bbox.set_spacing(6);
205                 job_vbox.pack_start(bbox, false, true, 0);
206
207                 cancel_button = new Button.with_mnemonic("_Cancel");
208
209                 cancel_button.clicked += on_cancel;
210
211                 bbox.pack_start(cancel_button, false, true, 0);
212
213                 bus = Bus.get(BusType.SESSION);
214
215                 manager = bus.get_object(
216                                 "org.freedesktop.systemd1",
217                                 "/org/freedesktop/systemd1",
218                                 "org.freedesktop.systemd1") as Manager;
219
220                 manager.unit_new += on_unit_new;
221                 manager.job_new += on_job_new;
222                 manager.unit_removed += on_unit_removed;
223                 manager.job_removed += on_job_removed;
224
225                 manager.subscribe();
226
227                 clear_unit();
228                 populate_unit_model();
229                 populate_job_model();
230         }
231
232         public void populate_unit_model() throws DBus.Error {
233                 unit_model.clear();
234
235                 var list = manager.list_units();
236
237                 foreach (var i in list) {
238                         TreeIter iter;
239
240                         Unit u = bus.get_object(
241                                         "org.freedesktop.systemd1",
242                                         i.unit_path,
243                                         "org.freedesktop.systemd1.Unit") as Unit;
244
245                         unit_model.append(out iter);
246                         unit_model.set(iter,
247                                        0, i.id,
248                                        1, i.description,
249                                        2, i.load_state,
250                                        3, i.active_state,
251                                        4, i.job_type != "" ? "→ %s".printf(i.job_type) : "",
252                                        5, u);
253                 }
254         }
255
256         public void populate_job_model() throws DBus.Error {
257                 job_model.clear();
258
259                 var list = manager.list_jobs();
260
261                 foreach (var i in list) {
262                         TreeIter iter;
263
264                         Job j = bus.get_object(
265                                         "org.freedesktop.systemd1",
266                                         i.job_path,
267                                         "org.freedesktop.systemd1.Job") as Job;
268
269                         job_model.append(out iter);
270                         job_model.set(iter,
271                                       0, "%u".printf(i.id),
272                                       1, i.name,
273                                       2, "→ %s".printf(i.type),
274                                       3, i.state,
275                                       4, j);
276                 }
277         }
278
279         public Unit? get_current_unit() {
280                 TreePath p;
281                 unit_view.get_cursor(out p, null);
282
283                 if (p == null)
284                         return null;
285
286                 TreeIter iter;
287                 Unit u;
288
289                 unit_model.get_iter(out iter, p);
290                 unit_model.get(iter, 5, out u);
291
292                 return u;
293         }
294
295         public void unit_changed() {
296                 Unit u = get_current_unit();
297
298                 if (u == null)
299                         clear_unit();
300                 else
301                         show_unit(u);
302         }
303
304         public void clear_unit() {
305                 start_button.set_sensitive(false);
306                 stop_button.set_sensitive(false);
307                 reload_button.set_sensitive(false);
308                 restart_button.set_sensitive(false);
309
310                 unit_id_label.set_text_or_na();
311                 unit_description_label.set_text_or_na();
312                 unit_load_state_label.set_text_or_na();
313                 unit_active_state_label.set_text_or_na();
314                 unit_fragment_path_label.set_text_or_na();
315                 unit_active_enter_timestamp_label.set_text_or_na();
316                 unit_active_exit_timestamp_label.set_text_or_na();
317                 unit_can_reload_label.set_text_or_na();
318                 unit_can_start_label.set_text_or_na();
319         }
320
321         public void show_unit(Unit unit) {
322                 unit_id_label.set_text_or_na(unit.id);
323                 unit_description_label.set_text_or_na(unit.description);
324                 unit_load_state_label.set_text_or_na(unit.load_state);
325                 unit_active_state_label.set_text_or_na(unit.active_state);
326                 unit_fragment_path_label.set_text_or_na(unit.fragment_path);
327
328                 uint64 t = unit.active_enter_timestamp;
329                 if (t > 0) {
330                         TimeVal tv = { (long) (t / 1000000), (long) (t % 1000000) };
331                         unit_active_enter_timestamp_label.set_text_or_na(tv.to_iso8601());
332                 } else
333                         unit_active_enter_timestamp_label.set_text_or_na();
334
335                 t = unit.active_exit_timestamp;
336                 if (t > 0) {
337                         TimeVal tv = { (long) (t / 1000000), (long) (t % 1000000) };
338                         unit_active_exit_timestamp_label.set_text_or_na(tv.to_iso8601());
339                 } else
340                         unit_active_exit_timestamp_label.set_text_or_na();
341
342                 bool b = unit.can_start;
343                 start_button.set_sensitive(b);
344                 stop_button.set_sensitive(b);
345                 restart_button.set_sensitive(b);
346                 unit_can_start_label.set_text_or_na(b ? "Yes" : "No");
347
348                 b = unit.can_reload;
349                 reload_button.set_sensitive(b);
350                 unit_can_reload_label.set_text_or_na(b ? "Yes" : "No");
351         }
352
353         public Job? get_current_job() {
354                 TreePath p;
355                 job_view.get_cursor(out p, null);
356
357                 if (p == null)
358                         return null;
359
360                 TreeIter iter;
361                 Job *j;
362
363                 job_model.get_iter(out iter, p);
364                 job_model.get(iter, 4, out j);
365
366                 return j;
367         }
368
369         public void job_changed() {
370                 Job j = get_current_job();
371
372                 if (j == null)
373                         clear_job();
374                 else
375                         show_job(j);
376         }
377
378         public void clear_job() {
379                 job_id_label.set_text_or_na();
380                 job_state_label.set_text_or_na();
381                 job_type_label.set_text_or_na();
382         }
383
384         public void show_job(Job job) {
385                 job_id_label.set_text_or_na("%u".printf(job.id));
386                 job_state_label.set_text_or_na(job.state);
387                 job_type_label.set_text_or_na(job.job_type);
388         }
389
390         public void on_start() {
391                 Unit u = get_current_unit();
392
393                 if (u == null)
394                         return;
395
396                 try {
397                         u.start("replace");
398                 } catch (DBus.Error e) {
399                         message("%s", e.message);
400                 }
401         }
402
403         public void on_stop() {
404                 Unit u = get_current_unit();
405
406                 if (u == null)
407                         return;
408
409                 try {
410                         u.stop("replace");
411                 } catch (DBus.Error e) {
412                         message("%s", e.message);
413                 }
414         }
415
416         public void on_reload() {
417                 Unit u = get_current_unit();
418
419                 if (u == null)
420                         return;
421
422                 try {
423                         u.reload("replace");
424                 } catch (DBus.Error e) {
425                         message("%s", e.message);
426                 }
427         }
428
429         public void on_restart() {
430                 Unit u = get_current_unit();
431
432                 if (u == null)
433                         return;
434
435                 try {
436                         u.restart("replace");
437                 } catch (DBus.Error e) {
438                         message("%s", e.message);
439                 }
440         }
441
442         public void on_cancel() {
443                 Job j = get_current_job();
444
445                 if (j == null)
446                         return;
447
448                 try {
449                         j.cancel();
450                 } catch (DBus.Error e) {
451                         message("%s", e.message);
452                 }
453         }
454
455         public void on_unit_new(string id, ObjectPath path) {
456                 stderr.printf("new path %s", path);
457
458                 Unit u = bus.get_object(
459                                 "org.freedesktop.systemd1",
460                                 path,
461                                 "org.freedesktop.systemd1.Unit") as Unit;
462
463                 string t = "";
464                 Unit.JobLink jl = u.job;
465
466                 if (jl.id != 0) {
467                         Job j = bus.get_object(
468                                         "org.freedesktop.systemd1",
469                                         jl.path,
470                                         "org.freedesktop.systemd1.Job") as Job;
471
472                         t = j.job_type;
473                 }
474
475                 TreeIter iter;
476                 unit_model.append(out iter);
477                 unit_model.set(iter,
478                                0, u.id,
479                                1, u.description,
480                                2, u.load_state,
481                                3, u.active_state,
482                                4, t != "" ? "→ %s".printf(t) : "",
483                                5, u);
484         }
485
486         public void on_job_new(uint32 id, ObjectPath path) {
487                 stderr.printf("new path %s", path);
488
489                 Job j = bus.get_object(
490                                 "org.freedesktop.systemd1",
491                                 path,
492                                 "org.freedesktop.systemd1.Job") as Job;
493
494                 TreeIter iter;
495                 job_model.append(out iter);
496                 job_model.set(iter,
497                               0, "%u".printf(j.id),
498                               1, j.unit.id,
499                               2, "→ %s".printf(j.job_type),
500                               3, j.state,
501                               4, j);
502         }
503
504         public void on_unit_removed(string id, ObjectPath path) {
505                 stdout.printf("Unit %s removed.\n", id);
506
507                 /* FIXME */
508         }
509
510         public void on_job_removed(uint32 id, ObjectPath path) {
511                 stdout.printf("Job %u removed.\n", id);
512
513                 /* FIXME */
514         }
515 }
516
517 int main (string[] args) {
518         Gtk.init(ref args);
519
520         try {
521                 MainWindow window = new MainWindow();
522                 window.show_all();
523         } catch (DBus.Error e) {
524                 message("%s", e.message);
525         }
526
527         Gtk.main();
528         return 0;
529 }