Blame misc/mntent_r.c

Packit 6c4009
/* Utilities for reading/writing fstab, mtab, etc.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <mntent.h>
Packit Service 2ef5af
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdio_ext.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
Packit 6c4009
#define flockfile(s) _IO_flockfile (s)
Packit 6c4009
#define funlockfile(s) _IO_funlockfile (s)
Packit 6c4009
Packit 6c4009
#undef __setmntent
Packit 6c4009
#undef __endmntent
Packit 6c4009
#undef __getmntent_r
Packit 6c4009
Packit 6c4009
/* Prepare to begin reading and/or writing mount table entries from the
Packit 6c4009
   beginning of FILE.  MODE is as for `fopen'.  */
Packit 6c4009
FILE *
Packit 6c4009
__setmntent (const char *file, const char *mode)
Packit 6c4009
{
Packit 6c4009
  /* Extend the mode parameter with "c" to disable cancellation in the
Packit 6c4009
     I/O functions and "e" to set FD_CLOEXEC.  */
Packit 6c4009
  size_t modelen = strlen (mode);
Packit 6c4009
  char newmode[modelen + 3];
Packit 6c4009
  memcpy (mempcpy (newmode, mode, modelen), "ce", 3);
Packit 6c4009
  FILE *result = fopen (file, newmode);
Packit 6c4009
Packit 6c4009
  if (result != NULL)
Packit 6c4009
    /* We do the locking ourselves.  */
Packit 6c4009
    __fsetlocking (result, FSETLOCKING_BYCALLER);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__setmntent)
