1 #include <nm_core.h>
2 #include <nm_form.h>
3 #include <nm_utils.h>
4 #include <nm_string.h>
5 #include <nm_vector.h>
6 #include <nm_window.h>
7 #include <nm_menu.h>
8 #include <nm_machine.h>
9 #include <nm_hw_info.h>
10 #include <nm_network.h>
11 #include <nm_database.h>
12 #include <nm_cfg_file.h>
13 #include <nm_vm_control.h>
14 #include <nm_qmp_control.h>
15 #include <nm_edit_vm.h>
16 
17 static const char NM_LC_VM_FORM_CPU[]       = "CPU count";
18 static const char NM_LC_VM_FORM_MEM_BEGIN[] = "Memory [4-";
19 static const char NM_LC_VM_FORM_MEM_END[]   = "]Mb";
20 static const char NM_LC_VM_FORM_KVM[]       = "KVM [yes/no]";
21 static const char NM_LC_VM_FORM_HCPU[]      = "Host CPU [yes/no]";
22 static const char NM_LC_VM_FORM_NET_IFS[]   = "Network interfaces";
23 static const char NM_LC_VM_FORM_DRV_IF[]    = "Disk interface";
24 static const char NM_LC_VM_FORM_DRV_DIS[]   = "Discard mode";
25 static const char NM_LC_VM_FORM_USB[]       = "USB [yes/no]";
26 static const char NM_LC_VM_FORM_USBT[]      = "USB version";
27 static const char NM_LC_VM_FORM_MACH[]      = "Machine type";
28 static const char NM_LC_VM_FORM_ARGS[]      = "Extra QEMU args";
29 static const char NM_LC_VM_FORM_GROUP[]     = "Group";
30 
31 static void nm_edit_vm_init_windows(nm_form_t *form);
32 static void nm_edit_vm_fields_setup(const nm_vmctl_data_t *cur);
33 static size_t nm_edit_vm_labels_setup();
34 static int nm_edit_vm_get_data(nm_vm_t *vm, const nm_vmctl_data_t *cur);
35 static void nm_edit_vm_update_db(nm_vm_t *vm, const nm_vmctl_data_t *cur, uint64_t mac);
36 
37 enum {
38     NM_LBL_CPUNUM = 0, NM_FLD_CPUNUM,
39     NM_LBL_RAMTOT, NM_FLD_RAMTOT,
40     NM_LBL_KVMFLG, NM_FLD_KVMFLG,
41     NM_LBL_HOSCPU, NM_FLD_HOSCPU,
42     NM_LBL_IFSCNT, NM_FLD_IFSCNT,
43     NM_LBL_DISKIN, NM_FLD_DISKIN,
44     NM_LBL_DISCARD, NM_FLD_DISCARD,
45     NM_LBL_USBUSE, NM_FLD_USBUSE,
46     NM_LBL_USBTYP, NM_FLD_USBTYP,
47     NM_LBL_MACH, NM_FLD_MACH,
48     NM_LBL_ARGS, NM_FLD_ARGS,
49     NM_LBL_GROUP, NM_FLD_GROUP,
50     NM_FLD_COUNT
51 };
52 
53 static nm_field_t *fields[NM_FLD_COUNT + 1];
54 
nm_edit_vm_init_windows(nm_form_t * form)55 static void nm_edit_vm_init_windows(nm_form_t *form)
56 {
57     if (form) {
58         nm_form_window_init();
59         nm_form_data_t *form_data = (nm_form_data_t *)form_userptr(form);
60         if (form_data)
61             form_data->parent_window = action_window;
62     } else {
63         werase(action_window);
64         werase(help_window);
65     }
66 
67     nm_init_side();
68     nm_init_action(_(NM_MSG_EDIT_VM));
69     nm_init_help_edit();
70 
71     nm_print_vm_menu(NULL);
72 }
73 
nm_edit_vm(const nm_str_t * name)74 void nm_edit_vm(const nm_str_t *name)
75 {
76     nm_form_data_t *form_data = NULL;
77     nm_form_t *form = NULL;
78     nm_vm_t vm = NM_INIT_VM;
79     nm_vmctl_data_t cur_settings = NM_VMCTL_INIT_DATA;
80     uint64_t last_mac;
81     size_t msg_len;
82 
83     nm_edit_vm_init_windows(NULL);
84 
85     nm_vmctl_get_data(name, &cur_settings);
86 
87     msg_len = nm_edit_vm_labels_setup();
88 
89     form_data = nm_form_data_new(
90         action_window, nm_edit_vm_init_windows, msg_len, NM_FLD_COUNT / 2, NM_TRUE);
91 
92     if (nm_form_data_update(form_data, 0, 0) != NM_OK)
93         goto out;
94 
95     for (size_t n = 0; n < NM_FLD_COUNT; n++) {
96         switch (n) {
97             case NM_FLD_CPUNUM:
98                 fields[n] = nm_field_regexp_new(
99                     n / 2, form_data, "^[0-9]{1}(:[0-9]{1})?(:[0-9]{1})? *$");
100                 break;
101             case NM_FLD_RAMTOT:
102                 fields[n] = nm_field_integer_new(
103                     n / 2, form_data, 0, 4, nm_hw_total_ram());
104                 break;
105             case NM_FLD_KVMFLG:
106                 fields[n] = nm_field_enum_new(
107                     n / 2, form_data, nm_form_yes_no, false, false);
108                 break;
109             case NM_FLD_HOSCPU:
110                 fields[n] = nm_field_enum_new(
111                     n / 2, form_data, nm_form_yes_no, false, false);
112                 break;
113             case NM_FLD_IFSCNT:
114                 fields[n] = nm_field_integer_new(n / 2, form_data, 1, 0, 64);
115                 break;
116             case NM_FLD_DISKIN:
117                 fields[n] = nm_field_enum_new(
118                     n / 2, form_data, nm_form_drive_drv, false, false);
119                 break;
120             case NM_FLD_DISCARD:
121                 fields[n] = nm_field_enum_new(
122                     n / 2, form_data, nm_form_yes_no, false, false);
123                 break;
124             case NM_FLD_USBUSE:
125                 fields[n] = nm_field_enum_new(
126                     n / 2, form_data, nm_form_yes_no, false, false);
127                 break;
128             case NM_FLD_USBTYP:
129                 fields[n] = nm_field_enum_new(
130                     n / 2, form_data, nm_form_usbtype, false, false);
131                 break;
132             case NM_FLD_MACH:
133                 fields[n] = nm_field_enum_new(
134                     n / 2, form_data,
135                     nm_mach_get(nm_vect_str(&cur_settings.main, NM_SQL_ARCH)),
136                     false, false
137                 );
138                 break;
139             case NM_FLD_ARGS:
140                 fields[n] = nm_field_default_new(n / 2, form_data);
141                 break;
142             case NM_FLD_GROUP:
143                 fields[n] = nm_field_default_new(n / 2, form_data);
144                 break;
145             default:
146                 fields[n] = nm_field_label_new(n / 2, form_data);
147                 break;
148         }
149     }
150     fields[NM_FLD_COUNT] = NULL;
151 
152     nm_edit_vm_labels_setup();
153     nm_edit_vm_fields_setup(&cur_settings);
154     nm_fields_unset_status(fields);
155 
156     form = nm_form_new(form_data, fields);
157     nm_form_post(form);
158 
159     if (nm_form_draw(&form) != NM_OK)
160         goto out;
161 
162     last_mac = nm_form_get_last_mac();
163 
164     if (nm_edit_vm_get_data(&vm, &cur_settings) != NM_OK)
165         goto out;
166 
167     nm_edit_vm_update_db(&vm, &cur_settings, last_mac);
168 
169 out:
170     NM_FORM_EXIT();
171     nm_vm_free(&vm);
172     nm_form_free(form);
173     nm_form_data_free(form_data);
174     nm_fields_free(fields);
175     nm_vmctl_free_data(&cur_settings);
176 }
177 
nm_edit_vm_fields_setup(const nm_vmctl_data_t * cur)178 static void nm_edit_vm_fields_setup(const nm_vmctl_data_t *cur)
179 {
180     nm_str_t buf = NM_INIT_STR;
181 
182     field_opts_off(fields[NM_FLD_ARGS], O_STATIC);
183 
184     set_field_buffer(fields[NM_FLD_CPUNUM], 0, nm_vect_str_ctx(&cur->main, NM_SQL_SMP));
185     set_field_buffer(fields[NM_FLD_RAMTOT], 0, nm_vect_str_ctx(&cur->main, NM_SQL_MEM));
186 
187     if (nm_str_cmp_st(nm_vect_str(&cur->main, NM_SQL_KVM), NM_ENABLE) == NM_OK)
188         set_field_buffer(fields[NM_FLD_KVMFLG], 0, nm_form_yes_no[0]);
189     else
190         set_field_buffer(fields[NM_FLD_KVMFLG], 0, nm_form_yes_no[1]);
191 
192     if (nm_str_cmp_st(nm_vect_str(&cur->main, NM_SQL_HCPU), NM_ENABLE) == NM_OK)
193         set_field_buffer(fields[NM_FLD_HOSCPU], 0, nm_form_yes_no[0]);
194     else
195         set_field_buffer(fields[NM_FLD_HOSCPU], 0, nm_form_yes_no[1]);
196 
197     nm_str_format(&buf, "%zu", cur->ifs.n_memb / NM_IFS_IDX_COUNT);
198     set_field_buffer(fields[NM_FLD_IFSCNT], 0, buf.data);
199     set_field_buffer(fields[NM_FLD_DISKIN], 0, nm_vect_str_ctx(&cur->drives, NM_SQL_DRV_TYPE));
200     if (nm_str_cmp_st(nm_vect_str(&cur->drives, NM_SQL_DRV_DISC), NM_ENABLE) == NM_OK)
201         set_field_buffer(fields[NM_FLD_DISCARD], 0, nm_form_yes_no[0]);
202     else
203         set_field_buffer(fields[NM_FLD_DISCARD], 0, nm_form_yes_no[1]);
204 
205     if (nm_str_cmp_st(nm_vect_str(&cur->main, NM_SQL_USBF), NM_ENABLE) == NM_OK)
206         set_field_buffer(fields[NM_FLD_USBUSE], 0, nm_form_yes_no[0]);
207     else
208         set_field_buffer(fields[NM_FLD_USBUSE], 0, nm_form_yes_no[1]);
209 
210     set_field_buffer(fields[NM_FLD_USBTYP], 0, nm_vect_str_ctx(&cur->main, NM_SQL_USBT));
211     set_field_buffer(fields[NM_FLD_MACH], 0, nm_vect_str_ctx(&cur->main, NM_SQL_MACH));
212     set_field_buffer(fields[NM_FLD_ARGS], 0, nm_vect_str_ctx(&cur->main, NM_SQL_ARGS));
213     set_field_buffer(fields[NM_FLD_GROUP], 0, nm_vect_str_ctx(&cur->main, NM_SQL_GROUP));
214 
215 #if defined (NM_OS_FREEBSD)
216     field_opts_off(fields[NM_FLD_USBUSE], O_ACTIVE);
217 #endif
218 
219     nm_str_free(&buf);
220 }
221 
nm_edit_vm_labels_setup()222 static size_t nm_edit_vm_labels_setup()
223 {
224     nm_str_t buf = NM_INIT_STR;
225     size_t max_label_len = 0;
226     size_t msg_len = 0;
227 
228     for (size_t n = 0; n < NM_FLD_COUNT; n++) {
229         switch (n) {
230         case NM_LBL_CPUNUM:
231             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_CPU));
232             break;
233         case NM_LBL_RAMTOT:
234             nm_str_format(&buf, "%s%u%s",
235                 _(NM_LC_VM_FORM_MEM_BEGIN), nm_hw_total_ram(), _(NM_LC_VM_FORM_MEM_END));
236             break;
237         case NM_LBL_KVMFLG:
238             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_KVM));
239             break;
240         case NM_LBL_HOSCPU:
241             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_HCPU));
242             break;
243         case NM_LBL_IFSCNT:
244             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_NET_IFS));
245             break;
246         case NM_LBL_DISKIN:
247             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_DRV_IF));
248             break;
249         case NM_LBL_DISCARD:
250             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_DRV_DIS));
251             break;
252         case NM_LBL_USBUSE:
253             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_USB));
254             break;
255         case NM_LBL_USBTYP:
256             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_USBT));
257             break;
258         case NM_LBL_MACH:
259             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_MACH));
260             break;
261         case NM_LBL_ARGS:
262             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_ARGS));
263             break;
264         case NM_LBL_GROUP:
265             nm_str_format(&buf, "%s", _(NM_LC_VM_FORM_GROUP));
266             break;
267         default:
268             continue;
269         }
270 
271         msg_len = mbstowcs(NULL, buf.data, buf.len);
272         if (msg_len > max_label_len)
273             max_label_len = msg_len;
274 
275         if (fields[n])
276             set_field_buffer(fields[n], 0, buf.data);
277     }
278 
279     nm_str_free(&buf);
280     return max_label_len;
281 }
282 
nm_edit_vm_get_data(nm_vm_t * vm,const nm_vmctl_data_t * cur)283 static int nm_edit_vm_get_data(nm_vm_t *vm, const nm_vmctl_data_t *cur)
284 {
285     int rc;
286     nm_vect_t err = NM_INIT_VECT;
287 
288     nm_str_t ifs = NM_INIT_STR;
289     nm_str_t usb = NM_INIT_STR;
290     nm_str_t kvm = NM_INIT_STR;
291     nm_str_t hcpu = NM_INIT_STR;
292     nm_str_t discard = NM_INIT_STR;
293 
294     nm_get_field_buf(fields[NM_FLD_CPUNUM], &vm->cpus);
295     nm_get_field_buf(fields[NM_FLD_RAMTOT], &vm->memo);
296     nm_get_field_buf(fields[NM_FLD_KVMFLG], &kvm);
297     nm_get_field_buf(fields[NM_FLD_HOSCPU], &hcpu);
298     nm_get_field_buf(fields[NM_FLD_IFSCNT], &ifs);
299     nm_get_field_buf(fields[NM_FLD_DISKIN], &vm->drive.driver);
300     nm_get_field_buf(fields[NM_FLD_DISCARD], &discard);
301     nm_get_field_buf(fields[NM_FLD_USBUSE], &usb);
302     nm_get_field_buf(fields[NM_FLD_USBTYP], &vm->usb_type);
303     nm_get_field_buf(fields[NM_FLD_MACH], &vm->mach);
304     nm_get_field_buf(fields[NM_FLD_ARGS], &vm->cmdappend);
305     nm_get_field_buf(fields[NM_FLD_GROUP], &vm->group);
306 
307     if (field_status(fields[NM_FLD_CPUNUM]))
308         nm_form_check_data(_("CPU cores"), vm->cpus, err);
309     if (field_status(fields[NM_FLD_RAMTOT]))
310         nm_form_check_data(_("Memory"), vm->memo, err);
311     if (field_status(fields[NM_FLD_KVMFLG]))
312         nm_form_check_data(_("KVM"), kvm, err);
313     if (field_status(fields[NM_FLD_HOSCPU]))
314         nm_form_check_data(_("Host CPU"), kvm, err);
315     if (field_status(fields[NM_FLD_IFSCNT]))
316         nm_form_check_data(_("Network interfaces"), ifs, err);
317     if (field_status(fields[NM_FLD_DISKIN]))
318         nm_form_check_data(_("Disk interface"), vm->drive.driver, err);
319     if (field_status(fields[NM_FLD_DISCARD]))
320         nm_form_check_data(_("Discard mode"), discard, err);
321     if (field_status(fields[NM_FLD_USBUSE]))
322         nm_form_check_data(_("USB"), usb, err);
323     if (field_status(fields[NM_FLD_USBTYP]))
324         nm_form_check_data(_("USB version"), vm->usb_type, err);
325 
326     if ((rc = nm_print_empty_fields(&err)) == NM_ERR)
327         goto out;
328 
329     if (field_status(fields[NM_FLD_KVMFLG])) {
330         if (nm_str_cmp_st(&kvm, "yes") == NM_OK) {
331             vm->kvm.enable = 1;
332         } else {
333             if (!field_status(fields[NM_FLD_HOSCPU]) &&
334                     (nm_str_cmp_st(nm_vect_str(&cur->main, NM_SQL_HCPU), NM_ENABLE) == NM_OK)) {
335                 rc = NM_ERR;
336                 NM_FORM_RESET();
337                 nm_warn(_(NM_MSG_HCPU_KVM));
338                 goto out;
339             }
340         }
341     }
342 
343     if (field_status(fields[NM_FLD_DISCARD])) {
344         if (nm_str_cmp_st(&discard, "yes") == NM_OK) {
345             vm->drive.discard = 1;
346         }
347     }
348 
349     if (field_status(fields[NM_FLD_HOSCPU])) {
350         if (nm_str_cmp_st(&hcpu, "yes") == NM_OK) {
351             if (((!vm->kvm.enable) && (field_status(fields[NM_FLD_KVMFLG]))) ||
352                     ((nm_str_cmp_st(nm_vect_str(&cur->main, NM_SQL_KVM), NM_DISABLE) == NM_OK) &&
353                      !field_status(fields[NM_FLD_KVMFLG]))) {
354                 rc = NM_ERR;
355                 NM_FORM_RESET();
356                 nm_warn(_(NM_MSG_HCPU_KVM));
357                 goto out;
358             }
359             vm->kvm.hostcpu_enable = 1;
360         }
361     }
362 
363     if (field_status(fields[NM_FLD_IFSCNT]))
364         vm->ifs.count = nm_str_stoui(&ifs, 10);
365 
366     if (field_status(fields[NM_FLD_USBUSE])) {
367         if (nm_str_cmp_st(&usb, "yes") == NM_OK)
368             vm->usb_enable = 1;
369     }
370 
371 out:
372     nm_str_free(&ifs);
373     nm_str_free(&usb);
374     nm_str_free(&kvm);
375     nm_str_free(&hcpu);
376     nm_str_free(&discard);
377     nm_vect_free(&err, NULL);
378 
379     return rc;
380 }
381 
nm_edit_vm_update_db(nm_vm_t * vm,const nm_vmctl_data_t * cur,uint64_t mac)382 static void nm_edit_vm_update_db(nm_vm_t *vm, const nm_vmctl_data_t *cur, uint64_t mac)
383 {
384     nm_str_t query = NM_INIT_STR;
385 
386     if (field_status(fields[NM_FLD_CPUNUM])) {
387         nm_str_format(&query, "UPDATE vms SET smp='%s' WHERE name='%s'",
388             vm->cpus.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
389         nm_db_edit(query.data);
390     }
391 
392     if (field_status(fields[NM_FLD_RAMTOT])) {
393         nm_str_format(&query, "UPDATE vms SET mem='%s' WHERE name='%s'",
394             vm->memo.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
395         nm_db_edit(query.data);
396     }
397 
398     if (field_status(fields[NM_FLD_KVMFLG])) {
399         nm_str_format(&query, "UPDATE vms SET kvm='%s' WHERE name='%s'",
400             vm->kvm.enable ? NM_ENABLE : NM_DISABLE,
401             nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
402         nm_db_edit(query.data);
403     }
404 
405     if (field_status(fields[NM_FLD_HOSCPU])) {
406         nm_str_format(&query, "UPDATE vms SET hcpu='%s' WHERE name='%s'",
407             vm->kvm.hostcpu_enable ? NM_ENABLE : NM_DISABLE,
408             nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
409         nm_db_edit(query.data);
410     }
411 
412     if (field_status(fields[NM_FLD_IFSCNT])) {
413         size_t cur_count = cur->ifs.n_memb / NM_IFS_IDX_COUNT;
414 
415         if (vm->ifs.count < cur_count) {
416             for (; cur_count > vm->ifs.count; cur_count--) {
417                 size_t idx_shift = NM_IFS_IDX_COUNT * (cur_count - 1);
418 
419                 nm_str_format(&query, NM_DEL_IFACE_SQL,
420                     nm_vect_str_ctx(&cur->main, NM_SQL_NAME),
421                     nm_vect_str_ctx(&cur->ifs, NM_SQL_IF_NAME + idx_shift));
422                 nm_db_edit(query.data);
423             }
424         }
425 
426         if (vm->ifs.count > cur_count) {
427             for (size_t n = cur_count; n < vm->ifs.count; n++) {
428                 int altname;
429                 nm_str_t if_name = NM_INIT_STR;
430                 nm_str_t if_name_copy = NM_INIT_STR;
431                 nm_str_t maddr = NM_INIT_STR;
432                 mac++;
433 
434                 nm_net_mac_n2s(mac, &maddr);
435                 nm_str_format(&if_name, "%s_eth%zu",
436                     nm_vect_str_ctx(&cur->main, NM_SQL_NAME), n);
437                 nm_str_copy(&if_name_copy, &if_name);
438 
439                 altname = nm_net_fix_tap_name(&if_name, &maddr);
440 
441                 nm_str_format(&query,
442                     "INSERT INTO ifaces(vm_name, if_name, mac_addr, if_drv, vhost, macvtap, altname) "
443                     "VALUES('%s', '%s', '%s', '%s', '%s', '%s', '%s')",
444                     nm_vect_str_ctx(&cur->main, NM_SQL_NAME),
445                     if_name.data,
446                     maddr.data,
447                     NM_DEFAULT_NETDRV,
448 #if defined (NM_OS_LINUX)
449                     NM_ENABLE,
450 #else
451                     NM_DISABLE,
452 #endif
453                     NM_DISABLE,
454                     (altname) ? if_name_copy.data : "");
455                 nm_db_edit(query.data);
456 
457                 nm_str_free(&if_name);
458                 nm_str_free(&if_name_copy);
459                 nm_str_free(&maddr);
460             }
461         }
462     }
463 
464     if (field_status(fields[NM_FLD_DISKIN])) {
465         nm_str_format(&query, "UPDATE drives SET drive_drv='%s' WHERE vm_name='%s'",
466             vm->drive.driver.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
467         nm_db_edit(query.data);
468     }
469 
470     if (field_status(fields[NM_FLD_DISCARD])) {
471         nm_str_format(&query, "UPDATE drives SET discard='%s' WHERE vm_name='%s'",
472             vm->drive.discard ? NM_ENABLE : NM_DISABLE,
473             nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
474         nm_db_edit(query.data);
475     }
476 
477     if (field_status(fields[NM_FLD_USBUSE])) {
478         nm_str_format(&query, "UPDATE vms SET usb='%s' WHERE name='%s'",
479             vm->usb_enable ? NM_ENABLE : NM_DISABLE,
480             nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
481         nm_db_edit(query.data);
482     }
483 
484     if (field_status(fields[NM_FLD_USBTYP])) {
485         nm_str_format(&query, "UPDATE vms SET usb_type='%s' WHERE name='%s'",
486             vm->usb_type.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
487         nm_db_edit(query.data);
488     }
489 
490     if (field_status(fields[NM_FLD_MACH])) {
491         nm_str_format(&query, "UPDATE vms SET machine='%s' WHERE name='%s'",
492             vm->mach.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
493         nm_db_edit(query.data);
494     }
495 
496     if (field_status(fields[NM_FLD_ARGS])) {
497         nm_str_format(&query, "UPDATE vms SET cmdappend='%s' WHERE name='%s'",
498             vm->cmdappend.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
499         nm_db_edit(query.data);
500     }
501 
502     if (field_status(fields[NM_FLD_GROUP])) {
503         nm_str_format(&query, "UPDATE vms SET team='%s' WHERE name='%s'",
504             vm->group.data, nm_vect_str_ctx(&cur->main, NM_SQL_NAME));
505         nm_db_edit(query.data);
506         if (nm_filter.type == NM_FILTER_GROUP) {
507             nm_filter.flags |= NM_FILTER_UPDATE;
508         }
509     }
510 
511     nm_str_free(&query);
512 }
513 
514 /* vim:set ts=4 sw=4: */
515