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 <rpc/rpc.h>
  28 #include <rpc/clnt.h>
  29 #include <rpc/clnt_soc.h>
  30 #include "nfs4_prot.h"
  31 #include "nfstcl4.h"
  32 
  33 /* nfsv4 operations table */
  34 NFSOP nfs_op[] = {
  35         {"Access",                      Access  },
  36         {"Close",                       Close   },
  37         {"Commit",                      Commit  },
  38         {"Create",                      Create  },
  39         {"Delegpurge",                  Delegpurge},
  40         {"Delegreturn",                 Delegreturn},
  41         {"Getattr",                     Getattr },
  42         {"Getfh",                       Getfh   },
  43         {"Illegal",                     Illegal },
  44         {"Link",                        Link    },
  45         {"Lock",                        Lock    },
  46         {"Lockt",                       Lockt   },
  47         {"Locku",                       Locku   },
  48         {"Lookup",                      Lookup  },
  49         {"Lookupp",                     Lookupp },
  50         {"Nverify",                     Nverify },
  51         {"Open",                        Open    },
  52         {"Openattr",                    Openattr},
  53         {"Open_confirm",                Open_confirm},
  54         {"Open_downgrade",              Open_downgrade},
  55         {"Putfh",                       Putfh   },
  56         {"Putpubfh",                    Putpubfh},
  57         {"Putrootfh",                   Putrootfh},
  58         {"Read",                        Read    },
  59         {"Readdir",                     Readdir },
  60         {"Readlink",                    Readlink},
  61         {"Release_lockowner",           Release_lockowner},
  62         {"Remove",                      Remove  },
  63         {"Rename",                      Rename  },
  64         {"Renew",                       Renew   },
  65         {"Restorefh",                   Restorefh},
  66         {"Savefh",                      Savefh  },
  67         {"Secinfo",                     Secinfo },
  68         {"Setattr",                     Setattr },
  69         {"Setclientid",                 Setclientid},
  70         {"Setclientid_confirm",         Setclientid_confirm},
  71         {"Verify",                      Verify  },
  72         {"Write",                       Write   },
  73         {0,                             0       },
  74 };
  75 
  76 /* ------------------------------ */
  77 /* Operation request functions.   */
  78 /* ------------------------------ */
  79 
  80 int
  81 Access(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
  82 {
  83         uint32_t access;
  84         char *acl, ac;
  85 
  86         nfs_argop4 *opp = new_argop();
  87 
  88         if (argc != 2) {
  89                 interp->result = "Usage: Access { rlmtdx i(0x100) }";
  90                 return (TCL_ERROR);
  91         }
  92 
  93         opp->argop = OP_ACCESS;
  94 
  95         access = (uint32_t)0;
  96         substitution(interp, argv[1]);
  97         argv[1] = interp->result;
  98         acl = argv[1];
  99         while ((ac = *acl++) != '\0') {
 100                 switch (ac) {
 101                 case 'r':
 102                         access = access | (uint32_t)ACCESS4_READ;
 103                         break;
 104                 case 'l':
 105                         access = access | (uint32_t)ACCESS4_LOOKUP;
 106                         break;
 107                 case 'm':
 108                         access = access | (uint32_t)ACCESS4_MODIFY;
 109                         break;
 110                 case 't':
 111                         access = access | (uint32_t)ACCESS4_EXTEND;
 112                         break;
 113                 case 'd':
 114                         access = access | (uint32_t)ACCESS4_DELETE;
 115                         break;
 116                 case 'x':
 117                         access = access | (uint32_t)ACCESS4_EXECUTE;
 118                         break;
 119                 case 'i':
 120                         access = access | (uint32_t)0x00000100;
 121                         break;
 122                 default:
 123                         interp->result =
 124                             "Unknown accessreq, use {rlmtdx i(0x100)}";
 125                         return (TCL_ERROR);
 126                 }
 127         }
 128 
 129         opp->nfs_argop4_u.opaccess.access = access;
 130 
 131         return (TCL_OK);
 132 }
 133 
 134 int
 135 Close(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 136 {
 137         stateid4 stateid;
 138         nfs_argop4 *opp = new_argop();
 139 
 140         if (argc < 3) {
 141                 interp->result = "Usage: Close seqid stateid{seqid other}";
 142                 return (TCL_ERROR);
 143         }
 144 
 145         opp->argop = OP_CLOSE;
 146         substitution(interp, argv[1]);
 147         argv[1] = interp->result;
 148         opp->nfs_argop4_u.opclose.seqid = (seqid4) atoi(argv[1]);
 149         substitution(interp, argv[2]);
 150         argv[2] = interp->result;
 151         if (str2stateid(interp, argv[2], &stateid) != TCL_OK) {
 152                 interp->result = "Close: str2stateid() error";
 153                 return (TCL_ERROR);
 154         }
 155         opp->nfs_argop4_u.opclose.open_stateid = stateid;
 156 
 157         return (TCL_OK);
 158 }
 159 
 160 int
 161 Commit(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 162 {
 163         nfs_argop4 *opp = new_argop();
 164 
 165         if (argc < 3) {
 166                 interp->result = "Usage: Commit offset count";
 167                 return (TCL_ERROR);
 168         }
 169 
 170         opp->argop = OP_COMMIT;
 171         substitution(interp, argv[1]);
 172         argv[1] = interp->result;
 173         opp->nfs_argop4_u.opcommit.offset = (offset4) atol(argv[1]);
 174         substitution(interp, argv[2]);
 175         argv[2] = interp->result;
 176         opp->nfs_argop4_u.opcommit.count = (count4) atoi(argv[2]);
 177 
 178         return (TCL_OK);
 179 }
 180 
 181 int
 182 Create(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 183 {
 184         char ct;
 185         char buf[80];
 186         char lv4[1024], lv5[1024];
 187         createtype4 ctype;
 188         bitmap4 bm;
 189         attrlist4 av;
 190 
 191         nfs_argop4 *opp = new_argop();
 192 
 193         if (argc < 4) {
 194                 interp->result = "Usage: Create objname "
 195                     "{{name val} {name val} ...}\n       "
 196                     "s | f | d | l linkdata | b specd1 specd2 | "
 197                     "c specd1 specd2";
 198                 return (TCL_ERROR);
 199         }
 200 
 201         opp->argop = OP_CREATE;
 202 
 203         substitution(interp, argv[3]);
 204         argv[3] = interp->result;
 205         ct = *argv[3];
 206         if (argc >= 5) {
 207                 substitution(interp, argv[4]);
 208                 strcpy(lv4, interp->result);
 209         }
 210         if (argc >= 6) {
 211                 substitution(interp, argv[5]);
 212                 strcpy(lv5, interp->result);
 213         }
 214         switch (ct) {
 215         case 'l':       ctype.type = NF4LNK;
 216                 if (argc != 5) {
 217                         interp->result = "Usage: "
 218                             "Create objname {attrs} l linkdata";
 219                         return (TCL_ERROR);
 220                 }
 221                 ctype.createtype4_u.linkdata = *str2utf8(lv4);
 222                 break;
 223         case 'b':       ctype.type = NF4BLK;
 224                 if (argc != 6) {
 225                         interp->result = "Usage: "
 226                             "Create objname {attrs} b specd1 specd2";
 227                         return (TCL_ERROR);
 228                 }
 229                 ctype.createtype4_u.devdata.specdata1 =
 230                     (uint32_t)atoi(lv4);
 231                 ctype.createtype4_u.devdata.specdata2 =
 232                     (uint32_t)atoi(lv5);
 233                 break;
 234         case 'c':       ctype.type = NF4CHR;
 235                 if (argc != 6) {
 236                         interp->result = "Usage: "
 237                             "Create objname {attrs} c specd1 specd2";
 238                         return (TCL_ERROR);
 239                 }
 240                 ctype.createtype4_u.devdata.specdata1 =
 241                     (uint32_t)atoi(lv4);
 242                 ctype.createtype4_u.devdata.specdata2 =
 243                     (uint32_t)atoi(lv5);
 244                 break;
 245         case 's':       ctype.type = NF4SOCK; break;
 246         case 'f':       ctype.type = NF4FIFO; break;
 247         case 'd':       ctype.type = NF4DIR;  break;
 248         /*
 249          * XXX the following 'r' type is added for testing BADTYPE
 250          */
 251         case 'r':       ctype.type = NF4REG;  break;
 252         default:
 253                 sprintf(buf, "Unknown create-type [%c]", ct);
 254                 interp->result = buf;
 255                 return (TCL_ERROR);
 256         }
 257 
 258         substitution(interp, argv[1]);
 259         argv[1] = interp->result;
 260         opp->nfs_argop4_u.opcreate.objname = *str2utf8(argv[1]);
 261 
 262         substitution(interp, argv[2]);
 263         argv[2] = interp->result;
 264         if ((attr_encode(interp, argv[2], &bm, &av)) != TCL_OK)
 265                 return (TCL_ERROR);
 266         opp->nfs_argop4_u.opcreate.createattrs.attrmask = bm;
 267         opp->nfs_argop4_u.opcreate.createattrs.attr_vals = av;
 268 
 269         opp->nfs_argop4_u.opcreate.objtype = ctype;
 270 
 271         return (TCL_OK);
 272 }
 273 
 274 int
 275 Delegpurge(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 276 {
 277         nfs_argop4 *opp = new_argop();
 278 
 279         if (argc < 2) {
 280                 interp->result = "Usage: Delegpurge clientid";
 281                 return (TCL_ERROR);
 282         }
 283 
 284         opp->argop = OP_DELEGPURGE;
 285         substitution(interp, argv[1]);
 286         argv[1] = interp->result;
 287         opp->nfs_argop4_u.opdelegpurge.clientid = strtoull(argv[1], NULL, 16);
 288 
 289         return (TCL_OK);
 290 }
 291 
 292 int
 293 Delegreturn(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 294 {
 295         int lc;
 296         char **lv;
 297         stateid4 stateid;
 298 
 299         nfs_argop4 *opp = new_argop();
 300 
 301         if (argc < 2) {
 302                 interp->result = "Usage: Delegreturn stateid{seqid other}";
 303                 return (TCL_ERROR);
 304         }
 305 
 306         opp->argop = OP_DELEGRETURN;
 307         substitution(interp, argv[1]);
 308         argv[1] = interp->result;
 309         if (str2stateid(interp, argv[1], &stateid) != TCL_OK) {
 310                 interp->result = "Delegreturn: str2stateid() error";
 311                 return (TCL_ERROR);
 312         }
 313 
 314         opp->nfs_argop4_u.opdelegreturn.deleg_stateid = stateid;
 315 
 316         return (TCL_OK);
 317 }
 318 
 319 int
 320 Getattr(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 321 {
 322         bitmap4 bm;
 323         int err;
 324         char lv1[2048];
 325 
 326         nfs_argop4 *opp = new_argop();
 327 
 328         if (argc != 2) {
 329                 interp->result =
 330                     "Usage: Getattr { attrname attrname ... }";
 331                 return (TCL_ERROR);
 332         }
 333 
 334         opp->argop = OP_GETATTR;
 335 
 336         substitution(interp, argv[1]);
 337         strcpy(lv1, interp->result);
 338         err = names2bitmap(interp, lv1, &bm);
 339         if (err != TCL_OK)
 340                 return (err);
 341 
 342         opp->nfs_argop4_u.opgetattr.attr_request = bm;
 343 
 344         return (TCL_OK);
 345 }
 346 
 347 int
 348 Getfh(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 349 {
 350         nfs_argop4 *opp = new_argop();
 351         if (argc != 1) {
 352                 interp->result = "Arguments ignored!\nUsage: Getfh";
 353         }
 354         opp->argop = OP_GETFH;
 355 
 356         return (TCL_OK);
 357 }
 358 
 359 int
 360 Illegal(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 361 {
 362         nfs_argop4 *opp = new_argop();
 363         if (argc != 1) {
 364                 interp->result = "Arguments ignored!\nUsage: Illegal";
 365         }
 366         opp->argop = OP_ILLEGAL;
 367 
 368         return (TCL_OK);
 369 }
 370 
 371 int
 372 Link(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 373 {
 374         nfs_argop4 *opp = new_argop();
 375 
 376         if (argc != 2) {
 377                 interp->result = "Usage: Link newname";
 378                 return (TCL_ERROR);
 379         }
 380 
 381         opp->argop = OP_LINK;
 382         substitution(interp, argv[1]);
 383         argv[1] = interp->result;
 384         opp->nfs_argop4_u.oplink.newname = *str2utf8(argv[1]);
 385 
 386         return (TCL_OK);
 387 }
 388 
 389 int
 390 Lock(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 391 {
 392         int     lt;
 393         bool_t  rc;
 394         stateid4 stateid;
 395         lock_owner4 lowner;
 396         seqid4 lseqid;
 397         seqid4 oseqid;
 398         int lc;
 399         char **lv;
 400         char buf[80], lv2[1024];
 401 
 402         nfs_argop4 *opp = new_argop();
 403 
 404         if (argc < 8) {
 405                 interp->result =
 406                     "Usage: Lock ltype(1|2|3|4) reclaim(T|F) offset "
 407                     "length newlock(T|F)\n       "
 408                     "stateid{seqid other} lseqid {oseqid clientid lowner}";
 409                 return (TCL_ERROR);
 410         }
 411 
 412         opp->argop = OP_LOCK;
 413         substitution(interp, argv[1]);
 414         argv[1] = interp->result;
 415         lt = atoi(argv[1]);
 416         switch (lt) {
 417         case 1:
 418                 opp->nfs_argop4_u.oplock.locktype = READ_LT;
 419                 break;
 420         case 2:
 421                 opp->nfs_argop4_u.oplock.locktype = WRITE_LT;
 422                 break;
 423         case 3:
 424                 opp->nfs_argop4_u.oplock.locktype = READW_LT;
 425                 break;
 426         case 4:
 427                 opp->nfs_argop4_u.oplock.locktype = WRITEW_LT;
 428                 break;
 429         default:
 430                 sprintf(buf, "Unknown lock-type [%s]", argv[1]);
 431                 interp->result = buf;
 432                 return (TCL_ERROR);
 433         }
 434         substitution(interp, argv[2]);
 435         argv[2] = interp->result;
 436         rc = argv[2][0];
 437         switch (rc) {
 438         case 'T':
 439         case 't':
 440                 opp->nfs_argop4_u.oplock.reclaim = TRUE;
 441                 break;
 442         case 'F':
 443         case 'f':
 444                 opp->nfs_argop4_u.oplock.reclaim = FALSE;
 445                 break;
 446         default:
 447                 sprintf(buf, "Unknown reclaim [%s]; should be T|F", argv[2]);
 448                 interp->result = buf;
 449                 return (TCL_ERROR);
 450         }
 451         substitution(interp, argv[3]);
 452         argv[3] = interp->result;
 453         opp->nfs_argop4_u.oplock.offset = (offset4) strtoull(argv[3], NULL, 10);
 454         substitution(interp, argv[4]);
 455         argv[4] = interp->result;
 456         opp->nfs_argop4_u.oplock.length = (length4) strtoull(argv[4], NULL, 10);
 457         substitution(interp, argv[5]);
 458         argv[5] = interp->result;
 459         rc = argv[5][0];
 460         substitution(interp, argv[6]);
 461         argv[6] = interp->result;
 462         if (str2stateid(interp, argv[6], &stateid) != TCL_OK) {
 463                 interp->result = "Lock: str2stateid() error";
 464                 return (TCL_ERROR);
 465         }
 466         substitution(interp, argv[7]);
 467         argv[7] = interp->result;
 468         lseqid = (seqid4) atoi(argv[7]);
 469         /*
 470          * argv[8] is for new open only;
 471          * Need to split "{oseqid clientid owner}".
 472          */
 473         substitution(interp, argv[8]);
 474         argv[8] = interp->result;
 475         if (Tcl_SplitList(interp, argv[8], &lc,
 476             (CONST84 char ***)&lv) != TCL_OK) {
 477                 sprintf(buf, "Lock arg error, can't split {%s}", argv[8]);
 478                 interp->result = buf;
 479                 return (TCL_ERROR);
 480         }
 481         if (lc < 3) {
 482                 sprintf(buf,
 483                     "Lock arg error, {%s} needs at least 3 fields", argv[8]);
 484                 interp->result = buf;
 485                 if (lv)
 486                         free((char *)lv);
 487                 return (TCL_ERROR);
 488         }
 489         substitution(interp, lv[0]);
 490         oseqid = (seqid4)atoi(interp->result);
 491         substitution(interp, lv[1]);
 492         lowner.clientid = (clientid4)strtoull(interp->result, NULL, 16);
 493         substitution(interp, lv[2]);
 494         strcpy(lv2, interp->result);
 495         lowner.owner.owner_val = lv2;
 496         lowner.owner.owner_len = strlen(lowner.owner.owner_val);
 497         switch (rc) {
 498         case 'T':
 499         case 't':
 500         opp->nfs_argop4_u.oplock.locker.new_lock_owner = TRUE;
 501         opp->nfs_argop4_u.oplock.locker.locker4_u.open_owner.open_stateid =
 502             stateid;
 503         opp->nfs_argop4_u.oplock.locker.locker4_u.open_owner.open_seqid =
 504             oseqid;
 505         opp->nfs_argop4_u.oplock.locker.locker4_u.open_owner.lock_seqid =
 506             lseqid;
 507         opp->nfs_argop4_u.oplock.locker.locker4_u.open_owner.lock_owner =
 508             lowner;
 509         break;
 510         case 'F':
 511         case 'f':
 512         opp->nfs_argop4_u.oplock.locker.new_lock_owner = FALSE;
 513         opp->nfs_argop4_u.oplock.locker.locker4_u.lock_owner.lock_stateid =
 514             stateid;
 515         opp->nfs_argop4_u.oplock.locker.locker4_u.lock_owner.lock_seqid =
 516             lseqid;
 517         break;
 518         default:
 519                 sprintf(buf, "Unknown newlock [%s]; should be T|F", argv[5]);
 520                 interp->result = buf;
 521                 if (lv)
 522                         free((char *)lv);
 523                 return (TCL_ERROR);
 524         }
 525 
 526         if (lv)
 527                 free((char *)lv);
 528         return (TCL_OK);
 529 }
 530 
 531 int
 532 Lockt(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 533 {
 534         int     lt;
 535         bool_t  rc;
 536         char buf[80], lv3[1024];
 537 
 538         nfs_argop4 *opp = new_argop();
 539 
 540         if (argc != 6) {
 541                 interp->result = "Usage: Lockt type(1|2|3|4) "
 542                     "clientid lowner offset length";
 543                 return (TCL_ERROR);
 544         }
 545 
 546         opp->argop = OP_LOCKT;
 547         substitution(interp, argv[1]);
 548         argv[1] = interp->result;
 549         lt = atoi(argv[1]);
 550         switch (lt) {
 551         case 1:
 552                 opp->nfs_argop4_u.oplockt.locktype = READ_LT;
 553                 break;
 554         case 2:
 555                 opp->nfs_argop4_u.oplockt.locktype = WRITE_LT;
 556                 break;
 557         case 3:
 558                 opp->nfs_argop4_u.oplockt.locktype = READW_LT;
 559                 break;
 560         case 4:
 561                 opp->nfs_argop4_u.oplockt.locktype = WRITEW_LT;
 562                 break;
 563         default:
 564                 sprintf(buf, "Unknown lock-type [%s]", argv[1]);
 565                 interp->result = buf;
 566                 return (TCL_ERROR);
 567         }
 568         substitution(interp, argv[2]);
 569         argv[2] = interp->result;
 570         opp->nfs_argop4_u.oplockt.owner.clientid =
 571             (clientid4) strtoull(argv[2], NULL, 16);
 572 
 573         substitution(interp, argv[3]);
 574         strcpy(lv3, interp->result);
 575 
 576         opp->nfs_argop4_u.oplockt.owner.owner.owner_val = lv3;
 577         opp->nfs_argop4_u.oplockt.owner.owner.owner_len = strlen(lv3);
 578         substitution(interp, argv[4]);
 579         argv[4] = interp->result;
 580         opp->nfs_argop4_u.oplockt.offset =
 581             (offset4) strtoull(argv[4], (char **)NULL, 10);
 582         substitution(interp, argv[5]);
 583         argv[5] = interp->result;
 584         opp->nfs_argop4_u.oplockt.length =
 585             (length4) strtoull(argv[5], (char **)NULL, 10);
 586 
 587         return (TCL_OK);
 588 }
 589 
 590 int
 591 Locku(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 592 {
 593         int     lt;
 594         char buf[80];
 595         stateid4 stateid;
 596 
 597         nfs_argop4 *opp = new_argop();
 598 
 599         if (argc != 6) {
 600                 interp->result =
 601                     "Usage: Locku type(1|2|3|4) lseqid "
 602                     "lstateid{seqid other} offset length";
 603                 return (TCL_ERROR);
 604         }
 605 
 606         opp->argop = OP_LOCKU;
 607         substitution(interp, argv[1]);
 608         argv[1] = interp->result;
 609         lt = atoi(argv[1]);
 610         switch (lt) {
 611         case 1:
 612                 opp->nfs_argop4_u.oplocku.locktype = READ_LT;
 613                 break;
 614         case 2:
 615                 opp->nfs_argop4_u.oplocku.locktype = WRITE_LT;
 616                 break;
 617         case 3:
 618                 opp->nfs_argop4_u.oplocku.locktype = READW_LT;
 619                 break;
 620         case 4:
 621                 opp->nfs_argop4_u.oplocku.locktype = WRITEW_LT;
 622                 break;
 623         default:
 624                 sprintf(buf, "Unknown locktype [%s]", argv[1]);
 625                 interp->result = buf;
 626                 return (TCL_ERROR);
 627         }
 628         substitution(interp, argv[2]);
 629         argv[2] = interp->result;
 630         opp->nfs_argop4_u.oplocku.seqid = (seqid4)atoi(argv[2]);
 631         substitution(interp, argv[3]);
 632         argv[3] = interp->result;
 633         if (str2stateid(interp, argv[3], &stateid) != TCL_OK) {
 634                 interp->result = "Locku: str2stateid() error";
 635                 return (TCL_ERROR);
 636         }
 637         opp->nfs_argop4_u.oplocku.lock_stateid = stateid;
 638         substitution(interp, argv[4]);
 639         argv[4] = interp->result;
 640         opp->nfs_argop4_u.oplocku.offset =
 641             (offset4) strtoull(argv[4], (char **)NULL, 10);
 642         substitution(interp, argv[5]);
 643         argv[5] = interp->result;
 644         opp->nfs_argop4_u.oplocku.length =
 645             (length4) strtoull(argv[5], (char **)NULL, 10);
 646 
 647         return (TCL_OK);
 648 }
 649 
 650 int
 651 Lookup(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 652 {
 653         nfs_argop4 *opp = new_argop();
 654 
 655         if (argc != 2) {
 656                 interp->result = "Usage: Lookup objname";
 657                 return (TCL_ERROR);
 658         }
 659 
 660         opp->argop = OP_LOOKUP;
 661 
 662         substitution(interp, argv[1]);
 663         argv[1] = interp->result;
 664         opp->nfs_argop4_u.oplookup.objname = *str2utf8(argv[1]);
 665 
 666         return (TCL_OK);
 667 }
 668 
 669 int
 670 Lookupp(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 671 {
 672         nfs_argop4 *opp = new_argop();
 673         if (argc != 1) {
 674                 interp->result = "Arguments ignored!\nUsage: Lookupp";
 675         }
 676         opp->argop = OP_LOOKUPP;
 677 
 678         return (TCL_OK);
 679 }
 680 
 681 int
 682 Nverify(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 683 {
 684         bitmap4 bm;
 685         attrlist4 av;
 686         char lv1[2048];
 687 
 688         nfs_argop4 *opp = new_argop();
 689 
 690         if (argc != 2) {
 691                 interp->result =
 692                     "Usage: Nverify { {name val} {name val} ... }";
 693                 return (TCL_ERROR);
 694         }
 695 
 696         opp->argop = OP_NVERIFY;
 697 
 698         substitution(interp, argv[1]);
 699         strcpy(lv1, interp->result);
 700         if ((attr_encode(interp, lv1, &bm, &av)) != TCL_OK)
 701                 return (TCL_ERROR);
 702 
 703         opp->nfs_argop4_u.opnverify.obj_attributes.attrmask = bm;
 704         opp->nfs_argop4_u.opnverify.obj_attributes.attr_vals = av;
 705 
 706         return (TCL_OK);
 707 }
 708 
 709 int
 710 Open(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 711 {
 712         nfs_argop4 *opp = new_argop();
 713 
 714         if (argc != 7) {
 715                 interp->result =
 716                     "Usage: Open\n       oseqid "
 717                     "access(1|2|3) deny(0|1|2|3) {clientid open_owner}\n"
 718                     "       {opentype(0|1) createmode(0|1|2) "
 719                     "{{name val} {name val}...} | createverf}\n       "
 720                     "{claim(0|1|2|3) {filename | delegate_type | "
 721                     "{delegate_stateid filename}}}\n       ";
 722                 return (TCL_ERROR);
 723         }
 724 
 725         opp->argop = OP_OPEN;
 726         substitution(interp, argv[1]);
 727         argv[1] = interp->result;
 728         opp->nfs_argop4_u.opopen.seqid = (seqid4)atoi(argv[1]);
 729         substitution(interp, argv[2]);
 730         argv[2] = interp->result;
 731         opp->nfs_argop4_u.opopen.share_access = (uint32_t)atoi(argv[2]);
 732         substitution(interp, argv[3]);
 733         argv[3] = interp->result;
 734         opp->nfs_argop4_u.opopen.share_deny = (uint32_t)atoi(argv[3]);
 735         /* no substitution is needed for argv[4] to argv[6] here, */
 736         /* since its done inside the set_xxxxx() functions */
 737         if (set_owner(interp, argv[4], &opp->nfs_argop4_u.opopen.owner)
 738             != TCL_OK)
 739                 return (TCL_ERROR);
 740         if (set_opentype(interp, argv[5], &opp->nfs_argop4_u.opopen.openhow)
 741             != TCL_OK)
 742                 return (TCL_ERROR);
 743         if (set_openclaim(interp, argv[6], &opp->nfs_argop4_u.opopen.claim)
 744             != TCL_OK)
 745                 return (TCL_ERROR);
 746 
 747         return (TCL_OK);
 748 }
 749 
 750 int
 751 Openattr(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 752 {
 753         bool_t cdir;
 754         char buf[80];
 755 
 756         nfs_argop4 *opp = new_argop();
 757 
 758         if (argc != 2) {
 759                 interp->result = "Usage: Openattr createdir(T|F)";
 760                 return (TCL_ERROR);
 761         }
 762 
 763         opp->argop = OP_OPENATTR;
 764 
 765         substitution(interp, argv[1]);
 766         argv[1] = interp->result;
 767         cdir = argv[1][0];
 768         switch (cdir) {
 769         case 'T':
 770         case 't':
 771                 opp->nfs_argop4_u.opopenattr.createdir = TRUE;
 772                 break;
 773         case 'F':
 774         case 'f':
 775                 opp->nfs_argop4_u.opopenattr.createdir = FALSE;
 776                 break;
 777         default:
 778                 sprintf(buf, "Unknown createdir [%s]; should be T|F", argv[1]);
 779                 interp->result = buf;
 780                 return (TCL_ERROR);
 781         }
 782 
 783         return (TCL_OK);
 784 }
 785 
 786 int
 787 Open_confirm(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 788 {
 789         stateid4 stateid;
 790         nfs_argop4 *opp = new_argop();
 791 
 792         if (argc != 3) {
 793                 interp->result = "Usage: Open_confirm "
 794                     "open_stateid{seqid other} seqid";
 795                 return (TCL_ERROR);
 796         }
 797 
 798         opp->argop = OP_OPEN_CONFIRM;
 799         substitution(interp, argv[1]);
 800         argv[1] = interp->result;
 801         if (str2stateid(interp, argv[1], &stateid) != TCL_OK) {
 802                 interp->result = "Open_confirm: str2stateid() error";
 803                 return (TCL_ERROR);
 804         }
 805         opp->nfs_argop4_u.opopen_confirm.open_stateid = stateid;
 806         substitution(interp, argv[2]);
 807         argv[2] = interp->result;
 808         opp->nfs_argop4_u.opopen_confirm.seqid = (seqid4) atoi(argv[2]);
 809 
 810         return (TCL_OK);
 811 }
 812 
 813 int
 814 Open_downgrade(ClientData clientData, Tcl_Interp *interp,
 815     int argc, char *argv[])
 816 {
 817         stateid4 stateid;
 818         nfs_argop4 *opp = new_argop();
 819 
 820         if (argc != 5) {
 821                 interp->result =
 822                     "Usage: Open_downgrade stateid{seqid other} "
 823                     "seqid access deny";
 824                 return (TCL_ERROR);
 825         }
 826 
 827         opp->argop = OP_OPEN_DOWNGRADE;
 828         substitution(interp, argv[1]);
 829         argv[1] = interp->result;
 830         if (str2stateid(interp, argv[1], &stateid) != TCL_OK) {
 831                 interp->result = "Open_downgrade: str2stateid() error";
 832                 return (TCL_ERROR);
 833         }
 834         opp->nfs_argop4_u.opopen_downgrade.open_stateid = stateid;
 835         substitution(interp, argv[2]);
 836         argv[2] = interp->result;
 837         opp->nfs_argop4_u.opopen_downgrade.seqid = (seqid4)atoi(argv[2]);
 838         substitution(interp, argv[3]);
 839         argv[3] = interp->result;
 840         opp->nfs_argop4_u.opopen_downgrade.share_access =
 841             (uint32_t)atoi(argv[3]);
 842         substitution(interp, argv[4]);
 843         argv[4] = interp->result;
 844         opp->nfs_argop4_u.opopen_downgrade.share_deny =
 845             (uint32_t)atoi(argv[4]);
 846 
 847         return (TCL_OK);
 848 }
 849 
 850 int
 851 Putfh(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 852 {
 853         char *fhstr;
 854         int fhlen;
 855         char *fhp;
 856 
 857         nfs_argop4 *opp = new_argop();
 858 
 859         if (argc != 2) {
 860                 interp->result = "Usage: Putfh <fh>";
 861                 return (TCL_ERROR);
 862         }
 863 
 864         opp->argop = OP_PUTFH;
 865         substitution(interp, argv[1]);
 866         argv[1] = interp->result;
 867         fhstr = argv[1];
 868         fhlen = (strlen(fhstr) + 1) / 2;
 869 
 870         fhp = malloc(fhlen);
 871         if (fhp == NULL) {
 872                 interp->result = "malloc failure in Putfh";
 873                 return (TCL_ERROR);
 874         }
 875         (void) memcpy(fhp, hex2bin(fhstr, (unsigned)fhlen), fhlen);
 876 
 877         opp->nfs_argop4_u.opputfh.object.nfs_fh4_len = fhlen;
 878         opp->nfs_argop4_u.opputfh.object.nfs_fh4_val = fhp;
 879 
 880         return (TCL_OK);
 881 }
 882 
 883 int
 884 Putpubfh(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 885 {
 886         nfs_argop4 *opp = new_argop();
 887         if (argc != 1) {
 888                 interp->result = "Arguments ignored!\nUsage: Putpubfh";
 889         }
 890         opp->argop = OP_PUTPUBFH;
 891 
 892         return (TCL_OK);
 893 }
 894 
 895 int
 896 Putrootfh(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 897 {
 898         nfs_argop4 *opp = new_argop();
 899         if (argc != 1) {
 900                 interp->result = "Arguments ignored!\nUsage: Putrootfh";
 901         }
 902         opp->argop = OP_PUTROOTFH;
 903 
 904         return (TCL_OK);
 905 }
 906 
 907 int
 908 Read(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 909 {
 910         stateid4 stateid;
 911         nfs_argop4 *opp = new_argop();
 912 
 913         if (argc != 4) {
 914                 interp->result = "Usage: Read stateid{seqid other} "
 915                     "offset count";
 916                 return (TCL_ERROR);
 917         }
 918 
 919         opp->argop = OP_READ;
 920 
 921         substitution(interp, argv[1]);
 922         argv[1] = interp->result;
 923         if (str2stateid(interp, argv[1], &stateid) != TCL_OK) {
 924                 interp->result = "Read: str2stateid() error";
 925                 return (TCL_ERROR);
 926         }
 927         opp->nfs_argop4_u.opread.stateid = stateid;
 928         substitution(interp, argv[2]);
 929         argv[2] = interp->result;
 930         opp->nfs_argop4_u.opread.offset =
 931             (offset4) strtoull(argv[2], (char **)NULL, 10);
 932         substitution(interp, argv[3]);
 933         argv[3] = interp->result;
 934         opp->nfs_argop4_u.opread.count = (count4) atoi(argv[3]);
 935 
 936         return (TCL_OK);
 937 }
 938 
 939 int
 940 Readdir(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
 941 {
 942         nfs_cookie4 cookie;
 943         verifier4 verf;
 944         count4 dircount;
 945         count4 maxcount;
 946         bitmap4 bm;
 947         int err;
 948         char lv3[1024], lv4[1024], lv5[2048];
 949 
 950         nfs_argop4 *opp = new_argop();
 951 
 952         if (argc != 6) {
 953                 interp->result =
 954                     "Usage: Readdir cookie verf "
 955                     "dircount maxcount {attrname ...}";
 956                 return (TCL_ERROR);
 957         }
 958 
 959         opp->argop = OP_READDIR;
 960 
 961         substitution(interp, argv[1]);
 962         argv[1] = interp->result;
 963 
 964         cookie = (nfs_cookie4) strtoull(argv[1], NULL, 10);
 965 
 966         substitution(interp, argv[2]);
 967         argv[2] = interp->result;
 968         (void) memcpy(verf, hex2bin(argv[2], sizeof (verf)), sizeof (verf));
 969 
 970         substitution(interp, argv[3]);
 971         strcpy(lv3, interp->result);
 972         if (Tcl_GetInt(interp, lv3, (int *)&dircount) != TCL_OK)
 973                 goto err;
 974 
 975         substitution(interp, argv[4]);
 976         strcpy(lv4, interp->result);
 977         if (Tcl_GetInt(interp, lv4, (int *)&maxcount) != TCL_OK)
 978                 goto err;
 979 
 980         opp->nfs_argop4_u.opreaddir.cookie = cookie;
 981         (void) memcpy(opp->nfs_argop4_u.opreaddir.cookieverf,
 982             verf, sizeof (verf));
 983         opp->nfs_argop4_u.opreaddir.dircount = dircount;
 984         opp->nfs_argop4_u.opreaddir.maxcount = maxcount;
 985 
 986         substitution(interp, argv[5]);
 987         strcpy(lv5, interp->result);
 988         err = names2bitmap(interp, lv5, &bm);
 989         if (err != TCL_OK)
 990                 return (err);
 991 
 992         opp->nfs_argop4_u.opreaddir.attr_request = bm;
 993 
 994         return (TCL_OK);
 995 
 996 err:
 997         return (TCL_ERROR);
 998 }
 999 
1000 int
1001 Readlink(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1002 {
1003         nfs_argop4 *opp = new_argop();
1004         if (argc != 1) {
1005                 interp->result = "Arguments ignored!\nUsage: Readlink";
1006         }
1007         opp->argop = OP_READLINK;
1008 
1009         return (TCL_OK);
1010 }
1011 
1012 int
1013 Release_lockowner(ClientData clientData, Tcl_Interp *interp,
1014         int argc, char *argv[])
1015 {
1016         char tmp[1024];
1017         nfs_argop4 *opp = new_argop();
1018 
1019         if (argc != 3) {
1020                 interp->result = "Usage: Release_lockowner clientid lowner";
1021                 return (TCL_ERROR);
1022         }
1023 
1024         opp->argop = OP_RELEASE_LOCKOWNER;
1025         substitution(interp, argv[1]);
1026         argv[1] = interp->result;
1027         opp->nfs_argop4_u.oprelease_lockowner.lock_owner.clientid =
1028             (clientid4) strtoull(argv[1], NULL, 16);
1029 
1030         substitution(interp, argv[2]);
1031         strcpy(tmp, interp->result);
1032         opp->nfs_argop4_u.oprelease_lockowner.lock_owner.owner.owner_val = tmp;
1033         opp->nfs_argop4_u.oprelease_lockowner.lock_owner.owner.owner_len =
1034             strlen(tmp);
1035 
1036         return (TCL_OK);
1037 }
1038 
1039 int
1040 Remove(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1041 {
1042         nfs_argop4 *opp = new_argop();
1043 
1044         if (argc != 2) {
1045                 interp->result = "Usage: Remove target";
1046                 return (TCL_ERROR);
1047         }
1048 
1049         opp->argop = OP_REMOVE;
1050         substitution(interp, argv[1]);
1051         argv[1] = interp->result;
1052         opp->nfs_argop4_u.oplink.newname = *str2utf8(argv[1]);
1053 
1054         return (TCL_OK);
1055 }
1056 
1057 int
1058 Rename(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1059 {
1060         nfs_argop4 *opp = new_argop();
1061 
1062         if (argc != 3) {
1063                 interp->result = "Usage: Rename oldname newname";
1064                 return (TCL_ERROR);
1065         }
1066 
1067         opp->argop = OP_RENAME;
1068         substitution(interp, argv[1]);
1069         argv[1] = interp->result;
1070         opp->nfs_argop4_u.oprename.oldname = *str2utf8(argv[1]);
1071         substitution(interp, argv[2]);
1072         argv[2] = interp->result;
1073         opp->nfs_argop4_u.oprename.newname = *str2utf8(argv[2]);
1074 
1075         return (TCL_OK);
1076 }
1077 
1078 int
1079 Renew(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1080 {
1081         nfs_argop4 *opp = new_argop();
1082 
1083         if (argc != 2) {
1084                 interp->result = "Usage: Renew clientid";
1085                 return (TCL_ERROR);
1086         }
1087 
1088         opp->argop = OP_RENEW;
1089 
1090         substitution(interp, argv[1]);
1091         argv[1] = interp->result;
1092         opp->nfs_argop4_u.oprenew.clientid =
1093             (clientid4) strtoull(argv[1], NULL, 16);
1094 
1095         return (TCL_OK);
1096 }
1097 
1098 int
1099 Restorefh(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1100 {
1101         nfs_argop4 *opp = new_argop();
1102         if (argc != 1) {
1103                 interp->result = "Arguments ignored!\nUsage: Restorefh";
1104         }
1105         opp->argop = OP_RESTOREFH;
1106 
1107         return (TCL_OK);
1108 }
1109 
1110 int
1111 Savefh(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1112 {
1113         nfs_argop4 *opp = new_argop();
1114         if (argc != 1) {
1115                 interp->result = "Arguments ignored!\nUsage: Savefh";
1116         }
1117         opp->argop = OP_SAVEFH;
1118 
1119         return (TCL_OK);
1120 }
1121 
1122 int
1123 Secinfo(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1124 {
1125         nfs_argop4 *opp = new_argop();
1126 
1127         if (argc != 2) {
1128                 interp->result = "Usage: Secinfo name";
1129                 return (TCL_ERROR);
1130         }
1131 
1132         opp->argop = OP_SECINFO;
1133         substitution(interp, argv[1]);
1134         argv[1] = interp->result;
1135         opp->nfs_argop4_u.opsecinfo.name = *str2utf8(argv[1]);
1136 
1137         return (TCL_OK);
1138 }
1139 
1140 int
1141 Setattr(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1142 {
1143         bitmap4 bm;
1144         attrlist4 av;
1145         stateid4 stateid;
1146         char lv2[2048];
1147 
1148         nfs_argop4 *opp = new_argop();
1149 
1150         if (argc != 3) {
1151                 interp->result =
1152                     "Usage: Setattr stateid{seqid other}"
1153                     " { {name val} {name val} ... }";
1154                 return (TCL_ERROR);
1155         }
1156         opp->argop = OP_SETATTR;
1157 
1158         substitution(interp, argv[1]);
1159         argv[1] = interp->result;
1160         if (str2stateid(interp, argv[1], &stateid) != TCL_OK) {
1161                 interp->result = "Setattr: str2stateid() error";
1162                 return (TCL_ERROR);
1163         }
1164         opp->nfs_argop4_u.opsetattr.stateid = stateid;
1165 
1166         substitution(interp, argv[2]);
1167         strcpy(lv2, interp->result);
1168         if ((attr_encode(interp, lv2, &bm, &av)) != TCL_OK)
1169                 return (TCL_ERROR);
1170         opp->nfs_argop4_u.opsetattr.obj_attributes.attrmask = bm;
1171         opp->nfs_argop4_u.opsetattr.obj_attributes.attr_vals = av;
1172 
1173         return (TCL_OK);
1174 }
1175 
1176 int
1177 Setclientid(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1178 {
1179         char lv2[1024];
1180         nfs_argop4 *opp = new_argop();
1181 
1182         if (argc != 4) {
1183                 interp->result =
1184                     "Usage: Setclientid verifier id {cb_prog netid addr} \n\
1185 \t(The callback is not yet implemented; its values are set to NULL.)";
1186                 return (TCL_ERROR);
1187         }
1188 
1189         opp->argop = OP_SETCLIENTID;
1190         substitution(interp, argv[1]);
1191         argv[1] = interp->result;
1192         (void) memcpy(opp->nfs_argop4_u.opsetclientid.client.verifier,
1193             hex2bin(argv[1], sizeof (verifier4)), sizeof (verifier4));
1194 
1195         substitution(interp, argv[2]);
1196         strcpy(lv2, interp->result);
1197         opp->nfs_argop4_u.opsetclientid.client.id.id_val = lv2;
1198         opp->nfs_argop4_u.opsetclientid.client.id.id_len = strlen(lv2);
1199 
1200         /*
1201          * XXX The callback program has not yet been implemented;
1202          * thus it uses NULL for these temporary.
1203          */
1204         opp->nfs_argop4_u.opsetclientid.callback.cb_program = 0;
1205         opp->nfs_argop4_u.opsetclientid.callback.cb_location.r_netid = NULL;
1206         opp->nfs_argop4_u.opsetclientid.callback.cb_location.r_addr = NULL;
1207 
1208 
1209         /*
1210          * XXX callback_ident is not yet implemented, nor it is the interface
1211          * to get its value from the user. Use 0 as a temporal value.
1212          * This is to avoid modifying all occurrences of setclientid in
1213          * testcases while callback is not implemented.
1214          */
1215         opp->nfs_argop4_u.opsetclientid.callback_ident = 0;
1216 
1217         return (TCL_OK);
1218 }
1219 
1220 int
1221 Setclientid_confirm(ClientData clientData, Tcl_Interp *interp,
1222     int argc, char *argv[])
1223 {
1224         nfs_argop4 *opp = new_argop();
1225 
1226         if (argc != 3) {
1227                 interp->result =
1228                     "Usage: Setclientid_confirm clientid verifier";
1229                 return (TCL_ERROR);
1230         }
1231 
1232         opp->argop = OP_SETCLIENTID_CONFIRM;
1233         substitution(interp, argv[1]);
1234         argv[1] = interp->result;
1235         opp->nfs_argop4_u.opsetclientid_confirm.clientid =
1236             (clientid4) strtoull(argv[1], NULL, 16);
1237         substitution(interp, argv[2]);
1238         argv[2] = interp->result;
1239         (void) memcpy(
1240             opp->nfs_argop4_u.opsetclientid_confirm.setclientid_confirm,
1241             hex2bin(argv[2], sizeof (verifier4)), sizeof (verifier4));
1242 
1243         return (TCL_OK);
1244 }
1245 
1246 int
1247 Verify(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1248 {
1249         bitmap4 bm;
1250         attrlist4 av;
1251         char lv1[2048];
1252 
1253         nfs_argop4 *opp = new_argop();
1254 
1255         if (argc != 2) {
1256                 interp->result =
1257                     "Usage: Verify { {name val} {name val} ... }";
1258                 return (TCL_ERROR);
1259         }
1260 
1261         opp->argop = OP_VERIFY;
1262 
1263         substitution(interp, argv[1]);
1264         strcpy(lv1, interp->result);
1265         if ((attr_encode(interp, lv1, &bm, &av)) != TCL_OK)
1266                 return (TCL_ERROR);
1267 
1268         opp->nfs_argop4_u.opverify.obj_attributes.attrmask = bm;
1269         opp->nfs_argop4_u.opverify.obj_attributes.attr_vals = av;
1270 
1271         return (TCL_OK);
1272 }
1273 
1274 int
1275 Write(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
1276 {
1277         stateid4 stateid;
1278         offset4 offset;
1279         stable_how4 stable;
1280         char *data;
1281         int datalen;
1282         char *dp;
1283         char sh, dt, buf[1024];
1284 
1285         nfs_argop4 *opp = new_argop();
1286 
1287         if (argc != 6) {
1288                 interp->result = "Usage: Write stateid{seqid other} "
1289                     "offset how-u|d|f datatype-a|h {data}";
1290                 return (TCL_ERROR);
1291         }
1292 
1293         opp->argop = OP_WRITE;
1294 
1295         substitution(interp, argv[1]);
1296         argv[1] = interp->result;
1297         if (str2stateid(interp, argv[1], &stateid) != TCL_OK) {
1298                 interp->result = "Write: str2stateid() error";
1299                 return (TCL_ERROR);
1300         }
1301         opp->nfs_argop4_u.opwrite.stateid = stateid;
1302 
1303         substitution(interp, argv[2]);
1304         argv[2] = interp->result;
1305         opp->nfs_argop4_u.opwrite.offset =
1306             (offset4) strtoull(argv[2], (char **)NULL, 10);
1307 
1308         substitution(interp, argv[3]);
1309         argv[3] = interp->result;
1310         sh = *argv[3];
1311         switch (sh) {
1312         case 'u':       stable = UNSTABLE4; break;
1313         case 'd':       stable = (uint32_t)DATA_SYNC4; break;
1314         case 'f':       stable = (uint32_t)FILE_SYNC4; break;
1315         default:
1316                 sprintf(buf, "Unknown stable_how (%s);\n", argv[3]);
1317                 strcat(buf, "use u-UNSTABLE, d-DATA_SYNC, f-FILE_SYNC");
1318                 interp->result = buf;
1319                 return (TCL_ERROR);
1320         }
1321         opp->nfs_argop4_u.opwrite.stable = stable;
1322 
1323         substitution(interp, argv[4]);
1324         argv[4] = interp->result;
1325         dt = *argv[4];
1326 
1327         /* save the data from interp->result to avoid being overwritten */
1328         substitution(interp, argv[5]);
1329         argv[5] = interp->result;
1330         datalen = strlen(argv[5]);
1331         data = malloc(datalen);
1332         if (data == NULL) {
1333                 interp->result = "Write: malloc() error";
1334                 return (TCL_ERROR);
1335         }
1336         (void) memcpy(data, argv[5], datalen);
1337         switch (dt) {
1338         case 'a':
1339                 opp->nfs_argop4_u.opwrite.data.data_val = data;
1340                 opp->nfs_argop4_u.opwrite.data.data_len = datalen;
1341                 break;
1342         case 'h':       /* XXX user entered HEX data, utf8string? */
1343                 datalen = strlen(data) / 2;
1344                 dp = malloc(datalen);
1345                 if (dp == NULL) {
1346                         interp->result = "malloc failure in Write";
1347                         return (TCL_ERROR);
1348                 }
1349                 (void) memcpy(dp, hex2bin(data, (unsigned)datalen), datalen);
1350                 opp->nfs_argop4_u.opwrite.data.data_val = dp;
1351                 opp->nfs_argop4_u.opwrite.data.data_len = datalen;
1352         default:
1353                 sprintf(buf, "Unknown data-type(%s);\n", argv[4]);
1354                 strcat(buf, "use a-ASCII, h-HEX_DATA");
1355                 interp->result = buf;
1356                 return (TCL_ERROR);
1357         }
1358 
1359         return (TCL_OK);
1360 }
1361 
1362 
1363 /* ---------------------------------------- */
1364 /* Operation result evaluation functions.   */
1365 /* ---------------------------------------- */
1366 
1367 /*
1368  * Now the functions to decode the result
1369  */
1370 
1371 int
1372 Access_res(Tcl_Interp *interp, Tcl_DString *strp, ACCESS4res *resp)
1373 {
1374         Tcl_DStringStartSublist(strp);
1375         Tcl_DStringAppendElement(strp, "Access");
1376         Tcl_DStringAppendElement(strp, errstr(resp->status));
1377 
1378         if (resp->status == NFS4_OK) {
1379                 char buf[80];
1380 
1381                 Tcl_DStringStartSublist(strp);
1382 
1383                 sprintf(buf, "supported %s",
1384                     access2name(resp->ACCESS4res_u.resok4.supported));
1385                 Tcl_DStringAppendElement(strp, buf);
1386                 sprintf(buf, "access %s",
1387                     access2name(resp->ACCESS4res_u.resok4.access));
1388                 Tcl_DStringAppendElement(strp, buf);
1389 
1390                 Tcl_DStringEndSublist(strp);
1391         }
1392 
1393         Tcl_DStringEndSublist(strp);
1394         return (TCL_OK);
1395 }
1396 
1397 int
1398 Close_res(Tcl_Interp *interp, Tcl_DString *strp, CLOSE4res *resp)
1399 {
1400         char buf[80];
1401         stateid4 stateid;
1402 
1403         Tcl_DStringStartSublist(strp);
1404         Tcl_DStringAppendElement(strp, "Close");
1405         Tcl_DStringAppendElement(strp, errstr(resp->status));
1406 
1407         stateid = resp->CLOSE4res_u.open_stateid;
1408         sprintf(buf, "%lu %s", stateid.seqid,
1409             bin2hex(stateid.other, sizeof (stateid.other)));
1410         Tcl_DStringAppendElement(strp, buf);
1411 
1412         Tcl_DStringEndSublist(strp);
1413         return (TCL_OK);
1414 }
1415 
1416 int
1417 Commit_res(Tcl_Interp *interp, Tcl_DString *strp, COMMIT4res *resp)
1418 {
1419         char buf[80];
1420         verifier4 verf;
1421 
1422         Tcl_DStringStartSublist(strp);
1423         Tcl_DStringAppendElement(strp, "Commit");
1424         Tcl_DStringAppendElement(strp, errstr(resp->status));
1425 
1426         if (resp->status == NFS4_OK) {
1427                 (void) memcpy(verf, resp->COMMIT4res_u.resok4.writeverf,
1428                     sizeof (verf));
1429                 sprintf(buf, "%s", bin2hex(verf, sizeof (verf)));
1430                 Tcl_DStringAppendElement(strp, buf);
1431         }
1432 
1433         Tcl_DStringEndSublist(strp);
1434         return (TCL_OK);
1435 }
1436 
1437 int
1438 Create_res(Tcl_Interp *interp, Tcl_DString *strp, CREATE4res *resp)
1439 {
1440         Tcl_DStringStartSublist(strp);
1441         Tcl_DStringAppendElement(strp, "Create");
1442         Tcl_DStringAppendElement(strp, errstr(resp->status));
1443 
1444         if (resp->status == NFS4_OK) {
1445                 char buf[80];
1446                 change_info4 c;
1447 
1448                 c = resp->CREATE4res_u.resok4.cinfo;
1449                 Tcl_DStringStartSublist(strp);
1450 
1451                 sprintf(buf, "atomic %s", c.atomic ? "true" : "false");
1452                 Tcl_DStringAppendElement(strp, buf);
1453                 sprintf(buf, "before %.8llx", c.before);
1454                 Tcl_DStringAppendElement(strp, buf);
1455                 sprintf(buf, "after %.8llx", c.after);
1456                 Tcl_DStringAppendElement(strp, buf);
1457 
1458                 Tcl_DStringStartSublist(strp);
1459                 prn_attrname(strp, &resp->CREATE4res_u.resok4.attrset);
1460                 Tcl_DStringEndSublist(strp);
1461 
1462                 Tcl_DStringEndSublist(strp);
1463         }
1464 
1465         Tcl_DStringEndSublist(strp);
1466         return (TCL_OK);
1467 }
1468 
1469 int
1470 Delegpurge_res(Tcl_Interp *interp, Tcl_DString *strp, DELEGPURGE4res *resp)
1471 {
1472         Tcl_DStringStartSublist(strp);
1473         Tcl_DStringAppendElement(strp, "Delegpurge");
1474         Tcl_DStringAppendElement(strp, errstr(resp->status));
1475         Tcl_DStringEndSublist(strp);
1476         return (TCL_OK);
1477 }
1478 
1479 int
1480 Delegreturn_res(Tcl_Interp *interp, Tcl_DString *strp, DELEGRETURN4res *resp)
1481 {
1482         Tcl_DStringStartSublist(strp);
1483         Tcl_DStringAppendElement(strp, "Delegreturn");
1484         Tcl_DStringAppendElement(strp, errstr(resp->status));
1485         Tcl_DStringEndSublist(strp);
1486         return (TCL_OK);
1487 }
1488 
1489 int
1490 Getattr_res(Tcl_Interp *interp, Tcl_DString *strp, GETATTR4res *resp)
1491 {
1492         Tcl_DStringStartSublist(strp);
1493         Tcl_DStringAppendElement(strp, "Getattr");
1494         Tcl_DStringAppendElement(strp, errstr(resp->status));
1495 
1496         if (resp->status == NFS4_OK) {
1497                 bitmap4 bm;
1498                 attrlist4 attrvals;
1499                 int err;
1500 
1501                 bm = resp->GETATTR4res_u.resok4.obj_attributes.attrmask;
1502                 attrvals = resp->GETATTR4res_u.resok4.obj_attributes.attr_vals;
1503                 err = attr_decode(interp, strp, &bm, &attrvals);
1504                 if (err != TCL_OK)
1505                         return (TCL_ERROR);
1506         }
1507 
1508         Tcl_DStringEndSublist(strp);
1509         return (TCL_OK);
1510 }
1511 
1512 int
1513 Getfh_res(Tcl_Interp *interp, Tcl_DString *strp, GETFH4res *resp)
1514 {
1515         Tcl_DStringStartSublist(strp);
1516         Tcl_DStringAppendElement(strp, "Getfh");
1517         Tcl_DStringAppendElement(strp, errstr(resp->status));
1518 
1519         if (resp->status == NFS4_OK) {
1520                 unsigned fh_len;
1521                 char *fh_val;
1522 
1523                 fh_len = resp->GETFH4res_u.resok4.object.nfs_fh4_len;
1524                 fh_val = resp->GETFH4res_u.resok4.object.nfs_fh4_val;
1525                 Tcl_DStringAppendElement(strp, bin2hex(fh_val, fh_len));
1526         }
1527 
1528         Tcl_DStringEndSublist(strp);
1529         return (TCL_OK);
1530 }
1531 
1532 int
1533 Illegal_res(Tcl_Interp *interp, Tcl_DString *strp, ILLEGAL4res *resp)
1534 {
1535         Tcl_DStringStartSublist(strp);
1536         Tcl_DStringAppendElement(strp, "Illegal");
1537         Tcl_DStringAppendElement(strp, errstr(resp->status));
1538         Tcl_DStringEndSublist(strp);
1539         return (TCL_OK);
1540 }
1541 
1542 int
1543 Link_res(Tcl_Interp *interp, Tcl_DString *strp, LINK4res *resp)
1544 {
1545         Tcl_DStringStartSublist(strp);
1546         Tcl_DStringAppendElement(strp, "Link");
1547         Tcl_DStringAppendElement(strp, errstr(resp->status));
1548 
1549         if (resp->status == NFS4_OK) {
1550                 char buf[80];
1551                 change_info4 c;
1552 
1553                 c = resp->LINK4res_u.resok4.cinfo;
1554                 Tcl_DStringStartSublist(strp);
1555 
1556                 sprintf(buf, "atomic %s", c.atomic ? "true" : "false");
1557                 Tcl_DStringAppendElement(strp, buf);
1558                 sprintf(buf, "before %.8llx", c.before);
1559                 Tcl_DStringAppendElement(strp, buf);
1560                 sprintf(buf, "after %.8llx", c.after);
1561                 Tcl_DStringAppendElement(strp, buf);
1562 
1563                 Tcl_DStringEndSublist(strp);
1564         }
1565 
1566         Tcl_DStringEndSublist(strp);
1567         return (TCL_OK);
1568 }
1569 
1570 int
1571 Lock_res(Tcl_Interp *interp, Tcl_DString *strp, LOCK4res *resp)
1572 {
1573         char buf[80];
1574 
1575         Tcl_DStringStartSublist(strp);
1576         Tcl_DStringAppendElement(strp, "Lock");
1577         Tcl_DStringAppendElement(strp, errstr(resp->status));
1578 
1579         if (resp->status == NFS4_OK) {
1580                 stateid4 stateid;
1581                 stateid = resp->LOCK4res_u.resok4.lock_stateid;
1582                 sprintf(buf, "%lu %s", stateid.seqid,
1583                     bin2hex(stateid.other, sizeof (stateid.other)));
1584                 Tcl_DStringAppendElement(strp, buf);
1585         } else {
1586                 if (resp->status == NFS4ERR_DENIED) {
1587                         lock_owner4 lowner;
1588 
1589                         sprintf(buf, "%llu %llu %d",
1590                             resp->LOCK4res_u.denied.offset,
1591                             resp->LOCK4res_u.denied.length,
1592                             resp->LOCK4res_u.denied.locktype);
1593                         Tcl_DStringAppendElement(strp, buf);
1594                         lowner = resp->LOCK4res_u.denied.owner;
1595                         sprintf(buf, "%llx ", lowner.clientid);
1596                         if (lowner.owner.owner_val != NULL)
1597                                 strncat(buf, lowner.owner.owner_val,
1598                                     lowner.owner.owner_len);
1599                         Tcl_DStringAppendElement(strp, buf);
1600                 }
1601         }
1602 
1603         Tcl_DStringEndSublist(strp);
1604         return (TCL_OK);
1605 }
1606 
1607 int
1608 Lockt_res(Tcl_Interp *interp, Tcl_DString *strp, LOCKT4res *resp)
1609 {
1610         Tcl_DStringStartSublist(strp);
1611         Tcl_DStringAppendElement(strp, "Lockt");
1612         Tcl_DStringAppendElement(strp, errstr(resp->status));
1613 
1614         if (resp->status == NFS4ERR_DENIED) {
1615                 char buf[80];
1616                 lock_owner4 lowner;
1617 
1618                 sprintf(buf, "%llu %llu %d",
1619                     resp->LOCKT4res_u.denied.offset,
1620                     resp->LOCKT4res_u.denied.length,
1621                     resp->LOCKT4res_u.denied.locktype);
1622                 Tcl_DStringAppendElement(strp, buf);
1623                 lowner = resp->LOCKT4res_u.denied.owner;
1624                 sprintf(buf, "%llx ", lowner.clientid);
1625                 if (lowner.owner.owner_val != NULL)
1626                         strncat(buf, lowner.owner.owner_val,
1627                             lowner.owner.owner_len);
1628                 Tcl_DStringAppendElement(strp, buf);
1629         }
1630 
1631         Tcl_DStringEndSublist(strp);
1632         return (TCL_OK);
1633 }
1634 
1635 int
1636 Locku_res(Tcl_Interp *interp, Tcl_DString *strp, LOCKU4res *resp)
1637 {
1638         char buf[80];
1639         stateid4 stateid;
1640 
1641         Tcl_DStringStartSublist(strp);
1642         Tcl_DStringAppendElement(strp, "Locku");
1643         Tcl_DStringAppendElement(strp, errstr(resp->status));
1644 
1645         stateid = resp->LOCKU4res_u.lock_stateid;
1646         sprintf(buf, "%lu %s", stateid.seqid,
1647             bin2hex(stateid.other, sizeof (stateid.other)));
1648         Tcl_DStringAppendElement(strp, buf);
1649 
1650         Tcl_DStringEndSublist(strp);
1651         return (TCL_OK);
1652 }
1653 
1654 int
1655 Lookup_res(Tcl_Interp *interp, Tcl_DString *strp, LOOKUP4res *resp)
1656 {
1657         Tcl_DStringStartSublist(strp);
1658         Tcl_DStringAppendElement(strp, "Lookup");
1659         Tcl_DStringAppendElement(strp, errstr(resp->status));
1660         Tcl_DStringEndSublist(strp);
1661         return (TCL_OK);
1662 }
1663 
1664 int
1665 Lookupp_res(Tcl_Interp *interp, Tcl_DString *strp, LOOKUPP4res *resp)
1666 {
1667         Tcl_DStringStartSublist(strp);
1668         Tcl_DStringAppendElement(strp, "Lookupp");
1669         Tcl_DStringAppendElement(strp, errstr(resp->status));
1670         Tcl_DStringEndSublist(strp);
1671         return (TCL_OK);
1672 }
1673 
1674 int
1675 Nverify_res(Tcl_Interp *interp, Tcl_DString *strp, NVERIFY4res *resp)
1676 {
1677         Tcl_DStringStartSublist(strp);
1678         Tcl_DStringAppendElement(strp, "Nverify");
1679         Tcl_DStringAppendElement(strp, errstr(resp->status));
1680         Tcl_DStringEndSublist(strp);
1681         return (TCL_OK);
1682 }
1683 
1684 int
1685 Open_res(Tcl_Interp *interp, Tcl_DString *strp, OPEN4res *resp)
1686 {
1687         Tcl_DStringStartSublist(strp);
1688         Tcl_DStringAppendElement(strp, "Open");
1689         Tcl_DStringAppendElement(strp, errstr(resp->status));
1690 
1691         if (resp->status == NFS4_OK) {
1692                 char buf[80];
1693                 change_info4 c;
1694                 stateid4 stateid;
1695 
1696                 /* Stateid for open */
1697                 stateid = resp->OPEN4res_u.resok4.stateid;
1698                 sprintf(buf, "%lu %s", stateid.seqid,
1699                     bin2hex(stateid.other, sizeof (stateid.other)));
1700                 Tcl_DStringAppendElement(strp, buf);
1701 
1702                 /* Directory Change Info */
1703                 Tcl_DStringStartSublist(strp);
1704                 c = resp->OPEN4res_u.resok4.cinfo;
1705                 sprintf(buf, "atomic %s", c.atomic ? "true" : "false");
1706                 Tcl_DStringAppendElement(strp, buf);
1707                 sprintf(buf, "before %.8llx", c.before);
1708                 Tcl_DStringAppendElement(strp, buf);
1709                 sprintf(buf, "after %.8llx", c.after);
1710                 Tcl_DStringAppendElement(strp, buf);
1711                 Tcl_DStringEndSublist(strp);
1712 
1713                 /* Result flags */
1714                 sprintf(buf, "%u", resp->OPEN4res_u.resok4.rflags);
1715                 Tcl_DStringAppendElement(strp, buf);
1716 
1717                 /* Info of the attribute from Open */
1718                 Tcl_DStringStartSublist(strp);
1719                 prn_attrname(strp, &resp->OPEN4res_u.resok4.attrset);
1720                 Tcl_DStringEndSublist(strp);
1721 
1722                 /* Info on any open delegation */
1723                 switch (resp->OPEN4res_u.resok4.delegation.delegation_type) {
1724                 open_read_delegation4 dr;
1725                 open_write_delegation4 dw;
1726                 nfs_modified_limit4 *p;
1727                 uint32_t s;
1728                 uint32_t b;
1729 
1730                 case OPEN_DELEGATE_NONE:
1731                 Tcl_DStringAppendElement(strp, "NONE");
1732                 break;
1733 
1734                 case OPEN_DELEGATE_READ:
1735                 Tcl_DStringStartSublist(strp);
1736                 Tcl_DStringAppendElement(strp, "READ");
1737                 dr = resp->OPEN4res_u.resok4.delegation.open_delegation4_u.read;
1738                 sprintf(buf, "%lu %s", dr.stateid.seqid,
1739                     bin2hex(dr.stateid.other,
1740                     sizeof (dr.stateid.other)));
1741                 Tcl_DStringAppendElement(strp, buf);
1742                 sprintf(buf, "%s %s",
1743                     dr.recall ? "true" : "false",
1744                     prn_ace4(dr.permissions));
1745                 Tcl_DStringAppendElement(strp, buf);
1746                 Tcl_DStringEndSublist(strp);
1747                 break;
1748 
1749                 case OPEN_DELEGATE_WRITE:
1750                 Tcl_DStringStartSublist(strp);
1751                 Tcl_DStringAppendElement(strp, "WRITE");
1752                 dw =
1753                     resp->OPEN4res_u.resok4.delegation.open_delegation4_u.write;
1754                 sprintf(buf, "%lu %s", dw.stateid.seqid,
1755                     bin2hex(dw.stateid.other,
1756                     sizeof (dw.stateid.other)));
1757                 Tcl_DStringAppendElement(strp, buf);
1758 
1759                 switch (dw.space_limit.limitby) {
1760                 case NFS_LIMIT_SIZE:
1761                 s = dw.space_limit.nfs_space_limit4_u.filesize;
1762                 sprintf(buf, "%s %s %llu %s",
1763                     dw.recall ? "true" : "false",
1764                     "SIZE", s, prn_ace4(dw.permissions));
1765                 Tcl_DStringAppendElement(strp, buf);
1766                 break;
1767 
1768                 case NFS_LIMIT_BLOCKS:
1769                 p = &(dw.space_limit.nfs_space_limit4_u.mod_blocks);
1770                 s = p->num_blocks;
1771                 b = p->bytes_per_block;
1772                 sprintf(buf, "%s %s %lu %lu %s",
1773                     dw.recall ? "true" : "false",
1774                     "BLOCKS", s, b, prn_ace4(dw.permissions));
1775                 Tcl_DStringAppendElement(strp, buf);
1776                 break;
1777 
1778                 default:
1779                 break;
1780                 }
1781 
1782                 Tcl_DStringEndSublist(strp);
1783                 break;
1784 
1785                 default:
1786                 break;
1787                 }
1788         }
1789 
1790         Tcl_DStringEndSublist(strp);
1791         return (TCL_OK);
1792 }
1793 
1794 int
1795 Openattr_res(Tcl_Interp *interp, Tcl_DString *strp, OPENATTR4res *resp)
1796 {
1797         Tcl_DStringStartSublist(strp);
1798         Tcl_DStringAppendElement(strp, "Openattr");
1799         Tcl_DStringAppendElement(strp, errstr(resp->status));
1800         Tcl_DStringEndSublist(strp);
1801         return (TCL_OK);
1802 }
1803 
1804 int
1805 Open_confirm_res(Tcl_Interp *interp, Tcl_DString *strp, OPEN_CONFIRM4res *resp)
1806 {
1807         Tcl_DStringStartSublist(strp);
1808         Tcl_DStringAppendElement(strp, "Open_confirm");
1809         Tcl_DStringAppendElement(strp, errstr(resp->status));
1810 
1811         if (resp->status == NFS4_OK) {
1812                 char buf[80];
1813                 stateid4 stateid;
1814 
1815                 stateid = resp->OPEN_CONFIRM4res_u.resok4.open_stateid;
1816                 sprintf(buf, "%lu %s", stateid.seqid,
1817                     bin2hex(stateid.other, sizeof (stateid.other)));
1818                 Tcl_DStringAppendElement(strp, buf);
1819         }
1820 
1821         Tcl_DStringEndSublist(strp);
1822         return (TCL_OK);
1823 }
1824 
1825 int
1826 Open_downgrade_res(Tcl_Interp *interp, Tcl_DString *strp,
1827     OPEN_DOWNGRADE4res *resp)
1828 {
1829         Tcl_DStringStartSublist(strp);
1830         Tcl_DStringAppendElement(strp, "Open_downgrade");
1831         Tcl_DStringAppendElement(strp, errstr(resp->status));
1832 
1833         if (resp->status == NFS4_OK) {
1834                 char buf[80];
1835                 stateid4 stateid;
1836 
1837                 stateid = resp->OPEN_DOWNGRADE4res_u.resok4.open_stateid;
1838                 sprintf(buf, "%lu %s", stateid.seqid,
1839                     bin2hex(stateid.other, sizeof (stateid.other)));
1840                 Tcl_DStringAppendElement(strp, buf);
1841         }
1842 
1843         Tcl_DStringEndSublist(strp);
1844         return (TCL_OK);
1845 }
1846 
1847 int
1848 Putfh_res(Tcl_Interp *interp, Tcl_DString *strp, PUTFH4res *resp)
1849 {
1850         Tcl_DStringStartSublist(strp);
1851         Tcl_DStringAppendElement(strp, "Putfh");
1852         Tcl_DStringAppendElement(strp, errstr(resp->status));
1853         Tcl_DStringEndSublist(strp);
1854         return (TCL_OK);
1855 }
1856 
1857 int
1858 Putpubfh_res(Tcl_Interp *interp, Tcl_DString *strp, PUTPUBFH4res *resp)
1859 {
1860         Tcl_DStringStartSublist(strp);
1861         Tcl_DStringAppendElement(strp, "Putpubfh");
1862         Tcl_DStringAppendElement(strp, errstr(resp->status));
1863         Tcl_DStringEndSublist(strp);
1864         return (TCL_OK);
1865 }
1866 
1867 int
1868 Putrootfh_res(Tcl_Interp *interp, Tcl_DString *strp, PUTROOTFH4res *resp)
1869 {
1870         Tcl_DStringStartSublist(strp);
1871         Tcl_DStringAppendElement(strp, "Putrootfh");
1872         Tcl_DStringAppendElement(strp, errstr(resp->status));
1873         Tcl_DStringEndSublist(strp);
1874         return (TCL_OK);
1875 }
1876 
1877 int
1878 Read_res(Tcl_Interp *interp, Tcl_DString *strp, READ4res *resp)
1879 {
1880         Tcl_DStringStartSublist(strp);
1881         Tcl_DStringAppendElement(strp, "Read");
1882         Tcl_DStringAppendElement(strp, errstr(resp->status));
1883 
1884         if (resp->status == NFS4_OK) {
1885                 bool_t eof;
1886                 uint_t len;
1887                 char *val;
1888                 char buf[80];
1889 
1890                 eof = resp->READ4res_u.resok4.eof;
1891                 len = resp->READ4res_u.resok4.data.data_len;
1892                 val = resp->READ4res_u.resok4.data.data_val;
1893 
1894                 Tcl_DStringStartSublist(strp);
1895                 sprintf(buf, "eof %s", eof ? "true" : "false");
1896                 Tcl_DStringAppendElement(strp, buf);
1897 
1898                 sprintf(buf, "len %u", len);
1899                 Tcl_DStringAppendElement(strp, buf);
1900 
1901                 if (val != NULL) {
1902                         char *np;
1903                         np = malloc(len + 1);
1904                         snprintf(np, (len + 1), "%s", val);
1905                         Tcl_DStringAppendElement(strp, np);
1906                         free(np);
1907                 }
1908                 Tcl_DStringEndSublist(strp);
1909         }
1910 
1911         Tcl_DStringEndSublist(strp);
1912         return (TCL_OK);
1913 }
1914 
1915 int
1916 Readdir_res(Tcl_Interp *interp, Tcl_DString *strp, READDIR4res *resp)
1917 {
1918         Tcl_DStringStartSublist(strp);
1919         Tcl_DStringAppendElement(strp, "Readdir");
1920         Tcl_DStringAppendElement(strp, errstr(resp->status));
1921 
1922         if (resp->status == NFS4_OK) {
1923                 nfs_cookie4 cookie;
1924                 verifier4 verf;
1925                 bool_t eof;
1926                 entry4 *d;
1927                 bitmap4 bm;
1928                 attrlist4 attrvals;
1929 
1930                 /* The cookie verifier */
1931                 (void) memcpy(verf, resp->READDIR4res_u.resok4.cookieverf,
1932                     sizeof (verf));
1933                 Tcl_DStringAppendElement(strp,
1934                     bin2hex(verf, sizeof (verf)));
1935 
1936                 /* The directory list */
1937                 Tcl_DStringStartSublist(strp);
1938                 eof = resp->READDIR4res_u.resok4.reply.eof;
1939                 for (d = resp->READDIR4res_u.resok4.reply.entries;
1940                     d != NULL; d = d->nextentry) {
1941                         char buf[64];
1942 
1943                         Tcl_DStringStartSublist(strp);
1944                         sprintf(buf, "%llu", d->cookie);
1945                         Tcl_DStringAppendElement(strp, buf);
1946                         Tcl_DStringAppendElement(strp, utf82str(d->name));
1947 
1948                         bm = d->attrs.attrmask;
1949                         attrvals = d->attrs.attr_vals;
1950                         attr_decode(interp, strp, &bm, &attrvals);
1951                         Tcl_DStringEndSublist(strp);
1952                 }
1953                 Tcl_DStringEndSublist(strp);
1954                 Tcl_DStringAppendElement(strp, eof ? "true" : "false");
1955         }
1956 
1957         Tcl_DStringEndSublist(strp);
1958         return (TCL_OK);
1959 }
1960 
1961 int
1962 Readlink_res(Tcl_Interp *interp, Tcl_DString *strp, READLINK4res *resp)
1963 {
1964         Tcl_DStringStartSublist(strp);
1965         Tcl_DStringAppendElement(strp, "Readlink");
1966         Tcl_DStringAppendElement(strp, errstr(resp->status));
1967 
1968         if (resp->status == NFS4_OK) {
1969                 linktext4 l;
1970                 char buf[256];
1971 
1972                 l = resp->READLINK4res_u.resok4.link;
1973                 snprintf(buf, l.utf8string_len + 1, "%s", l.utf8string_val);
1974                 Tcl_DStringAppendElement(strp, buf);
1975         }
1976 
1977         Tcl_DStringEndSublist(strp);
1978         return (TCL_OK);
1979 }
1980 
1981 int
1982 Release_lockowner_res(Tcl_Interp *interp, Tcl_DString *strp,
1983         RELEASE_LOCKOWNER4res *resp)
1984 {
1985         Tcl_DStringStartSublist(strp);
1986         Tcl_DStringAppendElement(strp, "Release_lockowner");
1987         Tcl_DStringAppendElement(strp, errstr(resp->status));
1988         Tcl_DStringEndSublist(strp);
1989         return (TCL_OK);
1990 }
1991 
1992 int
1993 Remove_res(Tcl_Interp *interp, Tcl_DString *strp, REMOVE4res *resp)
1994 {
1995         Tcl_DStringStartSublist(strp);
1996         Tcl_DStringAppendElement(strp, "Remove");
1997         Tcl_DStringAppendElement(strp, errstr(resp->status));
1998 
1999         if (resp->status == NFS4_OK) {
2000                 change_info4 c;
2001                 char buf[80];
2002 
2003                 c = resp->REMOVE4res_u.resok4.cinfo;
2004                 Tcl_DStringStartSublist(strp);
2005 
2006                 sprintf(buf, "atomic %s", c.atomic ? "true" : "false");
2007                 Tcl_DStringAppendElement(strp, buf);
2008                 sprintf(buf, "before %.8llx", c.before);
2009                 Tcl_DStringAppendElement(strp, buf);
2010                 sprintf(buf, "after %.8llx", c.after);
2011                 Tcl_DStringAppendElement(strp, buf);
2012 
2013                 Tcl_DStringEndSublist(strp);
2014         }
2015 
2016         Tcl_DStringEndSublist(strp);
2017         return (TCL_OK);
2018 }
2019 
2020 int
2021 Rename_res(Tcl_Interp *interp, Tcl_DString *strp, RENAME4res *resp)
2022 {
2023         Tcl_DStringStartSublist(strp);
2024         Tcl_DStringAppendElement(strp, "Rename");
2025         Tcl_DStringAppendElement(strp, errstr(resp->status));
2026 
2027         if (resp->status == NFS4_OK) {
2028                 change_info4 c;
2029                 char buf[80];
2030 
2031                 /* source cinfo */
2032                 c = resp->RENAME4res_u.resok4.source_cinfo;
2033                 Tcl_DStringStartSublist(strp);
2034                 Tcl_DStringAppendElement(strp, "source");
2035 
2036                 sprintf(buf, "atomic %s", c.atomic ? "true" : "false");
2037                 Tcl_DStringAppendElement(strp, buf);
2038                 sprintf(buf, "before %.8llx", c.before);
2039                 Tcl_DStringAppendElement(strp, buf);
2040                 sprintf(buf, "after %.8llx", c.after);
2041                 Tcl_DStringAppendElement(strp, buf);
2042 
2043                 Tcl_DStringEndSublist(strp);
2044 
2045                 /* target cinfo */
2046                 c = resp->RENAME4res_u.resok4.target_cinfo;
2047                 Tcl_DStringStartSublist(strp);
2048                 Tcl_DStringAppendElement(strp, "target");
2049 
2050                 sprintf(buf, "atomic %s", c.atomic ? "true" : "false");
2051                 Tcl_DStringAppendElement(strp, buf);
2052                 sprintf(buf, "before %.8llx", c.before);
2053                 Tcl_DStringAppendElement(strp, buf);
2054                 sprintf(buf, "after %.8llx", c.after);
2055                 Tcl_DStringAppendElement(strp, buf);
2056 
2057                 Tcl_DStringEndSublist(strp);
2058 
2059         }
2060 
2061         Tcl_DStringEndSublist(strp);
2062         return (TCL_OK);
2063 }
2064 
2065 int
2066 Renew_res(Tcl_Interp *interp, Tcl_DString *strp, RENEW4res *resp)
2067 {
2068         Tcl_DStringStartSublist(strp);
2069         Tcl_DStringAppendElement(strp, "Renew");
2070         Tcl_DStringAppendElement(strp, errstr(resp->status));
2071         Tcl_DStringEndSublist(strp);
2072         return (TCL_OK);
2073 }
2074 
2075 int
2076 Restorefh_res(Tcl_Interp *interp, Tcl_DString *strp, RESTOREFH4res *resp)
2077 {
2078         Tcl_DStringStartSublist(strp);
2079         Tcl_DStringAppendElement(strp, "Restorefh");
2080         Tcl_DStringAppendElement(strp, errstr(resp->status));
2081         Tcl_DStringEndSublist(strp);
2082         return (TCL_OK);
2083 }
2084 
2085 int
2086 Savefh_res(Tcl_Interp *interp, Tcl_DString *strp, SAVEFH4res *resp)
2087 {
2088         Tcl_DStringStartSublist(strp);
2089         Tcl_DStringAppendElement(strp, "Savefh");
2090         Tcl_DStringAppendElement(strp, errstr(resp->status));
2091         Tcl_DStringEndSublist(strp);
2092         return (TCL_OK);
2093 }
2094 
2095 int
2096 Secinfo_res(Tcl_Interp *interp, Tcl_DString *strp, SECINFO4res *resp)
2097 {
2098         Tcl_DStringStartSublist(strp);
2099         Tcl_DStringAppendElement(strp, "Secinfo");
2100         Tcl_DStringAppendElement(strp, errstr(resp->status));
2101 
2102         if (resp->status == NFS4_OK) {
2103                 secinfo4 *sp;
2104                 char buf[80];
2105                 char buf2[10];
2106                 int i;
2107 
2108                 Tcl_DStringStartSublist(strp);
2109                 for (i = 0;
2110                     i < resp->SECINFO4res_u.resok4.SECINFO4resok_len;
2111                     i++) {
2112 
2113                         sp = &resp->SECINFO4res_u.resok4.SECINFO4resok_val[i];
2114 
2115                         if (sp->flavor == AUTH_SYS) {
2116                                 sprintf(buf, "AUTH_SYS");
2117                         } else if (sp->flavor == AUTH_NONE) {
2118                                 sprintf(buf, "AUTH_NONE");
2119                         } else if (sp->flavor == AUTH_DH) {
2120                                 sprintf(buf, "AUTH_DH");
2121                         } else if (sp->flavor == RPCSEC_GSS) {
2122                                 /*
2123                                  * XXX used hardcoded mapping here:
2124                                  *      For Solaris,
2125                                  *      KRB5-OID=2A864886F712010202
2126                                  *      (in HEX); * XXX Need HEX
2127                                  *      values for LIBKEY & SPKM3 OID
2128                                  *      mapping as well.
2129                                  */
2130                                 char krboid[] = "2A864886F712010202";
2131                                 char lkeyoid[] = "1.3.6.1.5.5.9";
2132                                 char spkmoid[] = "1.3.6.1.5.5.1.3";
2133                                 char *oid;
2134                                 rpcsec_gss_info rinfo;
2135 
2136                                 sprintf(buf, "RPCSEC_GSS ");
2137                                 rinfo = sp->secinfo4_u.flavor_info;
2138                                 oid = bin2hex(rinfo.oid.sec_oid4_val,
2139                                     rinfo.oid.sec_oid4_len);
2140                                 if ((strcmp(oid, krboid)) == 0) {
2141                                         strcat(buf, "KRB5");
2142                                 } else if ((strcmp(oid, lkeyoid)) == 0) {
2143                                         strcat(buf, "LIBKEY");
2144                                 } else if ((strcmp(oid, spkmoid)) == 0) {
2145                                         strcat(buf, "SPKM3");
2146                                 } else {
2147                                         strcat(buf, oid);
2148                                 }
2149                                 sprintf(buf2, " %u", rinfo.qop);
2150                                 strcat(buf, buf2);
2151                                 switch (rinfo.service) {
2152                                 case RPC_GSS_SVC_NONE:
2153                                         strcat(buf, " NONE");
2154                                         break;
2155                                 case RPC_GSS_SVC_INTEGRITY:
2156                                         strcat(buf, " INTEGRITY");
2157                                         break;
2158                                 case RPC_GSS_SVC_PRIVACY:
2159                                         strcat(buf, " PRIVACY");
2160                                         break;
2161                                 default:
2162                                         break;
2163                                 }
2164                         } else {        /* unknown flavor, no mapping */
2165                                 sprintf(buf, "%u", sp->flavor);
2166                         }
2167                         Tcl_DStringAppendElement(strp, buf);
2168                 }
2169                 Tcl_DStringEndSublist(strp);
2170         }
2171 
2172         Tcl_DStringEndSublist(strp);
2173         return (TCL_OK);
2174 }
2175 
2176 int
2177 Setattr_res(Tcl_Interp *interp, Tcl_DString *strp, SETATTR4res *resp)
2178 {
2179         Tcl_DStringStartSublist(strp);
2180         Tcl_DStringAppendElement(strp, "Setattr");
2181         Tcl_DStringAppendElement(strp, errstr(resp->status));
2182 
2183         Tcl_DStringStartSublist(strp);
2184         prn_attrname(strp, &resp->attrsset);
2185         Tcl_DStringEndSublist(strp);
2186 
2187         Tcl_DStringEndSublist(strp);
2188         return (TCL_OK);
2189 }
2190 
2191 int
2192 Setclientid_res(Tcl_Interp *interp, Tcl_DString *strp, SETCLIENTID4res *resp)
2193 {
2194         verifier4 verf;
2195         char buf[80];
2196 
2197         Tcl_DStringStartSublist(strp);
2198         Tcl_DStringAppendElement(strp, "Setclientid");
2199         Tcl_DStringAppendElement(strp, errstr(resp->status));
2200 
2201         if (resp->status == NFS4_OK) {
2202                 /* the setclientid verifier */
2203                 (void) memcpy(verf,
2204                     resp->SETCLIENTID4res_u.resok4.setclientid_confirm,
2205                     sizeof (verf));
2206                 sprintf(buf, "%llx %s",
2207                     resp->SETCLIENTID4res_u.resok4.clientid,
2208                     bin2hex(verf, sizeof (verf)));
2209         } else if (resp->status == NFS4ERR_CLID_INUSE) {
2210                 sprintf(buf, "%s %s",
2211                     resp->SETCLIENTID4res_u.client_using.r_netid,
2212                     resp->SETCLIENTID4res_u.client_using.r_addr);
2213         }
2214         Tcl_DStringAppendElement(strp, buf);
2215         Tcl_DStringEndSublist(strp);
2216 
2217         return (TCL_OK);
2218 }
2219 
2220 int
2221 Setclientid_confirm_res(Tcl_Interp *interp, Tcl_DString *strp,
2222     SETCLIENTID_CONFIRM4res *resp)
2223 {
2224         Tcl_DStringStartSublist(strp);
2225         Tcl_DStringAppendElement(strp, "Setclientid_confirm");
2226         Tcl_DStringAppendElement(strp, errstr(resp->status));
2227         Tcl_DStringEndSublist(strp);
2228         return (TCL_OK);
2229 }
2230 
2231 int
2232 Verify_res(Tcl_Interp *interp, Tcl_DString *strp, VERIFY4res *resp)
2233 {
2234         Tcl_DStringStartSublist(strp);
2235         Tcl_DStringAppendElement(strp, "Verify");
2236         Tcl_DStringAppendElement(strp, errstr(resp->status));
2237         Tcl_DStringEndSublist(strp);
2238         return (TCL_OK);
2239 }
2240 
2241 int
2242 Write_res(Tcl_Interp *interp, Tcl_DString *strp, WRITE4res *resp)
2243 {
2244         Tcl_DStringStartSublist(strp);
2245         Tcl_DStringAppendElement(strp, "Write");
2246         Tcl_DStringAppendElement(strp, errstr(resp->status));
2247 
2248         if (resp->status == NFS4_OK) {
2249                 verifier4 verf;
2250                 char buf[81];
2251 
2252                 /* the write count */
2253                 sprintf(buf, "%u ", resp->WRITE4res_u.resok4.count);
2254 
2255                 /* the stable_how */
2256                 switch (resp->WRITE4res_u.resok4.committed) {
2257                 case 0:
2258                         strcat(buf, "UNSTABLE");
2259                         break;
2260                 case 1:
2261                         strcat(buf, "DATA_SYNC");
2262                         break;
2263                 case 2:
2264                         strcat(buf, "FILE_SYNC");
2265                         break;
2266                 default:
2267                         strcat(buf, "UNKNOWN");
2268                         break;
2269                 }
2270 
2271                 /* the write verifier */
2272                 (void) memcpy(verf, resp->WRITE4res_u.resok4.writeverf,
2273                     sizeof (verf));
2274                 strcat(buf, " ");
2275                 strcat(buf, bin2hex(verf, sizeof (verf)));
2276                 Tcl_DStringAppendElement(strp, buf);
2277         }
2278 
2279         Tcl_DStringEndSublist(strp);
2280         return (TCL_OK);
2281 }
2282 
2283 /*
2284  * Called to handle a compound result
2285  */
2286 int
2287 compound_result(Tcl_Interp *interp, COMPOUND4res *resp)
2288 {
2289         int ops_complete;
2290         nfs_resop4 *resop;
2291         Tcl_DString str;
2292         int i;
2293         int err = TCL_OK;
2294 
2295         Tcl_SetVar(interp, "status", errstr(resp->status), 0);
2296 
2297         if (resp->tag.utf8string_val == NULL)
2298                 Tcl_SetVar(interp, "tag", "", 0);
2299         else {
2300                 Tcl_SetVar(interp, "tag", utf82str(resp->tag), 0);
2301         }
2302 
2303         ops_complete = resp->resarray.resarray_len;
2304         Tcl_SetVar(interp, "opcount", itoa(ops_complete), 0);
2305 
2306         Tcl_DStringInit(&str);
2307 
2308         for (i = 0; i < ops_complete; i++) {
2309                 resop = &resp->resarray.resarray_val[i];
2310                 switch (resop->resop) {
2311                 case OP_ACCESS:
2312                         err = Access_res(interp, &str,
2313                             &resop->nfs_resop4_u.opaccess);
2314                         break;
2315 
2316                 case OP_CLOSE:
2317                         err = Close_res(interp, &str,
2318                             &resop->nfs_resop4_u.opclose);
2319                         break;
2320 
2321                 case OP_COMMIT:
2322                         err = Commit_res(interp, &str,
2323                             &resop->nfs_resop4_u.opcommit);
2324                         break;
2325 
2326                 case OP_CREATE:
2327                         err = Create_res(interp, &str,
2328                             &resop->nfs_resop4_u.opcreate);
2329                         break;
2330 
2331                 case OP_DELEGPURGE:
2332                         err = Delegpurge_res(interp, &str,
2333                             &resop->nfs_resop4_u.opdelegpurge);
2334                         break;
2335 
2336                 case OP_DELEGRETURN:
2337                         err = Delegreturn_res(interp, &str,
2338                             &resop->nfs_resop4_u.opdelegreturn);
2339                         break;
2340 
2341                 case OP_GETATTR:
2342                         err = Getattr_res(interp, &str,
2343                             &resop->nfs_resop4_u.opgetattr);
2344                         break;
2345 
2346                 case OP_GETFH:
2347                         err = Getfh_res(interp, &str,
2348                             &resop->nfs_resop4_u.opgetfh);
2349                         break;
2350 
2351                 case OP_ILLEGAL:
2352                         err = Illegal_res(interp, &str,
2353                             &resop->nfs_resop4_u.opillegal);
2354                         break;
2355 
2356                 case OP_LINK:
2357                         err = Link_res(interp, &str,
2358                             &resop->nfs_resop4_u.oplink);
2359                         break;
2360 
2361                 case OP_LOCK:
2362                         err = Lock_res(interp, &str,
2363                             &resop->nfs_resop4_u.oplock);
2364                         break;
2365 
2366                 case OP_LOCKT:
2367                         err = Lockt_res(interp, &str,
2368                             &resop->nfs_resop4_u.oplockt);
2369                         break;
2370 
2371                 case OP_LOCKU:
2372                         err = Locku_res(interp, &str,
2373                             &resop->nfs_resop4_u.oplocku);
2374                         break;
2375 
2376                 case OP_LOOKUP:
2377                         err = Lookup_res(interp, &str,
2378                             &resop->nfs_resop4_u.oplookup);
2379                         break;
2380 
2381                 case OP_LOOKUPP:
2382                         err = Lookupp_res(interp, &str,
2383                             &resop->nfs_resop4_u.oplookupp);
2384                         break;
2385 
2386                 case OP_NVERIFY:
2387                         err = Nverify_res(interp, &str,
2388                             &resop->nfs_resop4_u.opnverify);
2389                         break;
2390 
2391                 case OP_OPEN:
2392                         err = Open_res(interp, &str,
2393                             &resop->nfs_resop4_u.opopen);
2394                         break;
2395 
2396                 case OP_OPENATTR:
2397                         err = Openattr_res(interp, &str,
2398                             &resop->nfs_resop4_u.opopenattr);
2399                         break;
2400 
2401                 case OP_OPEN_CONFIRM:
2402                         err = Open_confirm_res(interp, &str,
2403                             &resop->nfs_resop4_u.opopen_confirm);
2404                         break;
2405 
2406                 case OP_OPEN_DOWNGRADE:
2407                         err = Open_downgrade_res(interp, &str,
2408                             &resop->nfs_resop4_u.opopen_downgrade);
2409                         break;
2410 
2411                 case OP_PUTFH:
2412                         err = Putfh_res(interp, &str,
2413                             &resop->nfs_resop4_u.opputfh);
2414                         break;
2415 
2416                 case OP_PUTPUBFH:
2417                         err = Putpubfh_res(interp, &str,
2418                             &resop->nfs_resop4_u.opputpubfh);
2419                         break;
2420 
2421                 case OP_PUTROOTFH:
2422                         err = Putrootfh_res(interp, &str,
2423                             &resop->nfs_resop4_u.opputrootfh);
2424                         break;
2425 
2426                 case OP_READ:
2427                         err = Read_res(interp, &str,
2428                             &resop->nfs_resop4_u.opread);
2429                         break;
2430 
2431                 case OP_READDIR:
2432                         err = Readdir_res(interp, &str,
2433                             &resop->nfs_resop4_u.opreaddir);
2434                         break;
2435 
2436                 case OP_READLINK:
2437                         err = Readlink_res(interp, &str,
2438                             &resop->nfs_resop4_u.opreadlink);
2439                         break;
2440 
2441                 case OP_RELEASE_LOCKOWNER:
2442                         err = Release_lockowner_res(interp, &str,
2443                             &resop->nfs_resop4_u.oprelease_lockowner);
2444                         break;
2445 
2446                 case OP_REMOVE:
2447                         err = Remove_res(interp, &str,
2448                             &resop->nfs_resop4_u.opremove);
2449                         break;
2450 
2451                 case OP_RENAME:
2452                         err = Rename_res(interp, &str,
2453                             &resop->nfs_resop4_u.oprename);
2454                         break;
2455 
2456                 case OP_RENEW:
2457                         err = Renew_res(interp, &str,
2458                             &resop->nfs_resop4_u.oprenew);
2459                         break;
2460 
2461                 case OP_RESTOREFH:
2462                         err = Restorefh_res(interp, &str,
2463                             &resop->nfs_resop4_u.oprestorefh);
2464                         break;
2465 
2466                 case OP_SAVEFH:
2467                         err = Savefh_res(interp, &str,
2468                             &resop->nfs_resop4_u.opsavefh);
2469                         break;
2470 
2471                 case OP_SECINFO:
2472                         err = Secinfo_res(interp, &str,
2473                             &resop->nfs_resop4_u.opsecinfo);
2474                         break;
2475 
2476                 case OP_SETATTR:
2477                         err = Setattr_res(interp, &str,
2478                             &resop->nfs_resop4_u.opsetattr);
2479                         break;
2480 
2481                 case OP_SETCLIENTID:
2482                         err = Setclientid_res(interp, &str,
2483                             &resop->nfs_resop4_u.opsetclientid);
2484                         break;
2485 
2486                 case OP_SETCLIENTID_CONFIRM:
2487                         err = Setclientid_confirm_res(interp, &str,
2488                             &resop->nfs_resop4_u.opsetclientid_confirm);
2489                         break;
2490 
2491                 case OP_VERIFY:
2492                         err = Verify_res(interp, &str,
2493                             &resop->nfs_resop4_u.opverify);
2494                         break;
2495 
2496                 case OP_WRITE:
2497                         err = Write_res(interp, &str,
2498                             &resop->nfs_resop4_u.opwrite);
2499                         break;
2500 
2501                 default:
2502                         (void) sprintf(interp->result,
2503                             "Unknown op in result: %d",
2504                             resop->resop);
2505                         err = TCL_ERROR;
2506                         break;
2507                 }
2508 
2509                 if (err != TCL_OK) {
2510                         Tcl_DStringFree(&str);
2511                         return (err);
2512                 }
2513         }
2514 
2515         Tcl_DStringResult(interp, &str);
2516 
2517         return (TCL_OK);
2518 }
2519 
2520 void
2521 op_createcom(Tcl_Interp *interp)
2522 {
2523         int i;
2524 
2525         for (i = 0; nfs_op[i].name != NULL; i++) {
2526                 Tcl_CreateCommand(interp,
2527                     nfs_op[i].name, nfs_op[i].func,
2528                     (ClientData)                NULL,
2529                     (Tcl_CmdDeleteProc *)       NULL);
2530         }
2531 }