summaryrefslogblamecommitdiffstats
path: root/c/src/exec/libnetworking/rtems/mkrootfs.c
blob: d8c6301b6a4e9b4c332d1182bdeef0faded0c09c (plain) (tree)



























































































































































































































































































































































                                                                            
/*
  ------------------------------------------------------------------------
  $Id$
  ------------------------------------------------------------------------
  
  Copyright Cybertec Pty Ltd, 2000
  All rights reserved Cybertec Pty Ltd, 2000

  COPYRIGHT (c) 1989-1998.
  On-Line Applications Research Corporation (OAR).
  Copyright assigned to U.S. Government, 1994.

  The license and distribution terms for this file may be
  found in the file LICENSE in this distribution or at
  
  http://www.OARcorp.com/rtems/license.html.

  This software with is provided ``as is'' and with NO WARRANTY.

  ------------------------------------------------------------------------

  Set of helpers when creating a root file system. The root filesystem
  in RTEMS is the In Memory Filesystem (IMFS). We could copy an exiting
  filesystem to here, how-ever a number of files can have target
  specific initialisation info which we need to write.
  
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <rtems/mkrootfs.h>

/*
 * A table a list of names and their modes.
 */

typedef struct rtems_rootfs_dir_table
{
  const char *name;
  int        mode;
} rtems_rootfs_dir_table;

/*
 * Table of directorys to make.
 */

static const rtems_rootfs_dir_table default_directories[] =
{
  { "/bin",     S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH },
  { "/etc",     S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH },
  { "/dev",     S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH },
  { "/usr/bin", S_IFDIR | S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH }
};

#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
#define MKDIR_MODE  (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)

/*
 * Build a path. Taken from the BSD `mkdir' command.
 */

int
rtems_rootfs_mkdir (const char *path_orig, mode_t omode)
{
  struct stat sb;
  mode_t      numask, oumask;
  int         first, last, retval;
  char        path[128];
  char        *p = path;

  if (strlen (path_orig) >= sizeof path)
  {
    printf ("root fs: mkdir path too long `%s'\n", path);
    return -1;
  }
    
  strcpy (path, path_orig);
  oumask = 0;
  retval = 0;
  if (p[0] == '/')    /* Skip leading '/'. */
    ++p;
  for (first = 1, last = 0; !last ; ++p)
  {
    if (p[0] == '\0')
      last = 1;
    else if (p[0] != '/')
      continue;
    *p = '\0';
    if (p[1] == '\0')
      last = 1;
    if (first)
    {
      /*
       * POSIX 1003.2:
       * For each dir operand that does not name an existing
       * directory, effects equivalent to those cased by the
       * following command shall occcur:
       *
       * mkdir -p -m $(umask -S),u+wx $(dirname dir) &&
       *    mkdir [-m mode] dir
       *
       * We change the user's umask and then restore it,
       * instead of doing chmod's.
       */
      oumask = umask(0);
      numask = oumask & ~(S_IWUSR | S_IXUSR);
      umask(numask);
      first = 0;
    }
    if (last)
      umask(oumask);
    if (stat(path, &sb))
    {
      if (errno != ENOENT)
      {
        printf ("root fs: error stat'ing path `%s', %s\n",
                path, strerror (errno));
        retval = 1;
        break;
      }
      if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
      {
        printf ("root fs: error building path `%s', %s\n",
                path, strerror (errno));
        retval = 1;
        break;
      }
    }
    else if ((sb.st_mode & S_IFMT) != S_IFDIR)
    {
      if (last)
        errno = EEXIST;
      else
        errno = ENOTDIR;
      printf ("root fs: path `%s' contains a file, %s\n",
              path, strerror (errno));
      retval = 1;
      break;
    }
    if (!last)
      *p = '/';
  }
  if (!first && !last)
    umask(oumask);
  return retval;
}

/*
 * Create enough files to support the networking stack.
 * Points to a table of strings.
 */

