1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 * Copyright 2026 Oxide Computer Company 24 */ 25 26 27 #ifndef _DEVINFO_DEVLINK_H 28 #define _DEVINFO_DEVLINK_H 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #define _POSIX_PTHREAD_SEMANTICS /* For readdir_r */ 35 36 #include <stdio.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <string.h> 40 #include <thread.h> 41 #include <synch.h> 42 #include <libdevinfo.h> 43 #include <limits.h> 44 #include <stdlib.h> 45 #include <dirent.h> 46 #include <regex.h> 47 #include <errno.h> 48 #include <stdarg.h> 49 #include <sys/uio.h> 50 #include <sys/types.h> 51 #include <sys/stat.h> 52 #include <sys/time.h> 53 #include <sys/mman.h> 54 #include <sys/wait.h> 55 #include <door.h> 56 #include <signal.h> 57 #include <sys/statvfs.h> 58 #include <sys/ccompile.h> 59 #include <stdbool.h> 60 #include <time.h> 61 #include <sys/crc32.h> 62 63 struct db_link { 64 uint32_t attr; /* primary or secondary */ 65 uint32_t path; /* link path */ 66 uint32_t content; /* link content */ 67 uint32_t sib; /* next link for same minor */ 68 }; 69 70 struct db_minor { 71 uint32_t name; /* minor name */ 72 uint32_t nodetype; /* minor node type */ 73 uint32_t sib; /* next minor for same node */ 74 uint32_t link; /* next minor for same node */ 75 }; 76 77 struct db_node { 78 uint32_t path; /* node path */ 79 uint32_t sib; /* node's sibling */ 80 uint32_t child; /* first child for this node */ 81 uint32_t minor; /* first minor for node */ 82 }; 83 84 typedef enum db_seg { 85 DB_NODE = 0, 86 DB_MINOR, 87 DB_LINK, 88 DB_STR, 89 DB_TYPES, /* Number of non-header segments */ 90 DB_HEADER 91 } db_seg_t; 92 93 struct db_hdr { 94 uint32_t magic; /* Magic number */ 95 uint32_t vers; /* database format version */ 96 uint32_t root_idx; /* index for root node */ 97 uint32_t dngl_idx; /* head of DB dangling links */ 98 uint32_t page_sz; /* page size for mmap alignment */ 99 uint32_t update_count; /* updates since last /dev synch up */ 100 uint32_t nelems[DB_TYPES]; /* Number of elements of each type */ 101 /* 102 * The following fields allow database corruption to be detected. 103 * The CRCs cover each segment's data and are stored by the writer. 104 * The writer identity fields allow a reader which detects 105 * corruption to report which process produced the database, and 106 * when. 107 */ 108 uint32_t crc[DB_TYPES]; /* CRC32 of each segment */ 109 uint32_t writer_pid; /* process which wrote the DB */ 110 uint32_t hdr_pad; /* explicit padding, always zero */ 111 uint64_t writer_time; /* write time, seconds since epoch */ 112 char writer_exec[24]; /* basename of writer's executable */ 113 }; 114 115 116 typedef struct cache_link { 117 char *path; /* link path */ 118 char *content; /* link content */ 119 uint_t attr; /* link attributes */ 120 struct cache_link *hash; /* next link on same hash chain */ 121 struct cache_link *sib; /* next link for same minor */ 122 struct cache_minor *minor; /* minor for this link */ 123 } cache_link_t; 124 125 typedef struct cache_minor { 126 char *name; /* minor name */ 127 char *nodetype; /* minor nodetype */ 128 struct cache_node *node; /* node for this minor */ 129 struct cache_minor *sib; /* next minor for same node */ 130 struct cache_link *link; /* first link pointing to minor */ 131 } cache_minor_t; 132 133 typedef struct cache_node { 134 char *path; /* path */ 135 struct cache_node *parent; /* node's parent */ 136 struct cache_node *sib; /* node's sibling */ 137 struct cache_node *child; /* first child for this node */ 138 struct cache_minor *minor; /* first minor for node */ 139 } cache_node_t; 140 141 struct cache { 142 uint_t flags; /* cache state */ 143 uint_t update_count; /* updates since /dev synchronization */ 144 uint_t hash_sz; /* number of hash chains */ 145 cache_link_t **hash; /* hash table */ 146 cache_node_t *root; /* root of cache tree */ 147 cache_link_t *dngl; /* list of dangling links */ 148 cache_minor_t *last_minor; /* last minor looked up */ 149 }; 150 151 struct db { 152 int db_fd; /* database file */ 153 uint_t flags; /* database open mode */ 154 struct db_hdr *hdr; /* DB header */ 155 int seg_prot[DB_TYPES]; /* protection for segments */ 156 caddr_t seg_base[DB_TYPES]; /* base address for segments */ 157 uint32_t str_crc; /* running CRC of written strings */ 158 }; 159 160 struct di_devlink_handle { 161 char *dev_dir; /* <root-dir>/dev */ 162 char *db_dir; /* <root-dir>/etc/dev */ 163 uint_t flags; /* handle flags */ 164 uint_t error; /* records errors encountered */ 165 int lock_fd; /* lock file for updates */ 166 struct cache cache; 167 struct db db; 168 }; 169 170 typedef struct link_desc { 171 regex_t *regp; 172 const char *minor_path; 173 uint_t flags; 174 void *arg; 175 int (*fcn)(di_devlink_t, void *); 176 int retval; 177 } link_desc_t; 178 179 struct tnode { 180 void *node; 181 int flags; 182 struct di_devlink_handle *handle; 183 }; 184 185 struct di_devlink { 186 char *rel_path; 187 char *abs_path; 188 char *content; 189 int type; 190 }; 191 192 typedef struct recurse { 193 void *data; 194 int (*fcn)(struct di_devlink_handle *, void *, const char *); 195 } recurse_t; 196 197 /* 198 * Debug levels currently defined. 199 */ 200 typedef enum { 201 DBG_ERR = 1, 202 DBG_LCK, 203 DBG_INFO, 204 DBG_STEP, 205 DBG_ALL 206 } debug_level_t; 207 208 209 #define DB_MAGIC 0xBAC2ACAB 210 #define DB_FILE ".devlink_db" 211 #define DB_TMP ".devlink_db_tmp" 212 #define DB_LOCK ".devlink_db_lock" 213 #define DB_CORRUPT ".devlink_db_corrupt" 214 #define DB_PERMS (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR) 215 #define DB_LOCK_PERMS DB_PERMS 216 #define DB_VERSION 2 /* version 2 added CRCs and writer identity */ 217 218 #define DB_NIL 0 219 220 #define DEV "/dev" 221 #define ETCDEV "/etc/dev" 222 #define DEVICES_SUFFIX "ices" 223 224 #define HDR_LEN sizeof (struct db_hdr) 225 226 #define AVG_CHAIN_SIZE 20 /* Average number of links per chain */ 227 #define MIN_HASH_SIZE 1024 /* Min number of chains in hash table */ 228 #define MAX_UPDATE_INTERVAL 5 /* Max DB writes before synching with /dev */ 229 #define MAX_LOCK_RETRY 5 /* Max attempts at locking the update lock */ 230 231 /* 232 * Various flags private to the implementation 233 */ 234 #define A_PRIMARY 0x0001U 235 #define A_SECONDARY 0x0002U 236 #define A_LINK_TYPES 0x0003U /* Mask */ 237 #define A_VALID 0x0004U 238 239 #define TYPE_DB 0x0008U 240 #define TYPE_CACHE 0x0010U 241 #define CREATE_FLAG 0x0020U 242 243 #define INSERT_HEAD 0x0040U 244 #define INSERT_TAIL 0x0080U 245 #define OPEN_RDWR 0x0100U 246 #define OPEN_RDONLY 0x0200U 247 #define OPEN_FLAGS 0x0300U /* Mask */ 248 #define UNLINK_FROM_HASH 0x0400U 249 250 #define SET_VALID_ATTR(a) ((a) |= A_VALID) 251 #define CLR_VALID_ATTR(a) ((a) &= ~A_VALID) 252 #define GET_VALID_ATTR(a) ((a) & A_VALID) 253 254 #define SET_DB_ERR(h) ((h)->error = 1) 255 #define DB_ERR(h) ((h)->error) 256 257 #define LOOKUP_DB(f) ((f) & TYPE_DB) 258 #define LOOKUP_CACHE(f) ((f) & TYPE_CACHE) 259 #define CREATE_ELEM(f) ((f) & CREATE_FLAG) 260 261 #define IS_RDWR(f) (((f) & OPEN_FLAGS) == OPEN_RDWR) 262 #define IS_RDONLY(f) (((f) & OPEN_FLAGS) == OPEN_RDONLY) 263 264 #define HDL_RDWR(h) (((h)->flags & OPEN_FLAGS) == OPEN_RDWR) 265 #define HDL_RDONLY(h) (((h)->flags & OPEN_FLAGS) == OPEN_RDONLY) 266 267 #define CACHE(h) (&(h)->cache) 268 #define CACHE_ROOT(h) (CACHE(h)->root) 269 #define CACHE_HASH(h, i) (CACHE(h)->hash[i]) 270 #define CACHE_LAST(h) (CACHE(h)->last_minor) 271 #define CACHE_EMPTY(h) (CACHE(h)->root == NULL && CACHE(h)->dngl == NULL) 272 273 #define DB(h) (&(h)->db) 274 #define DB_HDR(h) (DB(h)->hdr) 275 #define DB_NUM(h, t) (DB_HDR(h)->nelems[t]) 276 #define DB_SEG(h, t) (DB(h)->seg_base[t]) 277 #define DB_SEG_PROT(h, t) (DB(h)->seg_prot[t]) 278 279 #define DB_OPEN(h) (DB_HDR(h) != NULL) 280 #define DB_RDWR(h) ((DB(h)->flags & OPEN_FLAGS) == OPEN_RDWR) 281 #define DB_RDONLY(h) ((DB(h)->flags & OPEN_FLAGS) == OPEN_RDONLY) 282 283 #define DB_EMPTY(h) (DB_HDR(h)->root_idx == DB_NIL && \ 284 DB_HDR(h)->dngl_idx == DB_NIL) 285 286 #define TYPE_NONE(f) (((f) & DI_LINK_TYPES) == 0) 287 #define TYPE_PRI(f) (((f) & DI_LINK_TYPES) == DI_PRIMARY_LINK) 288 #define TYPE_SEC(f) (((f) & DI_LINK_TYPES) == DI_SECONDARY_LINK) 289 #define LINK_TYPE(f) ((f) & DI_LINK_TYPES) 290 #define VALID_TYPE(f) (TYPE_NONE(f) || TYPE_PRI(f) || TYPE_SEC(f)) 291 292 #define VALID_STR(h, i, s) ((i) + strlen(s) + 1 <= DB_HDR(h)->nelems[DB_STR]) 293 #define VALID_INDEX(h, t, i) ((i) < DB_HDR(h)->nelems[t]) 294 295 /* 296 * Environment variables used by DEBUG version of code. 297 */ 298 #define SKIP_DB "DEBUG_SKIP_DB" 299 #define SKIP_LAST_CACHE "DEBUG_SKIP_LAST_CACHE" 300 #define ALT_DB_DIR "DEBUG_ALT_DB_DIR" 301 302 /* 303 * Function prototypes 304 */ 305 static struct di_devlink_handle *handle_alloc(const char *dev_dir, 306 uint_t flags); 307 static int cache_alloc(struct di_devlink_handle *hdp); 308 static int open_db(struct di_devlink_handle *hdp, int flags); 309 static int invalid_db(struct di_devlink_handle *hdp, size_t fsize, long pg_sz); 310 static int read_nodes(struct di_devlink_handle *hdp, cache_node_t *pcnp, 311 uint32_t nidx); 312 static int read_minors(struct di_devlink_handle *hdp, cache_node_t *pcnp, 313 uint32_t nidx); 314 static int read_links(struct di_devlink_handle *hdp, cache_minor_t *pcmp, 315 uint32_t nidx); 316 static int init_hdr(struct di_devlink_handle *hdp, long page_sz, 317 uint32_t *count); 318 static size_t size_db(struct di_devlink_handle *hdp, long page_sz, 319 uint32_t *count); 320 static size_t seg_size(struct di_devlink_handle *hdp, int seg); 321 322 static cache_node_t *node_insert(struct di_devlink_handle *hdp, 323 cache_node_t *pcnp, const char *path, int insert); 324 static cache_minor_t *minor_insert(struct di_devlink_handle *hdp, 325 cache_node_t *pcnp, const char *name, const char *nodetype, 326 cache_minor_t **prev); 327 static cache_link_t *link_insert(struct di_devlink_handle *hdp, 328 cache_minor_t *mnp, const char *path, const char *content, uint32_t attr); 329 330 static void minor_delete(di_devlink_handle_t hdp, cache_minor_t *cmnp); 331 static void link_delete(di_devlink_handle_t hdp, cache_link_t *clp); 332 333 static int write_nodes(struct di_devlink_handle *hdp, struct db_node *pdnp, 334 cache_node_t *cnp, uint32_t *next); 335 static int write_minors(struct di_devlink_handle *hdp, struct db_node *pdnp, 336 cache_minor_t *cmnp, uint32_t *next); 337 static int write_links(struct di_devlink_handle *hdp, struct db_minor *pdmp, 338 cache_link_t *clp, uint32_t *next); 339 static void rm_link_from_hash(struct di_devlink_handle *hdp, cache_link_t *clp); 340 static uint32_t write_string(struct di_devlink_handle *hdp, const char *str, 341 uint32_t *next); 342 static int close_db(struct di_devlink_handle *hdp); 343 static uint32_t devlink_crc32(uint32_t crc, const void *buf, size_t len); 344 static uint32_t segment_crc(struct di_devlink_handle *hdp, db_seg_t seg, 345 int prot); 346 static bool verify_db_crc(struct di_devlink_handle *hdp); 347 static void seal_db(struct di_devlink_handle *hdp, uint32_t *next); 348 static void devlink_db_fault(struct di_devlink_handle *hdp, 349 const char *fmt, ...) __PRINTFLIKE(2) __NORETURN; 350 static void cache_free(struct di_devlink_handle *hdp); 351 static void handle_free(struct di_devlink_handle **pp); 352 static void resolve_dangling_links(struct di_devlink_handle *hdp); 353 static void subtree_free(struct di_devlink_handle *hdp, cache_node_t **pp); 354 static void node_free(cache_node_t **pp); 355 static void minor_free(struct di_devlink_handle *hdp, cache_minor_t **pp); 356 static void link_free(cache_link_t **pp); 357 static void count_node(cache_node_t *cnp, uint32_t *count); 358 static void count_minor(cache_minor_t *mnp, uint32_t *count); 359 static void count_link(cache_link_t *clp, uint32_t *count); 360 static void count_string(const char *str, uint32_t *count); 361 static int visit_node(const char *path, void *arg); 362 static int walk_tree(char *cur, void *arg, 363 int (*node_callback)(const char *path, void *arg)); 364 static void *lookup_node(struct di_devlink_handle *hdp, char *path, 365 const int flags); 366 static cache_link_t *add_link(struct di_devlink_handle *hdp, const char *link, 367 const char *content, int primary); 368 369 static void *lookup_minor(struct di_devlink_handle *hdp, const char *minor_path, 370 const char *nodetype, const int flags); 371 static cache_link_t *link_hash(di_devlink_handle_t hdp, const char *link, 372 uint_t flags); 373 374 static void hash_insert(struct di_devlink_handle *hdp, cache_link_t *clp); 375 static uint_t hashfn(struct di_devlink_handle *hdp, const char *str); 376 static void get_db_path(struct di_devlink_handle *hdp, const char *fname, 377 char *buf, size_t blen); 378 379 static struct db_node *get_node(struct di_devlink_handle *hdp, uint32_t idx); 380 static struct db_node *set_node(struct di_devlink_handle *hdp, uint32_t idx); 381 382 static struct db_minor *get_minor(struct di_devlink_handle *hdp, uint32_t idx); 383 static struct db_minor *set_minor(struct di_devlink_handle *hdp, uint32_t idx); 384 385 static struct db_link *get_link(struct di_devlink_handle *hdp, uint32_t idx); 386 static struct db_link *set_link(struct di_devlink_handle *hdp, uint32_t idx); 387 388 static char *get_string(struct di_devlink_handle *hdp, uint32_t idx); 389 static char *set_string(struct di_devlink_handle *hdp, uint32_t idx); 390 391 static void *map_seg(struct di_devlink_handle *hdp, uint32_t idx, int prot, 392 db_seg_t seg); 393 394 static int walk_db(struct di_devlink_handle *hdp, link_desc_t *linkp); 395 static int walk_all_links(struct di_devlink_handle *hdp, link_desc_t *linkp); 396 static int walk_matching_links(struct di_devlink_handle *hdp, 397 link_desc_t *linkp); 398 static int visit_link(struct di_devlink_handle *hdp, link_desc_t *linkp, 399 struct di_devlink *vlp); 400 401 static void walk_cache_minor(di_devlink_handle_t hdp, const char *mpath, 402 link_desc_t *linkp); 403 static int walk_cache_links(di_devlink_handle_t hdp, cache_link_t *clp, 404 link_desc_t *linkp); 405 static void walk_all_cache(di_devlink_handle_t hdp, link_desc_t *linkp); 406 static int cache_dev_link(struct di_devlink_handle *hdp, void *data, 407 const char *link_path); 408 409 static int walk_dev(struct di_devlink_handle *hdp, link_desc_t *linkp); 410 static int recurse_dev(struct di_devlink_handle *hdp, recurse_t *rp); 411 static int do_recurse(const char *dir, struct di_devlink_handle *hdp, 412 recurse_t *rp, int *retp); 413 414 static int check_attr(uint32_t attr); 415 static int attr2type(uint32_t attr); 416 417 static int check_args(link_desc_t *linkp); 418 419 static void *get_last_node(struct di_devlink_handle *hdp, const char *path, 420 int flags); 421 static void *get_last_minor(struct di_devlink_handle *hdp, 422 const char *devfs_path, const char *minor_name, int flags); 423 static void set_last_minor(struct di_devlink_handle *hdp, cache_minor_t *cmnp, 424 int flags); 425 426 static int enter_db_lock(struct di_devlink_handle *hdp, const char *root_dir); 427 static void exit_db_lock(struct di_devlink_handle *hdp); 428 429 static char *minor_colon(const char *path); 430 static const char *rel_path(struct di_devlink_handle *hdp, const char *path); 431 static int link_flag(uint_t flags); 432 static int s_readlink(const char *link, char *buf, size_t blen); 433 static cache_minor_t *link2minor(struct di_devlink_handle *hdp, 434 cache_link_t *clp); 435 static int link_cmp(cache_link_t *clp, const char *content, int type); 436 static void delete_unused_nodes(di_devlink_handle_t hdp, cache_node_t *cnp); 437 static void delete_unused_minor(di_devlink_handle_t hdp, cache_minor_t *cmnp); 438 static int synchronize_db(di_devlink_handle_t hdp); 439 static void devlink_dprintf(debug_level_t msglevel, const char *fmt, ...); 440 static di_devlink_handle_t devlink_snapshot(const char *root_dir); 441 static int devlink_create(const char *root, const char *name, int dca_flags); 442 static int dca_init(const char *name, struct dca_off *dcp, int dca_flags); 443 static void exec_cmd(const char *root, struct dca_off *dcp); 444 static int do_exec(const char *path, char *const argv[]); 445 static int start_daemon(const char *root, int install); 446 static int daemon_call(const char *root, struct dca_off *dcp); 447 448 int is_minor_node(const char *contents, const char **mn_root); 449 char *s_realpath(const char *path, char *resolved_path); 450 451 #ifdef __cplusplus 452 } 453 #endif 454 455 #endif /* _DEVINFO_DEVLINK_H */ 456