OSDN Git Service

e2initrd_helper: Fix memory leak on error
[android-x86/external-e2fsprogs.git] / misc / e2initrd_helper.c
1 /*
2  * e2initrd_helper.c - Get the filesystem table
3  *
4  * Copyright 2004 by Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11
12 #include <stdio.h>
13 #include <unistd.h>
14 #ifdef HAVE_STDLIB_H
15 #include <stdlib.h>
16 #endif
17 #include <ctype.h>
18 #include <string.h>
19 #include <time.h>
20 #ifdef HAVE_ERRNO_H
21 #include <errno.h>
22 #endif
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <utime.h>
27 #ifdef HAVE_GETOPT_H
28 #include <getopt.h>
29 #else
30 extern int optind;
31 extern char *optarg;
32 #endif
33
34 #include "ext2fs/ext2_fs.h"
35 #include "ext2fs/ext2fs.h"
36 #include "blkid/blkid.h"
37
38 #include "../version.h"
39 #include "nls-enable.h"
40
41 const char * program_name = "get_fstab";
42 char * device_name;
43 static int open_flag;
44 static int root_type;
45 static blkid_cache cache = NULL;
46
47 struct mem_file {
48         char    *buf;
49         int     size;
50         int     ptr;
51 };
52
53 struct fs_info {
54         char  *device;
55         char  *mountpt;
56         char  *type;
57         char  *opts;
58         int   freq;
59         int   passno;
60         int   flags;
61         struct fs_info *next;
62 };
63
64 static void usage(void)
65 {
66         fprintf(stderr,
67                 _("Usage: %s -r device\n"), program_name);
68         exit (1);
69 }
70
71 static errcode_t get_file(ext2_filsys fs, const char * filename,
72                    struct mem_file *ret_file)
73 {
74         errcode_t       retval;
75         char            *buf;
76         ext2_file_t     e2_file = NULL;
77         unsigned int    got;
78         struct ext2_inode inode;
79         ext2_ino_t      ino;
80
81         ret_file->buf = 0;
82         ret_file->size = 0;
83         ret_file->ptr = 0;
84
85         retval = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
86                               filename, &ino);
87         if (retval)
88                 return retval;
89
90         retval = ext2fs_read_inode(fs, ino, &inode);
91         if (retval)
92                 return retval;
93
94         if (inode.i_size_high || (inode.i_size > 65536))
95                 return EFBIG;
96
97         buf = malloc(inode.i_size + 1);
98         if (!buf)
99                 return ENOMEM;
100         memset(buf, 0, inode.i_size+1);
101
102         retval = ext2fs_file_open(fs, ino, 0, &e2_file);
103         if (retval)
104                 goto errout;
105
106         retval = ext2fs_file_read(e2_file, buf, inode.i_size, &got);
107         if (retval)
108                 goto errout;
109
110         retval = ext2fs_file_close(e2_file);
111         if (retval)
112                 goto errout;
113
114         ret_file->buf = buf;
115         ret_file->size = (int) got;
116         return 0;
117
118 errout:
119         free(buf);
120         if (e2_file)
121                 ext2fs_file_close(e2_file);
122         return retval;
123 }
124
125 static char *get_line(struct mem_file *file)
126 {
127         char    *cp, *ret;
128         int     s = 0;
129
130         cp = file->buf + file->ptr;
131         while (*cp && *cp != '\n') {
132                 cp++;
133                 s++;
134         }
135         ret = malloc(s+1);
136         if (!ret)
137                 return 0;
138         ret[s]=0;
139         memcpy(ret, file->buf + file->ptr, s);
140         while (*cp && (*cp == '\n' || *cp == '\r')) {
141                 cp++;
142                 s++;
143         }
144         file->ptr += s;
145         return ret;
146 }
147
148 static int mem_file_eof(struct mem_file *file)
149 {
150         return (file->ptr >= file->size);
151 }
152
153 /*
154  * fstab parsing code
155  */
156 static char *string_copy(const char *s)
157 {
158         char    *ret;
159
160         if (!s)
161                 return 0;
162         ret = malloc(strlen(s)+1);
163         if (ret)
164                 strcpy(ret, s);
165         return ret;
166 }
167
168 static char *skip_over_blank(char *cp)
169 {
170         while (*cp && isspace(*cp))
171                 cp++;
172         return cp;
173 }
174
175 static char *skip_over_word(char *cp)
176 {
177         while (*cp && !isspace(*cp))
178                 cp++;
179         return cp;
180 }
181
182 static char *parse_word(char **buf)
183 {
184         char *word, *next;
185
186         word = *buf;
187         if (*word == 0)
188                 return 0;
189
190         word = skip_over_blank(word);
191         next = skip_over_word(word);
192         if (*next)
193                 *next++ = 0;
194         *buf = next;
195         return word;
196 }
197
198 static void parse_escape(char *word)
199 {
200         char    *p, *q;
201         int     ac, i;
202
203         if (!word)
204                 return;
205
206         for (p = word, q = word; *p; p++, q++) {
207                 *q = *p;
208                 if (*p != '\\')
209                         continue;
210                 if (*++p == 0)
211                         break;
212                 if (*p == 't') {
213                         *q = '\t';
214                         continue;
215                 }
216                 if (*p == 'n') {
217                         *q = '\n';
218                         continue;
219                 }
220                 if (!isdigit(*p)) {
221                         *q = *p;
222                         continue;
223                 }
224                 ac = 0;
225                 for (i = 0; i < 3; i++, p++) {
226                         if (!isdigit(*p))
227                                 break;
228                         ac = (ac * 8) + (*p - '0');
229                 }
230                 *q = ac;
231                 p--;
232         }
233         *q = 0;
234 }
235
236 static int parse_fstab_line(char *line, struct fs_info *fs)
237 {
238         char    *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
239
240         if ((cp = strchr(line, '#')))
241                 *cp = 0;        /* Ignore everything after the comment char */
242         cp = line;
243
244         device = parse_word(&cp);
245         mntpnt = parse_word(&cp);
246         type = parse_word(&cp);
247         opts = parse_word(&cp);
248         freq = parse_word(&cp);
249         passno = parse_word(&cp);
250
251         if (!device)
252                 return -1;      /* Allow blank lines */
253
254         if (!mntpnt || !type)
255                 return -1;
256
257         parse_escape(device);
258         parse_escape(mntpnt);
259         parse_escape(type);
260         parse_escape(opts);
261         parse_escape(freq);
262         parse_escape(passno);
263
264         dev = blkid_get_devname(cache, device, NULL);
265         if (dev)
266                 device = dev;
267
268         if (strchr(type, ','))
269                 type = 0;
270
271         fs->device = string_copy(device);
272         fs->mountpt = string_copy(mntpnt);
273         fs->type = string_copy(type);
274         fs->opts = string_copy(opts ? opts : "");
275         fs->freq = freq ? atoi(freq) : -1;
276         fs->passno = passno ? atoi(passno) : -1;
277         fs->flags = 0;
278         fs->next = NULL;
279
280         free(dev);
281
282         return 0;
283 }
284
285 static void free_fstab_line(struct fs_info *fs)
286 {
287         if (fs->device)
288                 fs->device = 0;
289         if (fs->mountpt)
290                 fs->mountpt = 0;
291         if (fs->type)
292                 fs->type = 0;
293         if (fs->opts)
294                 fs->opts = 0;
295         memset(fs, 0, sizeof(struct fs_info));
296 }
297
298
299 static void PRS(int argc, char **argv)
300 {
301         int c;
302
303 #ifdef ENABLE_NLS
304         setlocale(LC_MESSAGES, "");
305         setlocale(LC_CTYPE, "");
306         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
307         textdomain(NLS_CAT_NAME);
308 #endif
309
310         while ((c = getopt(argc, argv, "rv")) != EOF) {
311                 switch (c) {
312                 case 'r':
313                         root_type++;
314                         break;
315
316                 case 'v':
317                         printf("%s %s (%s)\n", program_name,
318                                E2FSPROGS_VERSION, E2FSPROGS_DATE);
319                         break;
320                 default:
321                         usage();
322                 }
323         }
324         if (optind < argc - 1 || optind == argc)
325                 usage();
326         device_name = blkid_get_devname(NULL, argv[optind], NULL);
327         if (!device_name) {
328                 com_err("tune2fs", 0, _("Unable to resolve '%s'"),
329                         argv[optind]);
330                 exit(1);
331         }
332 }
333
334 static void get_root_type(ext2_filsys fs)
335 {
336         errcode_t retval;
337         struct mem_file file;
338         char            *buf;
339         struct fs_info fs_info;
340         int             ret;
341
342         retval = get_file(fs, "/etc/fstab", &file);
343
344         while (!mem_file_eof(&file)) {
345                 buf = get_line(&file);
346                 if (!buf)
347                         continue;
348
349                 ret = parse_fstab_line(buf, &fs_info);
350                 if (ret < 0)
351                         goto next_line;
352
353                 if (!strcmp(fs_info.mountpt, "/"))
354                         printf("%s\n", fs_info.type);
355
356                 free_fstab_line(&fs_info);
357
358         next_line:
359                 free(buf);
360         }
361 }
362
363
364 int main (int argc, char ** argv)
365 {
366         errcode_t retval;
367         ext2_filsys fs;
368         io_manager io_ptr;
369
370         add_error_table(&et_ext2_error_table);
371
372         blkid_get_cache(&cache, NULL);
373         PRS(argc, argv);
374
375 #ifdef CONFIG_TESTIO_DEBUG
376         if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
377                 io_ptr = test_io_manager;
378                 test_io_backing_manager = unix_io_manager;
379         } else
380 #endif
381                 io_ptr = unix_io_manager;
382         retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
383         if (retval)
384                 exit(1);
385
386         if (root_type)
387                 get_root_type(fs);
388
389         remove_error_table(&et_ext2_error_table);
390         return (ext2fs_close (fs) ? 1 : 0);
391 }