1 #include <nm_core.h>
2 #include <nm_form.h>
3 #include <nm_utils.h>
4 #include <nm_string.h>
5 #include <nm_window.h>
6 #include <nm_menu.h>
7 #include <nm_vector.h>
8 #include <nm_database.h>
9 #include <nm_usb_devices.h>
10 #include <nm_qmp_control.h>
11 #include <nm_usb_plug.h>
12 
13 static const char NM_LC_USB_FORM_MSG[] = "Device";
14 
15 static void nm_usb_attach_init_windows(nm_form_t *form);
16 static void nm_usb_detach_init_windows(nm_form_t *form);
17 static void nm_usb_plug_list(nm_vect_t *devs, nm_vect_t *names);
18 static int nm_usb_plug_get_data(const nm_str_t *name, nm_usb_data_t *usb,
19         const nm_vect_t *usb_list);
20 static int nm_usb_unplug_get_data(nm_usb_data_t *usb, const nm_vect_t *db_list);
21 static void nm_usb_plug_update_db(const nm_str_t *name, const nm_usb_data_t *usb);
22 
23 enum {
24     NM_LBL_USB_DEV = 0, NM_FLD_USB_DEV,
25     NM_FLD_COUNT
26 };
27 
28 static nm_field_t *fields[NM_FLD_COUNT + 1];
29 
nm_usb_attach_init_windows(nm_form_t * form)30 static void nm_usb_attach_init_windows(nm_form_t *form)
31 {
32     if (form) {
33         nm_form_window_init();
34         nm_form_data_t *form_data = (nm_form_data_t *)form_userptr(form);
35         if (form_data)
36             form_data->parent_window = action_window;
37     } else {
38         werase(action_window);
39         werase(help_window);
40     }
41 
42     nm_init_side();
43     nm_init_action(_(NM_MSG_USB_ATTACH));
44     nm_init_help_edit();
45 
46     nm_print_vm_menu(NULL);
47 }
48 
nm_usb_detach_init_windows(nm_form_t * form)49 static void nm_usb_detach_init_windows(nm_form_t *form)
50 {
51     if (form) {
52         nm_form_window_init();
53         nm_form_data_t *form_data = (nm_form_data_t *)form_userptr(form);
54         if (form_data)
55             form_data->parent_window = action_window;
56     } else {
57         werase(action_window);
58         werase(help_window);
59     }
60 
61     nm_init_side();
62     nm_init_action(_(NM_MSG_USB_DETACH));
63     nm_init_help_edit();
64 
65     nm_print_vm_menu(NULL);
66 }
67 
nm_usb_plug(const nm_str_t * name,int vm_status)68 void nm_usb_plug(const nm_str_t *name, int vm_status)
69 {
70     nm_form_data_t *form_data = NULL;
71     nm_form_t *form = NULL;
72     nm_str_t buf = NM_INIT_STR;
73     nm_vect_t usb_devs = NM_INIT_VECT;
74     nm_vect_t usb_names = NM_INIT_VECT;
75     nm_vect_t db_result = NM_INIT_VECT;
76     nm_usb_data_t usb = NM_INIT_USB_DATA;
77     size_t msg_len = mbstowcs(NULL, _(NM_LC_USB_FORM_MSG), strlen(_(NM_LC_USB_FORM_MSG)));
78 
79     /* check for usb enabled first */
80     nm_str_format(&buf, NM_USB_CHECK_SQL, name->data);
81     nm_db_select(buf.data, &db_result);
82 
83     if (vm_status && nm_str_cmp_st(nm_vect_str(&db_result, 0), NM_DISABLE) == NM_OK) {
84         nm_warn(_(NM_MSG_USB_DIS));
85         goto out;
86     }
87 
88     nm_usb_plug_list(&usb_devs, &usb_names);
89 
90     if (usb_names.n_memb == 0) {
91         nm_warn(_(NM_MSG_USB_MISS));
92         goto out;
93     }
94 
95     nm_usb_attach_init_windows(NULL);
96 
97     form_data = nm_form_data_new(
98         action_window, nm_usb_attach_init_windows, msg_len, NM_FLD_COUNT / 2, NM_TRUE);
99 
100     if (nm_form_data_update(form_data, 0, 0) != NM_OK)
101         goto out;
102 
103     fields[0] = nm_field_label_new(0, form_data);
104     fields[1] = nm_field_enum_new(0, form_data,
105         (const char **)usb_names.data, false, false);
106     fields[2] = NULL;
107 
108     set_field_buffer(fields[0], 0, _(NM_LC_USB_FORM_MSG));
109     field_opts_off(fields[1], O_STATIC);
110     set_field_buffer(fields[1], 0, *usb_names.data);
111     nm_fields_unset_status(fields);
112 
113     form = nm_form_new(form_data, fields);
114     nm_form_post(form);
115 
116     if (nm_form_draw(&form) != NM_OK)
117         goto out;
118 
119     if ((nm_usb_plug_get_data(name, &usb, &usb_devs)) != NM_OK)
120         goto out;
121 
122     if (vm_status)
123         if (nm_qmp_usb_attach(name, &usb) != NM_OK)
124             goto out;
125 
126     nm_usb_plug_update_db(name, &usb);
127 
128 out:
129     NM_FORM_EXIT();
130     nm_form_free(form);
131     nm_form_data_free(form_data);
132     nm_fields_free(fields);
133     nm_vect_free(&usb_names, NULL);
134     nm_vect_free(&usb_devs, nm_usb_vect_free_cb);
135     nm_vect_free(&db_result, nm_str_vect_free_cb);
136     nm_str_free(&buf);
137     nm_str_free(&usb.serial);
138 }
139 
nm_usb_unplug(const nm_str_t * name,int vm_status)140 void nm_usb_unplug(const nm_str_t *name, int vm_status)
141 {
142     nm_form_data_t *form_data = NULL;
143     nm_form_t *form = NULL;
144     nm_str_t buf = NM_INIT_STR;
145     nm_usb_data_t usb_data = NM_INIT_USB_DATA;
146     nm_usb_dev_t usb_dev = NM_INIT_USB;
147     nm_vect_t usb_names = NM_INIT_VECT;
148     nm_vect_t db_result = NM_INIT_VECT;
149     size_t msg_len = mbstowcs(NULL, _(NM_LC_USB_FORM_MSG), strlen(_(NM_LC_USB_FORM_MSG)));
150 
151     usb_data.dev = &usb_dev;
152 
153     nm_str_format(&buf, NM_USB_GET_SQL, name->data);
154     nm_db_select(buf.data, &db_result);
155 
156     if (!db_result.n_memb) {
157         nm_warn(_(NM_MSG_USB_NONE));
158         goto out;
159     }
160 
161     nm_usb_unplug_list(&db_result, &usb_names, true);
162 
163     nm_usb_detach_init_windows(NULL);
164 
165     form_data = nm_form_data_new(
166         action_window, nm_usb_detach_init_windows, msg_len, NM_FLD_COUNT / 2, NM_TRUE);
167 
168     if (nm_form_data_update(form_data, 0, 0) != NM_OK)
169         goto out;
170 
171     fields[0] = nm_field_label_new(0, form_data);
172     fields[1] = nm_field_enum_new(0, form_data,
173         (const char **)usb_names.data, false, false);
174     fields[2] = NULL;
175 
176     set_field_buffer(fields[0], 0, _(NM_LC_USB_FORM_MSG));
177     field_opts_off(fields[1], O_STATIC);
178     set_field_buffer(fields[1], 0, *usb_names.data);
179     nm_fields_unset_status(fields);
180 
181     form = nm_form_new(form_data, fields);
182     nm_form_post(form);
183 
184     if (nm_form_draw(&form) != NM_OK)
185         goto out;
186 
187     if (nm_usb_unplug_get_data(&usb_data, &db_result) != NM_OK)
188         goto out;
189 
190     if (vm_status)
191         (void) nm_qmp_usb_detach(name, &usb_data);
192 
193     nm_str_format(&buf, NM_USB_DELETE_SQL,
194             name->data,
195             usb_dev.name.data,
196             usb_dev.vendor_id.data,
197             usb_dev.product_id.data,
198             usb_data.serial.data);
199     nm_db_edit(buf.data);
200 
201 out:
202     NM_FORM_EXIT();
203     nm_form_free(form);
204     nm_form_data_free(form_data);
205     nm_fields_free(fields);
206     nm_vect_free(&usb_names, NULL);
207     nm_vect_free(&db_result, nm_str_vect_free_cb);
208     nm_usb_data_free(&usb_data);
209     nm_str_free(&buf);
210 }
211 
nm_usb_check_plugged(const nm_str_t * name)212 int nm_usb_check_plugged(const nm_str_t *name)
213 {
214     int rc = NM_ERR;
215     nm_vect_t db_result = NM_INIT_VECT;
216     nm_str_t query = NM_INIT_STR;
217 
218     nm_str_format(&query, NM_USB_GET_SQL, name->data);
219     nm_db_select(query.data, &db_result);
220 
221     if (!db_result.n_memb) {
222         rc = NM_OK;
223     }
224 
225     nm_vect_free(&db_result, nm_str_vect_free_cb);
226     nm_str_free(&query);
227 
228     return rc;
229 }
230 
nm_usb_unplug_list(const nm_vect_t * db_list,nm_vect_t * names,bool num)231 void nm_usb_unplug_list(const nm_vect_t *db_list, nm_vect_t *names, bool num)
232 {
233     size_t dev_count = db_list->n_memb / NM_USB_IDX_COUNT;
234     nm_str_t buf = NM_INIT_STR;
235 
236     for (size_t n = 0; n < dev_count; n++) {
237         size_t idx_shift = NM_USB_IDX_COUNT * n;
238 
239         if (num) {
240             nm_str_format(&buf, "%zu:%s [serial:%s]", n + 1,
241                     nm_vect_str_ctx(db_list, NM_SQL_USB_NAME + idx_shift),
242                     nm_vect_str_ctx(db_list, NM_SQL_USB_SERIAL + idx_shift));
243         } else {
244             nm_str_format(&buf, "%s [serial:%s]",
245                     nm_vect_str_ctx(db_list, NM_SQL_USB_NAME + idx_shift),
246                     nm_vect_str_ctx(db_list, NM_SQL_USB_SERIAL + idx_shift));
247         }
248         nm_vect_insert(names, buf.data, buf.len + 1, NULL);
249     }
250 
251     nm_str_free(&buf);
252 }
253 
nm_usb_plug_list(nm_vect_t * devs,nm_vect_t * names)254 static void nm_usb_plug_list(nm_vect_t *devs, nm_vect_t *names)
255 {
256     nm_usb_get_devs(devs);
257     nm_str_t dev_name = NM_INIT_STR;
258 
259     for (size_t n = 0; n < devs->n_memb; n++) {
260         nm_str_format(&dev_name, "%zu:%s", n + 1, nm_usb_name(devs->data[n])->data);
261         nm_vect_insert(names, dev_name.data, dev_name.len + 1, NULL);
262 
263         nm_debug("usb >> %03u:%03u %s:%s %s\n",
264                 *nm_usb_bus_num(devs->data[n]),
265                 *nm_usb_dev_addr(devs->data[n]),
266                 nm_usb_vendor_id(devs->data[n])->data,
267                 nm_usb_product_id(devs->data[n])->data,
268                 nm_usb_name(devs->data[n])->data);
269     }
270 
271     nm_vect_end_zero(names);
272     nm_str_free(&dev_name);
273 }
274 
nm_usb_plug_get_data(const nm_str_t * name,nm_usb_data_t * usb,const nm_vect_t * usb_list)275 static int nm_usb_plug_get_data(const nm_str_t *name, nm_usb_data_t *usb,
276         const nm_vect_t *usb_list)
277 {
278     int rc = NM_ERR;
279     nm_str_t buf = NM_INIT_STR;
280     nm_str_t input = NM_INIT_STR;
281     nm_vect_t db_list = NM_INIT_VECT;
282     uint32_t idx;
283     char *fo;
284 
285     nm_get_field_buf(fields[1], &input);
286     if (!input.len) {
287         nm_warn(_(NM_MSG_USB_EMPTY));
288         goto out;
289     }
290 
291     nm_str_copy(&buf, &input);
292     if ((fo = strchr(buf.data, ':')) == NULL) {
293         /* Reinsurance, "fo" will always be OK */
294         nm_warn(_(NM_MSG_USB_EDATA));
295         goto out;
296     }
297 
298     nm_str_trunc(&input, 0);
299     nm_str_add_text(&input, fo + 1);
300 
301     *fo = '\0';
302     idx = nm_str_stoui(&buf, 10);
303     usb->dev = usb_list->data[idx - 1];
304 
305     nm_usb_get_serial(usb->dev, &usb->serial);
306 
307     nm_str_format(&buf, NM_USB_EXISTS_SQL,
308             name->data,
309             usb->dev->name.data,
310             usb->dev->vendor_id.data,
311             usb->dev->product_id.data,
312             (usb->serial.data) ? usb->serial.data : "NULL");
313 
314     nm_db_select(buf.data, &db_list);
315 
316     if (db_list.n_memb) {
317         nm_warn(_(NM_MSG_USB_ATTAC));
318         goto out;
319     }
320 
321     rc = NM_OK;
322 out:
323     nm_str_free(&buf);
324     nm_str_free(&input);
325     nm_vect_free(&db_list, nm_str_vect_free_cb);
326 
327     return rc;
328 }
329 
nm_usb_unplug_get_data(nm_usb_data_t * usb,const nm_vect_t * db_list)330 static int nm_usb_unplug_get_data(nm_usb_data_t *usb, const nm_vect_t *db_list)
331 {
332     int rc = NM_ERR;
333     nm_str_t buf = NM_INIT_STR;
334     nm_str_t input = NM_INIT_STR;
335     uint32_t idx, idx_shift;
336     char *fo;
337 
338     nm_get_field_buf(fields[1], &input);
339     if (!input.len) {
340         nm_warn(_(NM_MSG_USB_EMPTY));
341         goto out;
342     }
343 
344     nm_str_copy(&buf, &input);
345     if ((fo = strchr(buf.data, ':')) == NULL) {
346         /* Reinsurance, "fo" will always be OK */
347         nm_warn(_(NM_MSG_USB_EDATA));
348         goto out;
349     }
350 
351     *fo = '\0';
352     idx = nm_str_stoui(&buf, 10);
353     idx_shift = --idx * NM_USB_IDX_COUNT;
354     nm_debug("s:%s, idx=%u\n", buf.data, idx);
355 
356     nm_str_copy(&usb->dev->name,
357             nm_vect_str(db_list, NM_SQL_USB_NAME + idx_shift));
358     nm_str_copy(&usb->dev->vendor_id,
359             nm_vect_str(db_list, NM_SQL_USB_VID + idx_shift));
360     nm_str_copy(&usb->dev->product_id,
361             nm_vect_str(db_list, NM_SQL_USB_PID + idx_shift));
362     nm_str_copy(&usb->serial,
363             nm_vect_str(db_list, NM_SQL_USB_SERIAL + idx_shift));
364 
365     rc = NM_OK;
366 out:
367     nm_str_free(&buf);
368     nm_str_free(&input);
369 
370     return rc;
371 }
372 
nm_usb_plug_update_db(const nm_str_t * name,const nm_usb_data_t * usb)373 static void nm_usb_plug_update_db(const nm_str_t *name, const nm_usb_data_t *usb)
374 {
375     nm_str_t query = NM_INIT_STR;
376 
377     nm_str_format(&query, NM_USB_ADD_SQL,
378             name->data,
379             usb->dev->name.data,
380             usb->dev->vendor_id.data,
381             usb->dev->product_id.data,
382             (usb->serial.data) ? usb->serial.data : "NULL");
383 
384     nm_db_edit(query.data);
385 
386     nm_str_free(&query);
387 }
388 /* vim:set ts=4 sw=4: */
389