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
223