int
rtems_rootfs_file_append (const char *file,
                          mode_t     omode,
                          const int  line_cnt,
                          const char **lines)
{
  struct stat sb;
  int         fd;
  int         i;

  /*
   * See is a file exists. If it does not, create the
   * file and the path to the file.
   */

  fd = -1;
  
  if (stat(file, &sb))
  {
    if (errno == ENOENT)
    {
      /*
       * Get the path to the file if one exists and create the
       * path. If it exists nothing happens.
       */

      int i = strlen (file);

      while (i)
      {
        if (file[i] == '/')
        {
          char path[128];

          if (i >= sizeof path)
          {
            printf ("root fs, path too long `%s'\n", file);
            return -1;
          }

          strncpy (path, file, i);
          path[i] = '\0';
          
          if (rtems_rootfs_mkdir (path, MKDIR_MODE))
            return -1;
          break;
        }
        i--;
      }
      
      if ((fd = open (file, O_CREAT | O_APPEND | O_WRONLY, omode)) < 0)
      {
        printf ("root fs, cannot create file `%s' : %s\n",
                file, strerror (errno));
        return -1;
      }
    }
  }

  if (fd < 0)
  {
    if ((fd = open (file, O_APPEND | O_WRONLY)) < 0)
    {
      printf ("root fs, cannot open file `%s' : %s\n",
              file, strerror (errno));
      return -1;
    }
  }
  
  for (i = 0; i < line_cnt; i++)
  {
    int len = strlen (lines[i]);

    if (len)
    {
      if (write (fd, lines[i], strlen (lines[i])) < 0)
      {
        close (fd);
        printf ("root fs, cannot write to `%s' : %s\n",
                file, strerror (errno));
        return -1;
      }
    }
  }
  
  return close (fd);
}

/*
 * Write hosts record.
 */

int
rtems_rootfs_append_host_rec (unsigned long cip,
                              const char    *cname,
                              const char    *dname)
{
  char           buf[128];
  char           *bufp = buf;
  const char     *bufl[1];
  struct in_addr ip;

  ip.s_addr = cip;
  
  if (cname && strlen (cname))
  {
    snprintf (bufp, sizeof (buf), "%s\t\t%s", inet_ntoa (ip), cname);
    bufp += strlen (buf);

    if (dname && strlen (dname))
    {
      snprintf (bufp, sizeof (buf), "\t\t%s.%s", cname, dname);
      bufp += strlen (buf);
    }
    
    strcat (buf, "\n");
 
    bufl[0] = buf;
    
    if (rtems_rootfs_file_append ("/etc/hosts", MKFILE_MODE, 1, bufl) < 0)
      return -1;
  }
  else
  {
    printf ("rootfs hosts rec append, no cname supplied\n");
    return -1;
  }

  return 0;
}

/*
 * Create a root file system.
 */

int
rtems_create_root_fs ()
{
  const char *lines[1];
  int        i;
  
  /*
   * Create the directories.
   */

  for (i = 0;
       i < (sizeof (default_directories) / sizeof (rtems_rootfs_dir_table));
       i++)
    if (rtems_rootfs_mkdir (default_directories[i].name,
                            default_directories[i].mode))
      return -1;

  /*
   * /etc/passwd, /etc/group
   * Maybe needed by some tools.
   */

  lines[0] = "root::0:0:root:/root:/bin/sh\n";
  
  if (rtems_rootfs_file_append ("/etc/passwd", MKFILE_MODE, 1, lines))
    return -1;
  
  lines[0] = "root::0:root\n";
  
  if (rtems_rootfs_file_append ("/etc/group", MKFILE_MODE, 1, lines))
    return -1;

  /*
   * The TCP/IP stack likes this one. If DNS does not work
   * use the host file.
   */
  
  lines[0] = "hosts,bind\n";
  
  if (rtems_rootfs_file_append ("/etc/host.conf", MKFILE_MODE, 1, lines))
    return -1;
  
  /*
   * Create a `/etc/hosts' file.
   */

  if (rtems_rootfs_append_host_rec (0x7f000001, "localhost", "localdomain"))
    return -1;
  
  return 0;
}