#include "string-util.h"
#include "strv.h"
#include "time-util.h"
+#include "utf8.h"
int device_new_aux(sd_device **ret) {
sd_device *device;
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device, sd_device, device_free);
+static bool property_is_valid(const char *key, const char *value) {
+ /* Device properties may be saved to database file, then may be parsed from the file. When if a
+ * property contains spurious characters, then the parser may be confused. Let's refuse spurious
+ * properties, even if it is internal, which will not be saved to database file, for consistency. */
+
+ if (isempty(key) || !in_charset(key, ALPHANUMERICAL "_."))
+ return false;
+
+ /* an empty value means unset the property, hence that's fine. */
+ if (isempty(value))
+ return true;
+
+ /* refuse invalid UTF8 and control characters */
+ if (!utf8_is_valid(value) || string_has_cc(value, /* ok= */ NULL))
+ return false;
+
+ return true;
+}
+
int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db) {
OrderedHashmap **properties;
assert(device);
assert(key);
+ if (!property_is_valid(key, value))
+ return -EINVAL;
+
if (db)
properties = &device->properties_db;
else
}
}
+TEST(device_add_property) {
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+ const char *val;
+
+ ASSERT_OK(sd_device_new_from_syspath(&dev, "/sys/class/net/lo"));
+
+ /* add a property */
+ ASSERT_OK(device_add_property(dev, "hoge", "foo"));
+ ASSERT_OK(sd_device_get_property_value(dev, "hoge", &val));
+ ASSERT_STREQ(val, "foo");
+
+ /* update an existing property */
+ ASSERT_OK(device_add_property(dev, "hoge", "bar"));
+ ASSERT_OK(sd_device_get_property_value(dev, "hoge", &val));
+ ASSERT_STREQ(val, "bar");
+
+ /* remove an existing property */
+ ASSERT_OK(device_add_property(dev, "hoge", NULL));
+ ASSERT_ERROR(sd_device_get_property_value(dev, "hoge", &val), ENOENT);
+
+ /* add a property again */
+ ASSERT_OK(device_add_property(dev, "hoge", "foo"));
+ ASSERT_OK(sd_device_get_property_value(dev, "hoge", &val));
+ ASSERT_STREQ(val, "foo");
+
+ /* remove it with an empty string */
+ ASSERT_OK(device_add_property(dev, "hoge", ""));
+ ASSERT_ERROR(sd_device_get_property_value(dev, "hoge", &val), ENOENT);
+
+ /* check internal property (starting with dot) */
+ ASSERT_OK(device_add_property(dev, ".hoge", "baz"));
+ ASSERT_OK(sd_device_get_property_value(dev, ".hoge", &val));
+ ASSERT_STREQ(val, "baz");
+
+ /* refuse invalid property names */
+ ASSERT_ERROR(device_add_property(dev, "hoge-hoge", "aaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge=hoge", "aaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge hoge", "aaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge\nhoge", "aaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge\rhoge", "aaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge\thoge", "aaa"), EINVAL);
+
+ /* refuse invalid property values */
+ ASSERT_ERROR(device_add_property(dev, "hoge", "aaa\naaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge", "aaa\raaa"), EINVAL);
+ ASSERT_ERROR(device_add_property(dev, "hoge", "aaa\taaa"), EINVAL);
+}
+
static int intro(void) {
int r;