LCOV - code coverage report
Current view: top level - libsystemd/sd-device - device-private.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 3 633 0.5 %
Date: 2015-07-29 18:47:03 Functions: 1 44 2.3 %

          Line data    Source code
       1             : /***
       2             :   This file is part of systemd.
       3             : 
       4             :   Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
       5             :   Copyright 2014 Tom Gundersen <teg@jklm.no>
       6             : 
       7             :   systemd is free software; you can redistribute it and/or modify it
       8             :   under the terms of the GNU Lesser General Public License as published by
       9             :   the Free Software Foundation; either version 2.1 of the License, or
      10             :   (at your option) any later version.
      11             : 
      12             :   systemd is distributed in the hope that it will be useful, but
      13             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      15             :   Lesser General Public License for more details.
      16             : 
      17             :   You should have received a copy of the GNU Lesser General Public License
      18             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      19             : ***/
      20             : 
      21             : #include <ctype.h>
      22             : #include <sys/types.h>
      23             : #include <net/if.h>
      24             : 
      25             : #include "util.h"
      26             : #include "macro.h"
      27             : #include "refcnt.h"
      28             : #include "path-util.h"
      29             : #include "strxcpyx.h"
      30             : #include "fileio.h"
      31             : #include "hashmap.h"
      32             : #include "set.h"
      33             : #include "strv.h"
      34             : #include "mkdir.h"
      35             : 
      36             : #include "sd-device.h"
      37             : 
      38             : #include "device-util.h"
      39             : #include "device-internal.h"
      40             : #include "device-private.h"
      41             : 
      42           0 : int device_add_property(sd_device *device, const char *key, const char *value) {
      43             :         int r;
      44             : 
      45           0 :         assert(device);
      46           0 :         assert(key);
      47             : 
      48           0 :         r = device_add_property_aux(device, key, value, false);
      49           0 :         if (r < 0)
      50           0 :                 return r;
      51             : 
      52           0 :         if (key[0] != '.') {
      53           0 :                 r = device_add_property_aux(device, key, value, true);
      54           0 :                 if (r < 0)
      55           0 :                         return r;
      56             :         }
      57             : 
      58           0 :         return 0;
      59             : }
      60             : 
      61           0 : static int device_add_property_internal_from_string(sd_device *device, const char *str) {
      62           0 :         _cleanup_free_ char *key = NULL;
      63             :         char *value;
      64             : 
      65           0 :         assert(device);
      66           0 :         assert(str);
      67             : 
      68           0 :         key = strdup(str);
      69           0 :         if (!key)
      70           0 :                 return -ENOMEM;
      71             : 
      72           0 :         value = strchr(key, '=');
      73           0 :         if (!value)
      74           0 :                 return -EINVAL;
      75             : 
      76           0 :         *value = '\0';
      77             : 
      78           0 :         if (isempty(++value))
      79           0 :                 value = NULL;
      80             : 
      81           0 :         return device_add_property_internal(device, key, value);
      82             : }
      83             : 
      84           0 : static int handle_db_line(sd_device *device, char key, const char *value) {
      85             :         char *path;
      86             :         int r;
      87             : 
      88           0 :         assert(device);
      89           0 :         assert(value);
      90             : 
      91           0 :         switch (key) {
      92             :         case 'S':
      93           0 :                 path = strjoina("/dev/", value);
      94           0 :                 r = device_add_devlink(device, path);
      95           0 :                 if (r < 0)
      96           0 :                         return r;
      97             : 
      98           0 :                 break;
      99             :         case 'L':
     100           0 :                 r = safe_atoi(value, &device->devlink_priority);
     101           0 :                 if (r < 0)
     102           0 :                         return r;
     103             : 
     104           0 :                 break;
     105             :         case 'E':
     106           0 :                 r = device_add_property_internal_from_string(device, value);
     107           0 :                 if (r < 0)
     108           0 :                         return r;
     109             : 
     110           0 :                 break;
     111             :         case 'G':
     112           0 :                 r = device_add_tag(device, value);
     113           0 :                 if (r < 0)
     114           0 :                         return r;
     115             : 
     116           0 :                 break;
     117             :         case 'W':
     118           0 :                 r = safe_atoi(value, &device->watch_handle);
     119           0 :                 if (r < 0)
     120           0 :                         return r;
     121             : 
     122           0 :                 break;
     123             :         case 'I':
     124           0 :                 r = device_set_usec_initialized(device, value);
     125           0 :                 if (r < 0)
     126           0 :                         return r;
     127             : 
     128           0 :                 break;
     129             :         default:
     130           0 :                 log_debug("device db: unknown key '%c'", key);
     131             :         }
     132             : 
     133           0 :         return 0;
     134             : }
     135             : 
     136           0 : void device_set_devlink_priority(sd_device *device, int priority) {
     137           0 :         assert(device);
     138             : 
     139           0 :         device->devlink_priority = priority;
     140           0 : }
     141             : 
     142           0 : void device_set_is_initialized(sd_device *device) {
     143           0 :         assert(device);
     144             : 
     145           0 :         device->is_initialized = true;
     146           0 : }
     147             : 
     148           0 : int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
     149             :         char num[DECIMAL_STR_MAX(usec_t)];
     150             :         usec_t usec_initialized;
     151             :         int r;
     152             : 
     153           0 :         assert(device);
     154             : 
     155           0 :         if (device_old && device_old->usec_initialized > 0)
     156           0 :                 usec_initialized = device_old->usec_initialized;
     157             :         else
     158           0 :                 usec_initialized = now(CLOCK_MONOTONIC);
     159             : 
     160           0 :         r = snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
     161           0 :         if (r < 0)
     162           0 :                 return -errno;
     163             : 
     164           0 :         r = device_set_usec_initialized(device, num);
     165           0 :         if (r < 0)
     166           0 :                 return r;
     167             : 
     168           0 :         return 0;
     169             : }
     170             : 
     171           0 : static int device_read_db(sd_device *device) {
     172           0 :         _cleanup_free_ char *db = NULL;
     173             :         char *path;
     174             :         const char *id, *value;
     175             :         char key;
     176             :         size_t db_len;
     177             :         unsigned i;
     178             :         int r;
     179             : 
     180             :         enum {
     181             :                 PRE_KEY,
     182             :                 KEY,
     183             :                 PRE_VALUE,
     184             :                 VALUE,
     185             :                 INVALID_LINE,
     186           0 :         } state = PRE_KEY;
     187             : 
     188           0 :         assert(device);
     189             : 
     190           0 :         if (device->db_loaded || device->sealed)
     191           0 :                 return 0;
     192             : 
     193           0 :         r = device_get_id_filename(device, &id);
     194           0 :         if (r < 0)
     195           0 :                 return r;
     196             : 
     197           0 :         path = strjoina("/run/udev/data/", id);
     198             : 
     199           0 :         r = read_full_file(path, &db, &db_len);
     200           0 :         if (r < 0) {
     201           0 :                 if (r == -ENOENT)
     202           0 :                         return 0;
     203             :                 else {
     204           0 :                         log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
     205           0 :                         return r;
     206             :                 }
     207             :         }
     208             : 
     209             :         /* devices with a database entry are initialized */
     210           0 :         device_set_is_initialized(device);
     211             : 
     212           0 :         for (i = 0; i < db_len; i++) {
     213           0 :                 switch (state) {
     214             :                 case PRE_KEY:
     215           0 :                         if (!strchr(NEWLINE, db[i])) {
     216           0 :                                 key = db[i];
     217             : 
     218           0 :                                 state = KEY;
     219             :                         }
     220             : 
     221           0 :                         break;
     222             :                 case KEY:
     223           0 :                         if (db[i] != ':') {
     224           0 :                                 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
     225             : 
     226           0 :                                 state = INVALID_LINE;
     227             :                         } else {
     228           0 :                                 db[i] = '\0';
     229             : 
     230           0 :                                 state = PRE_VALUE;
     231             :                         }
     232             : 
     233           0 :                         break;
     234             :                 case PRE_VALUE:
     235           0 :                         value = &db[i];
     236             : 
     237           0 :                         state = VALUE;
     238             : 
     239           0 :                         break;
     240             :                 case INVALID_LINE:
     241           0 :                         if (strchr(NEWLINE, db[i]))
     242           0 :                                 state = PRE_KEY;
     243             : 
     244           0 :                         break;
     245             :                 case VALUE:
     246           0 :                         if (strchr(NEWLINE, db[i])) {
     247           0 :                                 db[i] = '\0';
     248           0 :                                 r = handle_db_line(device, key, value);
     249           0 :                                 if (r < 0)
     250           0 :                                         log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
     251             : 
     252           0 :                                 state = PRE_KEY;
     253             :                         }
     254             : 
     255           0 :                         break;
     256             :                 default:
     257           0 :                         assert_not_reached("invalid state when parsing db");
     258             :                 }
     259             :         }
     260             : 
     261           0 :         device->db_loaded = true;
     262             : 
     263           0 :         return 0;
     264             : }
     265             : 
     266           0 : uint64_t device_get_properties_generation(sd_device *device) {
     267           0 :         assert(device);
     268             : 
     269           0 :         return device->properties_generation;
     270             : }
     271             : 
     272           0 : uint64_t device_get_tags_generation(sd_device *device) {
     273           0 :         assert(device);
     274             : 
     275           0 :         return device->tags_generation;
     276             : }
     277             : 
     278         420 : uint64_t device_get_devlinks_generation(sd_device *device) {
     279         420 :         assert(device);
     280             : 
     281         420 :         return device->devlinks_generation;
     282             : }
     283             : 
     284           0 : int device_get_devnode_mode(sd_device *device, mode_t *mode) {
     285             :         int r;
     286             : 
     287           0 :         assert(device);
     288           0 :         assert(mode);
     289             : 
     290           0 :         r = device_read_db(device);
     291           0 :         if (r < 0)
     292           0 :                 return r;
     293             : 
     294           0 :         *mode = device->devmode;
     295             : 
     296           0 :         return 0;
     297             : }
     298             : 
     299           0 : int device_get_devnode_uid(sd_device *device, uid_t *uid) {
     300             :         int r;
     301             : 
     302           0 :         assert(device);
     303           0 :         assert(uid);
     304             : 
     305           0 :         r = device_read_db(device);
     306           0 :         if (r < 0)
     307           0 :                 return r;
     308             : 
     309           0 :         *uid = device->devuid;
     310             : 
     311           0 :         return 0;
     312             : }
     313             : 
     314           0 : static int device_set_devuid(sd_device *device, const char *uid) {
     315             :         unsigned u;
     316             :         int r;
     317             : 
     318           0 :         assert(device);
     319           0 :         assert(uid);
     320             : 
     321           0 :         r = safe_atou(uid, &u);
     322           0 :         if (r < 0)
     323           0 :                 return r;
     324             : 
     325           0 :         r = device_add_property_internal(device, "DEVUID", uid);
     326           0 :         if (r < 0)
     327           0 :                 return r;
     328             : 
     329           0 :         device->devuid = u;
     330             : 
     331           0 :         return 0;
     332             : }
     333             : 
     334           0 : int device_get_devnode_gid(sd_device *device, gid_t *gid) {
     335             :         int r;
     336             : 
     337           0 :         assert(device);
     338           0 :         assert(gid);
     339             : 
     340           0 :         r = device_read_db(device);
     341           0 :         if (r < 0)
     342           0 :                 return r;
     343             : 
     344           0 :         *gid = device->devgid;
     345             : 
     346           0 :         return 0;
     347             : }
     348             : 
     349           0 : static int device_set_devgid(sd_device *device, const char *gid) {
     350             :         unsigned g;
     351             :         int r;
     352             : 
     353           0 :         assert(device);
     354           0 :         assert(gid);
     355             : 
     356           0 :         r = safe_atou(gid, &g);
     357           0 :         if (r < 0)
     358           0 :                 return r;
     359             : 
     360           0 :         r = device_add_property_internal(device, "DEVGID", gid);
     361           0 :         if (r < 0)
     362           0 :                 return r;
     363             : 
     364           0 :         device->devgid = g;
     365             : 
     366           0 :         return 0;
     367             : }
     368             : 
     369           0 : static int device_amend(sd_device *device, const char *key, const char *value) {
     370             :         int r;
     371             : 
     372           0 :         assert(device);
     373           0 :         assert(key);
     374           0 :         assert(value);
     375             : 
     376           0 :         if (streq(key, "DEVPATH")) {
     377             :                 char *path;
     378             : 
     379           0 :                 path = strjoina("/sys", value);
     380             : 
     381             :                 /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
     382           0 :                 r = device_set_syspath(device, path, false);
     383           0 :                 if (r < 0)
     384           0 :                         return log_debug_errno(r, "sd-device: could not set syspath to '%s': %m", path);
     385           0 :         } else if (streq(key, "SUBSYSTEM")) {
     386           0 :                 r = device_set_subsystem(device, value);
     387           0 :                 if (r < 0)
     388           0 :                         return log_debug_errno(r, "sd-device: could not set subsystem to '%s': %m", value);
     389           0 :         } else if (streq(key, "DEVTYPE")) {
     390           0 :                 r = device_set_devtype(device, value);
     391           0 :                 if (r < 0)
     392           0 :                         return log_debug_errno(r, "sd-device: could not set devtype to '%s': %m", value);
     393           0 :         } else if (streq(key, "DEVNAME")) {
     394           0 :                 r = device_set_devname(device, value);
     395           0 :                 if (r < 0)
     396           0 :                         return log_debug_errno(r, "sd-device: could not set devname to '%s': %m", value);
     397           0 :         } else if (streq(key, "USEC_INITIALIZED")) {
     398           0 :                 r = device_set_usec_initialized(device, value);
     399           0 :                 if (r < 0)
     400           0 :                         return log_debug_errno(r, "sd-device: could not set usec-initialized to '%s': %m", value);
     401           0 :         } else if (streq(key, "DRIVER")) {
     402           0 :                 r = device_set_driver(device, value);
     403           0 :                 if (r < 0)
     404           0 :                         return log_debug_errno(r, "sd-device: could not set driver to '%s': %m", value);
     405           0 :         } else if (streq(key, "IFINDEX")) {
     406           0 :                 r = device_set_ifindex(device, value);
     407           0 :                 if (r < 0)
     408           0 :                         return log_debug_errno(r, "sd-device: could not set ifindex to '%s': %m", value);
     409           0 :         } else if (streq(key, "DEVMODE")) {
     410           0 :                 r = device_set_devmode(device, value);
     411           0 :                 if (r < 0)
     412           0 :                         return log_debug_errno(r, "sd-device: could not set devmode to '%s': %m", value);
     413           0 :         } else if (streq(key, "DEVUID")) {
     414           0 :                 r = device_set_devuid(device, value);
     415           0 :                 if (r < 0)
     416           0 :                         return log_debug_errno(r, "sd-device: could not set devuid to '%s': %m", value);
     417           0 :         } else if (streq(key, "DEVGID")) {
     418           0 :                 r = device_set_devgid(device, value);
     419           0 :                 if (r < 0)
     420           0 :                         return log_debug_errno(r, "sd-device: could not set devgid to '%s': %m", value);
     421           0 :         } else if (streq(key, "DEVLINKS")) {
     422             :                 const char *word, *state;
     423             :                 size_t l;
     424             : 
     425           0 :                 FOREACH_WORD(word, l, value, state) {
     426           0 :                         char devlink[l + 1];
     427             : 
     428           0 :                         strncpy(devlink, word, l);
     429           0 :                         devlink[l] = '\0';
     430             : 
     431           0 :                         r = device_add_devlink(device, devlink);
     432           0 :                         if (r < 0)
     433           0 :                                 return log_debug_errno(r, "sd-device: could not add devlink '%s': %m", devlink);
     434             :                 }
     435           0 :         } else if (streq(key, "TAGS")) {
     436             :                 const char *word, *state;
     437             :                 size_t l;
     438             : 
     439           0 :                 FOREACH_WORD_SEPARATOR(word, l, value, ":", state) {
     440           0 :                         char tag[l + 1];
     441             : 
     442           0 :                         (void)strncpy(tag, word, l);
     443           0 :                         tag[l] = '\0';
     444             : 
     445           0 :                         r = device_add_tag(device, tag);
     446           0 :                         if (r < 0)
     447           0 :                                 return log_debug_errno(r, "sd-device: could not add tag '%s': %m", tag);
     448             :                 }
     449             :         } else {
     450           0 :                 r = device_add_property_internal(device, key, value);
     451           0 :                 if (r < 0)
     452           0 :                         return log_debug_errno(r, "sd-device: could not add property '%s=%s': %m", key, value);
     453             :         }
     454             : 
     455           0 :         return 0;
     456             : }
     457             : 
     458             : static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
     459             :         [DEVICE_ACTION_ADD] = "add",
     460             :         [DEVICE_ACTION_REMOVE] = "remove",
     461             :         [DEVICE_ACTION_CHANGE] = "change",
     462             :         [DEVICE_ACTION_MOVE] = "move",
     463             :         [DEVICE_ACTION_ONLINE] = "online",
     464             :         [DEVICE_ACTION_OFFLINE] = "offline",
     465             : };
     466             : 
     467           0 : DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
     468             : 
     469           0 : static int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
     470             :                          DeviceAction *_action) {
     471           0 :         DeviceAction action = _DEVICE_ACTION_INVALID;
     472           0 :         uint64_t seqnum = 0;
     473           0 :         const char *major = NULL, *minor = NULL;
     474             :         char *value;
     475             :         int r;
     476             : 
     477           0 :         assert(device);
     478           0 :         assert(key);
     479           0 :         assert(_major);
     480           0 :         assert(_minor);
     481           0 :         assert(_seqnum);
     482           0 :         assert(_action);
     483             : 
     484           0 :         value = strchr(key, '=');
     485           0 :         if (!value) {
     486           0 :                 log_debug("sd-device: not a key-value pair: '%s'", key);
     487           0 :                 return -EINVAL;
     488             :         }
     489             : 
     490           0 :         *value = '\0';
     491             : 
     492           0 :         value++;
     493             : 
     494           0 :         if (streq(key, "MAJOR"))
     495           0 :                 major = value;
     496           0 :         else if (streq(key, "MINOR"))
     497           0 :                 minor = value;
     498             :         else {
     499           0 :                 if (streq(key, "ACTION")) {
     500           0 :                         action = device_action_from_string(value);
     501           0 :                         if (action == _DEVICE_ACTION_INVALID)
     502           0 :                                 return -EINVAL;
     503           0 :                 } else if (streq(key, "SEQNUM")) {
     504           0 :                         r = safe_atou64(value, &seqnum);
     505           0 :                         if (r < 0)
     506           0 :                                 return r;
     507           0 :                         else if (seqnum == 0)
     508             :                                  /* kernel only sends seqnum > 0 */
     509           0 :                                 return -EINVAL;
     510             :                 }
     511             : 
     512           0 :                 r = device_amend(device, key, value);
     513           0 :                 if (r < 0)
     514           0 :                         return r;
     515             :         }
     516             : 
     517           0 :         if (major != 0)
     518           0 :                 *_major = major;
     519             : 
     520           0 :         if (minor != 0)
     521           0 :                 *_minor = minor;
     522             : 
     523           0 :         if (action != _DEVICE_ACTION_INVALID)
     524           0 :                 *_action = action;
     525             : 
     526           0 :         if (seqnum > 0)
     527           0 :                 *_seqnum = seqnum;
     528             : 
     529           0 :         return 0;
     530             : }
     531             : 
     532           0 : void device_seal(sd_device *device) {
     533           0 :         assert(device);
     534             : 
     535           0 :         device->sealed = true;
     536           0 : }
     537             : 
     538           0 : static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
     539           0 :         assert(device);
     540             : 
     541           0 :         if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) {
     542           0 :                 log_debug("sd-device: device created from strv lacks devpath, subsystem, action or seqnum");
     543           0 :                 return -EINVAL;
     544             :         }
     545             : 
     546           0 :         device->sealed = true;
     547             : 
     548           0 :         return 0;
     549             : }
     550             : 
     551           0 : int device_new_from_strv(sd_device **ret, char **strv) {
     552           0 :         _cleanup_device_unref_ sd_device *device = NULL;
     553             :         char **key;
     554           0 :         const char *major = NULL, *minor = NULL;
     555           0 :         DeviceAction action = _DEVICE_ACTION_INVALID;
     556             :         uint64_t seqnum;
     557             :         int r;
     558             : 
     559           0 :         assert(ret);
     560           0 :         assert(strv);
     561             : 
     562           0 :         r = device_new_aux(&device);
     563           0 :         if (r < 0)
     564           0 :                 return r;
     565             : 
     566           0 :         STRV_FOREACH(key, strv) {
     567           0 :                 r = device_append(device, *key, &major, &minor, &seqnum, &action);
     568           0 :                 if (r < 0)
     569           0 :                         return r;
     570             :         }
     571             : 
     572           0 :         if (major) {
     573           0 :                 r = device_set_devnum(device, major, minor);
     574           0 :                 if (r < 0)
     575           0 :                         return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
     576             :         }
     577             : 
     578           0 :         r = device_verify(device, action, seqnum);
     579           0 :         if (r < 0)
     580           0 :                 return r;
     581             : 
     582           0 :         *ret = device;
     583           0 :         device = NULL;
     584             : 
     585           0 :         return 0;
     586             : }
     587             : 
     588           0 : int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
     589           0 :         _cleanup_device_unref_ sd_device *device = NULL;
     590           0 :         const char *major = NULL, *minor = NULL;
     591           0 :         DeviceAction action = _DEVICE_ACTION_INVALID;
     592             :         uint64_t seqnum;
     593           0 :         unsigned i = 0;
     594             :         int r;
     595             : 
     596           0 :         assert(ret);
     597           0 :         assert(nulstr);
     598           0 :         assert(len);
     599             : 
     600           0 :         r = device_new_aux(&device);
     601           0 :         if (r < 0)
     602           0 :                 return r;
     603             : 
     604           0 :         while (i < len) {
     605             :                 char *key;
     606             :                 const char *end;
     607             : 
     608           0 :                 key = (char*)&nulstr[i];
     609           0 :                 end = memchr(key, '\0', len - i);
     610           0 :                 if (!end) {
     611           0 :                         log_debug("sd-device: failed to parse nulstr");
     612           0 :                         return -EINVAL;
     613             :                 }
     614           0 :                 i += end - key + 1;
     615             : 
     616           0 :                 r = device_append(device, key, &major, &minor, &seqnum, &action);
     617           0 :                 if (r < 0)
     618           0 :                         return r;
     619             :         }
     620             : 
     621           0 :         if (major) {
     622           0 :                 r = device_set_devnum(device, major, minor);
     623           0 :                 if (r < 0)
     624           0 :                         return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
     625             :         }
     626             : 
     627           0 :         r = device_verify(device, action, seqnum);
     628           0 :         if (r < 0)
     629           0 :                 return r;
     630             : 
     631           0 :         *ret = device;
     632           0 :         device = NULL;
     633             : 
     634           0 :         return 0;
     635             : }
     636             : 
     637           0 : static int device_update_properties_bufs(sd_device *device) {
     638             :         const char *val, *prop;
     639           0 :         _cleanup_free_ char **buf_strv = NULL;
     640           0 :         _cleanup_free_ uint8_t *buf_nulstr = NULL;
     641           0 :         size_t allocated_nulstr = 0;
     642           0 :         size_t nulstr_len = 0, num = 0, i = 0;
     643             : 
     644           0 :         assert(device);
     645             : 
     646           0 :         if (!device->properties_buf_outdated)
     647           0 :                 return 0;
     648             : 
     649           0 :         FOREACH_DEVICE_PROPERTY(device, prop, val) {
     650           0 :                 size_t len = 0;
     651             : 
     652           0 :                 len = strlen(prop) + 1 + strlen(val);
     653             : 
     654           0 :                 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
     655           0 :                 if (!buf_nulstr)
     656           0 :                         return -ENOMEM;
     657             : 
     658           0 :                 strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
     659           0 :                 nulstr_len += len + 1;
     660           0 :                 ++num;
     661             :         }
     662             : 
     663             :         /* build buf_strv from buf_nulstr */
     664           0 :         buf_strv = new0(char *, num + 1);
     665           0 :         if (!buf_strv)
     666           0 :                 return -ENOMEM;
     667             : 
     668           0 :         NULSTR_FOREACH(val, (char*) buf_nulstr) {
     669           0 :                 buf_strv[i] = (char *) val;
     670           0 :                 assert(i < num);
     671           0 :                 i++;
     672             :         }
     673             : 
     674           0 :         free(device->properties_nulstr);
     675           0 :         device->properties_nulstr = buf_nulstr;
     676           0 :         buf_nulstr = NULL;
     677           0 :         device->properties_nulstr_len = nulstr_len;
     678           0 :         free(device->properties_strv);
     679           0 :         device->properties_strv = buf_strv;
     680           0 :         buf_strv = NULL;
     681             : 
     682           0 :         device->properties_buf_outdated = false;
     683             : 
     684           0 :         return 0;
     685             : }
     686             : 
     687           0 : int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
     688             :         int r;
     689             : 
     690           0 :         assert(device);
     691           0 :         assert(nulstr);
     692           0 :         assert(len);
     693             : 
     694           0 :         r = device_update_properties_bufs(device);
     695           0 :         if (r < 0)
     696           0 :                 return r;
     697             : 
     698           0 :         *nulstr = device->properties_nulstr;
     699           0 :         *len = device->properties_nulstr_len;
     700             : 
     701           0 :         return 0;
     702             : }
     703             : 
     704           0 : int device_get_properties_strv(sd_device *device, char ***strv) {
     705             :         int r;
     706             : 
     707           0 :         assert(device);
     708           0 :         assert(strv);
     709             : 
     710           0 :         r = device_update_properties_bufs(device);
     711           0 :         if (r < 0)
     712           0 :                 return r;
     713             : 
     714           0 :         *strv = device->properties_strv;
     715             : 
     716           0 :         return 0;
     717             : }
     718             : 
     719           0 : int device_get_devlink_priority(sd_device *device, int *priority) {
     720             :         int r;
     721             : 
     722           0 :         assert(device);
     723           0 :         assert(priority);
     724             : 
     725           0 :         r = device_read_db(device);
     726           0 :         if (r < 0)
     727           0 :                 return r;
     728             : 
     729           0 :         *priority = device->devlink_priority;
     730             : 
     731           0 :         return 0;
     732             : }
     733             : 
     734           0 : int device_get_watch_handle(sd_device *device, int *handle) {
     735             :         int r;
     736             : 
     737           0 :         assert(device);
     738           0 :         assert(handle);
     739             : 
     740           0 :         r = device_read_db(device);
     741           0 :         if (r < 0)
     742           0 :                 return r;
     743             : 
     744           0 :         *handle = device->watch_handle;
     745             : 
     746           0 :         return 0;
     747             : }
     748             : 
     749           0 : void device_set_watch_handle(sd_device *device, int handle) {
     750           0 :         assert(device);
     751             : 
     752           0 :         device->watch_handle = handle;
     753           0 : }
     754             : 
     755           0 : int device_rename(sd_device *device, const char *name) {
     756           0 :         _cleanup_free_ char *dirname = NULL;
     757             :         char *new_syspath;
     758             :         const char *interface;
     759             :         int r;
     760             : 
     761           0 :         assert(device);
     762           0 :         assert(name);
     763             : 
     764           0 :         dirname = dirname_malloc(device->syspath);
     765           0 :         if (!dirname)
     766           0 :                 return -ENOMEM;
     767             : 
     768           0 :         new_syspath = strjoina(dirname, "/", name);
     769             : 
     770             :         /* the user must trust that the new name is correct */
     771           0 :         r = device_set_syspath(device, new_syspath, false);
     772           0 :         if (r < 0)
     773           0 :                 return r;
     774             : 
     775           0 :         r = sd_device_get_property_value(device, "INTERFACE", &interface);
     776           0 :         if (r >= 0) {
     777           0 :                 r = device_add_property_internal(device, "INTERFACE", name);
     778           0 :                 if (r < 0)
     779           0 :                         return r;
     780             : 
     781             :                 /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
     782           0 :                 r = device_add_property_internal(device, "INTERFACE_OLD", interface);
     783           0 :                 if (r < 0)
     784           0 :                         return r;
     785           0 :         } else if (r != -ENOENT)
     786           0 :                 return r;
     787             : 
     788           0 :         return 0;
     789             : }
     790             : 
     791           0 : int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
     792           0 :         _cleanup_device_unref_ sd_device *ret = NULL;
     793             :         int r;
     794             : 
     795           0 :         assert(old_device);
     796           0 :         assert(new_device);
     797             : 
     798           0 :         r = device_new_aux(&ret);
     799           0 :         if (r < 0)
     800           0 :                 return r;
     801             : 
     802           0 :         r = device_set_syspath(ret, old_device->syspath, false);
     803           0 :         if (r < 0)
     804           0 :                 return r;
     805             : 
     806           0 :         r = device_set_subsystem(ret, old_device->subsystem);
     807           0 :         if (r < 0)
     808           0 :                 return r;
     809             : 
     810           0 :         ret->devnum = old_device->devnum;
     811             : 
     812           0 :         *new_device = ret;
     813           0 :         ret = NULL;
     814             : 
     815           0 :         return 0;
     816             : }
     817             : 
     818           0 : int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
     819           0 :         _cleanup_device_unref_ sd_device *ret = NULL;
     820             :         int r;
     821             : 
     822           0 :         assert(old_device);
     823           0 :         assert(new_device);
     824             : 
     825           0 :         r = device_shallow_clone(old_device, &ret);
     826           0 :         if (r < 0)
     827           0 :                 return r;
     828             : 
     829           0 :         r = device_read_db(ret);
     830           0 :         if (r < 0)
     831           0 :                 return r;
     832             : 
     833           0 :         ret->sealed = true;
     834             : 
     835           0 :         *new_device = ret;
     836           0 :         ret = NULL;
     837             : 
     838           0 :         return 0;
     839             : }
     840             : 
     841           0 : int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
     842           0 :         _cleanup_device_unref_ sd_device *ret = NULL;
     843             :         int r;
     844             : 
     845           0 :         assert(new_device);
     846           0 :         assert(syspath);
     847           0 :         assert(action);
     848             : 
     849           0 :         r = sd_device_new_from_syspath(&ret, syspath);
     850           0 :         if (r < 0)
     851           0 :                 return r;
     852             : 
     853           0 :         r = device_read_uevent_file(ret);
     854           0 :         if (r < 0)
     855           0 :                 return r;
     856             : 
     857           0 :         r = device_add_property_internal(ret, "ACTION", action);
     858           0 :         if (r < 0)
     859           0 :                 return r;
     860             : 
     861           0 :         *new_device = ret;
     862           0 :         ret = NULL;
     863             : 
     864           0 :         return 0;
     865             : }
     866             : 
     867           0 : int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
     868             :         const char *property, *value;
     869             :         int r;
     870             : 
     871           0 :         assert(device_dst);
     872           0 :         assert(device_src);
     873             : 
     874           0 :         FOREACH_DEVICE_PROPERTY(device_src, property, value) {
     875           0 :                 r = device_add_property(device_dst, property, value);
     876           0 :                 if (r < 0)
     877           0 :                         return r;
     878             :         }
     879             : 
     880           0 :         return 0;
     881             : }
     882             : 
     883           0 : void device_cleanup_tags(sd_device *device) {
     884           0 :         assert(device);
     885             : 
     886           0 :         set_free_free(device->tags);
     887           0 :         device->tags = NULL;
     888           0 :         device->property_tags_outdated = true;
     889           0 :         device->tags_generation ++;
     890           0 : }
     891             : 
     892           0 : void device_cleanup_devlinks(sd_device *device) {
     893           0 :         assert(device);
     894             : 
     895           0 :         set_free_free(device->devlinks);
     896           0 :         device->devlinks = NULL;
     897           0 :         device->property_devlinks_outdated = true;
     898           0 :         device->devlinks_generation ++;
     899           0 : }
     900             : 
     901           0 : void device_remove_tag(sd_device *device, const char *tag) {
     902           0 :         assert(device);
     903           0 :         assert(tag);
     904             : 
     905           0 :         free(set_remove(device->tags, tag));
     906           0 :         device->property_tags_outdated = true;
     907           0 :         device->tags_generation ++;
     908           0 : }
     909             : 
     910           0 : static int device_tag(sd_device *device, const char *tag, bool add) {
     911             :         const char *id;
     912             :         char *path;
     913             :         int r;
     914             : 
     915           0 :         assert(device);
     916           0 :         assert(tag);
     917             : 
     918           0 :         r = device_get_id_filename(device, &id);
     919           0 :         if (r < 0)
     920           0 :                 return r;
     921             : 
     922           0 :         path = strjoina("/run/udev/tags/", tag, "/", id);
     923             : 
     924           0 :         if (add) {
     925           0 :                 r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
     926           0 :                 if (r < 0)
     927           0 :                         return r;
     928             :         } else {
     929           0 :                 r = unlink(path);
     930           0 :                 if (r < 0 && errno != ENOENT)
     931           0 :                         return -errno;
     932             :         }
     933             : 
     934           0 :         return 0;
     935             : }
     936             : 
     937           0 : int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
     938             :         const char *tag;
     939           0 :         int r = 0, k;
     940             : 
     941           0 :         if (add && device_old) {
     942             :                 /* delete possible left-over tags */
     943           0 :                 FOREACH_DEVICE_TAG(device_old, tag) {
     944           0 :                         if (!sd_device_has_tag(device, tag)) {
     945           0 :                                 k = device_tag(device_old, tag, false);
     946           0 :                                 if (r >= 0 && k < 0)
     947           0 :                                         r = k;
     948             :                         }
     949             :                 }
     950             :         }
     951             : 
     952           0 :         FOREACH_DEVICE_TAG(device, tag) {
     953           0 :                 k = device_tag(device, tag, add);
     954           0 :                 if (r >= 0 && k < 0)
     955           0 :                         r = k;
     956             :         }
     957             : 
     958           0 :         return r;
     959             : }
     960             : 
     961           0 : static bool device_has_info(sd_device *device) {
     962           0 :         assert(device);
     963             : 
     964           0 :         if (!set_isempty(device->devlinks))
     965           0 :                 return true;
     966             : 
     967           0 :         if (device->devlink_priority != 0)
     968           0 :                 return true;
     969             : 
     970           0 :         if (!ordered_hashmap_isempty(device->properties_db))
     971           0 :                 return true;
     972             : 
     973           0 :         if (!set_isempty(device->tags))
     974           0 :                 return true;
     975             : 
     976           0 :         if (device->watch_handle >= 0)
     977           0 :                 return true;
     978             : 
     979           0 :         return false;
     980             : }
     981             : 
     982           0 : void device_set_db_persist(sd_device *device) {
     983           0 :         assert(device);
     984             : 
     985           0 :         device->db_persist = true;
     986           0 : }
     987             : 
     988           0 : int device_update_db(sd_device *device) {
     989             :         const char *id;
     990             :         char *path;
     991           0 :         _cleanup_fclose_ FILE *f = NULL;
     992           0 :         _cleanup_free_ char *path_tmp = NULL;
     993             :         bool has_info;
     994             :         int r;
     995             : 
     996           0 :         assert(device);
     997             : 
     998           0 :         has_info = device_has_info(device);
     999             : 
    1000           0 :         r = device_get_id_filename(device, &id);
    1001           0 :         if (r < 0)
    1002           0 :                 return r;
    1003             : 
    1004           0 :         path = strjoina("/run/udev/data/", id);
    1005             : 
    1006             :         /* do not store anything for otherwise empty devices */
    1007           0 :         if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
    1008           0 :                 r = unlink(path);
    1009           0 :                 if (r < 0 && errno != ENOENT)
    1010           0 :                         return -errno;
    1011             : 
    1012           0 :                 return 0;
    1013             :         }
    1014             : 
    1015             :         /* write a database file */
    1016           0 :         r = mkdir_parents(path, 0755);
    1017           0 :         if (r < 0)
    1018           0 :                 return r;
    1019             : 
    1020           0 :         r = fopen_temporary(path, &f, &path_tmp);
    1021           0 :         if (r < 0)
    1022           0 :                 return r;
    1023             : 
    1024             :         /*
    1025             :          * set 'sticky' bit to indicate that we should not clean the
    1026             :          * database when we transition from initramfs to the real root
    1027             :          */
    1028           0 :         if (device->db_persist) {
    1029           0 :                 r = fchmod(fileno(f), 01644);
    1030           0 :                 if (r < 0) {
    1031           0 :                         r = -errno;
    1032           0 :                         goto fail;
    1033             :                 }
    1034             :         } else {
    1035           0 :                 r = fchmod(fileno(f), 0644);
    1036           0 :                 if (r < 0) {
    1037           0 :                         r = -errno;
    1038           0 :                         goto fail;
    1039             :                 }
    1040             :         }
    1041             : 
    1042           0 :         if (has_info) {
    1043             :                 const char *property, *value, *tag;
    1044             :                 Iterator i;
    1045             : 
    1046           0 :                 if (major(device->devnum) > 0) {
    1047             :                         const char *devlink;
    1048             : 
    1049           0 :                         FOREACH_DEVICE_DEVLINK(device, devlink)
    1050           0 :                                 fprintf(f, "S:%s\n", devlink + strlen("/dev/"));
    1051             : 
    1052           0 :                         if (device->devlink_priority != 0)
    1053           0 :                                 fprintf(f, "L:%i\n", device->devlink_priority);
    1054             : 
    1055           0 :                         if (device->watch_handle >= 0)
    1056           0 :                                 fprintf(f, "W:%i\n", device->watch_handle);
    1057             :                 }
    1058             : 
    1059           0 :                 if (device->usec_initialized > 0)
    1060           0 :                         fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
    1061             : 
    1062           0 :                 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
    1063           0 :                         fprintf(f, "E:%s=%s\n", property, value);
    1064             : 
    1065           0 :                 FOREACH_DEVICE_TAG(device, tag)
    1066           0 :                         fprintf(f, "G:%s\n", tag);
    1067             :         }
    1068             : 
    1069           0 :         r = fflush_and_check(f);
    1070           0 :         if (r < 0)
    1071           0 :                 goto fail;
    1072             : 
    1073           0 :         r = rename(path_tmp, path);
    1074           0 :         if (r < 0) {
    1075           0 :                 r = -errno;
    1076           0 :                 goto fail;
    1077             :         }
    1078             : 
    1079           0 :         log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
    1080             :                   path, device->devpath);
    1081             : 
    1082           0 :         return 0;
    1083             : 
    1084             : fail:
    1085           0 :         log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty",
    1086             :                         path, device->devpath);
    1087           0 :         unlink(path);
    1088           0 :         unlink(path_tmp);
    1089             : 
    1090           0 :         return r;
    1091             : }
    1092             : 
    1093           0 : int device_delete_db(sd_device *device) {
    1094             :         const char *id;
    1095             :         char *path;
    1096             :         int r;
    1097             : 
    1098           0 :         assert(device);
    1099             : 
    1100           0 :         r = device_get_id_filename(device, &id);
    1101           0 :         if (r < 0)
    1102           0 :                 return r;
    1103             : 
    1104           0 :         path = strjoina("/run/udev/data/", id);
    1105             : 
    1106           0 :         r = unlink(path);
    1107           0 :         if (r < 0 && errno != ENOENT)
    1108           0 :                 return -errno;
    1109             : 
    1110           0 :         return 0;
    1111             : }
    1112             : 
    1113           0 : int device_read_db_force(sd_device *device) {
    1114           0 :         assert(device);
    1115             : 
    1116           0 :         return device_read_db_aux(device, true);
    1117             : }

Generated by: LCOV version 1.11