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