/* * linux/lib/string.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include #include #include #ifndef __HAVE_ARCH_STRNICMP /** * strnicmp - Case insensitive, length-limited string comparison * @s1: One string * @s2: The other string * @len: the maximum number of characters to compare */ int strnicmp(const char *s1, const char *s2, size_t len) { /* Yes, Virginia, it had better be unsigned */ unsigned char c1, c2; c1 = 0; c2 = 0; if (len) { do { c1 = *s1; c2 = *s2; s1++; s2++; if (!c1) break; if (!c2) break; if (c1 == c2) continue; c1 = tolower(c1); c2 = tolower(c2); if (c1 != c2) break; } while (--len); } return (int)c1 - (int)c2; } #endif #ifndef __HAVE_ARCH_STRCPY /** * strcpy - Copy a %NUL terminated string * @dest: Where to copy the string to * @src: Where to copy the string from */ char * strcpy(char * dest,const char *src) { char *tmp = dest; while ((*dest++ = *src++) != '\0') /* nothing */; return tmp; } #endif #ifndef __HAVE_ARCH_STRNCPY /** * strncpy - Copy a length-limited, %NUL-terminated string * @dest: Where to copy the string to * @src: Where to copy the string from * @count: The maximum number of bytes to copy * * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. * However, the result is not %NUL-terminated if the source exceeds * @count bytes. */ char * strncpy(char * dest,const char *src,size_t count) { char *tmp = dest; while (count-- && (*dest++ = *src++) != '\0') /* nothing */; return tmp; } #endif #ifndef __HAVE_ARCH_STRLCPY /** * strlcpy - Copy a %NUL terminated string into a sized buffer * @dest: Where to copy the string to * @src: Where to copy the string from * @size: size of destination buffer * * Compatible with *BSD: the result is always a valid * NUL-terminated string that fits in the buffer (unless, * of course, the buffer size is zero). It does not pad * out the result like strncpy() does. */ size_t strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); if (size) { size_t len = (ret >= size) ? size-1 : ret; memcpy(dest, src, len); dest[len] = '\0'; } return ret; } EXPORT_SYMBOL(strlcpy); #endif #ifndef __HAVE_ARCH_STRCAT /** * strcat - Append one %NUL-terminated string to another * @dest: The string to be appended to * @src: The string to append to it */ char * strcat(char * dest, const char * src) { char *tmp = dest; while (*dest) dest++; while ((*dest++ = *src++) != '\0') ; return tmp; } #endif #ifndef __HAVE_ARCH_STRNCAT /** * strncat - Append a length-limited, %NUL-terminated string to another * @dest: The string to be appended to * @src: The string to append to it * @count: The maximum numbers of bytes to copy * * Note that in contrast to strncpy, strncat ensures the result is * terminated. */ char * strncat(char *dest, const char *src, size_t count) { char *tmp = dest; if (count) { while (*dest) dest++; while ((*dest++ = *src++)) { if (--count == 0) { *dest = '\0'; break; } } } return tmp; } #endif #ifndef __HAVE_ARCH_STRCMP /** * strcmp - Compare two strings * @cs: One string * @ct: Another string */ int strcmp(const char * cs,const char * ct) { register signed char __res; while (1) { if ((__res = *cs - *ct++) != 0 || !*cs++) break; } return __res; } #endif #ifndef __HAVE_ARCH_STRNCMP /** * strncmp - Compare two length-limited strings * @cs: One string * @ct: Another string * @count: The maximum number of bytes to compare */ int strncmp(const char * cs,const char * ct,size_t count) { register signed char __res = 0; while (count) { if ((__res = *cs - *ct++) != 0 || !*cs++) break; count--; } return __res; } #endif #ifndef __HAVE_ARCH_STRCHR /** * strchr - Find the first occurrence of a character in a string * @s: The string to be searched * @c: The character to search for */ char * strchr(const char * s, int c) { for(; *s != (char) c; ++s) if (*s == '\0') return NULL; return (char *) s; } #endif #ifndef __HAVE_ARCH_STRRCHR /** * strrchr - Find the last occurrence of a character in a string * @s: The string to be searched * @c: The character to search for */ char * strrchr(const char * s, int c) { const char *p = s + strlen(s); do { if (*p == (char)c) return (char *)p; } while (--p >= s); return NULL; } #endif #ifndef __HAVE_ARCH_STRLEN /** * strlen - Find the length of a string * @s: The string to be sized */ size_t strlen(const char * s) { const char *sc; for (sc = s; *sc != '\0'; ++sc) /* nothing */; return sc - s; } #endif #ifndef __HAVE_ARCH_STRNLEN /** * strnlen - Find the length of a length-limited string * @s: The string to be sized * @count: The maximum number of bytes to search */ size_t strnlen(const char * s, size_t count) { const char *sc; for (sc = s; count-- && *sc != '\0'; ++sc) /* nothing */; return sc - s; } #endif #ifndef __HAVE_ARCH_STRSPN /** * strspn - Calculate the length of the initial substring of @s which only * contain letters in @accept * @s: The string to be searched * @accept: The string to search for */ size_t strspn(const char *s, const char *accept) { const char *p; const char *a; size_t count = 0; for (p = s; *p != '\0'; ++p) { for (a = accept; *a != '\0'; ++a) { if (*p == *a) break; } if (*a == '\0') return count; ++count; } return count; } #endif #ifndef __HAVE_ARCH_STRPBRK /** * strpbrk - Find the first occurrence of a set of characters * @cs: The string to be searched * @ct: The characters to search for */ char * strpbrk(const char * cs,const char * ct) { const char *sc1,*sc2; for( sc1 = cs; *sc1 != '\0'; ++sc1) { for( sc2 = ct; *sc2 != '\0'; ++sc2) { if (*sc1 == *sc2) return (char *) sc1; } } return NULL; } #endif #ifndef __HAVE_ARCH_STRSEP /** * strsep - Split a string into tokens * @s: The string to be searched * @ct: The characters to search for * * strsep() updates @s to point after the token, ready for the next call. * * It returns empty tokens, too, behaving exactly like the libc function * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. * Same semantics, slimmer shape. ;) */ char * strsep(char **s, const char *ct) { char *sbegin = *s, *end; if (sbegin == NULL) return NULL; end = strpbrk(sbegin, ct); if (end) *end++ = '\0'; *s = end; return sbegin; } #endif #ifndef __HAVE_ARCH_MEMSET /** * memset - Fill a region of memory with the given value * @s: Pointer to the start of the area. * @c: The byte to fill the area with * @count: The size of the area. * * Do not use memset() to access IO space, use memset_io() instead. */ void * memset(void * s,int c,size_t count) { char *xs = (char *) s; while (count--) *xs++ = c; return s; } #endif #ifndef __HAVE_ARCH_BCOPY /** * bcopy - Copy one area of memory to another * @src: Where to copy from * @dest: Where to copy to * @count: The size of the area. * * Note that this is the same as memcpy(), with the arguments reversed. * memcpy() is the standard, bcopy() is a legacy BSD function. * * You should not use this function to access IO space, use memcpy_toio() * or memcpy_fromio() instead. */ char * bcopy(const char * src, char * dest, int count) { char *tmp = dest; while (count--) *tmp++ = *src++; return dest; } #endif #ifndef __HAVE_ARCH_MEMCPY /** * memcpy - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * You should not use this function to access IO space, use memcpy_toio() * or memcpy_fromio() instead. */ void * memcpy(void * dest,const void *src,size_t count) { char *tmp = (char *) dest, *s = (char *) src; while (count--) *tmp++ = *s++; return dest; } #endif #ifndef __HAVE_ARCH_MEMMOVE /** * memmove - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * Unlike memcpy(), memmove() copes with overlapping areas. */ void * memmove(void * dest,const void *src,size_t count) { char *tmp, *s; if (dest <= src) { tmp = (char *) dest; s = (char *) src; while (count--) *tmp++ = *s++; } else { tmp = (char *) dest + count; s = (char *) src + count; while (count--) *--tmp = *--s; } return dest; } #endif #ifndef __HAVE_ARCH_MEMCMP /** * memcmp - Compare two areas of memory * @cs: One area of memory * @ct: Another area of memory * @count: The size of the area. */ int memcmp(const void * cs,const void * ct,size_t count) { const unsigned char *su1, *su2; int res = 0; for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) if ((res = *su1 - *su2) != 0) break; return res; } #endif #ifndef __HAVE_ARCH_MEMSCAN /** * memscan - Find a character in an area of memory. * @addr: The memory area * @c: The byte to search for * @size: The size of the area. * * returns the address of the first occurrence of @c, or 1 byte past * the area if @c is not found */ void * memscan(void * addr, int c, size_t size) { unsigned char * p = (unsigned char *) addr; while (size) { if (*p == c) return (void *) p; p++; size--; } return (void *) p; } #endif #ifndef __HAVE_ARCH_STRSTR /** * strstr - Find the first substring in a %NUL terminated string * @s1: The string to be searched * @s2: The string to search for */ char * strstr(const char * s1,const char * s2) { int l1, l2; l2 = strlen(s2); if (!l2) return (char *) s1; l1 = strlen(s1); while (l1 >= l2) { l1--; if (!memcmp(s1,s2,l2)) return (char *) s1; s1++; } return NULL; } #endif #ifndef __HAVE_ARCH_MEMCHR /** * memchr - Find a character in an area of memory. * @s: The memory area * @c: The byte to search for * @n: The size of the area. * * returns the address of the first occurrence of @c, or %NULL * if @c is not found */ void *memchr(const void *s, int c, size_t n) { const unsigned char *p = s; while (n-- != 0) { if ((unsigned char)c == *p++) { return (void *)(p-1); } } return NULL; } #endif /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: */ #n180'>180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
/*
 * netlink/cache-api.h		Caching API
 *
 *	This library is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation version 2.1
 *	of the License.
 *
 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
 */

