xref: /illumos-gate/usr/src/cmd/fs.d/nfs/nfsref/nfsref.c (revision 2f172c55)
1*2f172c55SRobert Thurlow /*
2*2f172c55SRobert Thurlow  * CDDL HEADER START
3*2f172c55SRobert Thurlow  *
4*2f172c55SRobert Thurlow  * The contents of this file are subject to the terms of the
5*2f172c55SRobert Thurlow  * Common Development and Distribution License (the "License").
6*2f172c55SRobert Thurlow  * You may not use this file except in compliance with the License.
7*2f172c55SRobert Thurlow  *
8*2f172c55SRobert Thurlow  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2f172c55SRobert Thurlow  * or http://www.opensolaris.org/os/licensing.
10*2f172c55SRobert Thurlow  * See the License for the specific language governing permissions
11*2f172c55SRobert Thurlow  * and limitations under the License.
12*2f172c55SRobert Thurlow  *
13*2f172c55SRobert Thurlow  * When distributing Covered Code, include this CDDL HEADER in each
14*2f172c55SRobert Thurlow  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2f172c55SRobert Thurlow  * If applicable, add the following below this CDDL HEADER, with the
16*2f172c55SRobert Thurlow  * fields enclosed by brackets "[]" replaced with your own identifying
17*2f172c55SRobert Thurlow  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2f172c55SRobert Thurlow  *
19*2f172c55SRobert Thurlow  * CDDL HEADER END
20*2f172c55SRobert Thurlow  */
21*2f172c55SRobert Thurlow 
22*2f172c55SRobert Thurlow /*
23*2f172c55SRobert Thurlow  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*2f172c55SRobert Thurlow  * Use is subject to license terms.
25*2f172c55SRobert Thurlow  */
26*2f172c55SRobert Thurlow 
27*2f172c55SRobert Thurlow #include <stdio.h>
28*2f172c55SRobert Thurlow #include <unistd.h>
29*2f172c55SRobert Thurlow #include <strings.h>
30*2f172c55SRobert Thurlow #include <string.h>
31*2f172c55SRobert Thurlow #include <limits.h>
32*2f172c55SRobert Thurlow #include <libnvpair.h>
33*2f172c55SRobert Thurlow #include <locale.h>
34*2f172c55SRobert Thurlow #include <sys/stat.h>
35*2f172c55SRobert Thurlow #include <sys/fs_reparse.h>
36*2f172c55SRobert Thurlow #include <rp_plugin.h>
37*2f172c55SRobert Thurlow #include <uuid/uuid.h>
38*2f172c55SRobert Thurlow #include <sys/types.h>
39*2f172c55SRobert Thurlow #include <sys/stat.h>
40*2f172c55SRobert Thurlow #include <fcntl.h>
41*2f172c55SRobert Thurlow #include <priv.h>
42*2f172c55SRobert Thurlow #include <nfs/nfs4.h>
43*2f172c55SRobert Thurlow #include <rpcsvc/nfs4_prot.h>
44*2f172c55SRobert Thurlow #include "ref_subr.h"
45*2f172c55SRobert Thurlow 
46*2f172c55SRobert Thurlow #ifndef TEXT_DOMAIN
47*2f172c55SRobert Thurlow #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
48*2f172c55SRobert Thurlow #endif /* TEXT_DOMAIN */
49*2f172c55SRobert Thurlow 
50*2f172c55SRobert Thurlow extern int errno;
51*2f172c55SRobert Thurlow 
52*2f172c55SRobert Thurlow void
53*2f172c55SRobert Thurlow usage()
54*2f172c55SRobert Thurlow {
55*2f172c55SRobert Thurlow 	fprintf(stderr, gettext("Usage:\n"));
56*2f172c55SRobert Thurlow 	fprintf(stderr,
57*2f172c55SRobert Thurlow 	    gettext("\tnfsref [-t type] add path location [location ...]\n"));
58*2f172c55SRobert Thurlow 	fprintf(stderr, gettext("\tnfsref [-t type] remove path\n"));
59*2f172c55SRobert Thurlow 	fprintf(stderr, gettext("\tnfsref [-t type] lookup path\n"));
60*2f172c55SRobert Thurlow }
61*2f172c55SRobert Thurlow 
62*2f172c55SRobert Thurlow /*
63*2f172c55SRobert Thurlow  * Copy a string from source to destination, escaping space
64*2f172c55SRobert Thurlow  * with a backslash and escaping the escape character as well.
65*2f172c55SRobert Thurlow  */
66*2f172c55SRobert Thurlow int
67*2f172c55SRobert Thurlow add_escape(char *src, char *dest, int limit)
68*2f172c55SRobert Thurlow {
69*2f172c55SRobert Thurlow 	char *sp, *dp;
70*2f172c55SRobert Thurlow 	int destlen = 0;
71*2f172c55SRobert Thurlow 
72*2f172c55SRobert Thurlow 	sp = src;
73*2f172c55SRobert Thurlow 	dp = dest;
74*2f172c55SRobert Thurlow 
75*2f172c55SRobert Thurlow 	while (*sp && destlen < limit) {
76*2f172c55SRobert Thurlow 		if (*sp == '\\') {
77*2f172c55SRobert Thurlow 			*dp++ = '\\';
78*2f172c55SRobert Thurlow 			*dp++ = '\\';
79*2f172c55SRobert Thurlow 			destlen++;
80*2f172c55SRobert Thurlow 		} else if (*sp == ' ') {
81*2f172c55SRobert Thurlow 			*dp++ = '\\';
82*2f172c55SRobert Thurlow 			*dp++ = ' ';
83*2f172c55SRobert Thurlow 			destlen++;
84*2f172c55SRobert Thurlow 		} else
85*2f172c55SRobert Thurlow 			*dp++ = *sp;
86*2f172c55SRobert Thurlow 		destlen++;
87*2f172c55SRobert Thurlow 		sp++;
88*2f172c55SRobert Thurlow 	}
89*2f172c55SRobert Thurlow 	if (limit <= 0)
90*2f172c55SRobert Thurlow 		return (-1);
91*2f172c55SRobert Thurlow 	return (destlen);
92*2f172c55SRobert Thurlow }
93*2f172c55SRobert Thurlow 
94*2f172c55SRobert Thurlow int
95*2f172c55SRobert Thurlow addref(char *sl_path, char *svc_type, int optind, int argc, char *argv[])
96*2f172c55SRobert Thurlow {
97*2f172c55SRobert Thurlow 	int err, fd, i, len, oldlen, notfound = 0;
98*2f172c55SRobert Thurlow 	char *text, *location;
99*2f172c55SRobert Thurlow 	nvlist_t *nvl = NULL;
100*2f172c55SRobert Thurlow 	char buf[SYMLINK_MAX];
101*2f172c55SRobert Thurlow 	struct stat sbuf;
102*2f172c55SRobert Thurlow 
103*2f172c55SRobert Thurlow 	/* Get an nvlist */
104*2f172c55SRobert Thurlow 	nvl = reparse_init();
105*2f172c55SRobert Thurlow 	if (nvl == NULL)
106*2f172c55SRobert Thurlow 		return (ENOMEM);
107*2f172c55SRobert Thurlow 
108*2f172c55SRobert Thurlow 	/* Get the reparse point data, if the RP exists */
109*2f172c55SRobert Thurlow 	err = readlink(sl_path, buf, SYMLINK_MAX);
110*2f172c55SRobert Thurlow 	if (err == -1) {
111*2f172c55SRobert Thurlow 		if (errno == ENOENT) {
112*2f172c55SRobert Thurlow 			notfound = 1;
113*2f172c55SRobert Thurlow 			err = 0;
114*2f172c55SRobert Thurlow 		} else {
115*2f172c55SRobert Thurlow 			reparse_free(nvl);
116*2f172c55SRobert Thurlow 			return (errno);
117*2f172c55SRobert Thurlow 		}
118*2f172c55SRobert Thurlow 	} else {
119*2f172c55SRobert Thurlow 		buf[err] = '\0';
120*2f172c55SRobert Thurlow 	}
121*2f172c55SRobert Thurlow 
122*2f172c55SRobert Thurlow 	/* Get any data into nvlist */
123*2f172c55SRobert Thurlow 	if (notfound == 0)
124*2f172c55SRobert Thurlow 		err = reparse_parse(buf, nvl);
125*2f172c55SRobert Thurlow 	if (err != 0) {
126*2f172c55SRobert Thurlow 		reparse_free(nvl);
127*2f172c55SRobert Thurlow 		return (err);
128*2f172c55SRobert Thurlow 	}
129*2f172c55SRobert Thurlow 
130*2f172c55SRobert Thurlow 	/*
131*2f172c55SRobert Thurlow 	 * Accumulate multiple locations on the command line into 'buf'
132*2f172c55SRobert Thurlow 	 */
133*2f172c55SRobert Thurlow 	oldlen = len = 0;
134*2f172c55SRobert Thurlow 	location = NULL;
135*2f172c55SRobert Thurlow 	for (i = optind; i < argc; i++) {
136*2f172c55SRobert Thurlow 		bzero(buf, sizeof (buf));
137*2f172c55SRobert Thurlow 		len += add_escape(argv[i], buf, SYMLINK_MAX) + 2;
138*2f172c55SRobert Thurlow 		location = realloc(location, len);
139*2f172c55SRobert Thurlow 		location[oldlen] = '\0';
140*2f172c55SRobert Thurlow 		oldlen = len;
141*2f172c55SRobert Thurlow 		strlcat(location, buf, len);
142*2f172c55SRobert Thurlow 		strlcat(location, " ", len);
143*2f172c55SRobert Thurlow 	}
144*2f172c55SRobert Thurlow 	location[len - 2] = '\0';
145*2f172c55SRobert Thurlow 
146*2f172c55SRobert Thurlow 	/* Add to the list */
147*2f172c55SRobert Thurlow 	err = reparse_add(nvl, svc_type, location);
148*2f172c55SRobert Thurlow 	if (err) {
149*2f172c55SRobert Thurlow 		reparse_free(nvl);
150*2f172c55SRobert Thurlow 		return (err);
151*2f172c55SRobert Thurlow 	}
152*2f172c55SRobert Thurlow 
153*2f172c55SRobert Thurlow 	/* Get the new or modified symlink contents */
154*2f172c55SRobert Thurlow 	err = reparse_unparse(nvl, &text);
155*2f172c55SRobert Thurlow 	reparse_free(nvl);
156*2f172c55SRobert Thurlow 	if (err)
157*2f172c55SRobert Thurlow 		return (err);
158*2f172c55SRobert Thurlow 
159*2f172c55SRobert Thurlow 	/* Delete first if found */
160*2f172c55SRobert Thurlow 	if (notfound == 0) {
161*2f172c55SRobert Thurlow 		err =  reparse_delete(sl_path);
162*2f172c55SRobert Thurlow 		if (err) {
163*2f172c55SRobert Thurlow 			free(text);
164*2f172c55SRobert Thurlow 			return (err);
165*2f172c55SRobert Thurlow 		}
166*2f172c55SRobert Thurlow 	}
167*2f172c55SRobert Thurlow 
168*2f172c55SRobert Thurlow 	/* Finally, write out the reparse point */
169*2f172c55SRobert Thurlow 	err = reparse_create(sl_path, text);
170*2f172c55SRobert Thurlow 	free(text);
171*2f172c55SRobert Thurlow 	if (err)
172*2f172c55SRobert Thurlow 		return (err);
173*2f172c55SRobert Thurlow 
174*2f172c55SRobert Thurlow 	err = lstat(sl_path, &sbuf);
175*2f172c55SRobert Thurlow 	if (err == 0 && strcasecmp(sbuf.st_fstype, "ZFS") != 0)
176*2f172c55SRobert Thurlow 		printf(gettext(
177*2f172c55SRobert Thurlow 		    "Warning: referrals do not work on this filesystem\n"));
178*2f172c55SRobert Thurlow 
179*2f172c55SRobert Thurlow 	if (notfound)
180*2f172c55SRobert Thurlow 		printf(gettext("Created reparse point %s\n"), sl_path);
181*2f172c55SRobert Thurlow 	else
182*2f172c55SRobert Thurlow 		printf(gettext("Added to reparse point %s\n"), sl_path);
183*2f172c55SRobert Thurlow 
184*2f172c55SRobert Thurlow 	return (0);
185*2f172c55SRobert Thurlow }
186*2f172c55SRobert Thurlow 
187*2f172c55SRobert Thurlow int
188*2f172c55SRobert Thurlow delref(char *sl_path, char *svc_type)
189*2f172c55SRobert Thurlow {
190*2f172c55SRobert Thurlow 	char *cp;
191*2f172c55SRobert Thurlow 	char *svc_data;
192*2f172c55SRobert Thurlow 	int err;
193*2f172c55SRobert Thurlow 	nvlist_t *nvl;
194*2f172c55SRobert Thurlow 	nvpair_t *curr;
195*2f172c55SRobert Thurlow 	char buf[SYMLINK_MAX];
196*2f172c55SRobert Thurlow 	int fd, fd2;
197*2f172c55SRobert Thurlow 	FILE *fp, *fp2;
198*2f172c55SRobert Thurlow 	char uuid[UUID_PRINTABLE_STRING_LENGTH], path[256], loc[2048];
199*2f172c55SRobert Thurlow 
200*2f172c55SRobert Thurlow 	/* Get an nvlist */
201*2f172c55SRobert Thurlow 	if (!(nvl = reparse_init()))
202*2f172c55SRobert Thurlow 		return (ENOMEM);
203*2f172c55SRobert Thurlow 
204*2f172c55SRobert Thurlow 	/* Get the symlink data (should be there) */
205*2f172c55SRobert Thurlow 	err = readlink(sl_path, buf, SYMLINK_MAX);
206*2f172c55SRobert Thurlow 	if (err == -1) {
207*2f172c55SRobert Thurlow 		reparse_free(nvl);
208*2f172c55SRobert Thurlow 		return (errno);
209*2f172c55SRobert Thurlow 	}
210*2f172c55SRobert Thurlow 	buf[err] = '\0';
211*2f172c55SRobert Thurlow 
212*2f172c55SRobert Thurlow 	/* Get the records into the nvlist */
213*2f172c55SRobert Thurlow 	err = reparse_parse(buf, nvl);
214*2f172c55SRobert Thurlow 	if (err) {
215*2f172c55SRobert Thurlow 		reparse_free(nvl);
216*2f172c55SRobert Thurlow 		return (err);
217*2f172c55SRobert Thurlow 	}
218*2f172c55SRobert Thurlow 
219*2f172c55SRobert Thurlow 	/* Remove from nvlist */
220*2f172c55SRobert Thurlow 	err = reparse_remove(nvl, svc_type);
221*2f172c55SRobert Thurlow 	if (err) {
222*2f172c55SRobert Thurlow 		reparse_free(nvl);
223*2f172c55SRobert Thurlow 		return (err);
224*2f172c55SRobert Thurlow 	}
225*2f172c55SRobert Thurlow 
226*2f172c55SRobert Thurlow 	/* Any list entries left? If so, turn nvlist back to string. */
227*2f172c55SRobert Thurlow 	curr = nvlist_next_nvpair(nvl, NULL);
228*2f172c55SRobert Thurlow 	if (curr != NULL) {
229*2f172c55SRobert Thurlow 		err = reparse_unparse(nvl, &cp);
230*2f172c55SRobert Thurlow 		reparse_free(nvl);
231*2f172c55SRobert Thurlow 		if (err)
232*2f172c55SRobert Thurlow 			return (err);
233*2f172c55SRobert Thurlow 	} else {
234*2f172c55SRobert Thurlow 		reparse_free(nvl);
235*2f172c55SRobert Thurlow 		cp = NULL;
236*2f172c55SRobert Thurlow 	}
237*2f172c55SRobert Thurlow 
238*2f172c55SRobert Thurlow 	/* Finally, delete and perhaps recreate the reparse point */
239*2f172c55SRobert Thurlow 	err = reparse_delete(sl_path);
240*2f172c55SRobert Thurlow 	if (err) {
241*2f172c55SRobert Thurlow 		free(cp);
242*2f172c55SRobert Thurlow 		return (err);
243*2f172c55SRobert Thurlow 	}
244*2f172c55SRobert Thurlow 
245*2f172c55SRobert Thurlow 	if (cp != NULL) {
246*2f172c55SRobert Thurlow 		err = reparse_create(sl_path, cp);
247*2f172c55SRobert Thurlow 		free(cp);
248*2f172c55SRobert Thurlow 		if (err)
249*2f172c55SRobert Thurlow 			return (err);
250*2f172c55SRobert Thurlow 	}
251*2f172c55SRobert Thurlow 	printf(gettext("Removed svc_type '%s' from %s\n"), svc_type, sl_path);
252*2f172c55SRobert Thurlow 	return (err);
253*2f172c55SRobert Thurlow }
254*2f172c55SRobert Thurlow 
255*2f172c55SRobert Thurlow int
256*2f172c55SRobert Thurlow lookup(char *sl_path, char *svc_type, int type_set)
257*2f172c55SRobert Thurlow {
258*2f172c55SRobert Thurlow 	int err;
259*2f172c55SRobert Thurlow 	size_t bufsize;
260*2f172c55SRobert Thurlow 	char buf[1024];
261*2f172c55SRobert Thurlow 	char *type, *svc_data;
262*2f172c55SRobert Thurlow 	nvlist_t *nvl;
263*2f172c55SRobert Thurlow 	nvpair_t *curr;
264*2f172c55SRobert Thurlow 	fs_locations4 fsl;
265*2f172c55SRobert Thurlow 	XDR xdr;
266*2f172c55SRobert Thurlow 
267*2f172c55SRobert Thurlow 	if (!(nvl = reparse_init()))
268*2f172c55SRobert Thurlow 		return (-1);
269*2f172c55SRobert Thurlow 
270*2f172c55SRobert Thurlow 	/* Get reparse point data */
271*2f172c55SRobert Thurlow 	err = readlink(sl_path, buf, SYMLINK_MAX);
272*2f172c55SRobert Thurlow 	if (err == -1)
273*2f172c55SRobert Thurlow 		return (errno);
274*2f172c55SRobert Thurlow 	buf[err] = '\0';
275*2f172c55SRobert Thurlow 
276*2f172c55SRobert Thurlow 	/* Parse it to an nvlist */
277*2f172c55SRobert Thurlow 	err = reparse_parse(buf, nvl);
278*2f172c55SRobert Thurlow 	if (err) {
279*2f172c55SRobert Thurlow 		reparse_free(nvl);
280*2f172c55SRobert Thurlow 		return (err);
281*2f172c55SRobert Thurlow 	}
282*2f172c55SRobert Thurlow 
283*2f172c55SRobert Thurlow 	/* Look for entries of the requested service type */
284*2f172c55SRobert Thurlow 	curr = NULL;
285*2f172c55SRobert Thurlow 	while ((curr = nvlist_next_nvpair(nvl, curr)) != NULL) {
286*2f172c55SRobert Thurlow 		type = nvpair_name(curr);
287*2f172c55SRobert Thurlow 		if (type_set && strcasecmp(type, svc_type) == 0)
288*2f172c55SRobert Thurlow 			break;
289*2f172c55SRobert Thurlow 		if (!type_set && strncasecmp(type, "nfs", 3) == 0)
290*2f172c55SRobert Thurlow 			break;
291*2f172c55SRobert Thurlow 	}
292*2f172c55SRobert Thurlow 	if (curr == NULL) {
293*2f172c55SRobert Thurlow 		reparse_free(nvl);
294*2f172c55SRobert Thurlow 		return (ENOENT);
295*2f172c55SRobert Thurlow 	}
296*2f172c55SRobert Thurlow 
297*2f172c55SRobert Thurlow 	/* Get the service data and look it up */
298*2f172c55SRobert Thurlow 	nvpair_value_string(curr, &svc_data);
299*2f172c55SRobert Thurlow 
300*2f172c55SRobert Thurlow 	bufsize = sizeof (buf);
301*2f172c55SRobert Thurlow 	err = reparse_deref(type, svc_data, buf, &bufsize);
302*2f172c55SRobert Thurlow 	reparse_free(nvl);
303*2f172c55SRobert Thurlow 	if (err)
304*2f172c55SRobert Thurlow 		return (err);
305*2f172c55SRobert Thurlow 
306*2f172c55SRobert Thurlow 	xdrmem_create(&xdr, buf, bufsize, XDR_DECODE);
307*2f172c55SRobert Thurlow 	err = xdr_fs_locations4(&xdr, &fsl);
308*2f172c55SRobert Thurlow 	XDR_DESTROY(&xdr);
309*2f172c55SRobert Thurlow 	if (err != TRUE)
310*2f172c55SRobert Thurlow 		return (ENOENT);
311*2f172c55SRobert Thurlow 	printf(gettext("%s points to: "), sl_path);
312*2f172c55SRobert Thurlow 	print_referral_summary(&fsl);
313*2f172c55SRobert Thurlow 	return (0);
314*2f172c55SRobert Thurlow }
315*2f172c55SRobert Thurlow 
316*2f172c55SRobert Thurlow extern char *optarg;
317*2f172c55SRobert Thurlow extern int optind, optopt;
318*2f172c55SRobert Thurlow 
319*2f172c55SRobert Thurlow int
320*2f172c55SRobert Thurlow main(int argc, char *argv[])
321*2f172c55SRobert Thurlow {
322*2f172c55SRobert Thurlow 	char c, *command, *sl_path, *svc_type;
323*2f172c55SRobert Thurlow 	int type_set, err;
324*2f172c55SRobert Thurlow 
325*2f172c55SRobert Thurlow 	(void) setlocale(LC_ALL, "");
326*2f172c55SRobert Thurlow 	(void) textdomain(TEXT_DOMAIN);
327*2f172c55SRobert Thurlow 
328*2f172c55SRobert Thurlow 	svc_type = "nfs-basic";		/* Default from SMF some day */
329*2f172c55SRobert Thurlow 	type_set = 0;			/* Lookup any nfs type */
330*2f172c55SRobert Thurlow 
331*2f172c55SRobert Thurlow 	/* Look for options (just the service type now) */
332*2f172c55SRobert Thurlow 	while ((c = getopt(argc, argv, "t:")) != -1) {
333*2f172c55SRobert Thurlow 		switch (c) {
334*2f172c55SRobert Thurlow 		case 't':
335*2f172c55SRobert Thurlow 			svc_type = optarg;
336*2f172c55SRobert Thurlow 			type_set = 1;
337*2f172c55SRobert Thurlow 			break;
338*2f172c55SRobert Thurlow 
339*2f172c55SRobert Thurlow 		default:
340*2f172c55SRobert Thurlow 			usage();
341*2f172c55SRobert Thurlow 			exit(1);
342*2f172c55SRobert Thurlow 		}
343*2f172c55SRobert Thurlow 	}
344*2f172c55SRobert Thurlow 
345*2f172c55SRobert Thurlow 	/* Make sure there's at least a command and one argument */
346*2f172c55SRobert Thurlow 	if (optind + 1 >= argc) {
347*2f172c55SRobert Thurlow 		usage();
348*2f172c55SRobert Thurlow 		exit(1);
349*2f172c55SRobert Thurlow 	}
350*2f172c55SRobert Thurlow 
351*2f172c55SRobert Thurlow 	err = rp_plugin_init();
352*2f172c55SRobert Thurlow 	switch (err) {
353*2f172c55SRobert Thurlow 	case RP_OK:
354*2f172c55SRobert Thurlow 		break;
355*2f172c55SRobert Thurlow 	case RP_NO_PLUGIN_DIR:
356*2f172c55SRobert Thurlow 		fprintf(stderr,
357*2f172c55SRobert Thurlow 		    gettext("Warning: no plugin directory, continuing...\n"));
358*2f172c55SRobert Thurlow 		break;
359*2f172c55SRobert Thurlow 	case RP_NO_PLUGIN:
360*2f172c55SRobert Thurlow 		fprintf(stderr,
361*2f172c55SRobert Thurlow 		    gettext("Warning: no plugin found, continuing...\n"));
362*2f172c55SRobert Thurlow 		break;
363*2f172c55SRobert Thurlow 	case RP_NO_MEMORY:
364*2f172c55SRobert Thurlow 		fprintf(stderr,
365*2f172c55SRobert Thurlow 		    gettext("rp_plugin_init failed, no memory\n"));
366*2f172c55SRobert Thurlow 		exit(0);
367*2f172c55SRobert Thurlow 	default:
368*2f172c55SRobert Thurlow 		fprintf(stderr,
369*2f172c55SRobert Thurlow 		    gettext("rp_plugin_init failed, error %d\n"), err);
370*2f172c55SRobert Thurlow 		exit(0);
371*2f172c55SRobert Thurlow 	}
372*2f172c55SRobert Thurlow 
373*2f172c55SRobert Thurlow 	command = argv[optind++];
374*2f172c55SRobert Thurlow 	sl_path = argv[optind++];
375*2f172c55SRobert Thurlow 
376*2f172c55SRobert Thurlow 	if (strcmp(command, "add") == 0) {
377*2f172c55SRobert Thurlow 
378*2f172c55SRobert Thurlow 		if (optind >= argc) {
379*2f172c55SRobert Thurlow 			usage();
380*2f172c55SRobert Thurlow 			exit(1);
381*2f172c55SRobert Thurlow 		}
382*2f172c55SRobert Thurlow 
383*2f172c55SRobert Thurlow 		err = addref(sl_path, svc_type, optind, argc, argv);
384*2f172c55SRobert Thurlow 
385*2f172c55SRobert Thurlow 	} else if (strcmp(command, "remove") == 0) {
386*2f172c55SRobert Thurlow 
387*2f172c55SRobert Thurlow 		err = delref(sl_path, svc_type);
388*2f172c55SRobert Thurlow 
389*2f172c55SRobert Thurlow 	} else if (strcmp(command, "lookup") == 0) {
390*2f172c55SRobert Thurlow 
391*2f172c55SRobert Thurlow 		err = lookup(sl_path, svc_type, type_set);
392*2f172c55SRobert Thurlow 
393*2f172c55SRobert Thurlow 	} else {
394*2f172c55SRobert Thurlow 		usage();
395*2f172c55SRobert Thurlow 		exit(1);
396*2f172c55SRobert Thurlow 	}
397*2f172c55SRobert Thurlow 	if (err != 0)
398*2f172c55SRobert Thurlow 		fprintf(stderr, gettext("Command %s failed: %s\n"), command,
399*2f172c55SRobert Thurlow 		    strerror(err));
400*2f172c55SRobert Thurlow 	return (err);
401*2f172c55SRobert Thurlow }
402