1 /*
2  * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  * This file is part of TUD:OS and distributed under the terms of the
5  * GNU Lesser General Public License 2.1.
6  * Please see the COPYING-LGPL-2.1 file for details.
7  */
8 
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <cstdio>
12 #include <unistd.h>
13 #include <ctype.h>
14 #include <cstring>
15 #include <errno.h>
16 #include <sys/mman.h>
17 #include <sys/mount.h>
18 
19 static bool verbose;
20 
21 struct String
22 {
StringString23   String(const char *s, const char *e) : _s(s), _e(e), _p(s) {}
sString24   const char *s() const { return _s; }
eString25   const char *e() const { return _e; }
pString26   const char *p() const { return _p; }
lString27   unsigned l() const { return _e - _s; }
28 
next_spaceString29   const char *next_space()
30   {
31     const char *i = _p;
32     while (i < _e && !isspace(*i))
33       i++;
34     _p = i;
35     return _p;
36   }
eat_spaceString37   void eat_space()
38   {
39     while (_p < e() && isspace(*_p))
40       _p++;
41   }
42 
emptyString43   bool empty() const { return !(_e - _s); }
dupnultermstrString44   const char *dupnultermstr() const
45   { return strndup(s(), l()); }
46 
47   const char *_s, *_e, *_p;
48 };
49 
parse_fstab_line(const char * fn,int line_nr,const char * s,const char * end)50 static void parse_fstab_line(const char *fn, int line_nr,
51                              const char *s, const char *end)
52 {
53   const char *i = s;
54   while (i < end && *i != '#')
55     ++i;
56   end = i;
57 
58   if (s == end)
59     return;
60 
61   String line(s, end);
62   String from(line.s(), line.next_space());
63 
64   line.next_space();
65   line.eat_space();
66 
67   const char *x = line.p();
68   String mountpoint(x, line.next_space());
69 
70   line.next_space();
71   line.eat_space();
72 
73   x = line.p();
74   String fsname(x, line.next_space());
75 
76   line.next_space();
77   line.eat_space();
78 
79   x = line.p();
80   String data(x, line.next_space());
81 
82   if (from.empty() || mountpoint.empty() || fsname.empty())
83     {
84       if (verbose)
85         printf("libmount: Invalid line: %s.%d: %.*s\n",
86                fn, line_nr, line.l(), line.s());
87       return;
88     }
89 
90   const char *s1 = from.dupnultermstr();
91   const char *s2 = mountpoint.dupnultermstr();
92   const char *s3 = fsname.dupnultermstr();
93   const char *s5 = data.dupnultermstr();
94   if (s1 && s2 && s3 && s5)
95     {
96       int r = mount(s1, *s2 == '/' ? s2 + 1 : s2, s3, 0, s5);
97       if (r < 0)
98         fprintf(stderr,
99                 "libmount: %s.%d: mount(\"%s\", \"%s\", \"%s\", %d, \"%s\"): %s\n",
100                 fn, line_nr, s1, s2, s3, 0, s5, strerror(errno));
101       else if (verbose)
102         printf("libmount: Mounted '%s' to '%s' with file-system '%s'\n",
103                s1, s2, s3);
104     }
105   else
106     fprintf(stderr, "libmount: %s.%d: memory allocation error\n", fn, line_nr);
107   free((void *)s5);
108   free((void *)s3);
109   free((void *)s2);
110   free((void *)s1);
111 }
112 
parse_fstab(const char * fn,char * fstab,size_t sz)113 static void parse_fstab(const char *fn, char *fstab, size_t sz)
114 {
115   char *s = fstab;
116   char *end = fstab + sz;
117   int line_nr = 1;
118 
119   if (verbose)
120     printf("libmount: Parsing '%s'\n", fn);
121 
122   while (s != end)
123     {
124       while (s < end && *s != '\n')
125         s++;
126       parse_fstab_line(fn, line_nr, fstab, s);
127       if (s == end)
128         break;
129       fstab = ++s;
130       line_nr++;
131     }
132 }
133 
134 static void libmount_init(void) __attribute__((constructor));
libmount_init()135 static void libmount_init()
136 {
137   verbose = getenv("FSTAB_DEBUG");
138 
139   const char *fstab_path = getenv("FSTAB_FILE");
140   if (!fstab_path)
141     fstab_path = "/etc/fstab";
142 
143   int fd = open(fstab_path, O_RDONLY);
144   if (fd < 0)
145     {
146       if (verbose)
147         printf("libmount: Could not open '%s': %s.\n", fstab_path, strerror(errno));
148       return;
149     }
150 
151   struct stat st;
152   if (fstat(fd, &st) < 0)
153     {
154       if (verbose)
155         printf("libmount: Could not stat '%s'.\n", fstab_path);
156       close(fd);
157       return;
158     }
159 
160   char *fstab = (char *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
161   if (fstab == MAP_FAILED)
162     {
163       if (verbose)
164         printf("libmount: Could not mmap '%s'.\n", fstab_path);
165       close(fd);
166       return;
167     }
168 
169   parse_fstab(fstab_path, fstab, st.st_size);
170 
171   munmap(fstab, st.st_size);
172   close(fd);
173 }
174