#ifndef NETLINK_CACHE_API_H_
#define NETLINK_CACHE_API_H_

#include <netlink/netlink.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @ingroup cache
 * @defgroup cache_api Cache Implementation
 * @brief
 *
 * @par 1) Cache Definition
 * @code
 * struct nl_cache_ops my_cache_ops = {
 * 	.co_name		= "route/link",
 * 	.co_protocol		= NETLINK_ROUTE,
 * 	.co_hdrsize		= sizeof(struct ifinfomsg),
 * 	.co_obj_ops		= &my_obj_ops,
 * };
 * @endcode
 *
 * @par 2) 
 * @code
 * // The simplest way to fill a cache is by providing a request-update
 * // function which must trigger a complete dump on the kernel-side of
 * // whatever the cache covers.
 * static int my_request_update(struct nl_cache *cache,
 * 				struct nl_sock *socket)
 * {
 * 	// In this example, we request a full dump of the interface table
 * 	return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
 * }
 *
 * // The resulting netlink messages sent back will be fed into a message
 * // parser one at a time. The message parser has to extract all relevant
 * // information from the message and create an object reflecting the
 * // contents of the message and pass it on to the parser callback function
 * // provide which will add the object to the cache.
 * static int my_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
 * 			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
 * {
 * 	struct my_obj *obj;
 *
 * 	obj = my_obj_alloc();
 * 	obj->ce_msgtype = nlh->nlmsg_type;
 *
 * 	// Parse the netlink message and continue creating the object.
 *
 * 	err = pp->pp_cb((struct nl_object *) obj, pp);
 * 	if (err < 0)
 * 		goto errout;
 * }
 *
 * struct nl_cache_ops my_cache_ops = {
 * 	...
 * 	.co_request_update	= my_request_update,
 * 	.co_msg_parser		= my_msg_parser,
 * };
 * @endcode
 *
 * @par 3) Notification based Updates
 * @code
 * // Caches can be kept up-to-date based on notifications if the kernel
 * // sends out notifications whenever an object is added/removed/changed.
 * //
 * // It is trivial to support this, first a list of groups needs to be
 * // defined which are required to join in order to receive all necessary
 * // notifications. The groups are separated by address family to support
 * // the common situation where a separate group is used for each address
 * // family. If there is only one group, simply specify AF_UNSPEC.
 * static struct nl_af_group addr_groups[] = {
 * 	{ AF_INET,	RTNLGRP_IPV4_IFADDR },
 * 	{ AF_INET6,	RTNLGRP_IPV6_IFADDR },
 * 	{ END_OF_GROUP_LIST },
 * };
 *
 * // In order for the caching system to know the meaning of each message
 * // type it requires a table which maps each supported message type to
 * // a cache action, e.g. RTM_NEWADDR means address has been added or
 * // updated, RTM_DELADDR means address has been removed.
 * static struct nl_cache_ops rtnl_addr_ops = {
 * 	...
 * 	.co_msgtypes		= {
 * 					{ RTM_NEWADDR, NL_ACT_NEW, "new" },
 * 					{ RTM_DELADDR, NL_ACT_DEL, "del" },
 * 					{ RTM_GETADDR, NL_ACT_GET, "get" },
 * 					END_OF_MSGTYPES_LIST,
 * 				},
 * 	.co_groups		= addr_groups,
 * };
 *
 * // It is now possible to keep the cache up-to-date using the cache manager.
 * @endcode
 * @{
 */

enum {
	NL_ACT_UNSPEC,
	NL_ACT_NEW,
	NL_ACT_DEL,
	NL_ACT_GET,
	NL_ACT_SET,
	NL_ACT_CHANGE,
	__NL_ACT_MAX,
};

#define NL_ACT_MAX (__NL_ACT_MAX - 1)

#define END_OF_MSGTYPES_LIST	{ -1, -1, NULL }

/**
 * Message type to cache action association
 */
struct nl_msgtype
{
	/** Netlink message type */
	int			mt_id;

	/** Cache action to take */
	int			mt_act;

	/** Name of operation for human-readable printing */
	char *			mt_name;
};

/**
 * Address family to netlink group association
 */
struct nl_af_group
{
	/** Address family */
	int			ag_family;

	/** Netlink group identifier */
	int			ag_group;
};

#define END_OF_GROUP_LIST AF_UNSPEC, 0

struct nl_parser_param
{
	int             (*pp_cb)(struct nl_object *, struct nl_parser_param *);
	void *            pp_arg;
};

/**
 * Cache Operations
 */
struct nl_cache_ops
{
	char  *			co_name;

	int			co_hdrsize;
	int			co_protocol;
	struct nl_af_group *	co_groups;
	
	/**
	 * Called whenever an update of the cache is required. Must send
	 * a request message to the kernel requesting a complete dump.
	 */
	int   (*co_request_update)(struct nl_cache *, struct nl_sock *);

	/**
	 * Called whenever a message was received that needs to be parsed.
	 * Must parse the message and call the paser callback function
	 * (nl_parser_param) provided via the argument.
	 */
	int   (*co_msg_parser)(struct nl_cache_ops *, struct sockaddr_nl *,
			       struct nlmsghdr *, struct nl_parser_param *);

	struct nl_object_ops *	co_obj_ops;

	struct nl_cache_ops *co_next;
	struct nl_cache *co_major_cache;
	struct genl_ops *	co_genl;
	struct nl_msgtype	co_msgtypes[];
};

/** @} */

#ifdef __cplusplus
}
#endif

#endif