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