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 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * The dlmgmtd daemon is started by the datalink-management SMF service.
  29  * This daemon is used to manage <link name, linkid> mapping and the
  30  * persistent datalink configuration.
  31  *
  32  * Today, the <link name, linkid> mapping and the persistent configuration
  33  * of datalinks is kept in /etc/dladm/datalink.conf, and the daemon keeps
  34  * a copy of the datalinks in the memory (see dlmgmt_id_avl and
  35  * dlmgmt_name_avl). The active <link name, linkid> mapping is kept in
  36  * /etc/svc/volatile/dladm cache file, so that the mapping can be recovered
  37  * when dlmgmtd exits for some reason (e.g., when dlmgmtd is accidentally
  38  * killed).
  39  */
  40 
  41 #include <assert.h>
  42 #include <errno.h>
  43 #include <fcntl.h>
  44 #include <priv.h>
 
 
 108                     strerror(err));
 109                 return (err);
 110         }
 111         return (err);
 112 }
 113 
 114 static void
 115 dlmgmt_door_fini(void)
 116 {
 117         if (dlmgmt_door_fd == -1)
 118                 return;
 119 
 120         if (door_revoke(dlmgmt_door_fd) == -1) {
 121                 dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
 122                     DLMGMT_DOOR, strerror(errno));
 123         }
 124         (void) dlmgmt_set_doorfd(B_FALSE);
 125         dlmgmt_door_fd = -1;
 126 }
 127 
 128 int
 129 dlmgmt_door_attach(zoneid_t zoneid, char *rootdir)
 130 {
 131         int     fd;
 132         int     err = 0;
 133         char    doorpath[MAXPATHLEN];
 134 
 135         (void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir,
 136             DLMGMT_DOOR);
 137 
 138         /*
 139          * Create the door file for dlmgmtd.
 140          */
 141         if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) {
 142                 err = errno;
 143                 dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath,
 144                     strerror(err));
 145                 return (err);
 146         }
 147         (void) close(fd);
 148         if (chown(doorpath, UID_DLADM, GID_NETADM) == -1)
 149                 return (errno);
 150 
 151         /*
 152          * fdetach first in case a previous daemon instance exited
 153          * ungracefully.
 154          */
 155         (void) fdetach(doorpath);
 156         if (fattach(dlmgmt_door_fd, doorpath) != 0) {
 
 175 int
 176 dlmgmt_zone_init(zoneid_t zoneid)
 177 {
 178         char    rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN];
 179         int     err;
 180         struct stat statbuf;
 181 
 182         if (zoneid == GLOBAL_ZONEID) {
 183                 rootdir[0] = '\0';
 184         } else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir,
 185             sizeof (rootdir)) < 0) {
 186                 return (errno);
 187         }
 188 
 189         /*
 190          * Create the DLMGMT_TMPFS_DIR directory.
 191          */
 192         (void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir,
 193             DLMGMT_TMPFS_DIR);
 194         if (stat(tmpfsdir, &statbuf) < 0) {
 195                 if (mkdir(tmpfsdir, (mode_t)0755) < 0)
 196                         return (errno);
 197         } else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
 198                 return (ENOTDIR);
 199         }
 200 
 201         if ((chmod(tmpfsdir, 0755) < 0) ||
 202             (chown(tmpfsdir, UID_DLADM, GID_NETADM) < 0)) {
 203                 return (EPERM);
 204         }
 205 
 206         if ((err = dlmgmt_db_init(zoneid)) != 0)
 207                 return (err);
 208         return (dlmgmt_door_attach(zoneid, rootdir));
 209 }
 210 
 211 /*
 212  * Initialize each running zone.
 213  */
 214 static int
 215 dlmgmt_allzones_init(void)
 216 {
 217         int             err, i;
 218         zoneid_t        *zids = NULL;
 219         uint_t          nzids, nzids_saved;
 220 
 221         if (zone_list(NULL, &nzids) != 0)
 222                 return (errno);
 223 again:
 224         nzids *= 2;
 225         if ((zids = malloc(nzids * sizeof (zoneid_t))) == NULL)
 226                 return (errno);
 227         nzids_saved = nzids;
 228         if (zone_list(zids, &nzids) != 0) {
 229                 free(zids);
 230                 return (errno);
 231         }
 232         if (nzids > nzids_saved) {
 233                 free(zids);
 234                 goto again;
 235         }
 236 
 237         for (i = 0; i < nzids; i++) {
 238                 if ((err = dlmgmt_zone_init(zids[i])) != 0)
 239                         break;
 240         }
 241         free(zids);
 242         return (err);
 243 }
 244 
 245 static int
 246 dlmgmt_init(void)
 247 {
 248         int     err;
 249         char    *fmri, *c;
 250         char    filename[MAXPATHLEN];
 251 
 252         if (dladm_open(&dld_handle) != DLADM_STATUS_OK) {
 253                 dlmgmt_log(LOG_ERR, "dladm_open() failed");
 254                 return (EPERM);
 255         }
 256 
 257         if (signal(SIGTERM, dlmgmtd_exit) == SIG_ERR ||
 258             signal(SIGINT, dlmgmtd_exit) == SIG_ERR) {
 259                 err = errno;
 260                 dlmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
 261                     strerror(err));
 262                 return (err);
 263         }
 264 
 265         /*
 266          * First derive the name of the cache file from the FMRI name. This
 267          * cache name is used to keep active datalink configuration.
 268          */
 269         if (debug) {
 270                 (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
 271                     DLMGMT_TMPFS_DIR, progname, ".debug.cache");
 272         } else {
 273                 if ((fmri = getenv("SMF_FMRI")) == NULL) {
 274                         dlmgmt_log(LOG_ERR, "dlmgmtd is an smf(5) managed "
 275                             "service and should not be run from the command "
 276                             "line.");
 277                         return (EINVAL);
 278                 }
 279 
 280                 /*
 281                  * The FMRI name is in the form of
 282                  * svc:/service/service:instance.  We need to remove the
 283                  * prefix "svc:/" and replace '/' with '-'.  The cache file
 284                  * name is in the form of "service:instance.cache".
 
 | 
 
 
   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 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright 2014 Joyent, Inc.  All rights reserved.
  26  */
  27 
  28 /*
  29  * The dlmgmtd daemon is started by the datalink-management SMF service.
  30  * This daemon is used to manage <link name, linkid> mapping and the
  31  * persistent datalink configuration.
  32  *
  33  * Today, the <link name, linkid> mapping and the persistent configuration
  34  * of datalinks is kept in /etc/dladm/datalink.conf, and the daemon keeps
  35  * a copy of the datalinks in the memory (see dlmgmt_id_avl and
  36  * dlmgmt_name_avl). The active <link name, linkid> mapping is kept in
  37  * /etc/svc/volatile/dladm cache file, so that the mapping can be recovered
  38  * when dlmgmtd exits for some reason (e.g., when dlmgmtd is accidentally
  39  * killed).
  40  */
  41 
  42 #include <assert.h>
  43 #include <errno.h>
  44 #include <fcntl.h>
  45 #include <priv.h>
 
 
 109                     strerror(err));
 110                 return (err);
 111         }
 112         return (err);
 113 }
 114 
 115 static void
 116 dlmgmt_door_fini(void)
 117 {
 118         if (dlmgmt_door_fd == -1)
 119                 return;
 120 
 121         if (door_revoke(dlmgmt_door_fd) == -1) {
 122                 dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
 123                     DLMGMT_DOOR, strerror(errno));
 124         }
 125         (void) dlmgmt_set_doorfd(B_FALSE);
 126         dlmgmt_door_fd = -1;
 127 }
 128 
 129 static int
 130 dlmgmt_door_attach(zoneid_t zoneid, char *rootdir)
 131 {
 132         int     fd;
 133         int     err = 0;
 134         char    doorpath[MAXPATHLEN];
 135         struct stat statbuf;
 136 
 137         /* Handle running in a non-native branded zone (i.e. has /native) */
 138         (void) snprintf(doorpath, sizeof (doorpath), "%s/native%s",
 139             rootdir, DLMGMT_TMPFS_DIR);
 140         if (stat(doorpath, &statbuf) == 0) {
 141                 (void) snprintf(doorpath, sizeof (doorpath), "%s/native%s",
 142                     rootdir, DLMGMT_DOOR);
 143         } else {
 144                 (void) snprintf(doorpath, sizeof (doorpath), "%s%s",
 145                     rootdir, DLMGMT_DOOR);
 146         }
 147 
 148         /*
 149          * Create the door file for dlmgmtd.
 150          */
 151         if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) {
 152                 err = errno;
 153                 dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath,
 154                     strerror(err));
 155                 return (err);
 156         }
 157         (void) close(fd);
 158         if (chown(doorpath, UID_DLADM, GID_NETADM) == -1)
 159                 return (errno);
 160 
 161         /*
 162          * fdetach first in case a previous daemon instance exited
 163          * ungracefully.
 164          */
 165         (void) fdetach(doorpath);
 166         if (fattach(dlmgmt_door_fd, doorpath) != 0) {
 
 185 int
 186 dlmgmt_zone_init(zoneid_t zoneid)
 187 {
 188         char    rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN];
 189         int     err;
 190         struct stat statbuf;
 191 
 192         if (zoneid == GLOBAL_ZONEID) {
 193                 rootdir[0] = '\0';
 194         } else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir,
 195             sizeof (rootdir)) < 0) {
 196                 return (errno);
 197         }
 198 
 199         /*
 200          * Create the DLMGMT_TMPFS_DIR directory.
 201          */
 202         (void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir,
 203             DLMGMT_TMPFS_DIR);
 204         if (stat(tmpfsdir, &statbuf) < 0) {
 205                 if (mkdir(tmpfsdir, (mode_t)0755) < 0) {
 206                         /*
 207                          * Handle running in a non-native branded zone
 208                          * (i.e. has /native)
 209                          */
 210                         (void) snprintf(tmpfsdir, sizeof (tmpfsdir),
 211                             "%s/native%s", rootdir, DLMGMT_TMPFS_DIR);
 212                         if (mkdir(tmpfsdir, (mode_t)0755) < 0)
 213                                 return (errno);
 214                 }
 215         } else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
 216                 return (ENOTDIR);
 217         }
 218 
 219         if ((chmod(tmpfsdir, 0755) < 0) ||
 220             (chown(tmpfsdir, UID_DLADM, GID_NETADM) < 0)) {
 221                 return (EPERM);
 222         }
 223 
 224         if ((err = dlmgmt_db_init(zoneid, rootdir)) != 0)
 225                 return (err);
 226         return (dlmgmt_door_attach(zoneid, rootdir));
 227 }
 228 
 229 /*
 230  * Initialize each running zone.
 231  */
 232 static int
 233 dlmgmt_allzones_init(void)
 234 {
 235         int             i;
 236         zoneid_t        *zids = NULL;
 237         uint_t          nzids, nzids_saved;
 238 
 239         if (zone_list(NULL, &nzids) != 0)
 240                 return (errno);
 241 again:
 242         nzids *= 2;
 243         if ((zids = malloc(nzids * sizeof (zoneid_t))) == NULL)
 244                 return (errno);
 245         nzids_saved = nzids;
 246         if (zone_list(zids, &nzids) != 0) {
 247                 free(zids);
 248                 return (errno);
 249         }
 250         if (nzids > nzids_saved) {
 251                 free(zids);
 252                 goto again;
 253         }
 254 
 255         for (i = 0; i < nzids; i++) {
 256                 int res;
 257                 zone_status_t status;
 258 
 259                 /*
 260                  * Skip over zones that have gone away or are going down
 261                  * since we got the list.  Process all zones in the list,
 262                  * logging errors for any that failed.
 263                  */
 264                 if (zone_getattr(zids[i], ZONE_ATTR_STATUS, &status,
 265                     sizeof (status)) < 0)
 266                         continue;
 267                 switch (status) {
 268                         case ZONE_IS_SHUTTING_DOWN:
 269                         case ZONE_IS_EMPTY:
 270                         case ZONE_IS_DOWN:
 271                         case ZONE_IS_DYING:
 272                         case ZONE_IS_DEAD:
 273                                 /* FALLTHRU */
 274                                 continue;
 275                         default:
 276                                 break;
 277                 }
 278                 if ((res = dlmgmt_zone_init(zids[i])) != 0) {
 279                         (void) fprintf(stderr, "zone (%ld) init error %s",
 280                             zids[i], strerror(res));
 281                         dlmgmt_log(LOG_ERR, "zone (%d) init error %s",
 282                             zids[i], strerror(res));
 283                 }
 284         }
 285         free(zids);
 286         return (0);
 287 }
 288 
 289 static int
 290 dlmgmt_init(void)
 291 {
 292         int     err;
 293         char    *fmri, *c;
 294         char    filename[MAXPATHLEN];
 295 
 296         if (dladm_open(&dld_handle) != DLADM_STATUS_OK) {
 297                 dlmgmt_log(LOG_ERR, "dladm_open() failed");
 298                 return (EPERM);
 299         }
 300 
 301         if (signal(SIGTERM, dlmgmtd_exit) == SIG_ERR ||
 302             signal(SIGINT, dlmgmtd_exit) == SIG_ERR) {
 303                 err = errno;
 304                 dlmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
 305                     strerror(err));
 306                 return (err);
 307         }
 308 
 309         (void) unlink(ZONE_LOCK);
 310 
 311         /*
 312          * First derive the name of the cache file from the FMRI name. This
 313          * cache name is used to keep active datalink configuration.
 314          */
 315         if (debug) {
 316                 (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
 317                     DLMGMT_TMPFS_DIR, progname, ".debug.cache");
 318         } else {
 319                 if ((fmri = getenv("SMF_FMRI")) == NULL) {
 320                         dlmgmt_log(LOG_ERR, "dlmgmtd is an smf(5) managed "
 321                             "service and should not be run from the command "
 322                             "line.");
 323                         return (EINVAL);
 324                 }
 325 
 326                 /*
 327                  * The FMRI name is in the form of
 328                  * svc:/service/service:instance.  We need to remove the
 329                  * prefix "svc:/" and replace '/' with '-'.  The cache file
 330                  * name is in the form of "service:instance.cache".
 
 |