]> git.decadent.org.uk Git - nfs-utils.git/blob - support/nfs/nfs_mntent.c
Merge branch 'sid'
[nfs-utils.git] / support / nfs / nfs_mntent.c
1 /* Private version of the libc *mntent() routines. */
2 /* Note slightly different prototypes. */
3
4 /* 1999-02-22 Arkadiusz Miskiewicz <misiek@pld.ORG.PL>
5  * - added Native Language Support
6  *
7  * 2006-06-08 Amit Gud <agud@redhat.com>
8  * - Moved to nfs-utils/support/nfs from util-linux/mount
9  */
10
11 #include <stdio.h>
12 #include <string.h>             /* for index */
13 #include <ctype.h>              /* for isdigit */
14 #include <sys/stat.h>           /* for umask */
15 #include <unistd.h>             /* for ftruncate */
16
17 #include "nfs_mntent.h"
18 #include "nls.h"
19 #include "xcommon.h"
20
21 /* Unfortunately the classical Unix /etc/mtab and /etc/fstab
22    do not handle directory names containing spaces.
23    Here we mangle them, replacing a space by \040.
24    What do other Unices do? */
25
26 static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
27
28 static char *
29 mangle(const char *arg) {
30         const unsigned char *s = (const unsigned char *)arg;
31         char *ss, *sp;
32         unsigned int n;
33
34         n = strlen(arg);
35         ss = sp = xmalloc(4*n+1);
36         while(1) {
37                 for (n = 0; n < sizeof(need_escaping); n++) {
38                         if (*s == need_escaping[n]) {
39                                 *sp++ = '\\';
40                                 *sp++ = '0' + ((*s & 0300) >> 6);
41                                 *sp++ = '0' + ((*s & 070) >> 3);
42                                 *sp++ = '0' + (*s & 07);
43                                 goto next;
44                         }
45                 }
46                 *sp++ = *s;
47                 if (*s == 0)
48                         break;
49         next:
50                 s++;
51         }
52         return ss;
53 }
54
55 static int
56 is_space_or_tab (char c) {
57         return (c == ' ' || c == '\t');
58 }
59
60 static char *
61 skip_spaces(char *s) {
62         while (is_space_or_tab(*s))
63                 s++;
64         return s;
65 }
66
67 static char *
68 skip_nonspaces(char *s) {
69         while (*s && !is_space_or_tab(*s))
70                 s++;
71         return s;
72 }
73
74 #define isoctal(a) (((a) & ~7) == '0')
75
76 /* returns malloced pointer - no more strdup required */
77 static char *
78 unmangle(char *s) {
79         char *ret, *ss, *sp;
80
81         ss = skip_nonspaces(s);
82         ret = sp = xmalloc(ss-s+1);
83         while(s != ss) {
84                 if (*s == '\\' && isoctal(s[1]) && isoctal(s[2]) && isoctal(s[3])) {
85                         *sp++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
86                         s += 4;
87                 } else
88                         *sp++ = *s++;
89         }
90         *sp = 0;
91         return ret;
92 }
93
94 /*
95  * fstat'ing the file and allocating a buffer holding all of it
96  * may be a bad idea: if the file is /proc/mounts, the stat
97  * returns 0.
98  * (On the other hand, mangling and unmangling is meaningless
99  *  for /proc/mounts.)
100  */
101
102 mntFILE *
103 nfs_setmntent (const char *file, char *mode) {
104         mntFILE *mfp = xmalloc(sizeof(*mfp));
105         mode_t old_umask = umask(077);
106
107         mfp->mntent_fp = fopen(file, mode);
108         umask(old_umask);
109         mfp->mntent_file = xstrdup(file);
110         mfp->mntent_errs = (mfp->mntent_fp == NULL);
111         mfp->mntent_softerrs = 0;
112         mfp->mntent_lineno = 0;
113         return mfp;
114 }
115
116 void
117 nfs_endmntent (mntFILE *mfp) {
118         if (mfp) {
119                 if (mfp->mntent_fp)
120                         fclose(mfp->mntent_fp);
121                 if (mfp->mntent_file)
122                         free(mfp->mntent_file);
123                 free(mfp);
124         }
125 }
126
127 int
128 nfs_addmntent (mntFILE *mfp, struct mntent *mnt) {
129         char *m1, *m2, *m3, *m4;
130         int res;
131         off_t length;
132
133         if (fseek (mfp->mntent_fp, 0, SEEK_END))
134                 return 1;                       /* failure */
135         length = ftell(mfp->mntent_fp);
136
137         m1 = mangle(mnt->mnt_fsname);
138         m2 = mangle(mnt->mnt_dir);
139         m3 = mangle(mnt->mnt_type);
140         m4 = mangle(mnt->mnt_opts);
141
142         res = fprintf (mfp->mntent_fp, "%s %s %s %s %d %d\n",
143                        m1, m2, m3, m4, mnt->mnt_freq, mnt->mnt_passno);
144
145         free(m1);
146         free(m2);
147         free(m3);
148         free(m4);
149         if (res >= 0) {
150                 res = fflush(mfp->mntent_fp);
151                 if (res < 0)
152                         /* Avoid leaving a corrupt mtab file */
153                         ftruncate(fileno(mfp->mntent_fp), length);
154         }
155         return (res < 0) ? 1 : 0;
156 }
157
158 /* Read the next entry from the file fp. Stop reading at an incorrect entry. */
159 struct mntent *
160 nfs_getmntent (mntFILE *mfp) {
161         static char buf[4096];
162         static struct mntent me;
163         char *s;
164
165  again:
166         if (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX)
167                 return NULL;
168
169         /* read the next non-blank non-comment line */
170         do {
171                 if (fgets (buf, sizeof(buf), mfp->mntent_fp) == NULL)
172                         return NULL;
173
174                 mfp->mntent_lineno++;
175                 s = index (buf, '\n');
176                 if (s == NULL) {
177                         /* Missing final newline?  Otherwise extremely */
178                         /* long line - assume file was corrupted */
179                         if (feof(mfp->mntent_fp)) {
180                                 fprintf(stderr, _("[mntent]: warning: no final "
181                                         "newline at the end of %s\n"),
182                                         mfp->mntent_file);
183                                 s = index (buf, 0);
184                         } else {
185                                 mfp->mntent_errs = 1;
186                                 goto err;
187                         }
188                 }
189                 *s = 0;
190                 if (--s >= buf && *s == '\r')
191                         *s = 0;
192                 s = skip_spaces(buf);
193         } while (*s == '\0' || *s == '#');
194
195         me.mnt_fsname = unmangle(s);
196         s = skip_nonspaces(s);
197         s = skip_spaces(s);
198         me.mnt_dir = unmangle(s);
199         s = skip_nonspaces(s);
200         s = skip_spaces(s);
201         me.mnt_type = unmangle(s);
202         s = skip_nonspaces(s);
203         s = skip_spaces(s);
204         me.mnt_opts = unmangle(s);
205         s = skip_nonspaces(s);
206         s = skip_spaces(s);
207
208         if (isdigit(*s)) {
209                 me.mnt_freq = atoi(s);
210                 while(isdigit(*s)) s++;
211         } else
212                 me.mnt_freq = 0;
213         if(*s && !is_space_or_tab(*s))
214                 goto err;
215
216         s = skip_spaces(s);
217         if(isdigit(*s)) {
218                 me.mnt_passno = atoi(s);
219                 while(isdigit(*s)) s++;
220         } else
221                 me.mnt_passno = 0;
222         if(*s && !is_space_or_tab(*s))
223                 goto err;
224
225         /* allow more stuff, e.g. comments, on this line */
226
227         return &me;
228
229  err:
230         mfp->mntent_softerrs++;
231         fprintf(stderr, _("[mntent]: line %d in %s is bad%s\n"),
232                 mfp->mntent_lineno, mfp->mntent_file,
233                 (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) ?
234                 _("; rest of file ignored") : "");
235         goto again;
236 }