Back to index

glibc  2.9
mntent_r.c
Go to the documentation of this file.
00001 /* Utilities for reading/writing fstab, mtab, etc.
00002    Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <alloca.h>
00022 #include <mntent.h>
00023 #include <stdio.h>
00024 #include <stdio_ext.h>
00025 #include <string.h>
00026 #include <sys/types.h>
00027 
00028 #ifdef USE_IN_LIBIO
00029 # define flockfile(s) _IO_flockfile (s)
00030 # define funlockfile(s) _IO_funlockfile (s)
00031 #endif
00032 
00033 #undef __setmntent
00034 #undef __endmntent
00035 #undef __getmntent_r
00036 
00037 /* Prepare to begin reading and/or writing mount table entries from the
00038    beginning of FILE.  MODE is as for `fopen'.  */
00039 FILE *
00040 __setmntent (const char *file, const char *mode)
00041 {
00042   /* Extend the mode parameter with "c" to disable cancellation in the
00043      I/O functions.  */
00044   size_t modelen = strlen (mode);
00045   char newmode[modelen + 2];
00046   memcpy (mempcpy (newmode, mode, modelen), "c", 2);
00047   FILE *result = fopen (file, newmode);
00048 
00049   if (result != NULL)
00050     /* We do the locking ourselves.  */
00051     __fsetlocking (result, FSETLOCKING_BYCALLER);
00052 
00053   return result;
00054 }
00055 INTDEF(__setmntent)
00056 weak_alias (__setmntent, setmntent)
00057 
00058 
00059 /* Close a stream opened with `setmntent'.  */
00060 int
00061 __endmntent (FILE *stream)
00062 {
00063   if (stream)        /* SunOS 4.x allows for NULL stream */
00064     fclose (stream);
00065   return 1;          /* SunOS 4.x says to always return 1 */
00066 }
00067 INTDEF(__endmntent)
00068 weak_alias (__endmntent, endmntent)
00069 
00070 
00071 /* Since the values in a line are separated by spaces, a name cannot
00072    contain a space.  Therefore some programs encode spaces in names
00073    by the strings "\040".  We undo the encoding when reading an entry.
00074    The decoding happens in place.  */
00075 static char *
00076 decode_name (char *buf)
00077 {
00078   char *rp = buf;
00079   char *wp = buf;
00080 
00081   do
00082     if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' && rp[3] == '0')
00083       {
00084        /* \040 is a SPACE.  */
00085        *wp++ = ' ';
00086        rp += 3;
00087       }
00088     else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '1')
00089       {
00090        /* \011 is a TAB.  */
00091        *wp++ = '\t';
00092        rp += 3;
00093       }
00094     else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '2')
00095       {
00096        /* \012 is a NEWLINE.  */
00097        *wp++ = '\n';
00098        rp += 3;
00099       }
00100     else if (rp[0] == '\\' && rp[1] == '\\')
00101       {
00102        /* We have to escape \\ to be able to represent all characters.  */
00103        *wp++ = '\\';
00104        rp += 1;
00105       }
00106     else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' && rp[3] == '4')
00107       {
00108        /* \134 is also \\.  */
00109        *wp++ = '\\';
00110        rp += 3;
00111       }
00112     else
00113       *wp++ = *rp;
00114   while (*rp++ != '\0');
00115 
00116   return buf;
00117 }
00118 
00119 
00120 /* Read one mount table entry from STREAM.  Returns a pointer to storage
00121    reused on the next call, or null for EOF or error (use feof/ferror to
00122    check).  */
00123 struct mntent *
00124 __getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
00125 {
00126   char *cp;
00127   char *head;
00128 
00129   flockfile (stream);
00130   do
00131     {
00132       char *end_ptr;
00133 
00134       if (fgets_unlocked (buffer, bufsiz, stream) == NULL)
00135        {
00136          funlockfile (stream);
00137          return NULL;
00138        }
00139 
00140       end_ptr = strchr (buffer, '\n');
00141       if (end_ptr != NULL)  /* chop newline */
00142        *end_ptr = '\0';
00143       else
00144        {
00145          /* Not the whole line was read.  Do it now but forget it.  */
00146          char tmp[1024];
00147          while (fgets_unlocked (tmp, sizeof tmp, stream) != NULL)
00148            if (strchr (tmp, '\n') != NULL)
00149              break;
00150        }
00151 
00152       head = buffer + strspn (buffer, " \t");
00153       /* skip empty lines and comment lines:  */
00154     }
00155   while (head[0] == '\0' || head[0] == '#');
00156 
00157   cp = __strsep (&head, " \t");
00158   mp->mnt_fsname = cp != NULL ? decode_name (cp) : (char *) "";
00159   if (head)
00160     head += strspn (head, " \t");
00161   cp = __strsep (&head, " \t");
00162   mp->mnt_dir = cp != NULL ? decode_name (cp) : (char *) "";
00163   if (head)
00164     head += strspn (head, " \t");
00165   cp = __strsep (&head, " \t");
00166   mp->mnt_type = cp != NULL ? decode_name (cp) : (char *) "";
00167   if (head)
00168     head += strspn (head, " \t");
00169   cp = __strsep (&head, " \t");
00170   mp->mnt_opts = cp != NULL ? decode_name (cp) : (char *) "";
00171   switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
00172     {
00173     case 0:
00174       mp->mnt_freq = 0;
00175     case 1:
00176       mp->mnt_passno = 0;
00177     case 2:
00178       break;
00179     }
00180   funlockfile (stream);
00181 
00182   return mp;
00183 }
00184 INTDEF(__getmntent_r)
00185 weak_alias (__getmntent_r, getmntent_r)
00186 
00187 
00188 /* We have to use an encoding for names if they contain spaces or tabs.
00189    To be able to represent all characters we also have to escape the
00190    backslash itself.  This "function" must be a macro since we use
00191    `alloca'.  */
00192 #define encode_name(name) \
00193   do {                                                               \
00194     const char *rp = name;                                           \
00195                                                                      \
00196     while (*rp != '\0')                                                     \
00197       if (*rp == ' ' || *rp == '\t' || *rp == '\\')                         \
00198        break;                                                        \
00199       else                                                           \
00200        ++rp;                                                         \
00201                                                                      \
00202     if (*rp != '\0')                                                 \
00203       {                                                                     \
00204        /* In the worst case the length of the string can increase to        \
00205           founr times the current length.  */                               \
00206        char *wp;                                                     \
00207                                                                      \
00208        rp = name;                                                    \
00209        name = wp = (char *) alloca (strlen (name) * 4 + 1);                 \
00210                                                                      \
00211        do                                                            \
00212          if (*rp == ' ')                                             \
00213            {                                                         \
00214              *wp++ = '\\';                                           \
00215              *wp++ = '0';                                            \
00216              *wp++ = '4';                                            \
00217              *wp++ = '0';                                            \
00218            }                                                         \
00219          else if (*rp == '\t')                                              \
00220            {                                                         \
00221              *wp++ = '\\';                                           \
00222              *wp++ = '0';                                            \
00223              *wp++ = '1';                                            \
00224              *wp++ = '1';                                            \
00225            }                                                         \
00226          else if (*rp == '\n')                                              \
00227            {                                                         \
00228              *wp++ = '\\';                                           \
00229              *wp++ = '0';                                            \
00230              *wp++ = '1';                                            \
00231              *wp++ = '2';                                            \
00232            }                                                         \
00233          else if (*rp == '\\')                                              \
00234            {                                                         \
00235              *wp++ = '\\';                                           \
00236              *wp++ = '\\';                                           \
00237            }                                                         \
00238          else                                                        \
00239            *wp++ = *rp;                                              \
00240        while (*rp++ != '\0');                                               \
00241       }                                                                     \
00242   } while (0)
00243 
00244 
00245 /* Write the mount table entry described by MNT to STREAM.
00246    Return zero on success, nonzero on failure.  */
00247 int
00248 __addmntent (FILE *stream, const struct mntent *mnt)
00249 {
00250   struct mntent mntcopy = *mnt;
00251   if (fseek (stream, 0, SEEK_END))
00252     return 1;
00253 
00254   /* Encode spaces and tabs in the names.  */
00255   encode_name (mntcopy.mnt_fsname);
00256   encode_name (mntcopy.mnt_dir);
00257   encode_name (mntcopy.mnt_type);
00258   encode_name (mntcopy.mnt_opts);
00259 
00260   return (fprintf (stream, "%s %s %s %s %d %d\n",
00261                  mntcopy.mnt_fsname,
00262                  mntcopy.mnt_dir,
00263                  mntcopy.mnt_type,
00264                  mntcopy.mnt_opts,
00265                  mntcopy.mnt_freq,
00266                  mntcopy.mnt_passno)
00267          < 0 ? 1 : 0);
00268 }
00269 weak_alias (__addmntent, addmntent)
00270 
00271 
00272 /* Search MNT->mnt_opts for an option matching OPT.
00273    Returns the address of the substring, or null if none found.  */
00274 char *
00275 __hasmntopt (const struct mntent *mnt, const char *opt)
00276 {
00277   const size_t optlen = strlen (opt);
00278   char *rest = mnt->mnt_opts, *p;
00279 
00280   while ((p = strstr (rest, opt)) != NULL)
00281     {
00282       if ((p == rest || p[-1] == ',')
00283          && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
00284        return p;
00285 
00286       rest = strchr (p, ',');
00287       if (rest == NULL)
00288        break;
00289       ++rest;
00290     }
00291 
00292   return NULL;
00293 }
00294 weak_alias (__hasmntopt, hasmntopt)