Packit 6c4009
weak_alias (__setmntent, setmntent)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Close a stream opened with `setmntent'.  */
Packit 6c4009
int
Packit 6c4009
__endmntent (FILE *stream)
Packit 6c4009
{
Packit 6c4009
  if (stream)		/* SunOS 4.x allows for NULL stream */
Packit 6c4009
    fclose (stream);
Packit 6c4009
  return 1;		/* SunOS 4.x says to always return 1 */
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__endmntent)
Packit 6c4009
weak_alias (__endmntent, endmntent)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Since the values in a line are separated by spaces, a name cannot
Packit 6c4009
   contain a space.  Therefore some programs encode spaces in names
Packit 6c4009
   by the strings "\040".  We undo the encoding when reading an entry.
Packit 6c4009
   The decoding happens in place.  */
Packit 6c4009
static char *
Packit 6c4009
decode_name (char *buf)
Packit 6c4009
{
Packit 6c4009
  char *rp = buf;
Packit 6c4009
  char *wp = buf;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' && rp[3] == '0')
Packit 6c4009
      {
Packit 6c4009
	/* \040 is a SPACE.  */
Packit 6c4009
	*wp++ = ' ';
Packit 6c4009
	rp += 3;
Packit 6c4009
      }
Packit 6c4009
    else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '1')
Packit 6c4009
      {
Packit 6c4009
	/* \011 is a TAB.  */
Packit 6c4009
	*wp++ = '\t';
Packit 6c4009
	rp += 3;
Packit 6c4009
      }
Packit 6c4009
    else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '2')
Packit 6c4009
      {
Packit 6c4009
	/* \012 is a NEWLINE.  */
Packit 6c4009
	*wp++ = '\n';
Packit 6c4009
	rp += 3;
Packit 6c4009
      }
Packit 6c4009
    else if (rp[0] == '\\' && rp[1] == '\\')
Packit 6c4009
      {
Packit 6c4009
	/* We have to escape \\ to be able to represent all characters.  */
Packit 6c4009
	*wp++ = '\\';
Packit 6c4009
	rp += 1;
Packit 6c4009
      }
Packit 6c4009
    else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' && rp[3] == '4')
Packit 6c4009
      {
Packit 6c4009
	/* \134 is also \\.  */
Packit 6c4009
	*wp++ = '\\';
Packit 6c4009
	rp += 3;
Packit 6c4009
      }
Packit 6c4009
    else
Packit 6c4009
      *wp++ = *rp;
Packit 6c4009
  while (*rp++ != '\0');
Packit 6c4009
Packit 6c4009
  return buf;
Packit 6c4009
}
Packit 6c4009
Packit Service 2ef5af
static bool
Packit Service 2ef5af
get_mnt_entry (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
Packit 6c4009
{
Packit 6c4009
  char *cp;
Packit 6c4009
  char *head;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      char *end_ptr;
Packit 6c4009
Packit 6c4009
      if (__fgets_unlocked (buffer, bufsiz, stream) == NULL)
Packit Service 2ef5af
	  return false;
Packit 6c4009
Packit 6c4009
      end_ptr = strchr (buffer, '\n');
Packit 6c4009
      if (end_ptr != NULL)	/* chop newline */
Packit 6c4009
	{
Packit 6c4009
	  /* Do not walk past the start of buffer if it's all whitespace.  */
Packit 6c4009
	  while (end_ptr != buffer
Packit 6c4009
		 && (end_ptr[-1] == ' ' || end_ptr[-1] == '\t'))
Packit 6c4009
            end_ptr--;
Packit 6c4009
	  *end_ptr = '\0';
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* Not the whole line was read.  Do it now but forget it.  */
Packit 6c4009
	  char tmp[1024];
Packit 6c4009
	  while (__fgets_unlocked (tmp, sizeof tmp, stream) != NULL)
Packit 6c4009
	    if (strchr (tmp, '\n') != NULL)
Packit 6c4009
	      break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      head = buffer + strspn (buffer, " \t");
Packit 6c4009
      /* skip empty lines and comment lines:  */
Packit 6c4009
    }
Packit 6c4009
  while (head[0] == '\0' || head[0] == '#');
Packit 6c4009
Packit 6c4009
  cp = __strsep (&head, " \t");
Packit 6c4009
  mp->mnt_fsname = cp != NULL ? decode_name (cp) : (char *) "";
Packit 6c4009
  if (head)
Packit 6c4009
    head += strspn (head, " \t");
Packit 6c4009
  cp = __strsep (&head, " \t");
Packit 6c4009
  mp->mnt_dir = cp != NULL ? decode_name (cp) : (char *) "";
Packit 6c4009
  if (head)
Packit 6c4009
    head += strspn (head, " \t");
Packit 6c4009
  cp = __strsep (&head, " \t");
Packit 6c4009
  mp->mnt_type = cp != NULL ? decode_name (cp) : (char *) "";
Packit 6c4009
  if (head)
Packit 6c4009
    head += strspn (head, " \t");
Packit 6c4009
  cp = __strsep (&head, " \t");
Packit 6c4009
  mp->mnt_opts = cp != NULL ? decode_name (cp) : (char *) "";
Packit 6c4009
  switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
Packit 6c4009
    {
Packit 6c4009
    case 0:
Packit 6c4009
      mp->mnt_freq = 0;
Packit 6c4009
    case 1:
Packit 6c4009
      mp->mnt_passno = 0;
Packit 6c4009
    case 2:
Packit 6c4009
      break;
Packit 6c4009
    }
Packit Service 2ef5af
Packit Service 2ef5af
  return true;
Packit Service 2ef5af
}
Packit Service 2ef5af
Packit Service 2ef5af
/* Read one mount table entry from STREAM.  Returns a pointer to storage
Packit Service 2ef5af
   reused on the next call, or null for EOF or error (use feof/ferror to
Packit Service 2ef5af
   check).  */
Packit Service 2ef5af
struct mntent *
Packit Service 2ef5af
__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
Packit Service 2ef5af
{
Packit Service 2ef5af
  struct mntent *result;
Packit Service 2ef5af
Packit Service 2ef5af
  flockfile (stream);
Packit Service 2ef5af
  while (true)
Packit Service 2ef5af
    if (get_mnt_entry (stream, mp, buffer, bufsiz))
Packit Service 2ef5af
      {
Packit Service 2ef5af
	/* If the file system is autofs look for a mount option hint
Packit Service 2ef5af
	   ("ignore") to skip the entry.  */
Packit Service 2ef5af
	if (strcmp (mp->mnt_type, "autofs") == 0 && __hasmntopt (mp, "ignore"))
Packit Service 2ef5af
	  memset (mp, 0, sizeof (*mp));
Packit Service 2ef5af
	else
Packit Service 2ef5af
	  {
Packit Service 2ef5af
	    result = mp;
Packit Service 2ef5af
	    break;
Packit Service 2ef5af
	  }
Packit Service 2ef5af
      }
Packit Service 2ef5af
    else
Packit Service 2ef5af
      {
Packit Service 2ef5af
	result = NULL;
Packit Service 2ef5af
	break;
Packit Service 2ef5af
      }
Packit 6c4009
  funlockfile (stream);
Packit 6c4009
Packit Service 2ef5af
  return result;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__getmntent_r)
Packit 6c4009
weak_alias (__getmntent_r, getmntent_r)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We have to use an encoding for names if they contain spaces or tabs.
Packit 6c4009
   To be able to represent all characters we also have to escape the
Packit 6c4009
   backslash itself.  This "function" must be a macro since we use
Packit 6c4009
   `alloca'.  */
