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