1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include "nfs4_prot.h"
  28 #include "nfstcl4.h"
  29 #include "tcl.h"
  30 
  31 #define ATTR_NAME_LEN   25 /* longest attr name + space separator + null char */
  32 
  33 /* attributes table */
  34 ATTRINFO attr_info[] = {
  35         {"supported_attrs",     de_bitmap,      en_unimpl       }, /*  0 */
  36         {"type",                de_type,        en_type         }, /*  1 */
  37         {"fh_expire_type",      de_uint32,      en_uint32       }, /*  2 */
  38         {"change",              de_uint64,      en_uint64       }, /*  3 */
  39         {"size",                de_uint64,      en_uint64       }, /*  4 */
  40         {"link_support",        de_bool,        en_bool         }, /*  5 */
  41         {"symlink_support",     de_bool,        en_bool         }, /*  6 */
  42         {"named_attr",          de_bool,        en_bool         }, /*  7 */
  43         {"fsid",                de_fsid,        en_fsid         }, /*  8 */
  44         {"unique_handles",      de_bool,        en_bool         }, /*  9 */
  45         {"lease_time",          de_uint32,      en_uint32       }, /* 10 */
  46         {"rdattr_error",        de_stat4,       en_stat4        }, /* 11 */
  47         {"acl",                 de_acl,         en_acl          }, /* 12 */
  48         {"aclsupport",          de_uint32,      en_uint32       }, /* 13 */
  49         {"archive",             de_bool,        en_bool         }, /* 14 */
  50         {"cansettime",          de_bool,        en_bool         }, /* 15 */
  51         {"case_insensitive",    de_bool,        en_bool         }, /* 16 */
  52         {"case_preserving",     de_bool,        en_bool         }, /* 17 */
  53         {"chown_restricted",    de_bool,        en_bool         }, /* 18 */
  54         {"filehandle",          de_fhandle,     en_fhandle      }, /* 19 */
  55         {"fileid",              de_uint64,      en_uint64       }, /* 20 */
  56         {"files_avail",         de_uint64,      en_uint64       }, /* 21 */
  57         {"files_free",          de_uint64,      en_uint64       }, /* 22 */
  58         {"files_total",         de_uint64,      en_uint64       }, /* 23 */
  59         {"fs_locations",        de_fslocation,  en_unimpl       }, /* 24 */
  60         {"hidden",              de_bool,        en_bool         }, /* 25 */
  61         {"homogeneous",         de_bool,        en_bool         }, /* 26 */
  62         {"maxfilesize",         de_uint64,      en_uint64       }, /* 27 */
  63         {"maxlink",             de_uint32,      en_uint32       }, /* 28 */
  64         {"maxname",             de_uint32,      en_uint32       }, /* 29 */
  65         {"maxread",             de_uint64,      en_uint64       }, /* 30 */
  66         {"maxwrite",            de_uint64,      en_uint64       }, /* 31 */
  67         {"mimetype",            de_utf8string,  en_utf8string   }, /* 32 */
  68         {"mode",                de_mode,        en_mode         }, /* 33 */
  69         {"no_trunc",            de_bool,        en_bool         }, /* 34 */
  70         {"numlinks",            de_uint32,      en_uint32       }, /* 35 */
  71         {"owner",               de_utf8string,  en_utf8string   }, /* 36 */
  72         {"owner_group",         de_utf8string,  en_utf8string   }, /* 37 */
  73         {"quota_avail_hard",    de_uint64,      en_uint64       }, /* 38 */
  74         {"quota_avail_soft",    de_uint64,      en_uint64       }, /* 39 */
  75         {"quota_used",          de_uint64,      en_uint64       }, /* 40 */
  76         {"rawdev",              de_specdata,    en_specdata     }, /* 41 */
  77         {"space_avail",         de_uint64,      en_uint64       }, /* 42 */
  78         {"space_free",          de_uint64,      en_uint64       }, /* 43 */
  79         {"space_total",         de_uint64,      en_uint64       }, /* 44 */
  80         {"space_used",          de_uint64,      en_uint64       }, /* 45 */
  81         {"system",              de_bool,        en_bool         }, /* 46 */
  82         {"time_access",         de_time,        en_time         }, /* 47 */
  83         {"time_access_set",     de_time,        en_timeset      }, /* 48 */
  84         {"time_backup",         de_time,        en_time         }, /* 49 */
  85         {"time_create",         de_time,        en_time         }, /* 50 */
  86         {"time_delta",          de_time,        en_time         }, /* 51 */
  87         {"time_metadata",       de_time,        en_time         }, /* 52 */
  88         {"time_modify",         de_time,        en_time         }, /* 53 */
  89         {"time_modify_set",     de_time,        en_timeset      }, /* 54 */
  90         {"mounted_on_fileid",   de_uint64,      en_uint64       }  /* 55 */
  91 };
  92 
  93 int tblsize = sizeof (attr_info) / sizeof (attr_info[0]);
  94 
  95 #ifdef DEBUG_ACL
  96 static void debug_print_bitmap(char *name, bitmap4 *bitmap);
  97 static void debug_print_attrvals(char *name, attrlist4 *attrvals);
  98 static void debug_print_nvpairs(char *name, char *nvpairs);
  99 #endif
 100 
 101 
 102 /*
 103  * Given an attribute name - return its bit number.
 104  */
 105 int
 106 name2bit(char *name)
 107 {
 108         int i;
 109 
 110         for (i = 0; i < tblsize; i++)
 111                 if (strcmp(name, attr_info[i].name) == 0)
 112                         return (i);
 113         return (-1);
 114 }
 115 
 116 /*
 117  * Given an attribute bit number - return its name.
 118  */
 119 char *
 120 bit2name(int bit)
 121 {
 122         if ((bit < 0) || (bit > (tblsize - 1)))
 123                 return ("unknown");
 124 
 125         return (attr_info[bit].name);
 126 }
 127 
 128 /*
 129  * Given the attribute bitmap - prints the names where the bit is set.
 130  */
 131 void
 132 prn_attrname(Tcl_DString *strp, bitmap4 *bmp)
 133 {
 134         int i;
 135 
 136         for (i = 0; i < tblsize; i++) {
 137 
 138                 if (!getbit(bmp, i))
 139                         continue;
 140 
 141                 Tcl_DStringAppendElement(strp, bit2name(i));
 142         }
 143 }
 144 
 145 
 146 /* ------------------------------- */
 147 /* Attribute decoding functions.   */
 148 /* ------------------------------- */
 149 
 150 int
 151 de_bool(XDR *xdrp, Tcl_DString *strp, char *name) {
 152 
 153         bool_t b;
 154 
 155         if (xdr_bool(xdrp, &b) == FALSE)
 156                 return (TCL_ERROR);
 157 
 158         Tcl_DStringAppendElement(strp, name);
 159         Tcl_DStringAppendElement(strp, b ? "true":"false");
 160 
 161         return (TCL_OK);
 162 }
 163 
 164 int
 165 de_time(XDR *xdrp, Tcl_DString *strp, char *name) {
 166 
 167         nfstime4 t;
 168         char buf[64];
 169 
 170         if (xdr_nfstime4(xdrp, &t) == FALSE)
 171                 return (TCL_ERROR);
 172 
 173         Tcl_DStringAppendElement(strp, name);
 174         Tcl_DStringStartSublist(strp);
 175 
 176         (void) sprintf(buf, "%lld", t.seconds);
 177         Tcl_DStringAppendElement(strp, buf);
 178 
 179         (void) sprintf(buf, "%u", t.nseconds);
 180         Tcl_DStringAppendElement(strp, buf);
 181 
 182         Tcl_DStringEndSublist(strp);
 183 
 184         return (TCL_OK);
 185 }
 186 
 187 int
 188 de_uint64(XDR *xdrp, Tcl_DString *strp, char *name) {
 189 
 190         uint64_t val;
 191         char buf[64];
 192 
 193         if (xdr_uint64_t(xdrp, &val) == FALSE)
 194                 return (TCL_ERROR);
 195 
 196         Tcl_DStringAppendElement(strp, name);
 197         (void) sprintf(buf, "%llu", val);
 198         Tcl_DStringAppendElement(strp, buf);
 199 
 200         return (TCL_OK);
 201 }
 202 
 203 int
 204 de_uint32(XDR *xdrp, Tcl_DString *strp, char *name) {
 205 
 206         uint32_t val;
 207         char buf[64];
 208 
 209         if (xdr_uint32_t(xdrp, &val) == FALSE)
 210                 return (TCL_ERROR);
 211 
 212         Tcl_DStringAppendElement(strp, name);
 213         (void) sprintf(buf, "%u", val);
 214         Tcl_DStringAppendElement(strp, buf);
 215 
 216         return (TCL_OK);
 217 }
 218 
 219 int
 220 de_type(XDR *xdrp, Tcl_DString *strp, char *name) {
 221 
 222         fattr4_type t;
 223         char *p;
 224 
 225         if (xdr_fattr4_type(xdrp, &t) == FALSE)
 226                 return (TCL_ERROR);
 227 
 228         switch (t) {
 229         case NF4REG:            p = "reg"; break;
 230         case NF4DIR:            p = "dir"; break;
 231         case NF4BLK:            p = "blk"; break;
 232         case NF4CHR:            p = "chr"; break;
 233         case NF4LNK:            p = "lnk"; break;
 234         case NF4SOCK:           p = "sock"; break;
 235         case NF4FIFO:           p = "fifo"; break;
 236         case NF4ATTRDIR:        p = "attrdir"; break;
 237         case NF4NAMEDATTR:      p = "namedattr"; break;
 238         default:                p = "unknown"; break;
 239         }
 240 
 241         Tcl_DStringAppendElement(strp, name);
 242         Tcl_DStringAppendElement(strp, p);
 243 
 244         return (TCL_OK);
 245 }
 246 
 247 int
 248 de_bitmap(XDR *xdrp, Tcl_DString *strp, char *name) {
 249 
 250         bitmap4 supported;
 251         int maxattr;
 252         int i;
 253 
 254         (void) memset(&supported, 0, sizeof (bitmap4));
 255         if (xdr_fattr4_supported_attrs(xdrp, &supported) == FALSE)
 256                 return (TCL_ERROR);
 257 
 258         Tcl_DStringAppendElement(strp, name);
 259         Tcl_DStringStartSublist(strp);
 260 
 261         /*
 262          * Get the bit numbers (byte#s-of-int * 8 bits)
 263          */
 264         maxattr = supported.bitmap4_len * sizeof (uint32_t) * 8;
 265 
 266         /*
 267          * Test each attribute bit in the bitmap.
 268          * If it's set, append its name to the list
 269          */
 270         for (i = 0; i < maxattr; i++) {
 271                 if (! getbit(&supported, i))
 272                         continue;
 273 
 274                 Tcl_DStringAppendElement(strp, bit2name(i));
 275         }
 276         Tcl_DStringEndSublist(strp);
 277 
 278         return (TCL_OK);
 279 }
 280 
 281 int
 282 de_fsid(XDR *xdrp, Tcl_DString *strp, char *name) {
 283 
 284         fsid4 fsid;
 285         char buf[64];
 286 
 287         if (xdr_fsid4(xdrp, &fsid) == FALSE)
 288                 return (TCL_ERROR);
 289 
 290         Tcl_DStringAppendElement(strp, name);
 291 
 292         Tcl_DStringStartSublist(strp);
 293         (void) sprintf(buf, "%llu", fsid.major);
 294         Tcl_DStringAppendElement(strp, buf);
 295 
 296         (void) sprintf(buf, "%llu", fsid.minor);
 297         Tcl_DStringAppendElement(strp, buf);
 298         Tcl_DStringEndSublist(strp);
 299 
 300         return (TCL_OK);
 301 }
 302 
 303 int
 304 de_fhandle(XDR *xdrp, Tcl_DString *strp, char *name) {
 305 
 306         fattr4_filehandle fh;
 307         unsigned fh_len;
 308         char *fh_val;
 309 
 310         fh.nfs_fh4_val = NULL;
 311         if (xdr_fattr4_filehandle(xdrp, &fh) == FALSE)
 312                 return (TCL_ERROR);
 313 
 314         fh_len = fh.nfs_fh4_len;
 315         fh_val = fh.nfs_fh4_val;
 316 
 317         Tcl_DStringAppendElement(strp, name);
 318         Tcl_DStringAppendElement(strp, bin2hex(fh_val, fh_len));
 319 
 320         return (TCL_OK);
 321 }
 322 
 323 int
 324 de_mode(XDR *xdrp, Tcl_DString *strp, char *name) {
 325 
 326         mode4 m;
 327         char buf[64];
 328 
 329         if (xdr_fattr4_mode(xdrp, &m) == FALSE)
 330                 return (TCL_ERROR);
 331         Tcl_DStringAppendElement(strp, name);
 332         (void) sprintf(buf, "%o", m);
 333         Tcl_DStringAppendElement(strp, buf);
 334 
 335         return (TCL_OK);
 336 }
 337 
 338 int
 339 de_specdata(XDR *xdrp, Tcl_DString *strp, char *name) {
 340 
 341         static specdata4 dev;
 342         char buf[64];
 343 
 344         if (xdr_specdata4(xdrp, &dev) == FALSE)
 345                 return (TCL_ERROR);
 346 
 347         Tcl_DStringAppendElement(strp, name);
 348         (void) sprintf(buf, "%u %u", dev.specdata1, dev.specdata2);
 349         Tcl_DStringAppendElement(strp, buf);
 350 
 351         return (TCL_OK);
 352 }
 353 
 354 int
 355 de_utf8string(XDR *xdrp, Tcl_DString *strp, char *name) {
 356 
 357         static utf8string res;
 358         char *p;
 359 
 360         if (xdr_utf8string(xdrp, &res) == FALSE)
 361                 return (TCL_ERROR);
 362 
 363         p = malloc(res.utf8string_len + 1);
 364         (void) strncpy(p, res.utf8string_val, res.utf8string_len);
 365         p[res.utf8string_len] = '\0';
 366 
 367         Tcl_DStringAppendElement(strp, name);
 368         Tcl_DStringAppendElement(strp, p);
 369 
 370         free(p);
 371         return (TCL_OK);
 372 }
 373 
 374 int
 375 de_stat4(XDR *xdrp, Tcl_DString *strp, char *name) {
 376 
 377         nfsstat4 s;
 378 
 379         if (xdr_nfsstat4(xdrp, &s) == FALSE)
 380                 return (TCL_ERROR);
 381 
 382         Tcl_DStringAppendElement(strp, name);
 383         Tcl_DStringAppendElement(strp, errstr(s));
 384 
 385         return (TCL_OK);
 386 }
 387 
 388 int
 389 de_unimpl(XDR *xdrp, Tcl_DString *strp, char *name) {
 390 
 391         int b;
 392         xdr_bool(xdrp, &b); /* just advance the pointer */
 393         Tcl_DStringAppendElement(strp, name);
 394         Tcl_DStringAppendElement(strp, "not-yet-impl in nfsv4shell");
 395 
 396         return (TCL_OK);
 397 }
 398 
 399 int
 400 de_acl(XDR *xdrp, Tcl_DString *strp, char *name) {
 401         static  fattr4_acl facl;        /* acl struct to be decoded */
 402         char    *acl_buf;               /* buffer of decoded values to output */
 403         int     ret;
 404         int     i;
 405 
 406 #ifdef DEBUG_ACL
 407         (void) fprintf(stderr, "\nde_acl(xdrp, strp, name)\n");
 408         (void) fprintf(stderr, "\txdrp == %p, strp == %p, name == %s\n",
 409                 xdrp, strp, name ? name : "NULL");
 410 #endif
 411 
 412         if (xdr_fattr4_acl(xdrp, &facl) == FALSE) {
 413 #ifdef DEBUG_ACL
 414         (void) fprintf(stderr, "xdr_fattr4_acl() failed\n");
 415 #endif
 416                 ret = TCL_ERROR;
 417                 goto fin;
 418         }
 419 
 420         Tcl_DStringAppendElement(strp, name);
 421         Tcl_DStringStartSublist(strp);
 422         for (i = 0; i < facl.fattr4_acl_len; i++) {
 423                 acl_buf = out_ace4(facl.fattr4_acl_val[i], 0);
 424                 Tcl_DStringAppendElement(strp, acl_buf);
 425         }
 426         Tcl_DStringEndSublist(strp);
 427         ret = TCL_OK;
 428 
 429 fin:
 430         xdr_free(xdr_fattr4_acl, (char *)&facl);
 431         return (ret);
 432 }
 433 
 434 int
 435 de_fslocation(XDR *xdrp, Tcl_DString *strp, char *name) {
 436         static  fattr4_fs_locations fsl; /* fs_locations struct to be decoded */
 437         char    fs_buf[2048];           /* buffer of decoded values to output */
 438         int     ret;
 439         int     i, j;
 440         fs_location4 newloc;            /* the new rootpath location */
 441 
 442 #ifdef DEBUG_ATTR
 443         (void) fprintf(stderr, "\nde_fslocation(xdrp, strp, name)\n");
 444         (void) fprintf(stderr, "\txdrp == %p, strp == %p, name == %s\n",
 445                 xdrp, strp, name ? name : "NULL");
 446 #endif /* DEBUG_ATTR */
 447 
 448         if (xdr_fattr4_fs_locations(xdrp, &fsl) == FALSE) {
 449 #ifdef DEBUG_ATTR
 450         (void) fprintf(stderr, "xdr_fattr4_fs_locations() failed\n");
 451 #endif /* DEBUG_ATTR */
 452                 ret = TCL_ERROR;
 453                 goto fin;
 454         }
 455 
 456         Tcl_DStringAppendElement(strp, name);
 457 
 458         Tcl_DStringStartSublist(strp);
 459         sprintf(fs_buf, "");
 460         for (i = 0; i < fsl.fs_root.pathname4_len; i++) {
 461             strcat(fs_buf, utf82str(fsl.fs_root.pathname4_val[i]));
 462             if (i < (fsl.fs_root.pathname4_len - 1))
 463                         strcat(fs_buf, " ");
 464         }
 465         Tcl_DStringAppendElement(strp, fs_buf);
 466 
 467         Tcl_DStringStartSublist(strp);
 468         for (i = 0; i < fsl.locations.locations_len; i++) {
 469             newloc = fsl.locations.locations_val[i];
 470 
 471             Tcl_DStringStartSublist(strp);
 472             sprintf(fs_buf, "");
 473             for (j = 0; j < newloc.server.server_len; j++) {
 474                 strcat(fs_buf, utf82str(newloc.server.server_val[j]));
 475                 if (j < (newloc.server.server_len - 1))
 476                         strcat(fs_buf, " ");
 477             }
 478             Tcl_DStringAppendElement(strp, fs_buf);
 479 
 480             sprintf(fs_buf, "");
 481             for (j = 0; j < newloc.rootpath.pathname4_len; j++) {
 482                 strcat(fs_buf, utf82str(newloc.rootpath.pathname4_val[j]));
 483                 if (j < (newloc.rootpath.pathname4_len - 1))
 484                         strcat(fs_buf, " ");
 485             }
 486             Tcl_DStringAppendElement(strp, fs_buf);
 487             Tcl_DStringEndSublist(strp);
 488         }
 489         Tcl_DStringEndSublist(strp);
 490 
 491         Tcl_DStringEndSublist(strp);
 492         ret = TCL_OK;
 493 
 494 fin:
 495         xdr_free(xdr_fattr4_fs_locations, (char *)&fsl);
 496         return (ret);
 497 }
 498 
 499 /* ------------------------------- */
 500 /* Attribute encoding functions.   */
 501 /* ------------------------------- */
 502 
 503 int
 504 en_bool(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 505 
 506         bool_t b;
 507         char buf[80];
 508 
 509         substitution(interp, vp);
 510         vp = interp->result;
 511         if ((strcmp(vp, "true")) == 0)
 512                 b = TRUE;
 513         else if ((strcmp(vp, "false")) == 0)
 514                 b = FALSE;
 515         else {
 516                 sprintf(buf, "%s - boolean value", vp);
 517                 interp->result = buf;
 518                 return (TCL_ERROR);
 519         }
 520 
 521         if (xdr_bool(xdrp, &b) == FALSE)
 522                 return (TCL_ERROR);
 523         al->attrlist4_len += xdr_sizeof(xdr_bool, &b);
 524 
 525         return (TCL_OK);
 526 }
 527 
 528 int
 529 en_fhandle(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 530 
 531         fattr4_filehandle fh;
 532         char buf[80];
 533 
 534         substitution(interp, vp);
 535         vp = interp->result;
 536         fh.nfs_fh4_len = strlen(vp) / 2;
 537         fh.nfs_fh4_val = malloc(fh.nfs_fh4_len);
 538         if (fh.nfs_fh4_val == NULL) {
 539                 interp->result = "malloc failure in en_fhandle";
 540                 return (TCL_ERROR);
 541         }
 542         (void) memcpy(fh.nfs_fh4_val,
 543                 hex2bin(vp, ((unsigned)fh.nfs_fh4_len)), fh.nfs_fh4_len);
 544 
 545         if (xdr_fattr4_filehandle(xdrp, &fh) == FALSE)
 546                 return (TCL_ERROR);
 547 
 548         al->attrlist4_len += xdr_sizeof(xdr_fattr4_filehandle, &fh);
 549 
 550         return (TCL_OK);
 551 }
 552 
 553 int
 554 en_type(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 555 
 556         fattr4_type t;
 557         char buf[80];
 558 
 559         substitution(interp, vp);
 560         vp = interp->result;
 561         if ((strcmp(vp, "reg")) == 0)
 562                 t = NF4REG;
 563         else if ((strcmp(vp, "dir")) == 0)
 564                 t = NF4DIR;
 565         else if ((strcmp(vp, "blk")) == 0)
 566                 t = NF4BLK;
 567         else if ((strcmp(vp, "chr")) == 0)
 568                 t = NF4CHR;
 569         else if ((strcmp(vp, "lnk")) == 0)
 570                 t = NF4LNK;
 571         else if ((strcmp(vp, "sock")) == 0)
 572                 t = NF4SOCK;
 573         else if ((strcmp(vp, "fifo")) == 0)
 574                 t = NF4FIFO;
 575         else if ((strcmp(vp, "attrdir")) == 0)
 576                 t = NF4ATTRDIR;
 577         else if ((strcmp(vp, "namedattr")) == 0)
 578                 t = NF4NAMEDATTR;
 579         else {
 580                 sprintf(buf, "%s - unknown type", vp);
 581                 interp->result = buf;
 582                 return (TCL_ERROR);
 583         }
 584 
 585         if (xdr_fattr4_type(xdrp, &t) == FALSE)
 586                 return (TCL_ERROR);
 587         al->attrlist4_len += xdr_sizeof(xdr_fattr4_type, &t);
 588 
 589         return (TCL_OK);
 590 }
 591 
 592 int
 593 en_fsid(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 594 
 595         fattr4_fsid val;
 596         char buf[80];
 597         int lc;
 598         char **lv;
 599         int code = TCL_ERROR;
 600 
 601         /* need to split the fsid strings to major and minor */
 602         if (Tcl_SplitList(interp, vp, &lc, (CONST84 char ***)&lv) != TCL_OK) {
 603                 sprintf(buf, "encoding fsid error, can't split {%s}", vp);
 604                 interp->result = buf;
 605                 return (code);
 606         }
 607         if (lc != 2) {
 608                 sprintf(buf, "encoding fsid error, {%s} needs 2 fields", vp);
 609                 interp->result = buf;
 610                 goto lv_exit;
 611         }
 612 
 613         /* convert the strings to major & minor */
 614         substitution(interp, lv[0]);
 615         val.major = (uint64_t)strtoull(interp->result, NULL, 10);
 616         substitution(interp, lv[1]);
 617         val.minor = (uint64_t)strtoull(interp->result, NULL, 10);
 618 
 619         if (xdr_fattr4_fsid(xdrp, &val) == FALSE)
 620                 goto lv_exit;
 621 
 622         al->attrlist4_len += xdr_sizeof(xdr_fattr4_fsid, &val);
 623         code = TCL_OK;
 624 
 625 lv_exit:
 626         if (lv)
 627                 free((char *)lv);
 628         return (code);
 629 }
 630 
 631 int
 632 en_uint64(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 633 
 634         uint64_t val;
 635 
 636         substitution(interp, vp);
 637         vp = interp->result;
 638         val = (uint64_t)strtoull(vp, NULL, 0);
 639 
 640         if (xdr_uint64_t(xdrp, &val) == FALSE)
 641                 return (TCL_ERROR);
 642         al->attrlist4_len += xdr_sizeof(xdr_uint64_t, &val);
 643 
 644         return (TCL_OK);
 645 }
 646 
 647 int
 648 en_uint32(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 649 
 650         uint32_t val;
 651 
 652         substitution(interp, vp);
 653         vp = interp->result;
 654         val = (uint32_t)atoi(vp);
 655 
 656         if (xdr_uint32_t(xdrp, &val) == FALSE)
 657                 return (TCL_ERROR);
 658         al->attrlist4_len += xdr_sizeof(xdr_uint32_t, &val);
 659 
 660         return (TCL_OK);
 661 }
 662 
 663 int
 664 en_specdata(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 665         specdata4 sd4;
 666         char buf[80];
 667         int lc;
 668         char **lv;
 669         int code = TCL_ERROR;
 670 
 671         /* need to split the specdata strings to specdata1 and specdata2 */
 672         if (Tcl_SplitList(interp, vp, &lc, (CONST84 char ***)&lv) != TCL_OK) {
 673                 sprintf(buf, "encoding specdata error, can't split {%s}", vp);
 674                 interp->result = buf;
 675                 return (code);
 676         }
 677         if (lc != 2) {
 678                 sprintf(buf, "encoding specdata error, {%s} needs 2 fields",
 679                         vp);
 680                 interp->result = buf;
 681                 goto lv_exit;
 682         }
 683 
 684         /* convert the strings to specdata1 & specdata2 */
 685         substitution(interp, lv[0]);
 686         sd4.specdata1 = (uint32_t)atoi(interp->result);
 687         substitution(interp, lv[1]);
 688         sd4.specdata2 = (uint32_t)atoi(interp->result);
 689 
 690         if (xdr_specdata4(xdrp, &sd4) == FALSE)
 691                 goto lv_exit;
 692         al->attrlist4_len += xdr_sizeof(xdr_specdata4, &sd4);
 693         code = TCL_OK;
 694 
 695 lv_exit:
 696         if (lv)
 697                 free((char *)lv);
 698         return (code);
 699 }
 700 
 701 int
 702 en_mode(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 703 
 704         mode4 m;
 705         int   m_i;
 706         char buf[80];
 707 
 708         substitution(interp, vp);
 709         vp = interp->result;
 710         m_i = strtoll(vp, NULL, 8);
 711         if (m_i < 0)
 712                 return (TCL_ERROR);
 713         else
 714                 m = (mode4) m_i;
 715 
 716         if (xdr_mode4(xdrp, &m) == FALSE)
 717                 return (TCL_ERROR);
 718         al->attrlist4_len += xdr_sizeof(xdr_mode4, &m);
 719 
 720         return (TCL_OK);
 721 }
 722 
 723 int
 724 en_utf8string(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 725 
 726         utf8string *val;
 727 
 728         substitution(interp, vp);
 729         vp = interp->result;
 730         val = (utf8string *) str2utf8(vp);
 731 
 732         if (xdr_utf8string(xdrp, val) == FALSE)
 733                 return (TCL_ERROR);
 734         al->attrlist4_len += xdr_sizeof(xdr_utf8string, val);
 735 
 736         return (TCL_OK);
 737 }
 738 
 739 int
 740 en_time(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 741 
 742         nfstime4 tm;
 743         char buf[80];
 744         int lc;
 745         char **lv;
 746         int code = TCL_ERROR;
 747 
 748         /* need to split the time strings to second and nsecond */
 749         if (Tcl_SplitList(interp, vp, &lc, (CONST84 char ***)&lv) != TCL_OK) {
 750                 sprintf(buf, "encoding time error, can't split {%s}", vp);
 751                 interp->result = buf;
 752                 return (code);
 753         }
 754         if (lc != 2) {
 755                 sprintf(buf, "encoding time error, {%s} needs 2 fields", vp);
 756                 interp->result = buf;
 757                 goto lv_exit;
 758         }
 759 
 760         /* convert the strings to second & nsecond */
 761         substitution(interp, lv[0]);
 762         tm.seconds = (int64_t)strtoll(interp->result, NULL, 10);
 763         substitution(interp, lv[1]);
 764         tm.nseconds = (uint32_t)strtol(interp->result, NULL, 10);
 765 
 766         if (xdr_nfstime4(xdrp, &tm) == FALSE)
 767                 goto lv_exit;
 768         al->attrlist4_len += xdr_sizeof(xdr_nfstime4, &tm);
 769         code = TCL_OK;
 770 
 771 lv_exit:
 772         if (lv)
 773                 free((char *)lv);
 774         return (code);
 775 }
 776 
 777 int
 778 en_timeset(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 779 
 780         settime4 st;
 781         char buf[80];
 782         int lc;
 783         char **lv;
 784         int code = TCL_ERROR;
 785 
 786         /*
 787          * Assumed it always set to server's time; otherwise time
 788          * arguments are needed.  Thus set argument format to:
 789          *   {name 0} -> time_how4 will be SET_TO_SERVER_TIME4;
 790          *   {name {sec nsec}} -> time_how4 will be SET_TO_CLIENT_TIME4;
 791          */
 792 
 793         /* need to split the time strings to second and nsecond */
 794         if (Tcl_SplitList(interp, vp, &lc, (CONST84 char ***)&lv) != TCL_OK) {
 795                 sprintf(buf, "encoding time error, can't split {%s}", vp);
 796                 interp->result = buf;
 797                 return (code);
 798         }
 799         if (lc == 1) {
 800                 st.set_it = 0;          /* SET_TO_SERVER_TIME4 */
 801         } else if (lc == 2) {
 802                 st.set_it = 1;          /* SET_TO_CLIENT_TIME4 */
 803                 /* convert the strings to second & nsecond */
 804                 substitution(interp, lv[0]);
 805                 st.settime4_u.time.seconds =
 806                     (int64_t)strtoll(interp->result, NULL, 10);
 807                 substitution(interp, lv[1]);
 808                 st.settime4_u.time.nseconds
 809                     = (uint32_t)strtol(interp->result, NULL, 10);
 810         } else {
 811                 sprintf(buf,
 812                     "encoding time error, {%s} has more than 2 fields", vp);
 813                 interp->result = buf;
 814                 goto lv_exit;
 815         }
 816 
 817         if (xdr_settime4(xdrp, &st) == FALSE)
 818                 goto lv_exit;
 819         al->attrlist4_len += xdr_sizeof(xdr_settime4, &st);
 820         code = TCL_OK;
 821 
 822 lv_exit:
 823         if (lv)
 824                 free((char *)lv);
 825         return (code);
 826 }
 827 
 828 int
 829 en_stat4(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 830 
 831         nfsstat4 err;
 832 
 833         substitution(interp, vp);
 834         vp = interp->result;
 835         err = str2err(vp);
 836 
 837         if (xdr_nfsstat4(xdrp, &err) == FALSE)
 838                 return (TCL_ERROR);
 839         al->attrlist4_len += xdr_sizeof(xdr_nfsstat4, &err);
 840 
 841         return (TCL_OK);
 842 }
 843 
 844 int
 845 en_unimpl(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
 846 
 847         char buf[80];
 848 
 849         sprintf(buf, "this bit value %s is not implemented", vp);
 850         interp->result = buf;
 851 
 852         return (TCL_ERROR);
 853 }
 854 
 855 /*
 856  * Given a bitmap that describes which attributes are
 857  * contained in the XDR stream, this function decodes
 858  * the attributes and appends them to a list of strings.
 859  * e.g. "{{type dir} {size 1614} {mode 666}}"
 860  */
 861 int
 862 attr_decode(Tcl_Interp *interp, Tcl_DString *strp,
 863     bitmap4 *bmp, attrlist4 *attrvals)
 864 {
 865         XDR xdrs;
 866         ATTRINFO *aip;
 867         int i;
 868 
 869 #ifdef DEBUG_ACL
 870         (void) fprintf(stderr,
 871             "\nattr_decode(interp, strp, bmp, attrvals)\n"
 872             "\tinterp == %p"
 873             "\tstrp == %p\n",
 874             interp, strp);
 875         debug_print_bitmap("bmp", bmp);
 876         debug_print_attrvals("attrvals", attrvals);
 877 #endif
 878         Tcl_DStringStartSublist(strp);
 879 
 880         xdrmem_create(&xdrs, attrvals->attrlist4_val,
 881             attrvals->attrlist4_len, XDR_DECODE);
 882 
 883         for (i = 0; i < tblsize; i++) {
 884 
 885                 if (!getbit(bmp, i))
 886                         continue;
 887 
 888                 aip = &attr_info[i];
 889 
 890                 Tcl_DStringStartSublist(strp);
 891 
 892                 if ((aip->defunc)(&xdrs, strp, aip->name) != TCL_OK) {
 893                         char buf[80];
 894 
 895                         sprintf(buf, "attr=%s, decode error", aip->name);
 896                         interp->result = buf;
 897 #ifdef DEBUG_ACL
 898                         (void) fprintf(stderr,
 899                             "\tinterp->result == %s\n"
 900                             "attr_decode() == TCL_ERROR\n",
 901                             interp->result);
 902 #endif
 903                         return (TCL_ERROR);
 904                 }
 905 
 906                 Tcl_DStringEndSublist(strp);
 907         }
 908 
 909         Tcl_DStringEndSublist(strp);
 910 
 911 
 912         xdr_destroy(&xdrs);
 913 #ifdef DEBUG_ACL
 914         (void) fprintf(stderr, "attr_decode() == TCL_OK\n");
 915 #endif
 916         return (TCL_OK);
 917 }
 918 
 919 /*
 920  * This split a list of attribute {names val} pairs to get names and
 921  * attribute values; and set it to its bitmap and attrlists.
 922  */
 923 int
 924 attr_encode(Tcl_Interp *interp, char *nvpairs, bitmap4 *bmp, attrlist4 *al)
 925 {
 926         int attrcnt = 0;
 927         char **attrnv = NULL;
 928         int lc = 0;
 929         char **lv = NULL;
 930         char *names = NULL;
 931         char **vp = NULL;
 932         char buf[512] = "";
 933         char **tmp = NULL;
 934         char *temp = NULL;
 935         int bitno = 0;
 936         int i = 0;
 937         int code = TCL_ERROR;
 938 
 939 #ifdef DEBUG_ACL
 940         (void) fprintf(stderr,
 941             "\nattr_encode(interp, nvpairs, bmp, al)\n"
 942             "\tinterp == %p\n",
 943             interp);
 944         debug_print_nvpairs("nvpairs", nvpairs);
 945         (void) fprintf(stderr, "\tbmp == %p\n", bmp);
 946         (void) fprintf(stderr, "\tal == %p\n", al);
 947 #endif
 948 
 949         /*
 950          * First split the name_val pairs of the attributes.
 951          * should get attr count and {name val} string.
 952          */
 953         if (Tcl_SplitList(interp, nvpairs, &attrcnt,
 954             (CONST84 char ***)&attrnv) != TCL_OK) {
 955                 sprintf(buf, "Error in Tcl_SplitList():\n%s\n"
 956                     "attr_encode(): can't split nvpairs={%s}",
 957                     Tcl_GetStringResult(interp),
 958                     (nvpairs == NULL ? "" : nvpairs));
 959                 goto buf_exit;
 960         }
 961 
 962         /*
 963          * Allocate an array for the names;
 964          * assume longest name + space separator + null char
 965          * has ATTR_NAME_LEN bytes per name.
 966          */
 967         names = calloc(attrcnt, ATTR_NAME_LEN);
 968         if (names == NULL) {
 969                 sprintf(buf, "Out of memory in attr_encode()");
 970                 goto buf_exit;
 971         }
 972 
 973         names[0] = '\0';
 974         if ((vp = calloc(tblsize, sizeof (char *))) == NULL) {
 975                 sprintf(buf, "Out of memory in attr_encode()");
 976                 goto buf_exit;
 977         }
 978 
 979         /* Now go through the list  ... */
 980         for (i = 0; i < attrcnt; i++) {
 981                 char lv0[1024] = "";
 982                 char lv1[1024] = "";
 983 
 984                 /* Has to split it again for from {name val} pair */
 985                 if (Tcl_SplitList(interp, attrnv[i], &lc,
 986                     (CONST84 char ***)&lv) != TCL_OK) {
 987                         sprintf(buf, "Error in Tcl_SplitList():\n%s\n"
 988                             "attr_encode(): can't split attrnv[%d]={%s}",
 989                             Tcl_GetStringResult(interp), i,
 990                             (attrnv[i] == NULL ? "" : attrnv[i]));
 991                         goto buf_exit;
 992                 }
 993                 switch (lc) {
 994                 case 0:
 995                         if ((tmp = malloc(2*sizeof (char *))) == NULL) {
 996                                 sprintf(buf, "Out of memory in attr_encode()");
 997                                 goto buf_exit;
 998                         }
 999                         tmp[0] = "";
1000                         tmp[1] = "";
1001                         if (lv) {
1002                                 free((char *)lv);
1003                         }
1004                         lv = tmp;
1005                         break;
1006                 case 1: /* val is empty */
1007                         if ((tmp = malloc(2*sizeof (char *))) == NULL) {
1008                                 sprintf(buf, "Out of memory in attr_encode()");
1009                                 goto buf_exit;
1010                         }
1011                         tmp[1] = "";
1012                         tmp[0] = tmp[1];
1013                         if (lv) { /* kind of paranoid check since lc == 1 */
1014                                 tmp[0] = lv[0];
1015                                 free((char *)lv);
1016                         }
1017                         lv = tmp;
1018                         break;
1019                 case 2: /* when lc ==  2, every thing is OK */
1020                         break;
1021                 default:
1022                         if (lc < 0)
1023                                 /* paranoid test since lc should not be < 0 */
1024                                 goto error_exit;
1025                         /* (lc > 2) take rest of the tokens as one */
1026                         if ((temp = strstr(attrnv[i], lv[1])) == NULL) {
1027                                 /* no tokens? */
1028                                 goto error_exit;
1029                         }
1030                         lv[1] = temp;
1031                         break;
1032                 }
1033 
1034                 substitution(interp, lv[0]);
1035                 strcpy(lv0, interp->result);
1036                 if (lv[0] != '\0') {
1037                         strcat(names, lv0);
1038                 }
1039                 if (names[0] != '\0') { /* if any name is stored */
1040                         strcat(names, " ");
1041                 }
1042 
1043                 /* build the attribute value array */
1044                 if (lv0[0] != '\0') { /* if not empty */
1045                         if ((bitno = name2bit(lv0)) < 0) {
1046                                 sprintf(buf,
1047                                 "set_attrvals(): incorrect attribute name [%s]",
1048                                     lv0);
1049                                 goto buf_exit;
1050                         }
1051 
1052                         substitution(interp, lv[1]);
1053                         strcpy(lv1, interp->result);
1054                         vp[bitno] = malloc(sizeof (lv1) + 1);
1055                         if (vp[bitno] == NULL) {
1056                                 sprintf(buf, "Out of memory in attr_encode()");
1057                                 goto buf_exit;
1058                         }
1059                         strcpy(vp[bitno], lv1);
1060                 }
1061         }
1062 
1063         /* now set the bitmap */
1064         if ((names2bitmap(interp, names, bmp)) != TCL_OK) {
1065                 sprintf(buf, "attr_encode could not set bitmap");
1066                 goto buf_exit;
1067         }
1068 
1069         /* and the attrlist */
1070         if ((names2alist(interp, bmp, al, vp)) != TCL_OK) {
1071                 sprintf(buf, "attr_encode could not set attrlist");
1072                 goto buf_exit;
1073         }
1074 
1075         code = TCL_OK;
1076         goto lv_exit;
1077 
1078 error_exit:
1079         sprintf(buf, "attr_encode(): error in {name val}, {%s} lc=%d",
1080             (attrnv == NULL) ? "NULL" : attrnv[i], lc);
1081 buf_exit:
1082         Tcl_SetResult(interp, buf, TCL_VOLATILE);
1083 lv_exit:
1084         /* free temporal attribute values and array of pointers */
1085         for (i = 0; i < tblsize; i++) {
1086                 if (vp) {
1087                         if (vp[i]) {
1088                                 free(vp[i]);
1089                         }
1090                 }
1091         }
1092         if (vp) {
1093                 free(vp);
1094         }
1095         if (lv)
1096                 free((char *)lv);
1097         if (attrnv)
1098                 free((char *)attrnv);
1099         if (names)
1100                 free(names);
1101         return (code);
1102 }
1103 
1104 /*
1105  * Given the attribute bitmap and value, build the attrlists.
1106  */
1107 int
1108 names2alist(Tcl_Interp *interp, bitmap4 *bmp, attrlist4 *al, char **vp)
1109 {
1110         XDR xdrs;
1111         ATTRINFO *aip;
1112         int i;
1113         int vsize;
1114         char buf[128];
1115 
1116         /*
1117          * There are only 14 writable attributes (for Setattr);
1118          * But try to allocate big enough memory size and
1119          * hope it's enough.
1120          */
1121         vsize = 14 * 128;
1122         al->attrlist4_len = 0;
1123         al->attrlist4_val = malloc(vsize);
1124 
1125         xdrmem_create(&xdrs, al->attrlist4_val, vsize, XDR_ENCODE);
1126 
1127         for (i = 0; i < tblsize; i++) {
1128                 if (!getbit(bmp, i))
1129                         continue;
1130 
1131                 if (al->attrlist4_len >= vsize) {
1132                         interp->result =
1133                             "attribute encode error, attrlist len too long.";
1134                         return (TCL_ERROR);
1135                 }
1136 
1137                 aip = &attr_info[i];
1138 
1139 #ifdef DEBUG_ACL
1140                 if (aip->enfunc == en_acl) {
1141                         (void) fprintf(stderr,
1142                             "attr_encode(), line %d: about to call en_acl()\n",
1143                             __LINE__);
1144                 }
1145 #endif
1146                 if ((aip->enfunc)(&xdrs, interp, vp[i], al) != TCL_OK) {
1147                         sprintf(buf, "%s - %s",
1148                             "attribute encode error", interp->result);
1149                         interp->result = buf;
1150                         return (TCL_ERROR);
1151                 }
1152         }
1153 
1154         xdr_destroy(&xdrs);
1155 
1156         return (TCL_OK);
1157 }
1158 
1159 int
1160 en_acl(XDR *xdrp, Tcl_Interp *interp, char *vp, attrlist4 *al) {
1161 
1162         static fattr4_acl facl;
1163         nfsace4 *ace;
1164         char ebuf[80];
1165         char *aval;
1166         char **lv1, **lv2;
1167         int lc1, lc2;
1168         int i, ret;
1169 
1170 #ifdef DEBUG_ACL
1171         (void) fprintf(stderr, "\nen_acl(xdrp, interp, vp, al)\n");
1172         (void) fprintf(stderr,
1173             "\txprp == %p, interp == %p\n"
1174             "\tvp == %s\n",
1175             xdrp, interp, vp ? vp : "NULL");
1176         debug_print_attrvals("al", al);
1177 #endif
1178 
1179         /* split the acl_val for ace entries */
1180         if (Tcl_SplitList(interp, vp, &lc1, (CONST84 char ***)&lv1) != TCL_OK) {
1181                 (void) sprintf(ebuf,
1182                         "encoding time error, can't split {%s}", vp);
1183                 interp->result = ebuf;
1184                 return (TCL_ERROR);
1185         }
1186         if (lc1 <= 0) {
1187                 (void) sprintf(ebuf,
1188                         "encoding acl error, {%s} can't be <= 0", vp);
1189                 interp->result = ebuf;
1190                 if (lv1)
1191                         free((char *)lv1);
1192                 return (TCL_ERROR);
1193         }
1194 #ifdef DEBUG_ACL
1195         (void) fprintf(stderr, "Total of %d ace entries: \n", lc1);
1196 #endif
1197 
1198         ace = (nfsace4 *)calloc(lc1, sizeof (nfsace4));
1199         if (ace == (nfsace4 *)NULL) {
1200                 perror("calloc((nfsace4))");
1201                 (void) fprintf(stderr, "%d -- file %s, line %d\n",
1202                         lc1, __FILE__, __LINE__);
1203                 ret = TCL_ERROR;
1204                 goto fin;
1205         }
1206 
1207         for (i = 0; i < lc1; i++) {
1208                 substitution(interp, lv1[i]);
1209                 aval = interp->result;
1210                 /* Now split the acl_val entries */
1211                 if (Tcl_SplitList(interp, aval, &lc2,
1212                     (CONST84 char ***)&lv2) != TCL_OK) {
1213                     (void) sprintf(ebuf, "fail to split {%s}[%d]", aval, i);
1214                     interp->result = ebuf;
1215                     return (TCL_ERROR);
1216                 }
1217                 if (lc2 != 4) {
1218                     (void) sprintf(ebuf,
1219                         "en_acl(): not enough ace members, need 4\n");
1220                     interp->result = ebuf;
1221                     if (lv2)
1222                         free((char *)lv2);
1223                     return (TCL_ERROR);
1224                 }
1225 
1226                 substitution(interp, lv2[0]);
1227                 ace[i].type = (uint32_t)strtol(interp->result, NULL, 10);
1228                 substitution(interp, lv2[1]);
1229                 ace[i].flag = (uint32_t)strtol(interp->result, NULL, 16);
1230                 substitution(interp, lv2[2]);
1231                 ace[i].access_mask = (uint32_t)strtol(interp->result, NULL, 16);
1232                 substitution(interp, lv2[3]);
1233                 ace[i].who = *str2utf8(interp->result);
1234 #ifdef DEBUG_ACL
1235                 (void) fprintf(stderr, "ace[%d]: type=%d,", i, ace[i].type);
1236                 (void) fprintf(stderr, "flag=%x,", ace[i].flag);
1237                 (void) fprintf(stderr, "access_mask=%x,", ace[i].access_mask);
1238                 (void) fprintf(stderr, "who=%s\n", interp->result);
1239 #endif
1240                 free((char *)lv2);
1241         }
1242 
1243         facl.fattr4_acl_len = lc1;
1244         facl.fattr4_acl_val = ace;
1245         if (xdr_fattr4_acl(xdrp, &facl) == FALSE) {
1246 #ifdef DEBUG_ACL
1247                 (void) fprintf(stderr,
1248                     "en_acl(), line %d: xdr_fattr4_acl(xdrp, facl) failed\n",
1249                     __LINE__);
1250 #endif
1251                 ret = TCL_ERROR;
1252                 goto fin;
1253         }
1254         al->attrlist4_len += xdr_sizeof(xdr_fattr4_acl, &facl);
1255         ret = TCL_OK;
1256 
1257 fin:
1258         xdr_free(xdr_fattr4_acl, (char *)&facl);
1259         free((char *)lv1);
1260 #ifdef DEBUG_ACL
1261         (void) fprintf(stderr, "attr_encode() == %s\n",
1262                 (ret == TCL_OK) ? "TCL_OK" : "TCL_ERROR");
1263 #endif
1264         return (ret);
1265 }
1266 
1267 #ifdef DEBUG_ACL
1268 
1269 static void
1270 debug_print_bitmap(char *name, bitmap4 *bitmap)
1271 {
1272         uint_t i;
1273 
1274         (void) fprintf(stderr, "\t%s->bitmap4_len == %u\n",
1275             name, bitmap->bitmap4_len);
1276         for (i = 0; i < bitmap->bitmap4_len; i++)
1277                 (void) fprintf(stderr,
1278                     "\t%s->bitmap4_val[%u] == 0x%x\n",
1279                     name, i, bitmap->bitmap4_val[i]);
1280 }
1281 
1282 static void
1283 debug_print_attrvals(char *name, attrlist4 *attrlist)
1284 {
1285         uint_t i;
1286 
1287         (void) fprintf(stderr, "\t%s->attrlist4_len == %u\n",
1288             name, attrlist->attrlist4_len);
1289         for (i = 0; i < attrlist->attrlist4_len; i++)
1290                 (void) fprintf(stderr,
1291                     "\t%s->attrlist4_val[%u] == 0x%x\n",
1292                     name, i, attrlist->attrlist4_val[i]);
1293 }
1294 
1295 static void
1296 debug_print_nvpairs(char *name, char *nvpairs)
1297 {
1298         if (nvpairs == NULL) {
1299                 (void) fprintf(stderr, "\t%s == NULL\n", name);
1300         } else {
1301                 (void) fprintf(stderr, "\t%s == %s\n", name, nvpairs);
1302         }
1303 }
1304 
1305 #endif