]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/mkfs.c
audiohda: fix syntax error
[plan9front.git] / sys / src / cmd / disk / mkfs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <disk.h>
4 #include <auth.h>
5 #include <bio.h>
6
7 enum{
8         LEN = 4096,
9
10         /*
11          * types of destination file sytems
12          */
13         Fs = 0,
14         Archive,
15 };
16
17 void    protowarn(char *msg, void *);
18 void    protoenum(char *new, char *old, Dir *d, void *);
19
20 void    arch(Dir*);
21 void    copy(Dir*);
22 void    error(char *, ...);
23 void    mkdir(Dir*);
24 int     uptodate(Dir*, char*);
25 void    usage(void);
26 void    warn(char *, ...);
27
28 Biobufhdr bout;                 /* stdout when writing archive */
29 uchar   boutbuf[2*LEN];
30 char    newfile[LEN];
31 char    oldfile[LEN];
32 char    *proto;
33 char    *oldroot;
34 char    *newroot;
35 char    *prog = "mkfs";
36 char    *buf;
37 char    *zbuf;
38 int     buflen = 1024-8;
39 int     verb;
40 int     modes;
41 int     ream;
42 int     debug;
43 int     xflag;
44 int     oflag;
45 int     sfd;
46 int     fskind;                 /* Fs, Archive */
47 int     setuid;                 /* on Fs: set uid and gid? */
48 char    *user;
49
50 void
51 main(int argc, char **argv)
52 {
53         int i, errs;
54
55         quotefmtinstall();
56         user = getuser();
57         oldroot = "";
58         newroot = "/n/newfs";
59         fskind = Fs;
60         ARGBEGIN{
61         case 'a':
62                 fskind = Archive;
63                 newroot = "";
64                 Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf);
65                 break;
66         case 'd':
67                 if(fskind != Fs) {
68                         fprint(2, "cannot use -d with -a\n");
69                         usage();
70                 }
71                 fskind = Fs;
72                 newroot = EARGF(usage());
73                 break;
74         case 'D':
75                 debug = 1;
76                 break;
77         case 'p':
78                 modes = 1;
79                 break;
80         case 'r':
81                 ream = 1;
82                 break;
83         case 's':
84                 oldroot = EARGF(usage());
85                 break;
86         case 'U':
87                 setuid = 1;
88                 break;
89         case 'v':
90                 verb = 1;
91                 break;
92         case 'o':
93                 oflag = 1;
94                 break;
95         case 'x':
96                 xflag = 1;
97                 break;
98         case 'z':
99                 buflen = atoi(EARGF(usage()))-8;
100                 break;
101         default:
102                 usage();
103         }ARGEND
104
105         if(!argc)
106                 usage();
107
108         if((xflag || oflag) && fskind != Archive){
109                 fprint(2, "cannot use -x and -o without -a\n");
110                 usage();
111         }
112
113         buf = malloc(buflen);
114         zbuf = malloc(buflen);
115         memset(zbuf, 0, buflen);
116
117         errs = 0;
118         for(i = 0; i < argc; i++){
119                 proto = argv[i];
120                 fprint(2, "processing %q\n", proto);
121                 if(rdproto(proto, oldroot, protoenum, protowarn, nil) < 0){
122                         fprint(2, "%q: can't open %q: skipping\n", prog, proto);
123                         errs++;
124                         continue;
125                 }
126         }
127         fprint(2, "file system made\n");
128         if(errs)
129                 exits("skipped protos");
130         if(fskind == Archive){
131                 if(!xflag && !oflag)
132                         Bprint(&bout, "end of archive\n");
133                 Bterm(&bout);
134         }
135         exits(0);
136 }
137
138 /*
139  * check if file to is up to date with
140  * respect to the file represented by df
141  */
142 int
143 uptodate(Dir *df, char *to)
144 {
145         int ret;
146         Dir *dt;
147
148         if(fskind == Archive || ream || (dt = dirstat(to)) == nil)
149                 return 0;
150         ret = dt->mtime >= df->mtime;
151         free(dt);
152         return ret;
153 }
154
155 void
156 copy(Dir *d)
157 {
158         char cptmp[LEN], *p;
159         int f, t, n, needwrite, nowarnyet = 1;
160         vlong tot, len;
161         Dir nd;
162
163         f = open(oldfile, OREAD);
164         if(f < 0){
165                 warn("can't open %q: %r", oldfile);
166                 return;
167         }
168         t = -1;
169         if(fskind == Archive)
170                 arch(d);
171         else{
172                 strcpy(cptmp, newfile);
173                 p = utfrrune(cptmp, L'/');
174                 if(!p)
175                         error("internal temporary file error");
176                 strcpy(p+1, "__mkfstmp");
177                 t = create(cptmp, OWRITE, 0666);
178                 if(t < 0){
179                         warn("can't create %q: %r", newfile);
180                         close(f);
181                         return;
182                 }
183         }
184
185         needwrite = 0;
186         for(tot = 0; tot < d->length; tot += n){
187                 len = d->length - tot;
188                 /* don't read beyond d->length */
189                 if (len > buflen)
190                         len = buflen;
191                 n = read(f, buf, len);
192                 if(n <= 0) {
193                         if(n < 0 && nowarnyet) {
194                                 warn("can't read %q: %r", oldfile);
195                                 nowarnyet = 0;
196                         }
197                         /*
198                          * don't quit: pad to d->length (in pieces) to agree
199                          * with the length in the header, already emitted.
200                          */
201                         memset(buf, 0, len);
202                         n = len;
203                 }
204                 if(fskind == Archive){
205                         if(Bwrite(&bout, buf, n) != n)
206                                 error("write error: %r");
207                 }else if(memcmp(buf, zbuf, n) == 0){
208                         if(seek(t, n, 1) < 0)
209                                 error("can't write zeros to %q: %r", newfile);
210                         needwrite = 1;
211                 }else{
212                         if(write(t, buf, n) < n)
213                                 error("can't write %q: %r", newfile);
214                         needwrite = 0;
215                 }
216         }
217         close(f);
218         if(needwrite){
219                 if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1)
220                         error("can't write zero at end of %q: %r", newfile);
221         }
222         if(tot != d->length){
223                 /* this should no longer happen */
224                 warn("wrong number of bytes written to %q (was %lld should be %lld)\n",
225                         newfile, tot, d->length);
226                 if(fskind == Archive){
227                         warn("seeking to proper position\n");
228                         /* does no good if stdout is a pipe */
229                         Bseek(&bout, d->length - tot, 1);
230                 }
231         }
232         if(fskind == Archive)
233                 return;
234         remove(newfile);
235         nulldir(&nd);
236         nd.mode = d->mode;
237         nd.gid = d->gid;
238         nd.mtime = d->mtime;
239         nd.name = d->name;
240         if(dirfwstat(t, &nd) < 0)
241                 error("can't move tmp file to %q: %r", newfile);
242         nulldir(&nd);
243         nd.uid = d->uid;
244         dirfwstat(t, &nd);
245         close(t);
246 }
247
248 void
249 mkdir(Dir *d)
250 {
251         Dir *d1;
252         Dir nd;
253         int fd;
254
255         if(fskind == Archive){
256                 arch(d);
257                 return;
258         }
259         fd = create(newfile, OREAD, d->mode);
260         nulldir(&nd);
261         nd.mode = d->mode;
262         nd.gid = d->gid;
263         nd.mtime = d->mtime;
264         if(fd < 0){
265                 if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){
266                         free(d1);
267                         error("can't create %q", newfile);
268                 }
269                 free(d1);
270                 if(dirwstat(newfile, &nd) < 0)
271                         warn("can't set modes for %q: %r", newfile);
272                 nulldir(&nd);
273                 nd.uid = d->uid;
274                 dirwstat(newfile, &nd);
275                 return;
276         }
277         if(dirfwstat(fd, &nd) < 0)
278                 warn("can't set modes for %q: %r", newfile);
279         nulldir(&nd);
280         nd.uid = d->uid;
281         dirfwstat(fd, &nd);
282         close(fd);
283 }
284
285 void
286 arch(Dir *d)
287 {
288         Bprint(&bout, "%q %luo %q %q %lud %lld\n",
289                 newfile, d->mode, d->uid, d->gid, d->mtime, d->length);
290 }
291
292 void
293 protowarn(char *msg, void *)
294 {
295         warn("%s", msg);
296 }
297
298 void
299 protoenum(char *new, char *old, Dir *d, void *)
300 {
301         Dir nd;
302
303         sprint(newfile, "%s%s", newroot, new);
304         sprint(oldfile, "%s", old);
305
306         if(oflag){
307                 if(!(d->mode & DMDIR))
308                         Bprint(&bout, "%q\n", cleanname(oldfile));
309                 return;
310         }
311         if(xflag){
312                 Bprint(&bout, "%q\t%ld\t%lld\n", new, d->mtime, d->length);
313                 return;
314         }
315         if(verb && (fskind == Archive || ream))
316                 fprint(2, "%q\n", new);
317         if(fskind == Fs && !setuid){
318                 d->uid = "";
319                 d->gid = "";
320         }
321         if(!uptodate(d, newfile)){
322                 if(verb && (fskind != Archive && ream == 0))
323                         fprint(2, "%q\n", new);
324                 if(d->mode & DMDIR)
325                         mkdir(d);
326                 else
327                         copy(d);
328         }else if(modes){
329                 nulldir(&nd);
330                 nd.mode = d->mode;
331                 nd.gid = d->gid;
332                 nd.mtime = d->mtime;
333                 if(verb && (fskind != Archive && ream == 0))
334                         fprint(2, "%q\n", new);
335                 if(dirwstat(newfile, &nd) < 0)
336                         warn("can't set modes for %q: %r", new);
337                 nulldir(&nd);
338                 nd.uid = d->uid;
339                 dirwstat(newfile, &nd);
340         }
341 }
342
343 void
344 error(char *fmt, ...)
345 {
346         char buf[1024];
347         va_list arg;
348
349         sprint(buf, "%q: %q: ", prog, proto);
350         va_start(arg, fmt);
351         vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
352         va_end(arg);
353         fprint(2, "%s\n", buf);
354         exits(0);
355 }
356
357 void
358 warn(char *fmt, ...)
359 {
360         char buf[1024];
361         va_list arg;
362
363         sprint(buf, "%q: %q: ", prog, proto);
364         va_start(arg, fmt);
365         vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
366         va_end(arg);
367         fprint(2, "%s\n", buf);
368 }
369
370 void
371 usage(void)
372 {
373         fprint(2, "usage: %q [-adprvoxUD] [-d root] [-s source] [-z n] proto ...\n", prog);
374         exits("usage");
375 }