enable login utils
[framework/base/util-linux-ng.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 "sundries.h"
18 #include "xmalloc.h"
19 #include "nls.h"
20
21 int mount_quiet;
22 int verbose;
23 int nocanonicalize;
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 __attribute__ ((noreturn)) die(int err, const char *fmt, ...)
118 {
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 = strchr(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      if (options == NULL)
221           options = "";
222
223      len = strlen(test_opts);
224      q = alloca(len+1);
225      if (q == NULL)
226           die (EX_SYSERR, _("not enough memory"));
227      
228      for (p = test_opts; p < test_opts+len; p++) {
229           r = strchr(p, ',');
230           if (r) {
231                this_len = r-p;
232           } else {
233                this_len = strlen(p);
234           }
235           if (!this_len) continue; /* if two ',' appear in a row */
236           strncpy(q, p, this_len);
237           q[this_len] = '\0';
238           if (!check_option(options, q))
239                return 0; /* any match failure means failure */
240           p += this_len;
241      }
242
243      /* no match failures in list means success */
244      return 1;
245 }
246
247 int
248 is_pseudo_fs(const char *type)
249 {
250         if (type == NULL || *type == '/')
251                 return 0;
252         if (streq(type, "none") ||
253             streq(type, "proc") ||
254             streq(type, "tmpfs") ||
255             streq(type, "sysfs") ||
256             streq(type, "usbfs") ||
257             streq(type, "cgroup") ||
258             streq(type, "cpuset") ||
259             streq(type, "rpc_pipefs") ||
260             streq(type, "devpts") ||
261             streq(type, "securityfs") ||
262             streq(type, "debugfs"))
263                 return 1;
264         return 0;
265 }
266
267 /* Make a canonical pathname from PATH.  Returns a freshly malloced string.
268    It is up the *caller* to ensure that the PATH is sensible.  i.e.
269    canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
270    is not a legal pathname for ``/dev/fd0''.  Anything we cannot parse
271    we return unmodified.   */
272 char *
273 canonicalize_spec (const char *path)
274 {
275         char *res;
276
277         if (!path)
278                 return NULL;
279         if (nocanonicalize || is_pseudo_fs(path))
280                 return xstrdup(path);
281
282         res = canonicalize_path(path);
283         if (!res)
284                 die(EX_SYSERR, _("not enough memory"));
285         return res;
286 }
287
288 char *canonicalize (const char *path)
289 {
290         char *res;
291
292         if (!path)
293                 return NULL;
294         else if (nocanonicalize)
295                 return xstrdup(path);
296
297         res = canonicalize_path(path);
298         if (!res)
299                 die(EX_SYSERR, _("not enough memory"));
300         return res;
301 }
302