automotive-dlt
dlt-logstorage-udev.c
Go to the documentation of this file.
1 
24 /*******************************************************************************
25 ** **
26 ** SRC-MODULE: dlt-logstorage-udev.c **
27 ** **
28 ** TARGET : linux **
29 ** **
30 ** PROJECT : DLT **
31 ** **
32 ** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com **
33 ** Frederic Berat fberat@de.adit-jv.com **
34 ** **
35 ** PURPOSE : For udev-based handling of any device **
36 ** **
37 ** REMARKS : **
38 ** **
39 ** PLATFORM DEPENDANT [yes/no]: yes **
40 ** **
41 ** TO BE CHANGED BY USER [yes/no]: no **
42 ** **
43 *******************************************************************************/
44 
45 /*******************************************************************************
46 ** Author Identity **
47 ********************************************************************************
48 ** **
49 ** Initials Name Company **
50 ** -------- ------------------------- ---------------------------------- **
51 ** cl Christoph Lipka ADIT **
52 ** fb Frederic Berat ADIT **
53 *******************************************************************************/
54 
55 #define pr_fmt(fmt) "Udev control: "fmt
56 
57 #include <libudev.h>
58 #include <errno.h>
59 #include <mntent.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 
65 #include <sys/mount.h>
66 
67 #include "dlt-control-common.h"
68 #include "dlt-logstorage-common.h"
69 #include "dlt-logstorage-list.h"
70 #include "dlt-logstorage-udev.h"
71 
72 typedef struct {
73  struct udev *udev;
74  struct udev_monitor *mon;
76 
87 {
88  struct mntent *ent;
89  FILE *f;
90  char *mnt_point = NULL;
91 
92  if (dev_node == NULL)
93  {
94  return NULL;
95  }
96 
97  f = setmntent("/proc/mounts", "r");
98 
99  if (f == NULL)
100  {
101  pr_error("Cannot read /proc/mounts\n");
102  return NULL;
103  }
104 
105  while (NULL != (ent = getmntent(f)))
106  {
107  if (strncmp(ent->mnt_fsname, dev_node, strlen(ent->mnt_fsname)) == 0)
108  {
109  mnt_point = strdup(ent->mnt_dir);
110 
111  /* Remounting rw */
112  if (strlen(mnt_point))
113  {
114  /* capabilities needed. Thus we don't really car on failure.
115  * Therefor we can ignore the return value.
116  */
117  (void) mount(NULL, mnt_point, NULL, MS_REMOUNT, ent->mnt_opts);
118  }
119 
120  break;
121  }
122  }
123 
124  endmntent(f);
125 
126  return mnt_point;
127 }
128 
143 static int check_mountpoint_from_partition(int event, struct udev_device *part)
144 {
145  int logstorage_dev = 0;
146  char *mnt_point = NULL;
147  char *dev_node = NULL;
148  int ret = 0;
149 
150  if (!part)
151  {
152  pr_verbose("No partition structure given.\n");
153  return -1;
154  }
155 
156  pr_verbose("Checking mount point.\n");
157 
158  if (!udev_device_get_devnode(part))
159  {
160  pr_verbose("Skipping as no devnode.\n");
161  return 0;
162  }
163 
164  dev_node = strdup(udev_device_get_devnode(part));
165 
166  if (event == EVENT_MOUNTED)
167  {
168  mnt_point = dlt_logstorage_udev_get_mount_point(dev_node);
169  logstorage_dev = dlt_logstorage_check_config_file(mnt_point);
170 
171  if (logstorage_dev) /* Configuration file available, add node to internal list */
172  {
173  logstorage_store_dev_info(dev_node, mnt_point);
174  }
175  else
176  {
177  mnt_point = NULL;
178  }
179  }
180  else
181  {
182  /* remove device information */
183  mnt_point = logstorage_delete_dev_info(dev_node);
184  }
185 
186  if (mnt_point)
187  {
188  ret = dlt_logstorage_send_event(event, mnt_point);
189 
190  if (ret)
191  {
192  pr_error("Can't send event for %s to DLT.\n", mnt_point);
193  }
194  }
195 
196  free(dev_node);
197  free(mnt_point);
198 
199  return 0;
200 }
201 
210 {
211  const char *action;
212  int ret = 0;
214  LogstorageCtrlUdev *prvt = NULL;
215  struct udev_device *partition = NULL;
216 
217  if (!lctrl)
218  {
219  pr_error("Not able to get logstorage control instance.\n");
220  return -1;
221  }
222 
223  prvt = (LogstorageCtrlUdev *)lctrl->prvt;
224 
225  if (!prvt || !prvt->mon)
226  {
227  pr_error("Not able to get private data.\n");
228  return -1;
229  }
230 
231  partition = udev_monitor_receive_device(prvt->mon);
232 
233  if (!partition)
234  {
235  pr_error("Not able to get partition.\n");
236  return -1;
237  }
238 
239  action = udev_device_get_action(partition);
240 
241  if (!action)
242  {
243  pr_error("Not able to get action.\n");
244  udev_device_unref(partition);
245  return -1;
246  }
247 
248  pr_verbose("%s action received from udev for %s.\n",
249  action,
250  udev_device_get_devnode(partition));
251 
252  if (strncmp(action, "add", sizeof("add")) == 0)
253  {
254  /*TODO: This can be replaced by polling on /proc/mount.
255  * we could get event on modification, and keep track on a list
256  * of mounted devices. New devices could be check that way.
257  * That also would solve the unmount event issue.
258  * Then, udev is only interesting to simplify the check on new devices,
259  * and/or for hot unplug (without unmount).
260  */
261  usleep(500 * 1000);
263  }
264  else if (strncmp(action, "remove", sizeof("remove")) == 0)
265  {
267  }
268 
269  udev_device_unref(partition);
270 
271  return ret;
272 }
273 
283 static int dlt_logstorage_udev_check_mounted(struct udev *udev)
284 {
285  /* Create a list of the devices in the 'partition' subsystem. */
286  struct udev_enumerate *enumerate = udev_enumerate_new(udev);
287  struct udev_list_entry *devices = NULL;
288  struct udev_list_entry *dev_list_entry = NULL;
289 
290  if (!enumerate)
291  {
292  pr_error("Can't enumerate devices.\n");
293  return -1;
294  }
295 
296  udev_enumerate_add_match_subsystem(enumerate, "block");
297  udev_enumerate_add_match_property(enumerate, "DEVTYPE", "partition");
298  udev_enumerate_scan_devices(enumerate);
299 
300  devices = udev_enumerate_get_list_entry(enumerate);
301 
302  /* For each list entry, get the corresponding device */
303  udev_list_entry_foreach(dev_list_entry, devices) {
304  const char *path;
305  struct udev_device *partition = NULL;
306 
307  /* Get the filename of the /sys entry for the device
308  * and create a udev_device object representing it
309  */
310  path = udev_list_entry_get_name(dev_list_entry);
311  partition = udev_device_new_from_syspath(udev, path);
312 
313  if (!partition)
314  {
315  continue;
316  }
317 
318  pr_verbose("Found device %s %s %s.\n",
319  path,
320  udev_device_get_devnode(partition),
321  udev_device_get_devtype(partition));
322 
323  /* Check the device and clean-up */
325  udev_device_unref(partition);
326  }
327 
328  /* Free the enumerator object */
329  udev_enumerate_unref(enumerate);
330 
331  return 0;
332 }
333 
341 {
343  LogstorageCtrlUdev *prvt = NULL;
344 
345  if (!lctrl)
346  {
347  return -1;
348  }
349 
350  prvt = (LogstorageCtrlUdev *)lctrl->prvt;
351 
352  if (prvt->mon)
353  {
354  udev_monitor_unref(prvt->mon);
355  }
356 
357  if (prvt->udev)
358  {
359  udev_unref(prvt->udev);
360  }
361 
362  free(prvt);
363  lctrl->prvt = NULL;
364 
365  return 0;
366 }
367 
375 {
376  int ret = 0;
377 
379  LogstorageCtrlUdev *prvt = NULL;
380 
381  pr_verbose("Initializing.\n");
382 
383  if (!lctrl)
384  {
385  pr_error("Not able to get logstorage control instance.\n");
386  return -1;
387  }
388 
389  lctrl->prvt = calloc(1, sizeof(LogstorageCtrlUdev));
390 
391  if (!lctrl->prvt)
392  {
393  pr_error("No memory to allocate private data.\n");
394  return -1;
395  }
396 
397  prvt = (LogstorageCtrlUdev *)lctrl->prvt;
398 
399  /* Initialize udev object */
400  prvt->udev = udev_new();
401 
402  if (!prvt->udev)
403  {
404  pr_error("Cannot initialize udev object\n");
406  return -1;
407  }
408 
409  /* setup udev monitor which will report events when
410  * devices attached to the system change. Events include
411  * "add", "remove", "change", etc */
412  prvt->mon = udev_monitor_new_from_netlink(prvt->udev, "udev");
413 
414  if (!prvt->mon)
415  {
416  pr_error("Cannot initialize udev monitor\n");
418  return -1;
419  }
420 
421  ret = udev_monitor_filter_add_match_subsystem_devtype(prvt->mon,
422  "block",
423  NULL);
424 
425  if (ret)
426  {
427  pr_error("Cannot attach filter to monitor: %s.\n", strerror(-ret));
429  return -1;
430  }
431 
432  ret = udev_monitor_enable_receiving(prvt->mon);
433 
434  if (ret < 0)
435  {
436  pr_error("Cannot start receiving: %s.\n", strerror(-ret));
438  return -1;
439  }
440 
441  /* get file descriptor */
442  lctrl->fd = udev_monitor_get_fd(prvt->mon);
443  /* set callback function */
445 
446  /* check if there is something already mounted */
448 }
static DltLogstorageCtrl lctrl
char * logstorage_delete_dev_info(const char *node)
Remove a device from the list.
static int logstorage_udev_udevd_callback(void)
Handles the udev events.
#define EVENT_UNMOUNTING
DltLogstorageCtrl * get_logstorage_control(void)
static char * dlt_logstorage_udev_get_mount_point(char *dev_node)
Get mount point of a device node.
int dlt_logstorage_check_config_file(char *mnt_point)
Search for config file in given mount point.
struct udev_monitor * mon
int dlt_logstorage_udev_deinit(void)
Clean-up the udev data.
static int check_mountpoint_from_partition(int event, struct udev_device *part)
Check if the daemon needs to be notified by the event.
int logstorage_store_dev_info(const char *node, const char *path)
Add new device in the list.
#define pr_error(fmt,...)
int dlt_logstorage_send_event(int type, char *mount_point)
Send a logstorage event to DLT.
#define pr_verbose(fmt,...)
#define EVENT_MOUNTED
static int dlt_logstorage_udev_check_mounted(struct udev *udev)
Check all partitions on the system to find configuration file.
int dlt_logstorage_udev_init(void)
Initialize the private data.
#define NULL
Definition: dlt_common.h:232