iconv: Suppress array out of bounds warning.
[platform/upstream/glibc.git] / misc / mntent_r.c
1 /* Utilities for reading/writing fstab, mtab, etc.
2    Copyright (C) 1995-2015 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <alloca.h>
20 #include <mntent.h>
21 #include <stdio.h>
22 #include <stdio_ext.h>
23 #include <string.h>
24 #include <sys/types.h>
25
26 #define flockfile(s) _IO_flockfile (s)
27 #define funlockfile(s) _IO_funlockfile (s)
28
29 #undef __setmntent
30 #undef __endmntent
31 #undef __getmntent_r
32
33 /* Prepare to begin reading and/or writing mount table entries from the
34    beginning of FILE.  MODE is as for `fopen'.  */
35 FILE *
36 __setmntent (const char *file, const char *mode)
37 {
38   /* Extend the mode parameter with "c" to disable cancellation in the
39      I/O functions and "e" to set FD_CLOEXEC.  */
40   size_t modelen = strlen (mode);
41   char newmode[modelen + 3];
42   memcpy (mempcpy (newmode, mode, modelen), "ce", 3);
43   FILE *result = fopen (file, newmode);
44
45   if (result != NULL)
46     /* We do the locking ourselves.  */
47     __fsetlocking (result, FSETLOCKING_BYCALLER);
48
49   return result;
50 }
51 libc_hidden_def (__setmntent)
52 weak_alias (__setmntent, setmntent)
53
54
55 /* Close a stream opened with `setmntent'.  */
56 int
57 __endmntent (FILE *stream)
58 {
59   if (stream)           /* SunOS 4.x allows for NULL stream */
60     fclose (stream);
61   return 1;             /* SunOS 4.x says to always return 1 */
62 }
63 libc_hidden_def (__endmntent)
64 weak_alias (__endmntent, endmntent)
65
66
67 /* Since the values in a line are separated by spaces, a name cannot
68    contain a space.  Therefore some programs encode spaces in names
69    by the strings "\040".  We undo the encoding when reading an entry.
70    The decoding happens in place.  */
71 static char *
72 decode_name (char *buf)
73 {
74   char *rp = buf;
75   char *wp = buf;
76
77   do
78     if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' && rp[3] == '0')
79       {
80         /* \040 is a SPACE.  */
81         *wp++ = ' ';
82         rp += 3;
83       }
84     else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '1')
85       {
86         /* \011 is a TAB.  */
87         *wp++ = '\t';
88         rp += 3;
89       }
90     else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '2')
91       {
92         /* \012 is a NEWLINE.  */
93         *wp++ = '\n';
94         rp += 3;
95       }
96     else if (rp[0] == '\\' && rp[1] == '\\')
97       {
98         /* We have to escape \\ to be able to represent all characters.  */
99         *wp++ = '\\';
100         rp += 1;
101       }
102     else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' && rp[3] == '4')
103       {
104         /* \134 is also \\.  */
105         *wp++ = '\\';
106         rp += 3;
107       }
108     else
109       *wp++ = *rp;
110   while (*rp++ != '\0');
111
112   return buf;
113 }
114
115
116 /* Read one mount table entry from STREAM.  Returns a pointer to storage
117    reused on the next call, or null for EOF or error (use feof/ferror to
118    check).  */
119 struct mntent *
120 __getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
121 {
122   char *cp;
123   char *head;
124
125   flockfile (stream);
126   do
127     {
128       char *end_ptr;
129
130       if (__fgets_unlocked (buffer, bufsiz, stream) == NULL)
131         {
132           funlockfile (stream);
133           return NULL;
134         }
135
136       end_ptr = strchr (buffer, '\n');
137       if (end_ptr != NULL)      /* chop newline */
138         {
139           while (end_ptr[-1] == ' ' || end_ptr[-1] == '\t')
140             end_ptr--;
141           *end_ptr = '\0';
142         }
143       else
144         {
145           /* Not the whole line was read.  Do it now but forget it.  */
146           char tmp[1024];
147           while (__fgets_unlocked (tmp, sizeof tmp, stream) != NULL)
148             if (strchr (tmp, '\n') != NULL)
149               break;
150         }
151
152       head = buffer + strspn (buffer, " \t");
153       /* skip empty lines and comment lines:  */
154     }
155   while (head[0] == '\0' || head[0] == '#');
156
157   cp = __strsep (&head, " \t");
158   mp->mnt_fsname = cp != NULL ? decode_name (cp) : (char *) "";
159   if (head)
160     head += strspn (head, " \t");
161   cp = __strsep (&head, " \t");
162   mp->mnt_dir = cp != NULL ? decode_name (cp) : (char *) "";
163   if (head)
164     head += strspn (head, " \t");
165   cp = __strsep (&head, " \t");
166   mp->mnt_type = cp != NULL ? decode_name (cp) : (char *) "";
167   if (head)
168     head += strspn (head, " \t");
169   cp = __strsep (&head, " \t");
170   mp->mnt_opts = cp != NULL ? decode_name (cp) : (char *) "";
171   switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
172     {
173     case 0:
174       mp->mnt_freq = 0;
175     case 1:
176       mp->mnt_passno = 0;
177     case 2:
178       break;
179     }
180   funlockfile (stream);
181
182   return mp;
183 }
184 libc_hidden_def (__getmntent_r)
185 weak_alias (__getmntent_r, getmntent_r)
186
187
188 /* We have to use an encoding for names if they contain spaces or tabs.
189    To be able to represent all characters we also have to escape the
190    backslash itself.  This "function" must be a macro since we use
191    `alloca'.  */
192 #define encode_name(name) \
193   do {                                                                        \
194     const char *rp = name;                                                    \
195                                                                               \
196     while (*rp != '\0')                                                       \
197       if (*rp == ' ' || *rp == '\t' || *rp == '\n' || *rp == '\\')            \
198         break;                                                                \
199       else                                                                    \
200         ++rp;                                                                 \
201                                                                               \
202     if (*rp != '\0')                                                          \
203       {                                                                       \
204         /* In the worst case the length of the string can increase to         \
205            four times the current length.  */                                 \
206         char *wp;                                                             \
207                                                                               \
208         rp = name;                                                            \
209         name = wp = (char *) alloca (strlen (name) * 4 + 1);                  \
210                                                                               \
211         do                                                                    \
212           if (*rp == ' ')                                                     \
213             {                                                                 \
214               *wp++ = '\\';                                                   \
215               *wp++ = '0';                                                    \
216               *wp++ = '4';                                                    \
217               *wp++ = '0';                                                    \
218             }                                                                 \
219           else if (*rp == '\t')                                               \
220             {                                                                 \
221               *wp++ = '\\';                                                   \
222               *wp++ = '0';                                                    \
223               *wp++ = '1';                                                    \
224               *wp++ = '1';                                                    \
225             }                                                                 \
226           else if (*rp == '\n')                                               \
227             {                                                                 \
228               *wp++ = '\\';                                                   \
229               *wp++ = '0';                                                    \
230               *wp++ = '1';                                                    \
231               *wp++ = '2';                                                    \
232             }                                                                 \
233           else if (*rp == '\\')                                               \
234             {                                                                 \
235               *wp++ = '\\';                                                   \
236               *wp++ = '\\';                                                   \
237             }                                                                 \
238           else                                                                \
239             *wp++ = *rp;                                                      \
240         while (*rp++ != '\0');                                                \
241       }                                                                       \
242   } while (0)
243
244
245 /* Write the mount table entry described by MNT to STREAM.
246    Return zero on success, nonzero on failure.  */
247 int
248 __addmntent (FILE *stream, const struct mntent *mnt)
249 {
250   struct mntent mntcopy = *mnt;
251   if (fseek (stream, 0, SEEK_END))
252     return 1;
253
254   /* Encode spaces and tabs in the names.  */
255   encode_name (mntcopy.mnt_fsname);
256   encode_name (mntcopy.mnt_dir);
257   encode_name (mntcopy.mnt_type);
258   encode_name (mntcopy.mnt_opts);
259
260   return (fprintf (stream, "%s %s %s %s %d %d\n",
261                    mntcopy.mnt_fsname,
262                    mntcopy.mnt_dir,
263                    mntcopy.mnt_type,
264                    mntcopy.mnt_opts,
265                    mntcopy.mnt_freq,
266                    mntcopy.mnt_passno) < 0
267           || fflush (stream) != 0);
268 }
269 weak_alias (__addmntent, addmntent)
270
271
272 /* Search MNT->mnt_opts for an option matching OPT.
273    Returns the address of the substring, or null if none found.  */
274 char *
275 __hasmntopt (const struct mntent *mnt, const char *opt)
276 {
277   const size_t optlen = strlen (opt);
278   char *rest = mnt->mnt_opts, *p;
279
280   while ((p = strstr (rest, opt)) != NULL)
281     {
282       if ((p == rest || p[-1] == ',')
283           && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
284         return p;
285
286       rest = strchr (p, ',');
287       if (rest == NULL)
288         break;
289       ++rest;
290     }
291
292   return NULL;
293 }
294 weak_alias (__hasmntopt, hasmntopt)