Packit 6c4009
#define encode_name(name) \
Packit 6c4009
  do {									      \
Packit 6c4009
    const char *rp = name;						      \
Packit 6c4009
									      \
Packit 6c4009
    while (*rp != '\0')							      \
Packit 6c4009
      if (*rp == ' ' || *rp == '\t' || *rp == '\n' || *rp == '\\')	      \
Packit 6c4009
	break;								      \
Packit 6c4009
      else								      \
Packit 6c4009
	++rp;								      \
Packit 6c4009
									      \
Packit 6c4009
    if (*rp != '\0')							      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* In the worst case the length of the string can increase to	      \
Packit 6c4009
	   four times the current length.  */				      \
Packit 6c4009
	char *wp;							      \
Packit 6c4009
									      \
Packit 6c4009
	rp = name;							      \
Packit 6c4009
	name = wp = (char *) alloca (strlen (name) * 4 + 1);		      \
Packit 6c4009
									      \
Packit 6c4009
	do								      \
Packit 6c4009
	  if (*rp == ' ')						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      *wp++ = '\\';						      \
Packit 6c4009
	      *wp++ = '0';						      \
Packit 6c4009
	      *wp++ = '4';						      \
Packit 6c4009
	      *wp++ = '0';						      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (*rp == '\t')						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      *wp++ = '\\';						      \
Packit 6c4009
	      *wp++ = '0';						      \
Packit 6c4009
	      *wp++ = '1';						      \
Packit 6c4009
	      *wp++ = '1';						      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (*rp == '\n')						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      *wp++ = '\\';						      \
Packit 6c4009
	      *wp++ = '0';						      \
Packit 6c4009
	      *wp++ = '1';						      \
Packit 6c4009
	      *wp++ = '2';						      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (*rp == '\\')						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      *wp++ = '\\';						      \
Packit 6c4009
	      *wp++ = '\\';						      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else								      \
Packit 6c4009
	    *wp++ = *rp;						      \
Packit 6c4009
	while (*rp++ != '\0');						      \
Packit 6c4009
      }									      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Write the mount table entry described by MNT to STREAM.
Packit 6c4009
   Return zero on success, nonzero on failure.  */
Packit 6c4009
int
Packit 6c4009
__addmntent (FILE *stream, const struct mntent *mnt)
Packit 6c4009
{
Packit 6c4009
  struct mntent mntcopy = *mnt;
Packit 6c4009
  if (fseek (stream, 0, SEEK_END))
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  /* Encode spaces and tabs in the names.  */
Packit 6c4009
  encode_name (mntcopy.mnt_fsname);
Packit 6c4009
  encode_name (mntcopy.mnt_dir);
Packit 6c4009
  encode_name (mntcopy.mnt_type);
Packit 6c4009
  encode_name (mntcopy.mnt_opts);
Packit 6c4009
Packit 6c4009
  return (fprintf (stream, "%s %s %s %s %d %d\n",
Packit 6c4009
		   mntcopy.mnt_fsname,
Packit 6c4009
		   mntcopy.mnt_dir,
Packit 6c4009
		   mntcopy.mnt_type,
Packit 6c4009
		   mntcopy.mnt_opts,
Packit 6c4009
		   mntcopy.mnt_freq,
Packit 6c4009
		   mntcopy.mnt_passno) < 0
Packit 6c4009
	  || fflush (stream) != 0);
Packit 6c4009
}
Packit 6c4009
weak_alias (__addmntent, addmntent)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Search MNT->mnt_opts for an option matching OPT.
Packit 6c4009
   Returns the address of the substring, or null if none found.  */
Packit 6c4009
char *
Packit 6c4009
__hasmntopt (const struct mntent *mnt, const char *opt)
Packit 6c4009
{
Packit 6c4009
  const size_t optlen = strlen (opt);
Packit 6c4009
  char *rest = mnt->mnt_opts, *p;
Packit 6c4009
Packit 6c4009
  while ((p = strstr (rest, opt)) != NULL)
Packit 6c4009
    {
Packit 6c4009
      if ((p == rest || p[-1] == ',')
Packit 6c4009
	  && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
Packit 6c4009
	return p;
Packit 6c4009
Packit 6c4009
      rest = strchr (p, ',');
Packit 6c4009
      if (rest == NULL)
Packit 6c4009
	break;
Packit 6c4009
      ++rest;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__hasmntopt)
Packit 6c4009
weak_alias (__hasmntopt, hasmntopt)