![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0-or-later 0002 /* 0003 * lib/textsearch.c Generic text search interface 0004 * 0005 * Authors: Thomas Graf <tgraf@suug.ch> 0006 * Pablo Neira Ayuso <pablo@netfilter.org> 0007 * 0008 * ========================================================================== 0009 */ 0010 0011 /** 0012 * DOC: ts_intro 0013 * INTRODUCTION 0014 * 0015 * The textsearch infrastructure provides text searching facilities for 0016 * both linear and non-linear data. Individual search algorithms are 0017 * implemented in modules and chosen by the user. 0018 * 0019 * ARCHITECTURE 0020 * 0021 * .. code-block:: none 0022 * 0023 * User 0024 * +----------------+ 0025 * | finish()|<--------------(6)-----------------+ 0026 * |get_next_block()|<--------------(5)---------------+ | 0027 * | | Algorithm | | 0028 * | | +------------------------------+ 0029 * | | | init() find() destroy() | 0030 * | | +------------------------------+ 0031 * | | Core API ^ ^ ^ 0032 * | | +---------------+ (2) (4) (8) 0033 * | (1)|----->| prepare() |---+ | | 0034 * | (3)|----->| find()/next() |-----------+ | 0035 * | (7)|----->| destroy() |----------------------+ 0036 * +----------------+ +---------------+ 0037 * 0038 * (1) User configures a search by calling textsearch_prepare() specifying 0039 * the search parameters such as the pattern and algorithm name. 0040 * (2) Core requests the algorithm to allocate and initialize a search 0041 * configuration according to the specified parameters. 0042 * (3) User starts the search(es) by calling textsearch_find() or 0043 * textsearch_next() to fetch subsequent occurrences. A state variable 0044 * is provided to the algorithm to store persistent variables. 0045 * (4) Core eventually resets the search offset and forwards the find() 0046 * request to the algorithm. 0047 * (5) Algorithm calls get_next_block() provided by the user continuously 0048 * to fetch the data to be searched in block by block. 0049 * (6) Algorithm invokes finish() after the last call to get_next_block 0050 * to clean up any leftovers from get_next_block. (Optional) 0051 * (7) User destroys the configuration by calling textsearch_destroy(). 0052 * (8) Core notifies the algorithm to destroy algorithm specific 0053 * allocations. (Optional) 0054 * 0055 * USAGE 0056 * 0057 * Before a search can be performed, a configuration must be created 0058 * by calling textsearch_prepare() specifying the searching algorithm, 0059 * the pattern to look for and flags. As a flag, you can set TS_IGNORECASE 0060 * to perform case insensitive matching. But it might slow down 0061 * performance of algorithm, so you should use it at own your risk. 0062 * The returned configuration may then be used for an arbitrary 0063 * amount of times and even in parallel as long as a separate struct 0064 * ts_state variable is provided to every instance. 0065 * 0066 * The actual search is performed by either calling 0067 * textsearch_find_continuous() for linear data or by providing 0068 * an own get_next_block() implementation and 0069 * calling textsearch_find(). Both functions return 0070 * the position of the first occurrence of the pattern or UINT_MAX if 0071 * no match was found. Subsequent occurrences can be found by calling 0072 * textsearch_next() regardless of the linearity of the data. 0073 * 0074 * Once you're done using a configuration it must be given back via 0075 * textsearch_destroy. 0076 * 0077 * EXAMPLE:: 0078 * 0079 * int pos; 0080 * struct ts_config *conf; 0081 * struct ts_state state; 0082 * const char *pattern = "chicken"; 0083 * const char *example = "We dance the funky chicken"; 0084 * 0085 * conf = textsearch_prepare("kmp", pattern, strlen(pattern), 0086 * GFP_KERNEL, TS_AUTOLOAD); 0087 * if (IS_ERR(conf)) { 0088 * err = PTR_ERR(conf); 0089 * goto errout; 0090 * } 0091 * 0092 * pos = textsearch_find_continuous(conf, &state, example, strlen(example)); 0093 * if (pos != UINT_MAX) 0094 * panic("Oh my god, dancing chickens at %d\n", pos); 0095 * 0096 * textsearch_destroy(conf); 0097 */ 0098 /* ========================================================================== */ 0099 0100 #include <linux/module.h> 0101 #include <linux/types.h> 0102 #include <linux/string.h> 0103 #include <linux/init.h> 0104 #include <linux/rculist.h> 0105 #include <linux/rcupdate.h> 0106 #include <linux/err.h> 0107 #include <linux/textsearch.h> 0108 #include <linux/slab.h> 0109 0110 static LIST_HEAD(ts_ops); 0111 static DEFINE_SPINLOCK(ts_mod_lock); 0112 0113 static inline struct ts_ops *lookup_ts_algo(const char *name) 0114 { 0115 struct ts_ops *o; 0116 0117 rcu_read_lock(); 0118 list_for_each_entry_rcu(o, &ts_ops, list) { 0119 if (!strcmp(name, o->name)) { 0120 if (!try_module_get(o->owner)) 0121 o = NULL; 0122 rcu_read_unlock(); 0123 return o; 0124 } 0125 } 0126 rcu_read_unlock(); 0127 0128 return NULL; 0129 } 0130 0131 /** 0132 * textsearch_register - register a textsearch module 0133 * @ops: operations lookup table 0134 * 0135 * This function must be called by textsearch modules to announce 0136 * their presence. The specified &@ops must have %name set to a 0137 * unique identifier and the callbacks find(), init(), get_pattern(), 0138 * and get_pattern_len() must be implemented. 0139 * 0140 * Returns 0 or -EEXISTS if another module has already registered 0141 * with same name. 0142 */ 0143 int textsearch_register(struct ts_ops *ops) 0144 { 0145 int err = -EEXIST; 0146 struct ts_ops *o; 0147 0148 if (ops->name == NULL || ops->find == NULL || ops->init == NULL || 0149 ops->get_pattern == NULL || ops->get_pattern_len == NULL) 0150 return -EINVAL; 0151 0152 spin_lock(&ts_mod_lock); 0153 list_for_each_entry(o, &ts_ops, list) { 0154 if (!strcmp(ops->name, o->name)) 0155 goto errout; 0156 } 0157 0158 list_add_tail_rcu(&ops->list, &ts_ops); 0159 err = 0; 0160 errout: 0161 spin_unlock(&ts_mod_lock); 0162 return err; 0163 } 0164 EXPORT_SYMBOL(textsearch_register); 0165 0166 /** 0167 * textsearch_unregister - unregister a textsearch module 0168 * @ops: operations lookup table 0169 * 0170 * This function must be called by textsearch modules to announce 0171 * their disappearance for examples when the module gets unloaded. 0172 * The &ops parameter must be the same as the one during the 0173 * registration. 0174 * 0175 * Returns 0 on success or -ENOENT if no matching textsearch 0176 * registration was found. 0177 */ 0178 int textsearch_unregister(struct ts_ops *ops) 0179 { 0180 int err = 0; 0181 struct ts_ops *o; 0182 0183 spin_lock(&ts_mod_lock); 0184 list_for_each_entry(o, &ts_ops, list) { 0185 if (o == ops) { 0186 list_del_rcu(&o->list); 0187 goto out; 0188 } 0189 } 0190 0191 err = -ENOENT; 0192 out: 0193 spin_unlock(&ts_mod_lock); 0194 return err; 0195 } 0196 EXPORT_SYMBOL(textsearch_unregister); 0197 0198 struct ts_linear_state 0199 { 0200 unsigned int len; 0201 const void *data; 0202 }; 0203 0204 static unsigned int get_linear_data(unsigned int consumed, const u8 **dst, 0205 struct ts_config *conf, 0206 struct ts_state *state) 0207 { 0208 struct ts_linear_state *st = (struct ts_linear_state *) state->cb; 0209 0210 if (likely(consumed < st->len)) { 0211 *dst = st->data + consumed; 0212 return st->len - consumed; 0213 } 0214 0215 return 0; 0216 } 0217 0218 /** 0219 * textsearch_find_continuous - search a pattern in continuous/linear data 0220 * @conf: search configuration 0221 * @state: search state 0222 * @data: data to search in 0223 * @len: length of data 0224 * 0225 * A simplified version of textsearch_find() for continuous/linear data. 0226 * Call textsearch_next() to retrieve subsequent matches. 0227 * 0228 * Returns the position of first occurrence of the pattern or 0229 * %UINT_MAX if no occurrence was found. 0230 */ 0231 unsigned int textsearch_find_continuous(struct ts_config *conf, 0232 struct ts_state *state, 0233 const void *data, unsigned int len) 0234 { 0235 struct ts_linear_state *st = (struct ts_linear_state *) state->cb; 0236 0237 conf->get_next_block = get_linear_data; 0238 st->data = data; 0239 st->len = len; 0240 0241 return textsearch_find(conf, state); 0242 } 0243 EXPORT_SYMBOL(textsearch_find_continuous); 0244 0245 /** 0246 * textsearch_prepare - Prepare a search 0247 * @algo: name of search algorithm 0248 * @pattern: pattern data 0249 * @len: length of pattern 0250 * @gfp_mask: allocation mask 0251 * @flags: search flags 0252 * 0253 * Looks up the search algorithm module and creates a new textsearch 0254 * configuration for the specified pattern. 0255 * 0256 * Note: The format of the pattern may not be compatible between 0257 * the various search algorithms. 0258 * 0259 * Returns a new textsearch configuration according to the specified 0260 * parameters or a ERR_PTR(). If a zero length pattern is passed, this 0261 * function returns EINVAL. 0262 */ 0263 struct ts_config *textsearch_prepare(const char *algo, const void *pattern, 0264 unsigned int len, gfp_t gfp_mask, int flags) 0265 { 0266 int err = -ENOENT; 0267 struct ts_config *conf; 0268 struct ts_ops *ops; 0269 0270 if (len == 0) 0271 return ERR_PTR(-EINVAL); 0272 0273 ops = lookup_ts_algo(algo); 0274 #ifdef CONFIG_MODULES 0275 /* 0276 * Why not always autoload you may ask. Some users are 0277 * in a situation where requesting a module may deadlock, 0278 * especially when the module is located on a NFS mount. 0279 */ 0280 if (ops == NULL && flags & TS_AUTOLOAD) { 0281 request_module("ts_%s", algo); 0282 ops = lookup_ts_algo(algo); 0283 } 0284 #endif 0285 0286 if (ops == NULL) 0287 goto errout; 0288 0289 conf = ops->init(pattern, len, gfp_mask, flags); 0290 if (IS_ERR(conf)) { 0291 err = PTR_ERR(conf); 0292 goto errout; 0293 } 0294 0295 conf->ops = ops; 0296 return conf; 0297 0298 errout: 0299 if (ops) 0300 module_put(ops->owner); 0301 0302 return ERR_PTR(err); 0303 } 0304 EXPORT_SYMBOL(textsearch_prepare); 0305 0306 /** 0307 * textsearch_destroy - destroy a search configuration 0308 * @conf: search configuration 0309 * 0310 * Releases all references of the configuration and frees 0311 * up the memory. 0312 */ 0313 void textsearch_destroy(struct ts_config *conf) 0314 { 0315 if (conf->ops) { 0316 if (conf->ops->destroy) 0317 conf->ops->destroy(conf); 0318 module_put(conf->ops->owner); 0319 } 0320 0321 kfree(conf); 0322 } 0323 EXPORT_SYMBOL(textsearch_destroy);
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |