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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
32 #include <libnvpair.h>
35 #include <sys/fs_reparse.h>
36 #include <rp_plugin.h>
37 #include <uuid/uuid.h>
38 #include <sys/types.h>
43 #include <rpcsvc/nfs4_prot.h>
47 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
48 #endif /* TEXT_DOMAIN */
55 fprintf(stderr
, gettext("Usage:\n"));
57 gettext("\tnfsref [-t type] add path location [location ...]\n"));
58 fprintf(stderr
, gettext("\tnfsref [-t type] remove path\n"));
59 fprintf(stderr
, gettext("\tnfsref [-t type] lookup path\n"));
63 * Copy a string from source to destination, escaping space
64 * with a backslash and escaping the escape character as well.
67 add_escape(char *src
, char *dest
, int limit
)
75 while (*sp
&& destlen
< limit
) {
80 } else if (*sp
== ' ') {
95 addref(char *sl_path
, char *svc_type
, int optind
, int argc
, char *argv
[])
97 int err
, fd
, i
, len
, oldlen
, notfound
= 0;
98 char *text
, *location
;
100 char buf
[SYMLINK_MAX
];
104 nvl
= reparse_init();
108 /* Get the reparse point data, if the RP exists */
109 err
= readlink(sl_path
, buf
, SYMLINK_MAX
);
111 if (errno
== ENOENT
) {
122 /* Get any data into nvlist */
124 err
= reparse_parse(buf
, nvl
);
131 * Accumulate multiple locations on the command line into 'buf'
135 for (i
= optind
; i
< argc
; i
++) {
136 bzero(buf
, sizeof (buf
));
137 len
+= add_escape(argv
[i
], buf
, SYMLINK_MAX
) + 2;
138 location
= realloc(location
, len
);
139 location
[oldlen
] = '\0';
141 strlcat(location
, buf
, len
);
142 strlcat(location
, " ", len
);
144 location
[len
- 2] = '\0';
146 /* Add to the list */
147 err
= reparse_add(nvl
, svc_type
, location
);
153 /* Get the new or modified symlink contents */
154 err
= reparse_unparse(nvl
, &text
);
159 /* Delete first if found */
161 err
= reparse_delete(sl_path
);
168 /* Finally, write out the reparse point */
169 err
= reparse_create(sl_path
, text
);
174 err
= lstat(sl_path
, &sbuf
);
175 if (err
== 0 && strcasecmp(sbuf
.st_fstype
, "ZFS") != 0)
177 "Warning: referrals do not work on this filesystem\n"));
180 printf(gettext("Created reparse point %s\n"), sl_path
);
182 printf(gettext("Added to reparse point %s\n"), sl_path
);
188 delref(char *sl_path
, char *svc_type
)
195 char buf
[SYMLINK_MAX
];
198 char uuid
[UUID_PRINTABLE_STRING_LENGTH
], path
[256], loc
[2048];
201 if (!(nvl
= reparse_init()))
204 /* Get the symlink data (should be there) */
205 err
= readlink(sl_path
, buf
, SYMLINK_MAX
);
212 /* Get the records into the nvlist */
213 err
= reparse_parse(buf
, nvl
);
219 /* Remove from nvlist */
220 err
= reparse_remove(nvl
, svc_type
);
226 /* Any list entries left? If so, turn nvlist back to string. */
227 curr
= nvlist_next_nvpair(nvl
, NULL
);
229 err
= reparse_unparse(nvl
, &cp
);
238 /* Finally, delete and perhaps recreate the reparse point */
239 err
= reparse_delete(sl_path
);
246 err
= reparse_create(sl_path
, cp
);
251 printf(gettext("Removed svc_type '%s' from %s\n"), svc_type
, sl_path
);
256 lookup(char *sl_path
, char *svc_type
, int type_set
)
261 char *type
, *svc_data
;
267 if (!(nvl
= reparse_init()))
270 /* Get reparse point data */
271 err
= readlink(sl_path
, buf
, SYMLINK_MAX
);
276 /* Parse it to an nvlist */
277 err
= reparse_parse(buf
, nvl
);
283 /* Look for entries of the requested service type */
285 while ((curr
= nvlist_next_nvpair(nvl
, curr
)) != NULL
) {
286 type
= nvpair_name(curr
);
287 if (type_set
&& strcasecmp(type
, svc_type
) == 0)
289 if (!type_set
&& strncasecmp(type
, "nfs", 3) == 0)
297 /* Get the service data and look it up */
298 nvpair_value_string(curr
, &svc_data
);
300 bufsize
= sizeof (buf
);
301 err
= reparse_deref(type
, svc_data
, buf
, &bufsize
);
306 xdrmem_create(&xdr
, buf
, bufsize
, XDR_DECODE
);
307 err
= xdr_fs_locations4(&xdr
, &fsl
);
311 printf(gettext("%s points to: "), sl_path
);
312 print_referral_summary(&fsl
);
317 extern int optind
, optopt
;
320 main(int argc
, char *argv
[])
322 char c
, *command
, *sl_path
, *svc_type
;
325 (void) setlocale(LC_ALL
, "");
326 (void) textdomain(TEXT_DOMAIN
);
328 svc_type
= "nfs-basic"; /* Default from SMF some day */
329 type_set
= 0; /* Lookup any nfs type */
331 /* Look for options (just the service type now) */
332 while ((c
= getopt(argc
, argv
, "t:")) != -1) {
345 /* Make sure there's at least a command and one argument */
346 if (optind
+ 1 >= argc
) {
351 err
= rp_plugin_init();
355 case RP_NO_PLUGIN_DIR
:
357 gettext("Warning: no plugin directory, continuing...\n"));
361 gettext("Warning: no plugin found, continuing...\n"));
365 gettext("rp_plugin_init failed, no memory\n"));
369 gettext("rp_plugin_init failed, error %d\n"), err
);
373 command
= argv
[optind
++];
374 sl_path
= argv
[optind
++];
376 if (strcmp(command
, "add") == 0) {
378 if (optind
>= argc
) {
383 err
= addref(sl_path
, svc_type
, optind
, argc
, argv
);
385 } else if (strcmp(command
, "remove") == 0) {
387 err
= delref(sl_path
, svc_type
);
389 } else if (strcmp(command
, "lookup") == 0) {
391 err
= lookup(sl_path
, svc_type
, type_set
);
398 fprintf(stderr
, gettext("Command %s failed: %s\n"), command
,