1 /*-
2  * Copyright (c) 2012 Department of Software Engineering,
3  *                        University of Szeged, Hungary
4  * Copyright (c) 2012 Tamas Toth <ttoth@inf.u-szeged.hu>
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by the Department of Software Engineering, University of Szeged, Hungary
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35 
36 #include <sys/param.h>
37 
38 #include <assert.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <util.h>
45 
46 #include "makefs.h"
47 #include "chfs_makefs.h"
48 
49 #include "chfs/chfs_mkfs.h"
50 
51 static void chfs_validate(const char *, fsnode *, fsinfo_t *);
52 static int chfs_create_image(const char *, fsinfo_t *);
53 static int chfs_populate_dir(const char *, fsnode *, fsnode *, fsinfo_t *);
54 
55 
56 void
chfs_prep_opts(fsinfo_t * fsopts)57 chfs_prep_opts(fsinfo_t *fsopts)
58 {
59           chfs_opt_t *chfs_opts = ecalloc(1, sizeof(*chfs_opts));
60 
61           const option_t chfs_options[] = {
62                     { 'p', "pagesize", &chfs_opts->pagesize, OPT_INT32,
63                       1, INT_MAX, "page size" },
64                     { 'e', "eraseblock", &chfs_opts->eraseblock, OPT_INT32,
65                       1, INT_MAX, "eraseblock size" },
66                     { 'm', "mediatype", &chfs_opts->mediatype, OPT_INT32,
67                       0, 1, "type of the media, 0 (nor) or 1 (nand)" },
68                     { .name = NULL }
69           };
70 
71           chfs_opts->pagesize = -1;
72           chfs_opts->eraseblock = -1;
73           chfs_opts->mediatype = -1;
74 
75           fsopts->size = 0;
76           fsopts->fs_specific = chfs_opts;
77           fsopts->fs_options = copy_opts(chfs_options);
78 }
79 
80 void
chfs_cleanup_opts(fsinfo_t * fsopts)81 chfs_cleanup_opts(fsinfo_t *fsopts)
82 {
83           free(fsopts->fs_specific);
84           free(fsopts->fs_options);
85 }
86 
87 int
chfs_parse_opts(const char * option,fsinfo_t * fsopts)88 chfs_parse_opts(const char *option, fsinfo_t *fsopts)
89 {
90 
91           assert(option != NULL);
92           assert(fsopts != NULL);
93 
94           return set_option(fsopts->fs_options, option, NULL, 0) != -1;
95 }
96 
97 void
chfs_makefs(const char * image,const char * dir,fsnode * root,fsinfo_t * fsopts)98 chfs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
99 {
100           struct timeval      start;
101 
102           assert(image != NULL);
103           assert(dir != NULL);
104           assert(root != NULL);
105           assert(fsopts != NULL);
106 
107           TIMER_START(start);
108           chfs_validate(dir, root, fsopts);
109           TIMER_RESULTS(start, "chfs_validate");
110 
111           printf("Creating `%s'\n", image);
112           TIMER_START(start);
113           if (chfs_create_image(image, fsopts) == -1) {
114                     errx(EXIT_FAILURE, "Image file `%s' not created", image);
115           }
116           TIMER_RESULTS(start, "chfs_create_image");
117 
118           fsopts->curinode = CHFS_ROOTINO;
119           root->inode->ino = CHFS_ROOTINO;
120 
121           printf("Populating `%s'\n", image);
122           TIMER_START(start);
123           write_eb_header(fsopts);
124           if (!chfs_populate_dir(dir, root, root, fsopts)) {
125                     errx(EXIT_FAILURE, "Image file `%s' not populated", image);
126           }
127           TIMER_RESULTS(start, "chfs_populate_dir");
128 
129           padblock(fsopts);
130 
131           if (close(fsopts->fd) == -1) {
132                     err(EXIT_FAILURE, "Closing `%s'", image);
133           }
134           fsopts->fd = -1;
135 
136           printf("Image `%s' complete\n", image);
137 }
138 
139 static void
chfs_validate(const char * dir,fsnode * root,fsinfo_t * fsopts)140 chfs_validate(const char* dir, fsnode *root, fsinfo_t *fsopts)
141 {
142           chfs_opt_t *chfs_opts;
143           assert(dir != NULL);
144           assert(root != NULL);
145           assert(fsopts != NULL);
146 
147           chfs_opts = fsopts->fs_specific;
148 
149           if (chfs_opts->pagesize == -1) {
150                     chfs_opts->pagesize = DEFAULT_PAGESIZE;
151           }
152           if (chfs_opts->eraseblock == -1) {
153                     chfs_opts->eraseblock = DEFAULT_ERASEBLOCK;
154           }
155           if (chfs_opts->mediatype == -1) {
156                     chfs_opts->mediatype = DEFAULT_MEDIATYPE;
157           }
158 }
159 
160 static int
chfs_create_image(const char * image,fsinfo_t * fsopts)161 chfs_create_image(const char *image, fsinfo_t *fsopts)
162 {
163           assert(image != NULL);
164           assert(fsopts != NULL);
165 
166           if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
167                     warn("Can't open `%s' for writing", image);
168                     return -1;
169           }
170 
171           return fsopts->fd;
172 }
173 
174 static int
chfs_populate_dir(const char * dir,fsnode * root,fsnode * parent,fsinfo_t * fsopts)175 chfs_populate_dir(const char *dir, fsnode *root, fsnode *parent,
176     fsinfo_t *fsopts)
177 {
178           fsnode *cur;
179           char path[MAXPATHLEN + 1];
180 
181           assert(dir != NULL);
182           assert(root != NULL);
183           assert(fsopts != NULL);
184 
185           for (cur = root->next; cur != NULL; cur = cur->next) {
186                     if ((cur->inode->flags & FI_ALLOCATED) == 0) {
187                               cur->inode->flags |= FI_ALLOCATED;
188                               if (cur != root) {
189                                         fsopts->curinode++;
190                                         cur->inode->ino = fsopts->curinode;
191                                         cur->parent = parent;
192                               }
193                     }
194 
195                     if (cur->inode->flags & FI_WRITTEN) {
196                               continue; // hard link
197                     }
198                     cur->inode->flags |= FI_WRITTEN;
199 
200                     write_vnode(fsopts, cur);
201                     write_dirent(fsopts, cur);
202                     if (!S_ISDIR(cur->type & S_IFMT)) {
203                               write_file(fsopts, cur, dir);
204                     }
205           }
206 
207           for (cur = root; cur != NULL; cur = cur->next) {
208                     if (cur->child == NULL) {
209                               continue;
210                     }
211                     if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir,
212                         cur->name) >= sizeof(path)) {
213                               errx(EXIT_FAILURE, "Pathname too long");
214                     }
215                     if (!chfs_populate_dir(path, cur->child, cur, fsopts)) {
216                               return 0;
217                     }
218           }
219 
220           return 1;
221 }
222