xref: /titanic_44/usr/src/lib/libdladm/common/libdladm.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <stropts.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <libdevinfo.h>
39 #include <libdlpi.h>
40 #include <libdladm.h>
41 #include <libintl.h>
42 #include <sys/dld.h>
43 #include <net/if.h>
44 
45 #define	DLADM_DB	"/etc/datalink.conf"
46 #define	DLADM_DB_TMP	"/etc/datalink.conf.new"
47 #define	DLADM_DB_LOCK	"/tmp/datalink.conf.lock"
48 #define	DLADM_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
49 
50 #define	MAXLINELEN	1024
51 #define	LISTSZ		1024
52 #define	MAXPATHLEN	1024
53 
54 #define	BLANK_LINE(s)	((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
55 
56 typedef	struct i_dladm_walk {
57 	int		fd;
58 	boolean_t	found;
59 	const char	*name;
60 } i_dladm_walk_t;
61 
62 /*
63  * Open and lock the aggregation configuration file lock. The lock is
64  * acquired as a reader (F_RDLCK) or writer (F_WRLCK).
65  */
66 static int
67 i_dladm_lock_db(short type)
68 {
69 	int lock_fd;
70 	struct flock lock;
71 
72 	if ((lock_fd = open(DLADM_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC,
73 	    DLADM_DB_PERMS)) < 0)
74 		return (-1);
75 
76 	lock.l_type = type;
77 	lock.l_whence = SEEK_SET;
78 	lock.l_start = 0;
79 	lock.l_len = 0;
80 
81 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
82 		(void) close(lock_fd);
83 		(void) unlink(DLADM_DB_LOCK);
84 		return (-1);
85 	}
86 	return (lock_fd);
87 }
88 
89 /*
90  * Unlock and close the specified file.
91  */
92 static void
93 i_dladm_unlock_db(int fd)
94 {
95 	struct flock lock;
96 
97 	if (fd < 0)
98 		return;
99 
100 	lock.l_type = F_UNLCK;
101 	lock.l_whence = SEEK_SET;
102 	lock.l_start = 0;
103 	lock.l_len = 0;
104 
105 	(void) fcntl(fd, F_SETLKW, &lock);
106 	(void) close(fd);
107 	(void) unlink(DLADM_DB_LOCK);
108 }
109 
110 /*
111  * Parse a line of the configuration file, returns -1 if an error
112  * occured.
113  */
114 static int
115 i_dladm_db_decode(char *buf, char *name, dladm_attr_t *dap)
116 {
117 	char		*attr[DLADM_NATTR + 1];
118 	char		*endp = NULL;
119 	char		*lasts = NULL;
120 	uint_t		i;
121 
122 	attr[0] = strtok_r(buf, " \t\n", &lasts);
123 	for (i = 1; i < DLADM_NATTR + 1; i++) {
124 		if ((attr[i] = strtok_r(NULL, " \t\n", &lasts)) == NULL)
125 			return (-1);
126 	}
127 
128 	if (i != DLADM_NATTR + 1) {
129 		errno = EINVAL;
130 		return (-1);
131 	}
132 
133 	(void) strlcpy(name, attr[0], IFNAMSIZ);
134 	(void) strlcpy(dap->da_dev, attr[1], MAXNAMELEN);
135 
136 	errno = 0;
137 	dap->da_port = (int)strtol(attr[2], &endp, 10);
138 	if (errno != 0 || *endp != '\0') {
139 		return (-1);
140 	}
141 
142 	errno = 0;
143 	dap->da_vid = (int)strtol(attr[3], &endp, 10);
144 	if (errno != 0 || *endp != '\0') {
145 		return (-1);
146 	}
147 
148 	return (0);
149 }
150 
151 /*
152  * Add a datalink of the specified name and attributes to
153  * the configuration repository.
154  */
155 static int
156 i_dladm_db_add(const char *name, dladm_attr_t *dap, const char *root,
157     dladm_diag_t *diag)
158 {
159 	FILE		*fp;
160 	int		lock_fd, retval = -1;
161 	char		line[MAXLINELEN];
162 	char		dl_name[IFNAMSIZ];
163 	dladm_attr_t	da;
164 	char		*db_file;
165 	char		db_file_buf[MAXPATHLEN];
166 
167 	if (root == NULL) {
168 		db_file = DLADM_DB;
169 	} else {
170 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
171 		    DLADM_DB);
172 		db_file = db_file_buf;
173 	}
174 
175 	if ((lock_fd = i_dladm_lock_db(F_WRLCK)) < 0)
176 		return (-1);
177 
178 	if ((fp = fopen(db_file, "r+")) == NULL &&
179 	    (fp = fopen(db_file, "w")) == NULL) {
180 		*diag = DLADM_DIAG_REPOSITORY_OPENFAIL;
181 		i_dladm_unlock_db(lock_fd);
182 		return (-1);
183 	}
184 
185 	while (fgets(line, MAXLINELEN, fp) != NULL) {
186 		/* skip comments and blank lines */
187 		if (BLANK_LINE(line))
188 			continue;
189 
190 		/* skip corrupted lines */
191 		if (i_dladm_db_decode(line, dl_name, &da) < 0)
192 			continue;
193 
194 		if (strcmp(dl_name, name) == 0) {
195 			errno = EEXIST;
196 			goto failed;
197 		}
198 
199 		if (strcmp(da.da_dev, dap->da_dev) == 0 &&
200 		    da.da_port == dap->da_port &&
201 		    da.da_vid == dap->da_vid) {
202 			errno = EEXIST;
203 			goto failed;
204 		}
205 	}
206 
207 	(void) snprintf(line, MAXPATHLEN, "%s\t%s\t%u\t%u\n",
208 	    name, dap->da_dev, dap->da_port, dap->da_vid);
209 
210 	if (fputs(line, fp) == EOF) {
211 		*diag = DLADM_DIAG_REPOSITORY_WRITEFAIL;
212 		goto failed;
213 	}
214 
215 	if (fflush(fp) == EOF)
216 		goto failed;
217 
218 	retval = 0;
219 
220 failed:
221 	(void) fclose(fp);
222 	i_dladm_unlock_db(lock_fd);
223 	return (retval);
224 }
225 
226 /*
227  * Remove the datalink of the specified name from the configuration repository.
228  */
229 static int
230 i_dladm_db_remove(const char *name, const char *root)
231 {
232 	FILE		*fp;
233 	FILE		*nfp;
234 	int		nfd, lock_fd;
235 	char		line[MAXLINELEN];
236 	char		copy[MAXLINELEN];
237 	char		dl_name[IFNAMSIZ];
238 	dladm_attr_t	da;
239 	boolean_t	found = B_FALSE;
240 	char		*db_file, *tmp_db_file;
241 	char		db_file_buf[MAXPATHLEN];
242 	char		tmp_db_file_buf[MAXPATHLEN];
243 
244 	if (root == NULL) {
245 		db_file = DLADM_DB;
246 		tmp_db_file = DLADM_DB_TMP;
247 	} else {
248 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
249 		    DLADM_DB);
250 		(void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root,
251 		    DLADM_DB_TMP);
252 		db_file = db_file_buf;
253 		tmp_db_file = tmp_db_file_buf;
254 	}
255 
256 	if ((lock_fd = i_dladm_lock_db(F_WRLCK)) < 0)
257 		return (-1);
258 
259 	if ((fp = fopen(db_file, "r")) == NULL) {
260 		i_dladm_unlock_db(lock_fd);
261 		return (-1);
262 	}
263 
264 	if ((nfd = open(tmp_db_file, O_WRONLY | O_CREAT | O_TRUNC,
265 	    DLADM_DB_PERMS)) < 0) {
266 		(void) fclose(fp);
267 		i_dladm_unlock_db(lock_fd);
268 		return (-1);
269 	}
270 
271 	if ((nfp = fdopen(nfd, "w")) == NULL) {
272 		(void) close(nfd);
273 		(void) fclose(fp);
274 		(void) unlink(tmp_db_file);
275 		i_dladm_unlock_db(lock_fd);
276 		return (-1);
277 	}
278 
279 	while (fgets(line, MAXLINELEN, fp) != NULL) {
280 		(void) strlcpy(copy, line, MAXLINELEN);
281 
282 		/* skip comments */
283 		if (!BLANK_LINE(line)) {
284 			if (i_dladm_db_decode(line, dl_name, &da) < 0) {
285 				continue;
286 			}
287 
288 			if (strcmp(dl_name, name) == 0) {
289 				found = B_TRUE;
290 				continue;
291 			}
292 		}
293 
294 		if (fputs(copy, nfp) == EOF)
295 			goto failed;
296 	}
297 
298 	if (!found) {
299 		errno = ENOENT;
300 		goto failed;
301 	}
302 
303 	if (fflush(nfp) == EOF)
304 		goto failed;
305 
306 	(void) fclose(fp);
307 	(void) fclose(nfp);
308 	if (rename(tmp_db_file, db_file) < 0) {
309 		(void) unlink(tmp_db_file);
310 		i_dladm_unlock_db(lock_fd);
311 		return (-1);
312 	}
313 
314 	i_dladm_unlock_db(lock_fd);
315 	return (0);
316 
317 failed:
318 	(void) fclose(fp);
319 	(void) fclose(nfp);
320 	(void) unlink(tmp_db_file);
321 	i_dladm_unlock_db(lock_fd);
322 
323 	return (-1);
324 }
325 
326 /*
327  * For each datalink in the configuration repository, invoke the specified
328  * callback. If the datalink name is specified, the callback is invoked
329  * only for datalink of the matching name.
330  */
331 static void
332 i_dladm_db_walk(void (*fn)(void *, const char *, dladm_attr_t *),
333     const char *name, void *arg)
334 {
335 	FILE		*fp;
336 	int		lock_fd;
337 	char		line[MAXLINELEN];
338 	char		dl_name[IFNAMSIZ];
339 	dladm_attr_t	da;
340 
341 	lock_fd = i_dladm_lock_db(F_RDLCK);
342 
343 	if ((fp = fopen(DLADM_DB, "r")) == NULL) {
344 		i_dladm_unlock_db(lock_fd);
345 		return;
346 	}
347 
348 	while (fgets(line, MAXLINELEN, fp) != NULL) {
349 		/* skip comments */
350 		if (BLANK_LINE(line))
351 			continue;
352 
353 		if (i_dladm_db_decode(line, dl_name, &da) < 0)
354 			continue;
355 
356 		if (name != NULL && strcmp(name, dl_name) != 0)
357 			continue;
358 
359 		fn(arg, dl_name, &da);
360 	}
361 
362 	(void) fclose(fp);
363 	i_dladm_unlock_db(lock_fd);
364 }
365 
366 /*
367  * For each datalink in the configuration repository, invoke the
368  * specified callback.
369  */
370 void
371 dladm_db_walk(void (*fn)(void *, const char *, dladm_attr_t *),
372     void *arg)
373 {
374 	i_dladm_db_walk(fn, NULL, arg);
375 }
376 
377 /*
378  * Issue an ioctl to the specified file descriptor attached to the
379  * DLD control driver interface.
380  */
381 static int
382 i_dladm_ioctl(int fd, char *ic_dp, int ic_cmd, int ic_len)
383 {
384 	struct strioctl	iocb;
385 
386 	iocb.ic_cmd = ic_cmd;
387 	iocb.ic_timout = 0;
388 	iocb.ic_len = ic_len;
389 	iocb.ic_dp = ic_dp;
390 
391 	return (ioctl(fd, I_STR, &iocb));
392 }
393 
394 /*
395  * Issue a DLDIOCCREATE ioctl command.
396  */
397 static int
398 i_dladm_create(int fd, const char *name, dladm_attr_t *dap)
399 {
400 	dld_ioc_create_t	dic;
401 
402 	if (strlen(name) >= IFNAMSIZ) {
403 		errno = EINVAL;
404 		return (-1);
405 	}
406 
407 	(void) strlcpy(dic.dic_name, name, IFNAMSIZ);
408 	(void) strlcpy(dic.dic_dev, dap->da_dev, MAXNAMELEN);
409 	dic.dic_port = dap->da_port;
410 	dic.dic_vid = dap->da_vid;
411 
412 	return (i_dladm_ioctl(fd, (char *)&dic, DLDIOCCREATE, sizeof (dic)));
413 }
414 
415 /*
416  * Datalink bringup callback. Brings up the specified datalink.
417  */
418 static void
419 i_dladm_up(void *arg, const char *name, dladm_attr_t *dap)
420 {
421 	i_dladm_walk_t	*wp = arg;
422 
423 	wp->found = B_TRUE;
424 	(void) i_dladm_create(wp->fd, name, dap);
425 }
426 
427 /*
428  * Bring down the datalink of the specified name.
429  */
430 static int
431 i_dladm_destroy(int fd, const char *name)
432 {
433 	dld_ioc_destroy_t	did;
434 
435 	if (strlen(name) >= IFNAMSIZ) {
436 		errno = EINVAL;
437 		return (-1);
438 	}
439 
440 	(void) strlcpy(did.did_name, name, IFNAMSIZ);
441 
442 	return (i_dladm_ioctl(fd, (char *)&did, DLDIOCDESTROY, sizeof (did)));
443 }
444 
445 /*
446  * Bring down one or all currently active datalinks.
447  */
448 /*ARGSUSED*/
449 static void
450 i_dladm_down(void *arg, const char *name)
451 {
452 	i_dladm_walk_t	*wp = (i_dladm_walk_t *)arg;
453 
454 	wp->found = B_TRUE;
455 
456 	if (wp->name != NULL && strcmp(name, wp->name) != 0)
457 		return;
458 
459 	(void) i_dladm_destroy(wp->fd, name);
460 }
461 
462 /*
463  * Return the attributes of the specified datalink from the DLD driver.
464  */
465 static int
466 i_dladm_info(int fd, const char *name, dladm_attr_t *dap)
467 {
468 	dld_ioc_attr_t	dia;
469 
470 	if (strlen(name) >= IFNAMSIZ) {
471 		errno = EINVAL;
472 		return (-1);
473 	}
474 
475 	(void) strlcpy(dia.dia_name, name, IFNAMSIZ);
476 
477 	if (i_dladm_ioctl(fd, (char *)&dia, DLDIOCATTR, sizeof (dia)) < 0)
478 		return (-1);
479 
480 	(void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN);
481 	dap->da_port = dia.dia_port;
482 	dap->da_vid = dia.dia_vid;
483 
484 	return (0);
485 }
486 
487 /*
488  * Callback function used to count the number of DDI_NT_NET.
489  */
490 /* ARGSUSED */
491 static int
492 i_dladm_nt_net_count(di_node_t node, di_minor_t minor, void *arg)
493 {
494 	uint_t		*countp = arg;
495 
496 	(*countp)++;
497 	return (DI_WALK_CONTINUE);
498 }
499 
500 /*
501  * Adds a datalink to the array corresponding to arg.
502  */
503 static void
504 i_dladm_nt_net_add(void *arg, char *name)
505 {
506 	char		**array = arg;
507 	char		*elem;
508 
509 	for (;;) {
510 		elem = *(array++);
511 		if (elem[0] == '\0')
512 			break;
513 		if (strcmp(elem, name) == 0)
514 			return;
515 	}
516 
517 	(void) strlcpy(elem, name, MAXNAMELEN);
518 }
519 
520 /*
521  * Walker callback invoked for each DDI_NT_NET node.
522  */
523 static int
524 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg)
525 {
526 	dl_info_ack_t	dlia;
527 	char		name[IFNAMSIZ];
528 	int		fd;
529 	char		*provider;
530 	uint_t		ppa;
531 
532 	provider = di_minor_name(minor);
533 
534 	if ((fd = dlpi_open(provider)) < 0)
535 		return (DI_WALK_CONTINUE);
536 
537 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
538 		(void) dlpi_close(fd);
539 		return (DI_WALK_CONTINUE);
540 	}
541 
542 	if (dlia.dl_provider_style == DL_STYLE1) {
543 		i_dladm_nt_net_add(arg, provider);
544 		(void) dlpi_close(fd);
545 		return (DI_WALK_CONTINUE);
546 	}
547 
548 	ppa = di_instance(node);
549 
550 	if (dlpi_attach(fd, -1, ppa) < 0) {
551 		(void) dlpi_close(fd);
552 		return (DI_WALK_CONTINUE);
553 	}
554 
555 	(void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa);
556 	i_dladm_nt_net_add(arg, name);
557 	(void) dlpi_close(fd);
558 	return (DI_WALK_CONTINUE);
559 }
560 
561 /*
562  * Invoke the specified callback function for each active DDI_NT_NET
563  * node.
564  */
565 int
566 dladm_walk(void (*fn)(void *, const char *), void *arg)
567 {
568 	di_node_t	root;
569 	uint_t		count;
570 	char		**array;
571 	char		*elem;
572 	int		i;
573 
574 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
575 		errno = EFAULT;
576 		return (-1);
577 	}
578 
579 	count = 0;
580 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, (void *)&count,
581 	    i_dladm_nt_net_count);
582 
583 	if (count == 0)
584 		return (0);
585 
586 	if ((array = malloc(count * sizeof (char *))) == NULL)
587 		goto done;
588 
589 	for (i = 0; i < count; i++) {
590 		if ((array[i] = malloc(IFNAMSIZ)) != NULL) {
591 			(void) memset(array[i], '\0', IFNAMSIZ);
592 			continue;
593 		}
594 
595 		while (--i >= 0)
596 			free(array[i]);
597 		goto done;
598 	}
599 
600 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, (void *)array,
601 	    i_dladm_nt_net_walk);
602 	di_fini(root);
603 
604 	for (i = 0; i < count; i++) {
605 		elem = array[i];
606 		if (elem[0] != '\0')
607 			fn(arg, (const char *)elem);
608 		free(elem);
609 	}
610 
611 done:
612 	free(array);
613 	return (0);
614 }
615 
616 /*
617  * Create the link of specified name and attributes. Adds it to the
618  * configuration repository if DLADM_LINK_TEMP is not set. Errors
619  * will be ignored if DLADM_LINK_FORCED is set.
620  */
621 int
622 dladm_link(const char *name, dladm_attr_t *dap, int flags,
623     const char *root, dladm_diag_t *diag)
624 {
625 	int		fd;
626 	boolean_t	tempop = (flags & DLADM_LINK_TEMP);
627 	boolean_t	forced = (flags & DLADM_LINK_FORCED);
628 
629 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
630 		*diag = DLADM_DIAG_DEVICE_OPENFAIL;
631 		return (-1);
632 	}
633 
634 	if (!tempop) {
635 		if (i_dladm_db_add(name, dap, root, diag) < 0 && !forced)
636 			goto failed;
637 	}
638 
639 	if (i_dladm_create(fd, name, dap) < 0 && !forced) {
640 		if (errno == EINVAL) {
641 			*diag = DLADM_DIAG_INVALID_INTFNAME;
642 		}
643 		if (!tempop)
644 			(void) i_dladm_db_remove(name, root);
645 		goto failed;
646 	}
647 
648 	(void) close(fd);
649 	return (0);
650 
651 failed:
652 	(void) close(fd);
653 	return (-1);
654 }
655 
656 /*
657  * Instantiate the datalink of specified name. Brings up all datalinks
658  * if name is NULL.
659  */
660 int
661 dladm_up(const char *name, dladm_diag_t *diag)
662 {
663 	i_dladm_walk_t	walk;
664 
665 	if ((walk.fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
666 		*diag =
667 		    DLADM_DIAG_DEVICE_OPENFAIL;
668 		return (-1);
669 	}
670 
671 	walk.found = B_FALSE;
672 	i_dladm_db_walk(i_dladm_up, name, (void *)&walk);
673 	if (name != NULL && !walk.found) {
674 		(void) close(walk.fd);
675 		errno = ENOENT;
676 		return (-1);
677 	}
678 
679 	(void) close(walk.fd);
680 	return (0);
681 }
682 
683 /*
684  * Deletes the link of specified name.
685  */
686 int
687 dladm_unlink(const char *name, boolean_t tempop, const char *root,
688     dladm_diag_t *diag)
689 {
690 	int		fd;
691 
692 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
693 		*diag = DLADM_DIAG_DEVICE_OPENFAIL;
694 		return (-1);
695 	}
696 
697 	if (i_dladm_destroy(fd, name) < 0) {
698 		if (errno == EINVAL)
699 			*diag = DLADM_DIAG_INVALID_LINKNAME;
700 		goto failed;
701 	}
702 
703 	if (!tempop)
704 		(void) i_dladm_db_remove(name, root);
705 	(void) close(fd);
706 	return (0);
707 
708 failed:
709 	(void) close(fd);
710 	return (-1);
711 }
712 
713 /*
714  * Brings down the datalink of specified name. Brings down all datalinks
715  * if name == NULL.
716  */
717 int
718 dladm_down(const char *name, dladm_diag_t *diag)
719 {
720 	i_dladm_walk_t	walk;
721 
722 	if ((walk.fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
723 		*diag = DLADM_DIAG_DEVICE_OPENFAIL;
724 		return (-1);
725 	}
726 	walk.found = B_FALSE;
727 	walk.name = name;
728 
729 	if (dladm_walk(i_dladm_down, (void *)&walk) < 0) {
730 		(void) close(walk.fd);
731 		return (-1);
732 	}
733 
734 	if (name != NULL && !walk.found) {
735 		(void) close(walk.fd);
736 		errno = ENOENT;
737 		return (-1);
738 	}
739 
740 	(void) close(walk.fd);
741 	return (0);
742 }
743 
744 /*
745  * Returns the current attributes of the specified datalink.
746  */
747 int
748 dladm_info(const char *name, dladm_attr_t *dap)
749 {
750 	int		fd;
751 
752 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
753 		return (-1);
754 
755 	if (i_dladm_info(fd, name, dap) < 0)
756 		goto failed;
757 
758 	(void) close(fd);
759 	return (0);
760 
761 failed:
762 	(void) close(fd);
763 	return (-1);
764 }
765 
766 /*
767  * Causes the nodes corresponding to created or deleted datalinks to
768  * be created or deleted.
769  */
770 int
771 dladm_sync(void)
772 {
773 	di_devlink_handle_t	hdl;
774 
775 	if ((hdl = di_devlink_init(DLD_DRIVER_NAME, DI_MAKE_LINK)) == NULL)
776 		return (-1);
777 
778 	if (di_devlink_fini(&hdl) < 0)
779 		return (-1);
780 
781 	return (0);
782 }
783 
784 const char *
785 dladm_diag(dladm_diag_t diag) {
786 	switch (diag) {
787 	case DLADM_DIAG_INVALID_LINKNAME:
788 		return (gettext("invalid datalink name"));
789 	case DLADM_DIAG_INVALID_INTFNAME:
790 		return (gettext("invalid interface name"));
791 	case DLADM_DIAG_CORRUPT_REPOSITORY:
792 		return (gettext("configuration repository corrupt"));
793 	case DLADM_DIAG_REPOSITORY_OPENFAIL:
794 		return (gettext("configuration repository open failed"));
795 	case DLADM_DIAG_REPOSITORY_WRITEFAIL:
796 		return (gettext("write to configuration repository failed"));
797 	case DLADM_DIAG_REPOSITORY_CLOSEFAIL:
798 		return (gettext("configuration repository close failed"));
799 	case DLADM_DIAG_DEVICE_OPENFAIL:
800 		return (gettext("dld device open fail"));
801 	default:
802 		return (gettext("unknown diagnostic"));
803 	}
804 }
805