Print this page
NEX-19665 Several door servers don't properly handle exiting threads
Review by: Gordon Ross <gordon.ross@nexenta.com>
Review by: Evan Layton <evan.layton@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-1638 Updated DC Locator
Includes work by: matt.barden@nexenta.com, kevin.crowe@nexenta.com
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/idmap/idmapd/idmapd.c
+++ new/usr/src/cmd/idmap/idmapd/idmapd.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26
27 27 /*
28 28 * main() of idmapd(1M)
29 29 */
30 30
31 31 #include "idmapd.h"
32 32 #include <atomic.h>
33 33 #include <signal.h>
34 34 #include <rpc/pmap_clnt.h> /* for pmap_unset */
35 35 #include <string.h> /* strcmp */
36 36 #include <unistd.h> /* setsid */
37 37 #include <sys/types.h>
38 38 #include <memory.h>
39 39 #include <stropts.h>
40 40 #include <netconfig.h>
41 41 #include <sys/resource.h> /* rlimit */
42 42 #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */
43 43 #include <priv_utils.h> /* privileges */
44 44 #include <locale.h>
45 45 #include <sys/systeminfo.h>
46 46 #include <errno.h>
47 47 #include <sys/wait.h>
48 48 #include <sys/time.h>
49 49 #include <zone.h>
50 50 #include <door.h>
51 51 #include <port.h>
52 52 #include <tsol/label.h>
53 53 #include <sys/resource.h>
54 54 #include <sys/sid.h>
55 55 #include <sys/idmap.h>
56 56 #include <pthread.h>
57 57 #include <stdarg.h>
58 58 #include <assert.h>
59 59 #include <note.h>
60 60
61 61 #define CBUFSIZ 26 /* ctime(3c) */
62 62
63 63 static void term_handler(int);
64 64 static void init_idmapd();
65 65 static void fini_idmapd();
66 66
67 67 /* The DC Locator lives inside idmap (for now). */
68 68 extern void init_dc_locator(void);
69 69 extern void fini_dc_locator(void);
70 70
71 71 idmapd_state_t _idmapdstate;
72 72
73 73 SVCXPRT *xprt = NULL;
74 74
75 75 static int dfd = -1; /* our door server fildes, for unregistration */
76 76 static boolean_t degraded = B_FALSE;
|
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
77 77
78 78
79 79 static uint32_t num_threads = 0;
80 80 static pthread_key_t create_threads_key;
81 81 static uint32_t max_threads = 40;
82 82
83 83 /*
84 84 * Server door thread start routine.
85 85 *
86 86 * Set a TSD value to the door thread. This enables the destructor to
87 - * be called when this thread exits.
87 + * be called when this thread exits. Note that we need a non-NULL
88 + * value for this or the TSD destructor is not called.
88 89 */
89 90 /*ARGSUSED*/
90 91 static void *
91 92 idmapd_door_thread_start(void *arg)
92 93 {
93 - static void *value = 0;
94 + static void *value = "NON-NULL TSD";
94 95
95 96 /*
96 97 * Disable cancellation to avoid memory leaks from not running
97 98 * the thread cleanup code.
98 99 */
99 100 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
100 101 (void) pthread_setspecific(create_threads_key, value);
101 102 (void) door_return(NULL, 0, NULL, 0);
102 103
103 104 /* make lint happy */
104 105 return (NULL);
105 106 }
106 107
107 108 /*
108 109 * Server door threads creation
109 110 */
110 111 /*ARGSUSED*/
111 112 static void
112 113 idmapd_door_thread_create(door_info_t *dip)
113 114 {
114 115 int num;
115 116 pthread_t thread_id;
116 117
117 118 if ((num = atomic_inc_32_nv(&num_threads)) > max_threads) {
118 119 atomic_dec_32(&num_threads);
119 120 idmapdlog(LOG_DEBUG,
120 121 "thread creation refused - %d threads currently active",
121 122 num - 1);
122 123 return;
123 124 }
124 125 (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL);
125 126 idmapdlog(LOG_DEBUG,
126 127 "created thread ID %d - %d threads currently active",
127 128 thread_id, num);
128 129 }
|
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
129 130
130 131 /*
131 132 * Server door thread cleanup
132 133 */
133 134 /*ARGSUSED*/
134 135 static void
135 136 idmapd_door_thread_cleanup(void *arg)
136 137 {
137 138 int num;
138 139
140 + /* set TSD to NULL so we don't loop infinitely */
141 + (void) pthread_setspecific(create_threads_key, NULL);
139 142 num = atomic_dec_32_nv(&num_threads);
140 143 idmapdlog(LOG_DEBUG,
141 144 "exiting thread ID %d - %d threads currently active",
142 145 pthread_self(), num);
143 146 }
144 147
145 148 /*
146 149 * This is needed for mech_krb5 -- we run as daemon, yes, but we want
147 150 * mech_krb5 to think we're root so it can get host/nodename.fqdn
148 151 * tickets for us so we can authenticate to AD as the machine account
149 152 * that we are. For more details look at the entry point in mech_krb5
150 153 * corresponding to gss_init_sec_context().
151 154 *
152 155 * As a side effect of faking our effective UID to mech_krb5 we will use
153 156 * root's default ccache (/tmp/krb5cc_0). But if that's created by
154 157 * another process then we won't have access to it: we run as daemon and
155 158 * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache
156 159 * with others. We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main()
157 160 * to avoid this issue; see main().
158 161 *
159 162 * Someday we'll have gss/mech_krb5 extensions for acquiring initiator
160 163 * creds with keytabs/raw keys, and someday we'll have extensions to
161 164 * libsasl to specify creds/name to use on the initiator side, and
162 165 * someday we'll have extensions to libldap to pass those through to
163 166 * libsasl. Until then this interposer will have to do.
164 167 *
165 168 * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid()
166 169 * is defined but not used.
167 170 */
168 171 /*LINTLIBRARY*/
169 172 uid_t
170 173 app_krb5_user_uid(void)
171 174 {
172 175 return (0);
173 176 }
174 177
175 178 /*ARGSUSED*/
176 179 static void
177 180 term_handler(int sig)
178 181 {
179 182 idmapdlog(LOG_INFO, "Terminating.");
180 183 fini_dc_locator();
181 184 fini_idmapd();
182 185 _exit(0);
183 186 }
184 187
185 188 /*ARGSUSED*/
186 189 static void
187 190 usr1_handler(int sig)
188 191 {
189 192 NOTE(ARGUNUSED(sig))
190 193 print_idmapdstate();
191 194 }
192 195
193 196 static int pipe_fd = -1;
194 197
195 198 static void
196 199 daemonize_ready(void)
197 200 {
198 201 char data = '\0';
199 202 /*
200 203 * wake the parent
201 204 */
202 205 (void) write(pipe_fd, &data, 1);
203 206 (void) close(pipe_fd);
204 207 }
205 208
206 209 static int
207 210 daemonize_start(void)
208 211 {
209 212 char data;
210 213 int status;
211 214 int devnull;
212 215 int filedes[2];
213 216 pid_t pid;
214 217
215 218 (void) sigset(SIGPIPE, SIG_IGN);
216 219 devnull = open("/dev/null", O_RDONLY);
217 220 if (devnull < 0)
218 221 return (-1);
219 222 (void) dup2(devnull, 0);
220 223 (void) dup2(2, 1); /* stderr only */
221 224 if (pipe(filedes) < 0)
222 225 return (-1);
223 226 if ((pid = fork1()) < 0)
224 227 return (-1);
225 228 if (pid != 0) {
226 229 /*
227 230 * parent
228 231 */
229 232 (void) close(filedes[1]);
230 233 if (read(filedes[0], &data, 1) == 1) {
231 234 /* presume success */
232 235 _exit(0);
233 236 }
234 237 status = -1;
235 238 (void) wait4(pid, &status, 0, NULL);
236 239 if (WIFEXITED(status))
237 240 _exit(WEXITSTATUS(status));
238 241 else
239 242 _exit(-1);
240 243 }
241 244
242 245 /*
243 246 * child
244 247 */
245 248 pipe_fd = filedes[1];
246 249 (void) close(filedes[0]);
247 250 (void) setsid();
248 251 (void) umask(0077);
249 252 openlog("idmap", LOG_PID, LOG_DAEMON);
250 253
251 254 return (0);
252 255 }
253 256
254 257
255 258 int
256 259 main(int argc, char **argv)
257 260 {
258 261 int c;
259 262 struct rlimit rl;
260 263
261 264 if (rwlock_init(&_idmapdstate.rwlk_cfg, USYNC_THREAD, NULL) != 0)
262 265 return (-1);
263 266 if (mutex_init(&_idmapdstate.addisc_lk, USYNC_THREAD, NULL) != 0)
264 267 return (-1);
265 268 if (cond_init(&_idmapdstate.addisc_cv, USYNC_THREAD, NULL) != 0)
266 269 return (-1);
267 270
268 271 _idmapdstate.daemon_mode = TRUE;
269 272 while ((c = getopt(argc, argv, "d")) != -1) {
270 273 switch (c) {
271 274 case 'd':
272 275 _idmapdstate.daemon_mode = FALSE;
273 276 break;
274 277 default:
275 278 (void) fprintf(stderr,
276 279 "Usage: /usr/lib/idmapd [-d]\n");
277 280 return (SMF_EXIT_ERR_CONFIG);
278 281 }
279 282 }
280 283
281 284 /* set locale and domain for internationalization */
282 285 (void) setlocale(LC_ALL, "");
283 286 (void) textdomain(TEXT_DOMAIN);
284 287
285 288 idmap_set_logger(idmapdlog);
286 289 adutils_set_logger(idmapdlog);
287 290
288 291 if (is_system_labeled() && getzoneid() != GLOBAL_ZONEID) {
289 292 idmapdlog(LOG_ERR,
290 293 "with Trusted Extensions idmapd runs only in the "
291 294 "global zone");
292 295 exit(1);
293 296 }
294 297
295 298 /*
296 299 * Raise the fd limit to max
297 300 */
298 301 if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
299 302 idmapdlog(LOG_ERR, "getrlimit failed");
300 303 } else if (rl.rlim_cur < rl.rlim_max) {
301 304 rl.rlim_cur = rl.rlim_max;
302 305 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
303 306 idmapdlog(LOG_ERR,
304 307 "Unable to raise RLIMIT_NOFILE to %d",
305 308 rl.rlim_cur);
306 309 }
307 310
308 311 (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL);
309 312
310 313 if (_idmapdstate.daemon_mode == TRUE) {
311 314 if (daemonize_start() < 0) {
312 315 idmapdlog(LOG_ERR, "unable to daemonize");
313 316 exit(-1);
314 317 }
315 318 } else
316 319 (void) umask(0077);
317 320
318 321 idmap_init_tsd_key();
319 322
320 323 init_idmapd();
321 324 init_dc_locator();
322 325
323 326 /* signal handlers that should run only after we're initialized */
324 327 (void) sigset(SIGTERM, term_handler);
325 328 (void) sigset(SIGUSR1, usr1_handler);
326 329 (void) sigset(SIGHUP, idmap_cfg_hup_handler);
327 330
328 331 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
329 332 DAEMON_UID, DAEMON_GID,
330 333 PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ,
331 334 (char *)NULL) == -1) {
332 335 idmapdlog(LOG_ERR, "unable to drop privileges");
333 336 exit(1);
334 337 }
335 338
336 339 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
337 340 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
338 341
339 342 if (_idmapdstate.daemon_mode == TRUE)
340 343 daemonize_ready();
341 344
342 345 /* With doors RPC this just wastes this thread, oh well */
343 346 svc_run();
344 347 return (0);
345 348 }
346 349
347 350 static void
348 351 init_idmapd()
349 352 {
350 353 int error;
351 354 int connmaxrec = IDMAP_MAX_DOOR_RPC;
352 355
353 356
354 357 /* create directories as root and chown to daemon uid */
355 358 if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0)
356 359 exit(1);
357 360 if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0)
358 361 exit(1);
359 362
360 363 /*
361 364 * Set KRB5CCNAME in the environment. See app_krb5_user_uid()
362 365 * for more details. We blow away the existing one, if there is
363 366 * one.
364 367 */
365 368 (void) unlink(IDMAP_CACHEDIR "/ccache");
366 369 (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache");
367 370 (void) putenv("MS_INTEROP=1");
368 371
369 372 if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname,
370 373 sizeof (_idmapdstate.hostname)) == -1) {
371 374 error = errno;
|
↓ open down ↓ |
223 lines elided |
↑ open up ↑ |
372 375 idmapdlog(LOG_ERR, "unable to determine hostname, error: %d",
373 376 error);
374 377 exit(1);
375 378 }
376 379
377 380 if ((error = init_mapping_system()) < 0) {
378 381 idmapdlog(LOG_ERR, "unable to initialize mapping system");
379 382 exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1);
380 383 }
381 384
385 + /*
386 + * This means max_threads can't be updated without restarting idmap.
387 + */
388 + RDLOCK_CONFIG();
389 + max_threads = _idmapdstate.cfg->pgcfg.max_threads;
390 + UNLOCK_CONFIG();
391 +
382 392 (void) door_server_create(idmapd_door_thread_create);
383 393 if ((error = pthread_key_create(&create_threads_key,
384 394 idmapd_door_thread_cleanup)) != 0) {
385 395 idmapdlog(LOG_ERR, "unable to create threads key (%s)",
386 396 strerror(error));
387 397 goto errout;
388 398 }
389 399
390 400 xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec);
391 401 if (xprt == NULL) {
392 402 idmapdlog(LOG_ERR, "unable to create door RPC service");
393 403 goto errout;
394 404 }
395 405
396 406 if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) {
397 407 idmapdlog(LOG_ERR, "unable to limit RPC request size");
398 408 goto errout;
399 409 }
400 410
401 411 dfd = xprt->xp_fd;
402 412
403 413 if (dfd == -1) {
404 414 idmapdlog(LOG_ERR, "unable to register door");
405 415 goto errout;
406 416 }
407 417 if ((error = __idmap_reg(dfd)) != 0) {
408 418 idmapdlog(LOG_ERR, "unable to register door (%s)",
409 419 strerror(errno));
410 420 goto errout;
411 421 }
412 422
413 423 if ((error = allocids(_idmapdstate.new_eph_db,
414 424 8192, &_idmapdstate.next_uid,
415 425 8192, &_idmapdstate.next_gid)) != 0) {
416 426 idmapdlog(LOG_ERR, "unable to allocate ephemeral IDs (%s)",
417 427 strerror(errno));
418 428 _idmapdstate.next_uid = IDMAP_SENTINEL_PID;
419 429 _idmapdstate.limit_uid = IDMAP_SENTINEL_PID;
420 430 _idmapdstate.next_gid = IDMAP_SENTINEL_PID;
421 431 _idmapdstate.limit_gid = IDMAP_SENTINEL_PID;
422 432 } else {
423 433 _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192;
424 434 _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192;
425 435 }
426 436
427 437 if (DBG(CONFIG, 1))
428 438 print_idmapdstate();
429 439
430 440 return;
431 441
432 442 errout:
433 443 fini_idmapd();
434 444 exit(1);
435 445 }
436 446
437 447 static void
438 448 fini_idmapd()
439 449 {
440 450 (void) __idmap_unreg(dfd);
441 451 fini_mapping_system();
442 452 if (xprt != NULL)
443 453 svc_destroy(xprt);
444 454 }
445 455
446 456 static
447 457 const char *
448 458 get_fmri(void)
449 459 {
450 460 static char *fmri = NULL;
451 461 static char buf[60];
452 462 char *s;
453 463
454 464 membar_consumer();
455 465 s = fmri;
456 466 if (s != NULL && *s == '\0')
457 467 return (NULL);
458 468 else if (s != NULL)
459 469 return (s);
460 470
461 471 if ((s = getenv("SMF_FMRI")) == NULL || strlen(s) >= sizeof (buf))
462 472 buf[0] = '\0';
463 473 else
464 474 (void) strlcpy(buf, s, sizeof (buf));
465 475
466 476 membar_producer();
467 477 fmri = buf;
468 478
469 479 return (get_fmri());
470 480 }
471 481
472 482 /*
473 483 * Wrappers for smf_degrade/restore_instance()
474 484 *
475 485 * smf_restore_instance() is too heavy duty to be calling every time we
476 486 * have a successful AD name<->SID lookup.
477 487 */
478 488 void
479 489 degrade_svc(int poke_discovery, const char *reason)
480 490 {
481 491 const char *fmri;
482 492
483 493 membar_consumer();
484 494 if (degraded)
485 495 return;
486 496
487 497 idmapdlog(LOG_ERR, "Degraded operation (%s).", reason);
488 498
489 499 membar_producer();
490 500 degraded = B_TRUE;
491 501
492 502 if ((fmri = get_fmri()) != NULL)
493 503 (void) smf_degrade_instance(fmri, 0);
494 504
495 505 /*
496 506 * If the config update thread is in a state where auto-discovery could
497 507 * be re-tried, then this will make it try it -- a sort of auto-refresh.
498 508 */
499 509 if (poke_discovery)
500 510 idmap_cfg_poke_updates();
501 511 }
502 512
503 513 void
504 514 restore_svc(void)
505 515 {
506 516 const char *fmri;
507 517
508 518 membar_consumer();
509 519 if (!degraded)
510 520 return;
511 521
512 522 if ((fmri = get_fmri()) == NULL)
513 523 (void) smf_restore_instance(fmri);
514 524
515 525 membar_producer();
516 526 degraded = B_FALSE;
517 527
518 528 idmapdlog(LOG_NOTICE, "Normal operation restored");
519 529 }
520 530
521 531
522 532 /* printflike */
523 533 void
524 534 idmapdlog(int pri, const char *format, ...) {
525 535 static time_t prev_ts;
526 536 va_list args;
527 537 char cbuf[CBUFSIZ];
528 538 time_t ts;
529 539
530 540 ts = time(NULL);
531 541 if (prev_ts != ts) {
532 542 prev_ts = ts;
533 543 /* NB: cbuf has \n */
534 544 (void) fprintf(stderr, "@ %s",
535 545 ctime_r(&ts, cbuf, sizeof (cbuf)));
536 546 }
537 547
538 548 va_start(args, format);
539 549 (void) vfprintf(stderr, format, args);
540 550 (void) fprintf(stderr, "\n");
541 551 va_end(args);
542 552
543 553 /*
544 554 * We don't want to fill up the logs with useless messages when
545 555 * we're degraded, but we still want to log.
546 556 */
547 557 if (degraded)
548 558 pri = LOG_DEBUG;
549 559
550 560 va_start(args, format);
551 561 vsyslog(pri, format, args);
552 562 va_end(args);
553 563 }
554 564
555 565 static void
556 566 trace_str(nvlist_t *entry, char *n1, char *n2, char *str)
557 567 {
558 568 char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */
559 569
560 570 (void) strlcpy(name, n1, sizeof (name));
561 571 if (n2 != NULL)
562 572 (void) strlcat(name, n2, sizeof (name));
563 573
564 574 (void) nvlist_add_string(entry, name, str);
565 575 }
566 576
567 577 static void
568 578 trace_int(nvlist_t *entry, char *n1, char *n2, int64_t i)
569 579 {
570 580 char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */
571 581
572 582 (void) strlcpy(name, n1, sizeof (name));
573 583 if (n2 != NULL)
574 584 (void) strlcat(name, n2, sizeof (name));
575 585
576 586 (void) nvlist_add_int64(entry, name, i);
577 587 }
578 588
579 589 static void
580 590 trace_sid(nvlist_t *entry, char *n1, char *n2, idmap_sid *sid)
581 591 {
582 592 char *str;
583 593
584 594 (void) asprintf(&str, "%s-%u", sid->prefix, sid->rid);
585 595 if (str == NULL)
586 596 return;
587 597
588 598 trace_str(entry, n1, n2, str);
589 599 free(str);
590 600 }
591 601
592 602 static void
593 603 trace_id(nvlist_t *entry, char *fromto, idmap_id *id, char *name, char *domain)
594 604 {
595 605 trace_int(entry, fromto, IDMAP_TRACE_TYPE, (int64_t)id->idtype);
596 606 if (IS_ID_SID(*id)) {
597 607 if (name != NULL) {
598 608 char *str;
599 609
600 610 (void) asprintf(&str, "%s%s%s", name,
601 611 domain == NULL ? "" : "@",
602 612 domain == NULL ? "" : domain);
603 613 if (str != NULL) {
604 614 trace_str(entry, fromto, IDMAP_TRACE_NAME, str);
605 615 free(str);
606 616 }
607 617 }
608 618 if (id->idmap_id_u.sid.prefix != NULL) {
609 619 trace_sid(entry, fromto, IDMAP_TRACE_SID,
610 620 &id->idmap_id_u.sid);
611 621 }
612 622 } else if (IS_ID_POSIX(*id)) {
613 623 if (name != NULL)
614 624 trace_str(entry, fromto, IDMAP_TRACE_NAME, name);
615 625 if (id->idmap_id_u.uid != IDMAP_SENTINEL_PID) {
616 626 trace_int(entry, fromto, IDMAP_TRACE_UNIXID,
617 627 (int64_t)id->idmap_id_u.uid);
618 628 }
619 629 }
620 630 }
621 631
622 632 /*
623 633 * Record a trace event. TRACE() has already decided whether or not
624 634 * tracing is required; what we do here is collect the data and send it
625 635 * to its destination - to the trace log in the response, if
626 636 * IDMAP_REQ_FLG_TRACE is set, and to the SMF service log, if debug/mapping
627 637 * is greater than zero.
628 638 */
629 639 int
630 640 trace(idmap_mapping *req, idmap_id_res *res, char *fmt, ...)
631 641 {
632 642 va_list va;
633 643 char *buf;
634 644 int err;
635 645 nvlist_t *entry;
636 646
637 647 assert(req != NULL);
638 648 assert(res != NULL);
639 649
640 650 err = nvlist_alloc(&entry, NV_UNIQUE_NAME, 0);
641 651 if (err != 0) {
642 652 (void) fprintf(stderr, "trace nvlist_alloc(entry): %s\n",
643 653 strerror(err));
644 654 return (0);
645 655 }
646 656
647 657 trace_id(entry, "from", &req->id1, req->id1name, req->id1domain);
648 658 trace_id(entry, "to", &res->id, req->id2name, req->id2domain);
649 659
650 660 if (IDMAP_ERROR(res->retcode)) {
651 661 trace_int(entry, IDMAP_TRACE_ERROR, NULL,
652 662 (int64_t)res->retcode);
653 663 }
654 664
655 665 va_start(va, fmt);
656 666 (void) vasprintf(&buf, fmt, va);
657 667 va_end(va);
658 668 if (buf != NULL) {
659 669 trace_str(entry, IDMAP_TRACE_MESSAGE, NULL, buf);
660 670 free(buf);
661 671 }
662 672
663 673 if (DBG(MAPPING, 1))
664 674 idmap_trace_print_1(stderr, "", entry);
665 675
666 676 if (req->flag & IDMAP_REQ_FLG_TRACE) {
667 677 /* Lazily allocate the trace list */
668 678 if (res->info.trace == NULL) {
669 679 err = nvlist_alloc(&res->info.trace, 0, 0);
670 680 if (err != 0) {
671 681 res->info.trace = NULL; /* just in case */
672 682 (void) fprintf(stderr,
673 683 "trace nvlist_alloc(trace): %s\n",
674 684 strerror(err));
675 685 nvlist_free(entry);
676 686 return (0);
677 687 }
678 688 }
679 689 (void) nvlist_add_nvlist(res->info.trace, "", entry);
680 690 /* Note that entry is copied, so we must still free our copy */
681 691 }
682 692
683 693 nvlist_free(entry);
684 694
685 695 return (0);
686 696 }
|
↓ open down ↓ |
295 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX