]> git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/sundries.c
mount: move realpath.c code to lib/
[thirdparty/util-linux.git] / mount / sundries.c
1 /*
2 * Support functions. Exported functions are prototyped in sundries.h.
3 *
4 * added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927
5 *
6 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
7 * - added Native Language Support
8 *
9 */
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <mntent.h> /* for MNTTYPE_SWAP */
14
15 #include "canonicalize.h"
16
17 #include "fstab.h"
18 #include "sundries.h"
19 #include "xmalloc.h"
20 #include "nls.h"
21
22 int mount_quiet;
23 int verbose;
24 char *progname;
25
26 char *
27 xstrndup (const char *s, int n) {
28 char *t;
29
30 if (s == NULL)
31 die (EX_SOFTWARE, _("bug in xstrndup call"));
32
33 t = xmalloc(n+1);
34 strncpy(t,s,n);
35 t[n] = 0;
36
37 return t;
38 }
39
40 /* reallocates its first arg - typical use: s = xstrconcat3(s,t,u); */
41 char *
42 xstrconcat3 (char *s, const char *t, const char *u) {
43 size_t len = 0;
44
45 len = (s ? strlen(s) : 0) + (t ? strlen(t) : 0) + (u ? strlen(u) : 0);
46
47 if (!len)
48 return NULL;
49 if (!s) {
50 s = xmalloc(len + 1);
51 *s = '\0';
52 }
53 else
54 s = xrealloc(s, len + 1);
55 if (t)
56 strcat(s, t);
57 if (u)
58 strcat(s, u);
59 return s;
60 }
61
62 /* frees its first arg - typical use: s = xstrconcat4(s,t,u,v); */
63 char *
64 xstrconcat4 (char *s, const char *t, const char *u, const char *v) {
65 size_t len = 0;
66
67 len = (s ? strlen(s) : 0) + (t ? strlen(t) : 0) +
68 (u ? strlen(u) : 0) + (v ? strlen(v) : 0);
69
70 if (!len)
71 return NULL;
72 if (!s) {
73 s = xmalloc(len + 1);
74 *s = '\0';
75 }
76 else
77 s = xrealloc(s, len + 1);
78 if (t)
79 strcat(s, t);
80 if (u)
81 strcat(s, u);
82 if (v)
83 strcat(s, v);
84 return s;
85
86
87 }
88
89 /* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock. */
90 void
91 block_signals (int how) {
92 sigset_t sigs;
93
94 sigfillset (&sigs);
95 sigdelset(&sigs, SIGTRAP);
96 sigdelset(&sigs, SIGSEGV);
97 sigprocmask (how, &sigs, (sigset_t *) 0);
98 }
99
100
101 /* Non-fatal error. Print message and return. */
102 /* (print the message in a single printf, in an attempt
103 to avoid mixing output of several threads) */
104 void
105 error (const char *fmt, ...) {
106 va_list args;
107
108 if (mount_quiet)
109 return;
110 va_start (args, fmt);
111 vfprintf (stderr, fmt, args);
112 va_end (args);
113 fputc('\n', stderr);
114 }
115
116 /* Fatal error. Print message and exit. */
117 void
118 die(int err, const char *fmt, ...) {
119 va_list args;
120
121 va_start(args, fmt);
122 vfprintf(stderr, fmt, args);
123 fprintf(stderr, "\n");
124 va_end(args);
125
126 exit(err);
127 }
128
129 /* True if fstypes match. Null *TYPES means match anything,
130 except that swap types always return false. */
131 /* Accept nonfs,proc,devpts and nonfs,noproc,nodevpts
132 with the same meaning. */
133 int
134 matching_type (const char *type, const char *types) {
135 int no; /* negated types list */
136 int len;
137 const char *p;
138
139 if (streq (type, MNTTYPE_SWAP))
140 return 0;
141 if (types == NULL)
142 return 1;
143
144 no = 0;
145 if (!strncmp(types, "no", 2)) {
146 no = 1;
147 types += 2;
148 }
149
150 /* Does type occur in types, separated by commas? */
151 len = strlen(type);
152 p = types;
153 while(1) {
154 if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
155 (p[len+2] == 0 || p[len+2] == ','))
156 return 0;
157 if (strncmp(p, type, len) == 0 &&
158 (p[len] == 0 || p[len] == ','))
159 return !no;
160 p = index(p,',');
161 if (!p)
162 break;
163 p++;
164 }
165 return no;
166 }
167
168 /* Returns 1 if needle found or noneedle not found in haystack
169 * Otherwise returns 0
170 */
171 static int
172 check_option(const char *haystack, const char *needle) {
173 const char *p, *r;
174 int len, needle_len, this_len;
175 int no;
176
177 no = 0;
178 if (!strncmp(needle, "no", 2)) {
179 no = 1;
180 needle += 2;
181 }
182 needle_len = strlen(needle);
183 len = strlen(haystack);
184
185 for (p = haystack; p < haystack+len; p++) {
186 r = strchr(p, ',');
187 if (r) {
188 this_len = r-p;
189 } else {
190 this_len = strlen(p);
191 }
192 if (this_len != needle_len) {
193 p += this_len;
194 continue;
195 }
196 if (strncmp(p, needle, this_len) == 0)
197 return !no; /* foo or nofoo was found */
198 p += this_len;
199 }
200
201 return no; /* foo or nofoo was not found */
202 }
203
204
205 /* Returns 1 if each of the test_opts options agrees with the entire
206 * list of options.
207 * Returns 0 if any noopt is found in test_opts and opt is found in options.
208 * Returns 0 if any opt is found in test_opts but is not found in options.
209 * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
210 * DIFFERENT meanings; each option is matched explicitly as specified.
211 */
212 int
213 matching_opts (const char *options, const char *test_opts) {
214 const char *p, *r;
215 char *q;
216 int len, this_len;
217
218 if (test_opts == NULL)
219 return 1;
220
221 len = strlen(test_opts);
222 q = alloca(len+1);
223 if (q == NULL)
224 die (EX_SYSERR, _("not enough memory"));
225
226 for (p = test_opts; p < test_opts+len; p++) {
227 r = strchr(p, ',');
228 if (r) {
229 this_len = r-p;
230 } else {
231 this_len = strlen(p);
232 }
233 if (!this_len) continue; /* if two ',' appear in a row */
234 strncpy(q, p, this_len);
235 q[this_len] = '\0';
236 if (!check_option(options, q))
237 return 0; /* any match failure means failure */
238 p += this_len;
239 }
240
241 /* no match failures in list means success */
242 return 1;
243 }
244
245 /*
246 * Parses NAME=value, returns -1 on parse error, 0 success. The success is also
247 * when the 'spec' doesn't contain name=value pair (because the spec could be
248 * a devname too). In particular case the pointer 'name' is set to NULL.
249
250 * The result is a new allocated string (the 'name' pointer).
251 */
252 int
253 parse_spec(const char *spec, char **name, char **value)
254 {
255 char *vl, *tk, *cp;
256
257 *name = NULL;
258 *value = NULL;
259
260 if (!(cp = strchr(spec, '=')))
261 return 0; /* no name= */
262
263 tk = xstrdup(spec);
264 vl = tk + (cp - spec);
265 *vl++ = '\0';
266
267 if (*vl == '"' || *vl == '\'') {
268 if (!(cp = strrchr(vl+1, *vl))) {
269 free(tk);
270 return -1; /* parse error */
271 }
272 vl++;
273 *cp = '\0';
274 }
275
276 *name = tk;
277 *value = vl;
278 return 0;
279 }
280
281 int
282 is_pseudo_fs(const char *type)
283 {
284 if (type == NULL || *type == '/')
285 return 0;
286 if (streq(type, "none") ||
287 streq(type, "proc") ||
288 streq(type, "tmpfs") ||
289 streq(type, "sysfs") ||
290 streq(type, "devpts"))
291 return 1;
292 return 0;
293 }
294
295 /* Make a canonical pathname from PATH. Returns a freshly malloced string.
296 It is up the *caller* to ensure that the PATH is sensible. i.e.
297 canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
298 is not a legal pathname for ``/dev/fd0''. Anything we cannot parse
299 we return unmodified. */
300 char *
301 canonicalize_spec (const char *path)
302 {
303 char *res;
304
305 if (path == NULL)
306 return NULL;
307 if (is_pseudo_fs(path))
308 return xstrdup(path);
309
310 res = canonicalize_path(path);
311 if (!res)
312 die(EX_SYSERR, _("not enough memory"));
313 return res;
314 }
315
316 char *canonicalize (const char *path)
317 {
318 char *res = canonicalize_path(path);
319
320 if (!res)
321 die(EX_SYSERR, _("not enough memory"));
322 return res;
323 }
324