/* * We may decide to make the socket path customizable. For now * just assume it is in /sys/fs/cgroup/ which has some special * consequences */ static bool setup_cgroup_dir(void) { int ret; if (!dir_exists(CGDIR)) { nih_debug(CGDIR " does not exist"); return false; } if (daemon_running()) { nih_error("%s: cgmanager is already running", __func__); return false; } if (file_exists(CGMANAGER_SOCK)) { if (unlink(CGMANAGER_SOCK) < 0) { nih_error("%s: failed to delete stale cgmanager socket", __func__); return false; } } /* Check that /sys/fs/cgroup is writeable, else mount a tmpfs */ unlink(CGPROBE); ret = creat(CGPROBE, O_RDWR); if (ret >= 0) { close(ret); unlink(CGPROBE); return mkdir_cgmanager_dir(); } ret = mount("cgroup", CGDIR, "tmpfs", 0, "size=10000"); if (ret) { nih_debug("Failed to mount tmpfs on %s: %s", CGDIR, strerror(errno)); return false; } nih_debug("Mounted tmpfs onto %s", CGDIR); return mkdir_cgmanager_dir(); }
/** * make_safe_string: * @parent: parent, * @original: original string. * * Strip non-printable and non-blank bytes from specified string. * * Notes: * * Sadly, this is necessary as some hardware (such as battery devices) * exposes non-printable bytes in their descriptive registers to the * kernel. Since neither the kernel nor udev specify any encoding for * udev messages, these (probably bogus) bytes get passed up to userland * to deal with. This is sub-optimal since it implies that _every_ * application that processes udev messages must perform its own * sanitizing on the messages. Let's just hope they all deal with the * problem in the same way... * * Note that *iff* the kernel/udev did specify an encoding model, this * problem could go away since one of the lower layers could then * detect the out-of-bound data and deal with it at source. All instances * of this issue seen so far seem to indicate the binary control data * being presented by the hardware is in fact bogus ("corruption") and * looks like some block of memory has not been initialized correctly. * * The approach taken here is to simulate the approach already adopted * by 'upower' (up_device_supply_make_safe_string()), with the exception * that we also allow blank characters (such as tabs). * * Returns a copy of @original stripped of all non-printable and * non-blank characters, or NULL if insufficient memory. **/ char * make_safe_string (const void *parent, const char *original) { size_t len; size_t i, j; char *cleaned; nih_assert (original); len = strlen (original); cleaned = nih_alloc (parent, len + 1); if (! cleaned) return NULL; for (i=0, j=0; i < len; ) { /* Skip over bogus bytes */ if (! (isprint (original[i]) || isblank (original[i]))) { i++; continue; } /* Copy what remains */ cleaned[j] = original[i]; i++; j++; } /* Terminate */ cleaned[j] = '\0'; if (i != j) nih_debug ("removed unexpected bytes from udev message data"); /* Note that strictly we should realloc the string if * bogus bytes were found (since it will now be shorter). * However, since all the strings are short (and short-lived) we * do not do this to avoid the associated overhead. */ return cleaned; }
static void udev_monitor_watcher (struct udev_monitor *udev_monitor, NihIoWatch * watch, NihIoEvents events) { struct udev_device * udev_device; nih_local char * subsystem = NULL; nih_local char * action = NULL; nih_local char * kernel = NULL; nih_local char * devpath = NULL; nih_local char * devname = NULL; nih_local char * name = NULL; nih_local char ** env = NULL; const char * value = NULL; size_t env_len = 0; DBusPendingCall * pending_call; char *(*copy_string)(const void *, const char *) = NULL; udev_device = udev_monitor_receive_device (udev_monitor); if (! udev_device) return; copy_string = no_strip_udev_data ? nih_strdup : make_safe_string; value = udev_device_get_subsystem (udev_device); subsystem = value ? copy_string (NULL, value) : NULL; value = udev_device_get_action (udev_device); action = value ? copy_string (NULL, value) : NULL; value = udev_device_get_sysname (udev_device); kernel = value ? copy_string (NULL, value) : NULL; value = udev_device_get_devpath (udev_device); devpath = value ? copy_string (NULL, value) : NULL; value = udev_device_get_devnode (udev_device); devname = value ? copy_string (NULL, value) : NULL; /* Protect against the "impossible" */ if (! action) goto out; if (! strcmp (action, "add")) { name = NIH_MUST (nih_sprintf (NULL, "%s-device-added", subsystem)); } else if (! strcmp (action, "change")) { name = NIH_MUST (nih_sprintf (NULL, "%s-device-changed", subsystem)); } else if (! strcmp (action, "remove")) { name = NIH_MUST (nih_sprintf (NULL, "%s-device-removed", subsystem)); } else { name = NIH_MUST (nih_sprintf (NULL, "%s-device-%s", subsystem, action)); } env = NIH_MUST (nih_str_array_new (NULL)); if (kernel) { nih_local char *var = NULL; var = NIH_MUST (nih_sprintf (NULL, "KERNEL=%s", kernel)); NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var)); } if (devpath) { nih_local char *var = NULL; var = NIH_MUST (nih_sprintf (NULL, "DEVPATH=%s", devpath)); NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var)); } if (devname) { nih_local char *var = NULL; var = NIH_MUST (nih_sprintf (NULL, "DEVNAME=%s", devname)); NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var)); } if (subsystem) { nih_local char *var = NULL; var = NIH_MUST (nih_sprintf (NULL, "SUBSYSTEM=%s", subsystem)); NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var)); } if (action) { nih_local char *var = NULL; var = NIH_MUST (nih_sprintf (NULL, "ACTION=%s", action)); NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var)); } for (struct udev_list_entry *list_entry = udev_device_get_properties_list_entry (udev_device); list_entry != NULL; list_entry = udev_list_entry_get_next (list_entry)) { nih_local char *udev_name = NULL; nih_local char *udev_value = NULL; nih_local char *var = NULL; udev_name = copy_string (NULL, udev_list_entry_get_name (list_entry)); if (! strcmp (udev_name, "DEVPATH")) continue; if (! strcmp (udev_name, "DEVNAME")) continue; if (! strcmp (udev_name, "SUBSYSTEM")) continue; if (! strcmp (udev_name, "ACTION")) continue; udev_value = copy_string (NULL, udev_list_entry_get_value (list_entry)); var = NIH_MUST (nih_sprintf (NULL, "%s=%s", udev_name, udev_value)); NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var)); } nih_debug ("%s %s", name, devname ? devname : ""); pending_call = upstart_emit_event (upstart, name, env, FALSE, NULL, emit_event_error, NULL, NIH_DBUS_TIMEOUT_NEVER); if (! pending_call) { NihError *err; int saved = errno; err = nih_error_get (); nih_warn ("%s", err->message); if (saved != ENOMEM && subsystem) nih_warn ("Likely that udev '%s' event contains binary garbage", subsystem); nih_free (err); } dbus_pending_call_unref (pending_call); out: udev_device_unref (udev_device); }