Print this page
10106 libreparse needs smatch fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libreparse/common/fs_reparse_lib.c
+++ new/usr/src/lib/libreparse/common/fs_reparse_lib.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 +/*
28 + * Copyright (c) 2018, Joyent, Inc.
29 + */
30 +
27 31 #include <stdio.h>
28 32 #include <stdlib.h>
29 33 #include <unistd.h>
30 34 #include <strings.h>
31 35 #include <string.h>
32 36 #include <dirent.h>
33 37 #include <sys/types.h>
34 38 #include <sys/stat.h>
35 39 #include <sys/param.h>
36 40 #include <sys/errno.h>
37 41 #include <limits.h>
38 42 #include <libnvpair.h>
39 43 #include <dlfcn.h>
40 44 #include <libintl.h>
41 45 #include <sys/systeminfo.h>
42 46 #include <sys/fs_reparse.h>
43 47 #include "rp_plugin.h"
44 48
45 49 #define MAXISALEN 257 /* based on sysinfo(2) man page */
46 50
47 51 static rp_proto_handle_t rp_proto_handle;
48 52 static rp_proto_plugin_t *rp_proto_list;
49 53
50 54 int rp_plugin_init(void);
51 55 static void proto_plugin_fini(void);
52 56 static rp_plugin_ops_t *rp_find_protocol(const char *svctype);
53 57
54 58 extern int errno;
55 59 static int rp_plugin_inited = 0;
56 60
57 61 /*
58 62 * reparse_create()
59 63 *
60 64 * Create a symlink at the specified 'path' as a reparse point.
61 65 * This function will fail if path refers to an existing file system
62 66 * object or an object named string already exists at the given path.
63 67 *
64 68 * return 0 if ok else return error code.
65 69 */
66 70 int
67 71 reparse_create(const char *path, const char *data)
68 72 {
69 73 int err;
70 74 struct stat sbuf;
71 75
72 76 if (path == NULL || data == NULL)
73 77 return (EINVAL);
74 78
75 79 if ((err = reparse_validate(data)) != 0)
76 80 return (err);
77 81
78 82 /* check if object exists */
79 83 if (lstat(path, &sbuf) == 0)
80 84 return (EEXIST);
81 85
82 86 return (symlink(data, path) ? errno : 0);
83 87 }
84 88
85 89 /*
86 90 * reparse_unparse()
87 91 *
88 92 * Convert an nvlist back to a string format suitable to write
89 93 * to the reparse point symlink body. The string returned is in
90 94 * allocated memory and must be freed by the caller.
91 95 *
92 96 * return 0 if ok else return error code.
93 97 */
94 98 int
95 99 reparse_unparse(nvlist_t *nvl, char **stringp)
96 100 {
97 101 int err, buflen;
98 102 char *buf, *stype, *val;
99 103 nvpair_t *curr;
100 104
101 105 if (nvl == NULL || stringp == NULL ||
102 106 ((curr = nvlist_next_nvpair(nvl, NULL)) == NULL))
103 107 return (EINVAL);
104 108
105 109 buflen = SYMLINK_MAX;
106 110 if ((buf = malloc(buflen)) == NULL)
107 111 return (ENOMEM);
108 112
109 113 err = 0;
110 114 (void) snprintf(buf, buflen, "%s", FS_REPARSE_TAG_STR);
111 115 while (curr != NULL) {
112 116 if (!(stype = nvpair_name(curr))) {
113 117 err = EINVAL;
114 118 break;
115 119 }
116 120 if ((strlcat(buf, FS_TOKEN_START_STR, buflen) >= buflen) ||
117 121 (strlcat(buf, stype, buflen) >= buflen) ||
118 122 (strlcat(buf, ":", buflen) >= buflen) ||
119 123 (nvpair_value_string(curr, &val) != 0) ||
120 124 (strlcat(buf, val, buflen) >= buflen) ||
121 125 (strlcat(buf, FS_TOKEN_END_STR, buflen) >= buflen)) {
122 126 err = E2BIG;
123 127 break;
124 128 }
125 129 curr = nvlist_next_nvpair(nvl, curr);
126 130 }
127 131 if (err != 0) {
128 132 free(buf);
129 133 return (err);
130 134 }
131 135 if (strlcat(buf, FS_REPARSE_TAG_END_STR, buflen) >= buflen) {
132 136 free(buf);
133 137 return (E2BIG);
134 138 }
135 139
136 140 *stringp = buf;
137 141 return (0);
138 142 }
139 143
140 144 /*
141 145 * reparse_deref()
142 146 *
143 147 * Accepts the service-specific item from the reparse point and returns
144 148 * the service-specific data requested. The caller specifies the size
145 149 * of the buffer provided via *bufsz.
146 150 *
147 151 * if ok return 0 and *bufsz is updated to contain the actual length of
148 152 * the returned results, else return error code. If the error code is
149 153 * EOVERFLOW; results do not fit in the buffer, *bufsz will be updated
150 154 * to contain the number of bytes needed to hold the results.
151 155 */
152 156 int
153 157 reparse_deref(const char *svc_type, const char *svc_data, char *buf,
154 158 size_t *bufsz)
155 159 {
156 160 rp_plugin_ops_t *ops;
157 161
158 162 if ((svc_type == NULL) || (svc_data == NULL) || (buf == NULL) ||
159 163 (bufsz == NULL))
160 164 return (EINVAL);
161 165
162 166 ops = rp_find_protocol(svc_type);
163 167 if ((ops != NULL) && (ops->rpo_deref != NULL))
164 168 return (ops->rpo_deref(svc_type, svc_data, buf, bufsz));
165 169
166 170 /* no plugin, return error */
167 171 return (ENOTSUP);
168 172 }
169 173
170 174 /*
171 175 * reparse_delete()
172 176 *
173 177 * Delete a reparse point at a given pathname. It will fail if
174 178 * a reparse point does not exist at the given path or the pathname
175 179 * is not a symlink.
176 180 *
177 181 * return 0 if ok else return error code.
178 182 */
179 183 int
180 184 reparse_delete(const char *path)
181 185 {
182 186 struct stat sbuf;
183 187
184 188 if (path == NULL)
185 189 return (EINVAL);
186 190
187 191 /* check if object exists */
188 192 if (lstat(path, &sbuf) != 0)
189 193 return (errno);
190 194
191 195 if ((sbuf.st_mode & S_IFLNK) != S_IFLNK)
192 196 return (EINVAL);
193 197
194 198 return (unlink(path) ? errno : 0);
195 199 }
196 200
197 201 /*
198 202 * reparse_add()
199 203 *
200 204 * Add a service type entry to a nvlist with a copy of svc_data,
201 205 * replacing one of the same type if already present.
202 206 *
203 207 * return 0 if ok else return error code.
204 208 */
205 209 int
206 210 reparse_add(nvlist_t *nvl, const char *svc_type, const char *svc_data)
207 211 {
208 212 int err;
209 213 char *buf;
210 214 size_t bufsz;
211 215 rp_plugin_ops_t *ops;
212 216
213 217 if ((nvl == NULL) || (svc_type == NULL) || (svc_data == NULL))
214 218 return (EINVAL);
215 219
216 220 bufsz = SYMLINK_MAX; /* no need to mess around */
217 221 if ((buf = malloc(bufsz)) == NULL)
218 222 return (ENOMEM);
219 223
220 224 ops = rp_find_protocol(svc_type);
221 225 if ((ops != NULL) && (ops->rpo_form != NULL))
222 226 err = ops->rpo_form(svc_type, svc_data, buf, &bufsz);
223 227 else
224 228 err = ENOTSUP; /* no plugin */
225 229
226 230 if (err != 0) {
227 231 free(buf);
228 232 return (err);
229 233 }
230 234
231 235 err = nvlist_add_string(nvl, svc_type, buf);
232 236 free(buf);
233 237 return (err);
234 238 }
235 239
236 240 /*
237 241 * reparse_remove()
238 242 *
239 243 * Remove a service type entry from the nvlist, if present.
240 244 *
241 245 * return 0 if ok else return error code.
242 246 */
243 247 int
244 248 reparse_remove(nvlist_t *nvl, const char *svc_type)
245 249 {
246 250 if ((nvl == NULL) || (svc_type == NULL))
247 251 return (EINVAL);
248 252
249 253 return (nvlist_remove_all(nvl, svc_type));
250 254 }
251 255
252 256 /*
253 257 * Returns true if name is "." or "..", otherwise returns false.
254 258 */
255 259 static boolean_t
256 260 rp_is_dot_or_dotdot(const char *name)
257 261 {
258 262 if (*name != '.')
259 263 return (B_FALSE);
260 264
261 265 if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))
262 266 return (B_TRUE);
263 267
264 268 return (B_FALSE);
265 269 }
266 270
↓ open down ↓ |
230 lines elided |
↑ open up ↑ |
267 271 static void
268 272 proto_plugin_fini()
269 273 {
270 274 rp_proto_plugin_t *p;
271 275
272 276 /*
273 277 * Protocols may call this framework during _fini
274 278 */
275 279 for (p = rp_proto_list; p != NULL; p = p->plugin_next) {
276 280 if (p->plugin_ops->rpo_fini)
277 - p->plugin_ops->rpo_fini();
281 + (void) p->plugin_ops->rpo_fini();
278 282 }
279 283 while ((p = rp_proto_list) != NULL) {
280 284 rp_proto_list = p->plugin_next;
281 285 if (p->plugin_handle != NULL)
282 286 (void) dlclose(p->plugin_handle);
283 287 free(p);
284 288 }
285 289
286 290 if (rp_proto_handle.rp_ops != NULL) {
287 291 free(rp_proto_handle.rp_ops);
288 292 rp_proto_handle.rp_ops = NULL;
289 293 }
290 294 rp_proto_handle.rp_num_proto = 0;
291 295 }
292 296
293 297 /*
294 298 * rp_plugin_init()
295 299 *
296 300 * Initialize the service type specific plugin modules.
297 301 * For each reparse service type, there should be a plugin library for it.
298 302 * This function walks /usr/lib/reparse directory for plugin libraries.
299 303 * For each plugin library found, initialize it and add it to the internal
300 304 * list of service type plugin. These are used for service type specific
301 305 * operations.
302 306 */
303 307 int
304 308 rp_plugin_init()
305 309 {
306 310 int err, ret = RP_OK;
307 311 char isa[MAXISALEN], dirpath[MAXPATHLEN], path[MAXPATHLEN];
308 312 int num_protos = 0;
309 313 rp_proto_handle_t *rp_hdl;
310 314 rp_proto_plugin_t *proto, *tmp;
311 315 rp_plugin_ops_t *plugin_ops;
312 316 struct stat st;
313 317 void *dlhandle;
314 318 DIR *dir;
315 319 struct dirent *dent;
316 320
317 321 #if defined(_LP64)
318 322 if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
319 323 isa[0] = '\0';
320 324 #else
321 325 isa[0] = '\0';
322 326 #endif
323 327
324 328 (void) snprintf(dirpath, MAXPATHLEN,
325 329 "%s/%s", RP_LIB_DIR, isa);
326 330
327 331 if ((dir = opendir(dirpath)) == NULL)
328 332 return (RP_NO_PLUGIN_DIR);
329 333
330 334 while ((dent = readdir(dir)) != NULL) {
331 335 if (rp_is_dot_or_dotdot(dent->d_name))
332 336 continue;
333 337
334 338 (void) snprintf(path, MAXPATHLEN,
335 339 "%s/%s", dirpath, dent->d_name);
336 340
337 341 /*
338 342 * If file doesn't exist, don't try to map it
339 343 */
340 344 if (stat(path, &st) < 0)
341 345 continue;
342 346 if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL)
343 347 continue;
344 348
345 349 plugin_ops = (rp_plugin_ops_t *)
346 350 dlsym(dlhandle, "rp_plugin_ops");
347 351 if (plugin_ops == NULL) {
348 352 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
349 353 "Error in plugin ops for service type %s\n%s\n"),
350 354 dent->d_name, dlerror());
351 355 (void) dlclose(dlhandle);
352 356 continue;
353 357 }
354 358 proto = (rp_proto_plugin_t *)
355 359 calloc(1, sizeof (rp_proto_plugin_t));
356 360 if (proto == NULL) {
357 361 (void) dlclose(dlhandle);
358 362 (void) fprintf(stderr,
359 363 dgettext(TEXT_DOMAIN, "No memory for plugin %s\n"),
360 364 dent->d_name);
361 365 ret = RP_NO_MEMORY;
362 366 break;
363 367 }
364 368
365 369 proto->plugin_ops = plugin_ops;
366 370 proto->plugin_handle = dlhandle;
367 371 num_protos++;
368 372 proto->plugin_next = rp_proto_list;
369 373 rp_proto_list = proto;
370 374 }
371 375
372 376 (void) closedir(dir);
373 377
374 378 if ((num_protos == 0) && (ret == 0))
375 379 ret = RP_NO_PLUGIN;
376 380 /*
377 381 * There was an error, so cleanup prior to return of failure.
378 382 */
379 383 if (ret != RP_OK) {
380 384 proto_plugin_fini();
381 385 return (ret);
382 386 }
383 387
384 388 rp_proto_handle.rp_ops = (rp_plugin_ops_t **)calloc(num_protos,
385 389 sizeof (rp_plugin_ops_t *));
386 390 if (!rp_proto_handle.rp_ops) {
387 391 proto_plugin_fini();
388 392 return (RP_NO_MEMORY);
389 393 }
390 394
391 395 rp_hdl = &rp_proto_handle;
392 396 rp_hdl->rp_num_proto = 0;
393 397 for (tmp = rp_proto_list; rp_hdl->rp_num_proto < num_protos &&
394 398 tmp != NULL; tmp = tmp->plugin_next) {
395 399
396 400 err = RP_OK;
397 401 if (tmp->plugin_ops->rpo_init != NULL)
398 402 err = tmp->plugin_ops->rpo_init();
399 403 if (err != RP_OK)
400 404 continue;
401 405 rp_hdl->rp_ops[rp_hdl->rp_num_proto++] = tmp->plugin_ops;
402 406 }
403 407
404 408 return (rp_hdl->rp_num_proto > 0 ? RP_OK : RP_NO_PLUGIN);
405 409 }
406 410
407 411
408 412 /*
409 413 * find_protocol()
410 414 *
411 415 * Search the plugin list for the specified protocol and return the
412 416 * ops vector. return NULL if protocol is not defined.
413 417 */
414 418 static rp_plugin_ops_t *
415 419 rp_find_protocol(const char *svc_type)
416 420 {
417 421 int i;
418 422 rp_plugin_ops_t *ops = NULL;
419 423
420 424 if (svc_type == NULL)
421 425 return (NULL);
422 426
423 427 if (rp_plugin_inited == 0) {
424 428 if (rp_plugin_init() == RP_OK)
425 429 rp_plugin_inited = 1;
426 430 else
427 431 return (NULL);
428 432 }
429 433
430 434 for (i = 0; i < rp_proto_handle.rp_num_proto; i++) {
431 435 ops = rp_proto_handle.rp_ops[i];
432 436 if (ops->rpo_supports_svc(svc_type))
433 437 return (ops);
434 438
435 439 }
436 440 return (NULL);
437 441 }
↓ open down ↓ |
150 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX