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