xref: /titanic_50/usr/src/lib/libdladm/common/libdladm.c (revision f595a68a3b8953a12aa778c2abd7642df8da8c3a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22f4b3ec61Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <unistd.h>
297c478bd9Sstevel@tonic-gate #include <stropts.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
310ba2cbe9Sxc151355 #include <fcntl.h>
320ba2cbe9Sxc151355 #include <strings.h>
330ba2cbe9Sxc151355 #include <dirent.h>
340ba2cbe9Sxc151355 #include <sys/stat.h>
35*f595a68aSyz147064 #include <libdladm.h>
360ba2cbe9Sxc151355 #include <libdladm_impl.h>
3733343a97Smeem #include <libintl.h>
38aae21359Skrgopi 
390ba2cbe9Sxc151355 static char		dladm_rootdir[MAXPATHLEN] = "/";
400ba2cbe9Sxc151355 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * Issue an ioctl to the specified file descriptor attached to the
437c478bd9Sstevel@tonic-gate  * DLD control driver interface.
447c478bd9Sstevel@tonic-gate  */
450ba2cbe9Sxc151355 int
46210db224Sericheng i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	struct strioctl	iocb;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	iocb.ic_cmd = ic_cmd;
517c478bd9Sstevel@tonic-gate 	iocb.ic_timout = 0;
527c478bd9Sstevel@tonic-gate 	iocb.ic_len = ic_len;
53210db224Sericheng 	iocb.ic_dp = (char *)ic_dp;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	return (ioctl(fd, I_STR, &iocb));
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate 
580ba2cbe9Sxc151355 const char *
590ba2cbe9Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
600ba2cbe9Sxc151355 {
610ba2cbe9Sxc151355 	const char	*s;
620ba2cbe9Sxc151355 
630ba2cbe9Sxc151355 	switch (status) {
640ba2cbe9Sxc151355 	case DLADM_STATUS_OK:
650ba2cbe9Sxc151355 		s = "ok";
660ba2cbe9Sxc151355 		break;
670ba2cbe9Sxc151355 	case DLADM_STATUS_BADARG:
680ba2cbe9Sxc151355 		s = "invalid argument";
690ba2cbe9Sxc151355 		break;
700ba2cbe9Sxc151355 	case DLADM_STATUS_FAILED:
710ba2cbe9Sxc151355 		s = "operation failed";
720ba2cbe9Sxc151355 		break;
730ba2cbe9Sxc151355 	case DLADM_STATUS_TOOSMALL:
740ba2cbe9Sxc151355 		s = "buffer size too small";
750ba2cbe9Sxc151355 		break;
760ba2cbe9Sxc151355 	case DLADM_STATUS_NOTSUP:
770ba2cbe9Sxc151355 		s = "operation not supported";
780ba2cbe9Sxc151355 		break;
790ba2cbe9Sxc151355 	case DLADM_STATUS_NOTFOUND:
800ba2cbe9Sxc151355 		s = "object not found";
810ba2cbe9Sxc151355 		break;
820ba2cbe9Sxc151355 	case DLADM_STATUS_BADVAL:
830ba2cbe9Sxc151355 		s = "invalid value";
840ba2cbe9Sxc151355 		break;
850ba2cbe9Sxc151355 	case DLADM_STATUS_NOMEM:
860ba2cbe9Sxc151355 		s = "insufficient memory";
870ba2cbe9Sxc151355 		break;
880ba2cbe9Sxc151355 	case DLADM_STATUS_EXIST:
890ba2cbe9Sxc151355 		s = "object already exists";
900ba2cbe9Sxc151355 		break;
910ba2cbe9Sxc151355 	case DLADM_STATUS_LINKINVAL:
920ba2cbe9Sxc151355 		s = "invalid link";
930ba2cbe9Sxc151355 		break;
940ba2cbe9Sxc151355 	case DLADM_STATUS_PROPRDONLY:
950ba2cbe9Sxc151355 		s = "read-only property";
960ba2cbe9Sxc151355 		break;
970ba2cbe9Sxc151355 	case DLADM_STATUS_BADVALCNT:
980ba2cbe9Sxc151355 		s = "invalid number of values";
990ba2cbe9Sxc151355 		break;
1000ba2cbe9Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
1010ba2cbe9Sxc151355 		s = "database not found";
1020ba2cbe9Sxc151355 		break;
1030ba2cbe9Sxc151355 	case DLADM_STATUS_DENIED:
1040ba2cbe9Sxc151355 		s = "permission denied";
1050ba2cbe9Sxc151355 		break;
1060ba2cbe9Sxc151355 	case DLADM_STATUS_IOERR:
1070ba2cbe9Sxc151355 		s = "I/O error";
1080ba2cbe9Sxc151355 		break;
109f4b3ec61Sdh155122 	case DLADM_STATUS_TEMPONLY:
110f4b3ec61Sdh155122 		s = "change cannot be persistent, specify -t please";
111f4b3ec61Sdh155122 		break;
112*f595a68aSyz147064 	case DLADM_STATUS_TIMEDOUT:
113*f595a68aSyz147064 		s = "operation timed out";
114*f595a68aSyz147064 		break;
115*f595a68aSyz147064 	case DLADM_STATUS_ISCONN:
116*f595a68aSyz147064 		s = "already connected";
117*f595a68aSyz147064 		break;
118*f595a68aSyz147064 	case DLADM_STATUS_NOTCONN:
119*f595a68aSyz147064 		s = "not connected";
120*f595a68aSyz147064 		break;
121*f595a68aSyz147064 	case DLADM_STATUS_REPOSITORYINVAL:
122*f595a68aSyz147064 		s = "invalid configuration repository";
123*f595a68aSyz147064 		break;
124*f595a68aSyz147064 	case DLADM_STATUS_MACADDRINVAL:
125*f595a68aSyz147064 		s = "invalid MAC address";
126*f595a68aSyz147064 		break;
127*f595a68aSyz147064 	case DLADM_STATUS_KEYINVAL:
128*f595a68aSyz147064 		s = "invalid key";
129*f595a68aSyz147064 		break;
1300ba2cbe9Sxc151355 	default:
13133343a97Smeem 		s = "<unknown error>";
13233343a97Smeem 		break;
1330ba2cbe9Sxc151355 	}
13433343a97Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
1350ba2cbe9Sxc151355 	return (buf);
1360ba2cbe9Sxc151355 }
1370ba2cbe9Sxc151355 
1380ba2cbe9Sxc151355 /*
1390ba2cbe9Sxc151355  * Convert a unix errno to a dladm_status_t.
1400ba2cbe9Sxc151355  * We only convert errnos that are likely to be encountered. All others
1410ba2cbe9Sxc151355  * are mapped to DLADM_STATUS_FAILED.
1420ba2cbe9Sxc151355  */
1430ba2cbe9Sxc151355 dladm_status_t
1440ba2cbe9Sxc151355 dladm_errno2status(int err)
1450ba2cbe9Sxc151355 {
1460ba2cbe9Sxc151355 	switch (err) {
1470ba2cbe9Sxc151355 	case EINVAL:
1480ba2cbe9Sxc151355 		return (DLADM_STATUS_BADARG);
1490ba2cbe9Sxc151355 	case EEXIST:
1500ba2cbe9Sxc151355 		return (DLADM_STATUS_EXIST);
1510ba2cbe9Sxc151355 	case ENOENT:
1520ba2cbe9Sxc151355 		return (DLADM_STATUS_NOTFOUND);
1530ba2cbe9Sxc151355 	case ENOSPC:
1540ba2cbe9Sxc151355 		return (DLADM_STATUS_TOOSMALL);
1550ba2cbe9Sxc151355 	case ENOMEM:
1560ba2cbe9Sxc151355 		return (DLADM_STATUS_NOMEM);
1570ba2cbe9Sxc151355 	case ENOTSUP:
1580ba2cbe9Sxc151355 		return (DLADM_STATUS_NOTSUP);
1590ba2cbe9Sxc151355 	case EACCES:
1600ba2cbe9Sxc151355 		return (DLADM_STATUS_DENIED);
1610ba2cbe9Sxc151355 	case EIO:
1620ba2cbe9Sxc151355 		return (DLADM_STATUS_IOERR);
1630ba2cbe9Sxc151355 	default:
1640ba2cbe9Sxc151355 		return (DLADM_STATUS_FAILED);
1650ba2cbe9Sxc151355 	}
1660ba2cbe9Sxc151355 }
1670ba2cbe9Sxc151355 
1680ba2cbe9Sxc151355 /*
1690ba2cbe9Sxc151355  * These are the uid and gid of the user 'dladm'.
1700ba2cbe9Sxc151355  * The directory /etc/dladm and all files under it are owned by this user.
1710ba2cbe9Sxc151355  */
1720ba2cbe9Sxc151355 #define	DLADM_DB_OWNER		15
1730ba2cbe9Sxc151355 #define	DLADM_DB_GROUP		3
1740ba2cbe9Sxc151355 #define	LOCK_DB_PERMS		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
1750ba2cbe9Sxc151355 
1760ba2cbe9Sxc151355 static int
1770ba2cbe9Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
1780ba2cbe9Sxc151355 {
1790ba2cbe9Sxc151355 	int	lock_fd;
1800ba2cbe9Sxc151355 	struct  flock lock;
1810ba2cbe9Sxc151355 
1820ba2cbe9Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
1830ba2cbe9Sxc151355 	    LOCK_DB_PERMS)) < 0)
1840ba2cbe9Sxc151355 		return (-1);
1850ba2cbe9Sxc151355 
1860ba2cbe9Sxc151355 	lock.l_type = type;
1870ba2cbe9Sxc151355 	lock.l_whence = SEEK_SET;
1880ba2cbe9Sxc151355 	lock.l_start = 0;
1890ba2cbe9Sxc151355 	lock.l_len = 0;
1900ba2cbe9Sxc151355 
1910ba2cbe9Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
1920ba2cbe9Sxc151355 		int err = errno;
1930ba2cbe9Sxc151355 
1940ba2cbe9Sxc151355 		(void) close(lock_fd);
1950ba2cbe9Sxc151355 		(void) unlink(lock_file);
1960ba2cbe9Sxc151355 		errno = err;
1970ba2cbe9Sxc151355 		return (-1);
1980ba2cbe9Sxc151355 	}
1990ba2cbe9Sxc151355 	return (lock_fd);
2000ba2cbe9Sxc151355 }
2010ba2cbe9Sxc151355 
2020ba2cbe9Sxc151355 static void
2030ba2cbe9Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
2040ba2cbe9Sxc151355 {
2050ba2cbe9Sxc151355 	struct flock lock;
2060ba2cbe9Sxc151355 
2070ba2cbe9Sxc151355 	if (fd < 0)
2080ba2cbe9Sxc151355 		return;
2090ba2cbe9Sxc151355 
2100ba2cbe9Sxc151355 	lock.l_type = F_UNLCK;
2110ba2cbe9Sxc151355 	lock.l_whence = SEEK_SET;
2120ba2cbe9Sxc151355 	lock.l_start = 0;
2130ba2cbe9Sxc151355 	lock.l_len = 0;
2140ba2cbe9Sxc151355 
2150ba2cbe9Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
2160ba2cbe9Sxc151355 	(void) close(fd);
2170ba2cbe9Sxc151355 	(void) unlink(lock_file);
2180ba2cbe9Sxc151355 }
2190ba2cbe9Sxc151355 
2200ba2cbe9Sxc151355 dladm_status_t
2210ba2cbe9Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms,
2220ba2cbe9Sxc151355     dladm_status_t (*process_db)(void *, FILE *, FILE *),
2230ba2cbe9Sxc151355     void *arg, boolean_t writeop)
2240ba2cbe9Sxc151355 {
2250ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
2260ba2cbe9Sxc151355 	FILE		*fp, *nfp = NULL;
2270ba2cbe9Sxc151355 	char		lock[MAXPATHLEN];
2280ba2cbe9Sxc151355 	char		file[MAXPATHLEN];
2290ba2cbe9Sxc151355 	char		newfile[MAXPATHLEN];
2300ba2cbe9Sxc151355 	char		*db_basename;
2310ba2cbe9Sxc151355 	int		nfd, lock_fd;
2320ba2cbe9Sxc151355 
2330ba2cbe9Sxc151355 	/*
2340ba2cbe9Sxc151355 	 * If we are called from a boot script such as net-physical,
2350ba2cbe9Sxc151355 	 * it's quite likely that the root fs is still not writable.
2360ba2cbe9Sxc151355 	 * For this case, it's ok for the lock creation to fail since
2370ba2cbe9Sxc151355 	 * no one else could be accessing our configuration file.
2380ba2cbe9Sxc151355 	 */
2390ba2cbe9Sxc151355 	db_basename = strrchr(db_file, '/');
2400ba2cbe9Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
2410ba2cbe9Sxc151355 		return (dladm_errno2status(EINVAL));
2420ba2cbe9Sxc151355 	db_basename++;
2430ba2cbe9Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
2440ba2cbe9Sxc151355 	if ((lock_fd = i_dladm_lock_db
2450ba2cbe9Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
2460ba2cbe9Sxc151355 		return (dladm_errno2status(errno));
2470ba2cbe9Sxc151355 
2480ba2cbe9Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
2490ba2cbe9Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
2500ba2cbe9Sxc151355 		int	err = errno;
2510ba2cbe9Sxc151355 
2520ba2cbe9Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
2530ba2cbe9Sxc151355 		if (err == ENOENT)
2540ba2cbe9Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
2550ba2cbe9Sxc151355 
2560ba2cbe9Sxc151355 		return (dladm_errno2status(err));
2570ba2cbe9Sxc151355 	}
2580ba2cbe9Sxc151355 
2590ba2cbe9Sxc151355 	if (writeop) {
2600ba2cbe9Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
2610ba2cbe9Sxc151355 		    dladm_rootdir, db_file);
2620ba2cbe9Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
2630ba2cbe9Sxc151355 		    db_perms)) < 0) {
2640ba2cbe9Sxc151355 			(void) fclose(fp);
2650ba2cbe9Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
2660ba2cbe9Sxc151355 			return (dladm_errno2status(errno));
2670ba2cbe9Sxc151355 		}
2680ba2cbe9Sxc151355 
2690ba2cbe9Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
2700ba2cbe9Sxc151355 			(void) close(nfd);
2710ba2cbe9Sxc151355 			(void) fclose(fp);
2720ba2cbe9Sxc151355 			(void) unlink(newfile);
2730ba2cbe9Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
2740ba2cbe9Sxc151355 			return (dladm_errno2status(errno));
2750ba2cbe9Sxc151355 		}
2760ba2cbe9Sxc151355 	}
2770ba2cbe9Sxc151355 	status = (*process_db)(arg, fp, nfp);
2780ba2cbe9Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
2790ba2cbe9Sxc151355 		goto done;
2800ba2cbe9Sxc151355 
2810ba2cbe9Sxc151355 	/*
2820ba2cbe9Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
2830ba2cbe9Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
2840ba2cbe9Sxc151355 	 */
2850ba2cbe9Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
2860ba2cbe9Sxc151355 		if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) {
2870ba2cbe9Sxc151355 			status = dladm_errno2status(errno);
2880ba2cbe9Sxc151355 			goto done;
2890ba2cbe9Sxc151355 		}
2900ba2cbe9Sxc151355 	}
2910ba2cbe9Sxc151355 
2920ba2cbe9Sxc151355 	if (fflush(nfp) == EOF) {
2930ba2cbe9Sxc151355 		status = dladm_errno2status(errno);
2940ba2cbe9Sxc151355 		goto done;
2950ba2cbe9Sxc151355 	}
2960ba2cbe9Sxc151355 	(void) fclose(fp);
2970ba2cbe9Sxc151355 	(void) fclose(nfp);
2980ba2cbe9Sxc151355 
2990ba2cbe9Sxc151355 	if (rename(newfile, file) < 0) {
3000ba2cbe9Sxc151355 		(void) unlink(newfile);
3010ba2cbe9Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
3020ba2cbe9Sxc151355 		return (dladm_errno2status(errno));
3030ba2cbe9Sxc151355 	}
3040ba2cbe9Sxc151355 
3050ba2cbe9Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
3060ba2cbe9Sxc151355 	return (DLADM_STATUS_OK);
3070ba2cbe9Sxc151355 
3080ba2cbe9Sxc151355 done:
3090ba2cbe9Sxc151355 	if (nfp != NULL) {
3100ba2cbe9Sxc151355 		(void) fclose(nfp);
3110ba2cbe9Sxc151355 		if (status != DLADM_STATUS_OK)
3120ba2cbe9Sxc151355 			(void) unlink(newfile);
3130ba2cbe9Sxc151355 	}
3140ba2cbe9Sxc151355 	(void) fclose(fp);
3150ba2cbe9Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
3160ba2cbe9Sxc151355 	return (status);
3170ba2cbe9Sxc151355 }
3180ba2cbe9Sxc151355 
3190ba2cbe9Sxc151355 dladm_status_t
3200ba2cbe9Sxc151355 dladm_set_rootdir(const char *rootdir)
3210ba2cbe9Sxc151355 {
3220ba2cbe9Sxc151355 	DIR	*dp;
3230ba2cbe9Sxc151355 
3240ba2cbe9Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
3250ba2cbe9Sxc151355 	    (dp = opendir(rootdir)) == NULL)
3260ba2cbe9Sxc151355 		return (DLADM_STATUS_BADARG);
3270ba2cbe9Sxc151355 
3280ba2cbe9Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
3290ba2cbe9Sxc151355 	(void) closedir(dp);
3300ba2cbe9Sxc151355 	return (DLADM_STATUS_OK);
3310ba2cbe9Sxc151355 }
332