OpenSolaris_b135/lib/libdevinfo/devinfo_devlink.h

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 */