1 /* v/sist.c
2 **
3 */
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <uv.h>
11 
12 #include "all.h"
13 #include "vere/vere.h"
14 
15 #if defined(U3_OS_linux)
16 #include <stdio_ext.h>
17 #define fpurge(fd) __fpurge(fd)
18 #define DEVRANDOM "/dev/urandom"
19 #else
20 #define DEVRANDOM "/dev/random"
21 #endif
22 
23 
24 /* u3_sist_pack(): write a blob to disk, transferring.
25 */
26 c3_d
u3_sist_pack(c3_w tem_w,c3_w typ_w,c3_w * bob_w,c3_w len_w)27 u3_sist_pack(c3_w tem_w, c3_w typ_w, c3_w* bob_w, c3_w len_w)
28 {
29   u3_ulog* lug_u = &u3Z->lug_u;
30   c3_d     tar_d;
31   u3_ular  lar_u;
32 
33   tar_d = lug_u->len_d + len_w;
34 
35   lar_u.tem_w = tem_w;
36   lar_u.typ_w = typ_w;
37   lar_u.syn_w = u3r_mug_d(tar_d);
38   lar_u.mug_w = u3r_mug_both(u3r_mug_words(bob_w, len_w),
39                                u3r_mug_both(u3r_mug(lar_u.tem_w),
40                                               u3r_mug(lar_u.typ_w)));
41   lar_u.ent_d = u3A->ent_d;
42   u3A->ent_d++;
43   lar_u.len_w = len_w;
44 
45   if ( -1 == lseek64(lug_u->fid_i, 4ULL * tar_d, SEEK_SET) ) {
46     perror("lseek");
47     uL(fprintf(uH, "sist_pack: seek failed\n"));
48     c3_assert(0);
49   }
50   if ( sizeof(lar_u) != write(lug_u->fid_i, &lar_u, sizeof(lar_u)) ) {
51     perror("write");
52     uL(fprintf(uH, "sist_pack: write failed\n"));
53     c3_assert(0);
54   }
55   if ( -1 == lseek64(lug_u->fid_i, 4ULL * lug_u->len_d, SEEK_SET) ) {
56     perror("lseek");
57     uL(fprintf(uH, "sist_pack: seek failed\n"));
58     c3_assert(0);
59   }
60 #if 0
61   uL(fprintf(uH, "sist_pack: write %" PRIu64 ", %" PRIu64 ": lar ent %" PRIu64 ", len %d, mug %x\n",
62                  lug_u->len_d,
63                  tar_d,
64                  lar_u.ent_d,
65                  lar_u.len_w,
66                  lar_u.mug_w));
67 #endif
68   if ( (4 * len_w) != write(lug_u->fid_i, bob_w, (4 * len_w)) ) {
69     perror("write");
70     uL(fprintf(uH, "sist_pack: write failed\n"));
71     c3_assert(0);
72   }
73   lug_u->len_d += (c3_d)(lar_u.len_w + c3_wiseof(lar_u));
74   free(bob_w);
75 
76   //  Sync.  Or, what goes by sync.
77   {
78     fsync(lug_u->fid_i);    //  fsync is almost useless, F_FULLFSYNC too slow
79 #if defined(U3_OS_linux)
80     fdatasync(lug_u->fid_i);
81 #elif defined(U3_OS_osx)
82     fcntl(lug_u->fid_i, F_FULLFSYNC);
83 #elif defined(U3_OS_bsd)
84     fsync(lug_u->fid_i);
85 #else
86 #   error "port: datasync"
87 #endif
88   }
89 
90   return u3A->ent_d;
91 }
92 
93 /* u3_sist_put(): moronic key-value store put.
94 */
95 void
u3_sist_put(const c3_c * key_c,const c3_y * val_y,size_t siz_i)96 u3_sist_put(const c3_c* key_c, const c3_y* val_y, size_t siz_i)
97 {
98   c3_c ful_c[2048];
99   c3_i ret_i;
100   c3_i fid_i;
101 
102   ret_i = snprintf(ful_c, 2048, "%s/.urb/sis/_%s", u3_Host.dir_c, key_c);
103   c3_assert(ret_i < 2048);
104 
105   if ( (fid_i = open(ful_c, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0 ) {
106     uL(fprintf(uH, "sist: could not put %s\n", key_c));
107     perror("open");
108     u3_lo_bail();
109   }
110   if ( (ret_i = write(fid_i, val_y, siz_i)) != siz_i ) {
111     uL(fprintf(uH, "sist: could not write %s\n", key_c));
112     if ( ret_i < 0 ) {
113       perror("write");
114     }
115     u3_lo_bail();
116   }
117   ret_i = c3_sync(fid_i);
118   if ( ret_i < 0 ) {
119     perror("sync");
120   }
121   ret_i = close(fid_i);
122   c3_assert(0 == ret_i);
123 }
124 
125 /* u3_sist_has(): moronic key-value store existence check.
126 */
127 ssize_t
u3_sist_has(const c3_c * key_c)128 u3_sist_has(const c3_c* key_c)
129 {
130   c3_c        ful_c[2048];
131   c3_i        ret_i;
132   struct stat sat_u;
133 
134   ret_i = snprintf(ful_c, 2048, "%s/.urb/sis/_%s", u3_Host.dir_c, key_c);
135   c3_assert(ret_i < 2048);
136 
137   if ( (ret_i = stat(ful_c, &sat_u)) < 0 ) {
138     if ( errno == ENOENT ) {
139       return -1;
140     }
141     else {
142       uL(fprintf(uH, "sist: could not stat %s\n", key_c));
143       perror("stat");
144       u3_lo_bail();
145     }
146   }
147   else {
148     return sat_u.st_size;
149   }
150   c3_assert(!"not reached");
151 }
152 
153 /* u3_sist_get(): moronic key-value store get.
154 */
155 void
u3_sist_get(const c3_c * key_c,c3_y * val_y)156 u3_sist_get(const c3_c* key_c, c3_y* val_y)
157 {
158   c3_c        ful_c[2048];
159   c3_i        ret_i;
160   c3_i        fid_i;
161   struct stat sat_u;
162 
163   ret_i = snprintf(ful_c, 2048, "%s/.urb/sis/_%s", u3_Host.dir_c, key_c);
164   c3_assert(ret_i < 2048);
165 
166   if ( (fid_i = open(ful_c, O_RDONLY)) < 0 ) {
167     uL(fprintf(uH, "sist: could not get %s\n", key_c));
168     perror("open");
169     u3_lo_bail();
170   }
171   if ( (ret_i = fstat(fid_i, &sat_u)) < 0 ) {
172     uL(fprintf(uH, "sist: could not stat %s\n", key_c));
173     perror("fstat");
174     u3_lo_bail();
175   }
176   if ( (ret_i = read(fid_i, val_y, sat_u.st_size)) != sat_u.st_size ) {
177     uL(fprintf(uH, "sist: could not read %s\n", key_c));
178     if ( ret_i < 0 ) {
179       perror("read");
180     }
181     u3_lo_bail();
182   }
183   ret_i = close(fid_i);
184   c3_assert(0 == ret_i);
185 }
186 
187 /* u3_sist_nil(): moronic key-value store rm.
188 */
189 void
u3_sist_nil(const c3_c * key_c)190 u3_sist_nil(const c3_c* key_c)
191 {
192   c3_c ful_c[2048];
193   c3_i ret_i;
194 
195   ret_i = snprintf(ful_c, 2048, "%s/.urb/sis/_%s", u3_Host.dir_c, key_c);
196   c3_assert(ret_i < 2048);
197 
198   if ( (ret_i = unlink(ful_c)) < 0 ) {
199     if ( errno == ENOENT ) {
200       return;
201     }
202     else {
203       uL(fprintf(uH, "sist: could not unlink %s\n", key_c));
204       perror("unlink");
205       u3_lo_bail();
206     }
207   }
208 }
209 
210 /* _sist_suck(): past failure.
211 */
212 static void
_sist_suck(u3_noun ovo,u3_noun gon)213 _sist_suck(u3_noun ovo, u3_noun gon)
214 {
215   uL(fprintf(uH, "sing: ovum failed!\n"));
216   {
217     c3_c* hed_c = u3r_string(u3h(u3t(ovo)));
218 
219     uL(fprintf(uH, "fail %s\n", hed_c));
220     free(hed_c);
221   }
222 
223   u3_lo_punt(2, u3kb_flop(u3k(u3t(gon))));
224   // u3_loom_exit();
225 #if 1
226   u3_lo_exit();
227 
228   exit(1);
229 #else
230   u3z(ovo); u3z(gon);
231 #endif
232 }
233 
234 /* _sist_sing(): replay ovum from the past, time already set.
235 */
236 static void
_sist_sing(u3_noun ovo)237 _sist_sing(u3_noun ovo)
238 {
239   u3_noun gon = u3m_soft(0, u3v_poke, u3k(ovo));
240 
241   if ( u3_blip != u3h(gon) ) {
242     _sist_suck(ovo, gon);
243   }
244   else {
245     u3_noun vir = u3k(u3h(u3t(gon)));
246     u3_noun cor = u3k(u3t(u3t(gon)));
247     u3_noun nug;
248 
249     u3z(gon);
250     nug = u3v_nick(vir, cor);
251 
252     if ( u3_blip != u3h(nug) ) {
253       _sist_suck(ovo, nug);
254     }
255     else {
256       vir = u3h(u3t(nug));
257       cor = u3k(u3t(u3t(nug)));
258 
259       while ( u3_nul != vir ) {
260         u3_noun fex = u3h(vir);
261         u3_noun fav = u3t(fex);
262 
263         if ( (c3__init == u3h(fav)) || (c3__inuk == u3h(fav)) ) {
264           u3A->own = u3nc(u3k(u3t(fav)), u3A->own);
265         }
266         vir = u3t(vir);
267       }
268       u3z(nug);
269       u3z(u3A->roc);
270       u3A->roc = cor;
271     }
272     u3z(ovo);
273   }
274 }
275 
276 
277 /* _sist_home(): remains of "create ship directory" after refactor to u3m_boot().
278 */
279 static void
_sist_home()280 _sist_home()
281 {
282 #if 1
283   //  Copy zod files, if we're generating a carrier.
284   //
285   if ( u3_Host.ops_u.imp_c ) {
286     u3_unix_ef_initial_into();
287   }
288 #endif
289 }
290 
291 /* _sist_cask(): ask for a passcode.
292 */
293 static u3_noun
_sist_cask(c3_c * dir_c,u3_noun nun)294 _sist_cask(c3_c* dir_c, u3_noun nun)
295 {
296   c3_c   paw_c[60];
297   u3_noun key;
298 
299   uH;
300   while ( 1 ) {
301     printf("passcode for %s%s? ~", dir_c, (c3y == nun) ? " [none]" : "");
302 
303     paw_c[0] = 0;
304     c3_fpurge(stdin);
305     fgets(paw_c, 59, stdin);
306 
307     if ( '\n' == paw_c[0] ) {
308       if ( c3y == nun ) {
309         key = 0; break;
310       }
311       else {
312         continue;
313       }
314     }
315     else {
316       c3_c* say_c = c3_malloc(strlen(paw_c) + 2);
317       u3_noun say;
318 
319       say_c[0] = '~';
320       say_c[1] = 0;
321       strncat(say_c, paw_c, strlen(paw_c) - 1);
322 
323       say = u3do("slay", u3i_string(say_c));
324       if ( (u3_nul == say) ||
325            (u3_blip != u3h(u3t(say))) ||
326            ('p' != u3h(u3t(u3t(say)))) )
327       {
328         printf("invalid passcode\n");
329         continue;
330       }
331       key = u3k(u3t(u3t(u3t(say))));
332 
333       u3z(say);
334       break;
335     }
336   }
337   uL(0);
338   return key;
339 }
340 
341 /* _sist_text(): ask for a name string.
342 */
343 static u3_noun
_sist_text(c3_c * pom_c)344 _sist_text(c3_c* pom_c)
345 {
346   c3_c   paw_c[180];
347   u3_noun say;
348 
349   uH;
350   while ( 1 ) {
351     printf("%s: ", pom_c);
352 
353     paw_c[0] = 0;
354     fpurge(stdin);
355     fgets(paw_c, 179, stdin);
356 
357     if ( '\n' == paw_c[0] ) {
358       continue;
359     }
360     else {
361       c3_w len_w = strlen(paw_c);
362 
363       if ( paw_c[len_w - 1] == '\n' ) {
364         paw_c[len_w-1] = 0;
365       }
366       say = u3i_string(paw_c);
367       break;
368     }
369   }
370   uL(0);
371   return say;
372 }
373 
374 #if 0
375 /* _sist_bask(): ask a yes or no question.
376 */
377 static u3_noun
378 _sist_bask(c3_c* pop_c, u3_noun may)
379 {
380   u3_noun yam;
381 
382   uH;
383   while ( 1 ) {
384     c3_c ans_c[3];
385 
386     printf("%s [y/n]? ", pop_c);
387     ans_c[0] = 0;
388 
389     c3_fpurge(stdin);
390     fgets(ans_c, 2, stdin);
391 
392     if ( (ans_c[0] != 'y') && (ans_c[0] != 'n') ) {
393       continue;
394     } else {
395       yam = (ans_c[0] != 'n') ? c3y : c3n;
396       break;
397     }
398   }
399   uL(0);
400   return yam;
401 }
402 #endif
403 
404 /* u3_sist_rand(): fill a 512-bit (16-word) buffer.
405 */
406 void
u3_sist_rand(c3_w * rad_w)407 u3_sist_rand(c3_w* rad_w)
408 {
409   c3_i fid_i = open(DEVRANDOM, O_RDONLY);
410 
411   if ( 64 != read(fid_i, (c3_y*) rad_w, 64) ) {
412     c3_assert(!"lo_rand");
413   }
414   close(fid_i);
415 }
416 
417 /* _sist_fast(): offer to save passcode by mug in home directory.
418 */
419 static void
_sist_fast(u3_noun pas,c3_l key_l)420 _sist_fast(u3_noun pas, c3_l key_l)
421 {
422   c3_c    ful_c[2048];
423   c3_c*   hom_c = u3_Host.dir_c;
424   u3_noun gum   = u3dc("scot", 'p', key_l);
425   c3_c*   gum_c = u3r_string(gum);
426   u3_noun yek   = u3dc("scot", 'p', pas);
427   c3_c*   yek_c = u3r_string(yek);
428 
429   printf("saving passcode in %s/.urb/code.%s\r\n", hom_c, gum_c);
430   printf("(for real security, write it down and delete the file...)\r\n");
431   {
432     c3_i fid_i;
433 
434     snprintf(ful_c, 2048, "%s/.urb/code.%s", hom_c, gum_c);
435     if ( (fid_i = open(ful_c, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0 ) {
436       uL(fprintf(uH, "fast: could not save %s\n", ful_c));
437       u3_lo_bail();
438     }
439     write(fid_i, yek_c, strlen(yek_c));
440     close(fid_i);
441   }
442   free(gum_c);
443   u3z(gum);
444 
445   free(yek_c);
446   u3z(yek);
447 }
448 
449 /* _sist_staf(): try to load passcode by mug from home directory.
450 */
451 static u3_noun
_sist_staf(c3_l key_l)452 _sist_staf(c3_l key_l)
453 {
454   c3_c    ful_c[2048];
455   c3_c*   hom_c = u3_Host.dir_c;
456   u3_noun gum   = u3dc("scot", 'p', key_l);
457   c3_c*   gum_c = u3r_string(gum);
458   u3_noun txt;
459 
460   snprintf(ful_c, 2048, "%s/.urb/code.%s", hom_c, gum_c);
461   free(gum_c);
462   u3z(gum);
463   txt = u3_walk_safe(ful_c);
464 
465   if ( 0 == txt ) {
466     uL(fprintf(uH, "staf: no passcode %s\n", ful_c));
467     return 0;
468   }
469   else {
470     // c3_c* txt_c = u3r_string(txt);
471     u3_noun say = u3do("slay", txt);
472     u3_noun pas;
473 
474 
475     if ( (u3_nul == say) ||
476          (u3_blip != u3h(u3t(say))) ||
477          ('p' != u3h(u3t(u3t(say)))) )
478     {
479       uL(fprintf(uH, "staf: %s is corrupt\n", ful_c));
480       u3z(say);
481       return 0;
482     }
483     uL(fprintf(uH, "loaded passcode from %s\n", ful_c));
484     pas = u3k(u3t(u3t(u3t(say))));
485 
486     u3z(say);
487     return pas;
488   }
489 }
490 
491 /* _sist_fatt(): stretch a 64-bit passcode to make a 128-bit key.
492 */
493 static u3_noun
_sist_fatt(c3_l sal_l,u3_noun pas)494 _sist_fatt(c3_l sal_l, u3_noun pas)
495 {
496   c3_w i_w;
497   u3_noun key = pas;
498 
499   //  XX use scrypt() - this is a stupid iterated hash
500   //
501   for ( i_w = 0; i_w < 32768; i_w++ ) {
502     key = u3dc("shaf", sal_l, key);
503   }
504   return key;
505 }
506 
507 /* _sist_zest(): create a new, empty record.
508 */
509 static void
_sist_zest()510 _sist_zest()
511 {
512   struct stat buf_b;
513   c3_i        fid_i;
514   c3_c        ful_c[8193];
515   c3_l        sal_l;
516 
517   //  Create the ship directory.
518   //
519   _sist_home();
520 
521   //  Create the record file.
522   {
523     c3_i pig_i = O_CREAT | O_WRONLY | O_EXCL;
524 #ifdef O_DSYNC
525     pig_i |= O_DSYNC;
526 #endif
527     snprintf(ful_c, 2048, "%s/.urb/egz.hope", u3_Host.dir_c);
528 
529     if ( ((fid_i = open(ful_c, pig_i, 0600)) < 0) ||
530          (fstat(fid_i, &buf_b) < 0) )
531     {
532       uL(fprintf(uH, "can't create record (%s)\n", ful_c));
533       u3_lo_bail();
534     }
535 #ifdef F_NOCACHE
536     if ( -1 == fcntl(fid_i, F_NOCACHE, 1) ) {
537       uL(fprintf(uH, "zest: can't uncache %s: %s\n", ful_c, strerror(errno)));
538       u3_lo_bail();
539     }
540 #endif
541     u3Z->lug_u.fid_i = fid_i;
542   }
543 
544   //  Generate a 31-bit salt.
545   //
546   {
547     c3_w rad_w[16];
548 
549     c3_rand(rad_w);
550     sal_l = (0x7fffffff & rad_w[0]);
551   }
552 
553   //  Create and save a passcode.
554   //
555   {
556     c3_w rad_w[16];
557     u3_noun pas;
558 
559     c3_rand(rad_w);
560     pas = u3i_words(2, rad_w);
561 
562     u3A->key = _sist_fatt(sal_l, u3k(pas));
563     _sist_fast(pas, u3r_mug(u3A->key));
564   }
565 
566   //  Write the header.
567   {
568     u3_uled led_u;
569 
570     led_u.mag_l = u3r_mug('g');
571     led_u.kno_w = 163;
572 
573     if ( 0 == u3A->key ) {
574       led_u.key_l = 0;
575     } else {
576       led_u.key_l = u3r_mug(u3A->key);
577 
578       c3_assert(!(led_u.key_l >> 31));
579     }
580     led_u.sal_l = sal_l;
581     led_u.sev_l = u3A->sev_l;
582     led_u.tno_l = 1;
583 
584     if ( sizeof(led_u) != write(fid_i, &led_u, sizeof(led_u)) ) {
585       uL(fprintf(uH, "can't write record (%s)\n", ful_c));
586       u3_lo_bail();
587     }
588 
589     u3Z->lug_u.len_d = c3_wiseof(led_u);
590   }
591 
592   //  Work through the boot events.
593   u3_raft_work();
594 }
595 
596 /* _sist_make(): boot from scratch.
597 */
598 static void
_sist_make(u3_noun fav)599 _sist_make(u3_noun fav)
600 {
601   //  Initialize ames
602   u3_ames_ef_bake();
603 
604   //  Authenticate and initialize terminal.
605   //
606   u3_term_ef_bake(fav);
607 
608   //  Create the ship directory.
609   //
610   _sist_zest();
611 }
612 
613 /* _sist_rest_nuu(): upgrade log from previous format.
614 */
615 static void
_sist_rest_nuu(u3_ulog * lug_u,u3_uled led_u,c3_c * old_c)616 _sist_rest_nuu(u3_ulog* lug_u, u3_uled led_u, c3_c* old_c)
617 {
618   c3_c    nuu_c[2048];
619   u3_noun roe = u3_nul;
620   c3_i    fid_i = lug_u->fid_i;
621   c3_i    fud_i;
622   c3_i    ret_i;
623   c3_d    end_d = lug_u->len_d;
624 
625   uL(fprintf(uH, "rest: converting log from prior format\n"));
626 
627   c3_assert(led_u.mag_l == u3r_mug('f'));
628 
629   if ( -1 == lseek64(fid_i, 4ULL * end_d, SEEK_SET) ) {
630     uL(fprintf(uH, "rest_nuu failed (a)\n"));
631     perror("lseek64");
632     u3_lo_bail();
633   }
634 
635   while ( end_d != c3_wiseof(u3_uled) ) {
636     c3_d    tar_d;
637     u3_olar lar_u;
638     c3_w*   img_w;
639     u3_noun ron;
640 
641     tar_d = (end_d - (c3_d)c3_wiseof(u3_olar));
642 
643     if ( -1 == lseek64(fid_i, 4ULL * tar_d, SEEK_SET) ) {
644       uL(fprintf(uH, "rest_nuu failed (b)\n"));
645       perror("lseek64");
646       u3_lo_bail();
647     }
648     if ( sizeof(u3_olar) != read(fid_i, &lar_u, sizeof(u3_olar)) ) {
649       uL(fprintf(uH, "rest_nuu failed (c)\n"));
650       perror("read");
651       u3_lo_bail();
652     }
653 
654     if ( lar_u.syn_w != u3r_mug_d(tar_d) ) {
655       uL(fprintf(uH, "rest_nuu failed (d)\n"));
656       u3_lo_bail();
657     }
658 
659     img_w = c3_malloc(4 * lar_u.len_w);
660     end_d = (tar_d - (c3_d)lar_u.len_w);
661 
662     if ( -1 == lseek64(fid_i, 4ULL * end_d, SEEK_SET) ) {
663       uL(fprintf(uH, "rest_nuu failed (e)\n"));
664       perror("lseek64");
665       u3_lo_bail();
666     }
667     if ( (4 * lar_u.len_w) != read(fid_i, img_w, (4 * lar_u.len_w)) ) {
668       uL(fprintf(uH, "rest_nuu failed (f)\n"));
669       perror("read");
670       u3_lo_bail();
671     }
672 
673     ron = u3i_words(lar_u.len_w, img_w);
674     free(img_w);
675 
676     if ( lar_u.mug_w != u3r_mug(ron) ) {
677       uL(fprintf(uH, "rest_nuu failed (g)\n"));
678       u3_lo_bail();
679     }
680 
681     roe = u3nc(ron, roe);
682   }
683 
684   if ( 0 != close(fid_i) ) {
685     uL(fprintf(uH, "rest: could not close\n"));
686     perror("close");
687     u3_lo_bail();
688   }
689 
690   ret_i = snprintf(nuu_c, 2048, "%s/.urb/ham.hope", u3_Host.dir_c);
691   c3_assert(ret_i < 2048);
692 
693   if ( (fud_i = open(nuu_c, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0 ) {
694     uL(fprintf(uH, "rest: can't open record (%s)\n", nuu_c));
695     perror("open");
696     u3_lo_bail();
697   }
698 
699   led_u.mag_l = u3r_mug('g');
700   if ( (sizeof(led_u) != write(fud_i, &led_u, sizeof(led_u))) ) {
701     uL(fprintf(uH, "rest: can't write header\n"));
702     perror("write");
703     u3_lo_bail();
704   }
705 
706   {
707     c3_d ent_d = 1;
708 
709     c3_assert(end_d == c3_wiseof(u3_uled));
710     while ( u3_nul != roe ) {
711       u3_noun ovo = u3k(u3h(roe));
712       u3_noun nex = u3k(u3t(roe));
713       u3_ular lar_u;
714       c3_w*   img_w;
715       c3_d    tar_d;
716 
717       lar_u.len_w = u3r_met(5, ovo);
718       tar_d = end_d + lar_u.len_w;
719       lar_u.syn_w = u3r_mug(tar_d);
720       lar_u.ent_d = ent_d;
721       lar_u.tem_w = 0;
722       lar_u.typ_w = c3__ov;
723       lar_u.mug_w = u3r_mug_both(u3r_mug(ovo),
724                                    u3r_mug_both(u3r_mug(0),
725                                                   u3r_mug(c3__ov)));
726 
727       img_w = c3_malloc(lar_u.len_w << 2);
728       u3r_words(0, lar_u.len_w, img_w, ovo);
729       u3z(ovo);
730 
731       if ( (lar_u.len_w << 2) != write(fud_i, img_w, lar_u.len_w << 2) ) {
732         uL(fprintf(uH, "rest_nuu failed (h)\n"));
733         perror("write");
734         u3_lo_bail();
735       }
736       if ( sizeof(u3_ular) != write(fud_i, &lar_u, sizeof(u3_ular)) ) {
737         uL(fprintf(uH, "rest_nuu failed (i)\n"));
738         perror("write");
739         u3_lo_bail();
740       }
741 
742       ent_d++;
743       end_d = tar_d + c3_wiseof(u3_ular);
744       u3z(roe); roe = nex;
745     }
746   }
747   if ( 0 != rename(nuu_c, old_c) ) {
748     uL(fprintf(uH, "rest_nuu failed (k)\n"));
749     perror("rename");
750     u3_lo_bail();
751   }
752   if ( -1 == lseek64(fud_i, sizeof(u3_uled), SEEK_SET) ) {
753     uL(fprintf(uH, "rest_nuu failed (l)\n"));
754     perror("lseek64");
755     u3_lo_bail();
756   }
757   lug_u->fid_i = fud_i;
758   lug_u->len_d = end_d;
759 }
760 
761 /* _sist_rest(): restore from record, or exit.
762 */
763 static void
_sist_rest()764 _sist_rest()
765 {
766   struct stat buf_b;
767   c3_i        fid_i;
768   c3_c        ful_c[2048];
769   c3_d        old_d = u3A->ent_d;
770   c3_d        las_d = 0;
771   u3_noun     roe = u3_nul;
772   u3_noun     sev_l, key_l, sal_l;
773   u3_noun     ohh = c3n;
774 
775   if ( 0 != u3A->ent_d ) {
776     u3_noun ent;
777     c3_c*   ent_c;
778 
779     ent = u3i_chubs(1, &u3A->ent_d);
780     ent = u3dc("scot", c3__ud, ent);
781     ent_c = u3r_string(ent);
782     uL(fprintf(uH, "rest: checkpoint to event %s\n", ent_c));
783     free(ent_c);
784     u3z(ent);
785   }
786 
787   //  Open the fscking file.  Does it even exist?
788   {
789     c3_i pig_i = O_RDWR;
790 #ifdef O_DSYNC
791     pig_i |= O_DSYNC;
792 #endif
793     snprintf(ful_c, 2048, "%s/.urb/egz.hope", u3_Host.dir_c);
794     if ( ((fid_i = open(ful_c, pig_i)) < 0) || (fstat(fid_i, &buf_b) < 0) ) {
795       uL(fprintf(uH, "rest: can't open record (%s)\n", ful_c));
796       u3_lo_bail();
797 
798       return;
799     }
800 #ifdef F_NOCACHE
801     if ( -1 == fcntl(fid_i, F_NOCACHE, 1) ) {
802       uL(fprintf(uH, "rest: can't uncache %s: %s\n", ful_c, strerror(errno)));
803       u3_lo_bail();
804 
805       return;
806     }
807 #endif
808     u3Z->lug_u.fid_i = fid_i;
809     u3Z->lug_u.len_d = ((buf_b.st_size + 3ULL) >> 2ULL);
810   }
811 
812   //  Check the fscking header.  It's probably corrupt.
813   {
814     u3_uled led_u;
815 
816     if ( sizeof(led_u) != read(fid_i, &led_u, sizeof(led_u)) ) {
817       uL(fprintf(uH, "record (%s) is corrupt (a)\n", ful_c));
818       u3_lo_bail();
819     }
820 
821     if ( u3r_mug('f') == led_u.mag_l ) {
822       _sist_rest_nuu(&u3Z->lug_u, led_u, ful_c);
823       fid_i = u3Z->lug_u.fid_i;
824     }
825     else if (u3r_mug('g') != led_u.mag_l ) {
826       uL(fprintf(uH, "record (%s) is obsolete (or corrupt)\n", ful_c));
827       u3_lo_bail();
828     }
829 
830     if ( led_u.kno_w != 163 ) {
831       //  XX perhaps we should actually do something here
832       //
833       uL(fprintf(uH, "rest: (not) translating events (old %d, now %d)\n",
834                      led_u.kno_w,
835                      163));
836     }
837     sev_l = led_u.sev_l;
838     sal_l = led_u.sal_l;
839     key_l = led_u.key_l;
840 
841     {
842       u3_noun old = u3dc("scot", c3__uv, sev_l);
843       u3_noun nuu = u3dc("scot", c3__uv, u3A->sev_l);
844       c3_c* old_c = u3r_string(old);
845       c3_c* nuu_c = u3r_string(nuu);
846 
847       uL(fprintf(uH, "rest: old %s, new %s\n", old_c, nuu_c));
848       free(old_c); free(nuu_c);
849 
850       u3z(old); u3z(nuu);
851     }
852     c3_assert(sev_l != u3A->sev_l);   //  1 in 2 billion, just retry
853   }
854 
855   //  Oh, and let's hope you didn't forget the fscking passcode.
856   {
857     if ( 0 != key_l ) {
858       u3_noun pas = _sist_staf(key_l);
859       u3_noun key;
860 
861       while ( 1 ) {
862         pas = pas ? pas : _sist_cask(u3_Host.dir_c, c3n);
863 
864         key = _sist_fatt(sal_l, pas);
865 
866         if ( u3r_mug(key) != key_l ) {
867           uL(fprintf(uH, "incorrect passcode\n"));
868           u3z(key);
869           pas = 0;
870         }
871         else {
872           u3z(u3A->key);
873           u3A->key = key;
874           break;
875         }
876       }
877     }
878   }
879 
880   //  Read in the fscking events.  These are probably corrupt as well.
881   {
882     c3_d    ent_d;
883     c3_d    end_d;
884     u3_noun rup = c3n;
885 
886     end_d = u3Z->lug_u.len_d;
887     ent_d = 0;
888 
889     if ( -1 == lseek64(fid_i, 4ULL * end_d, SEEK_SET) ) {
890       fprintf(stderr, "end_d %" PRIu64 "\n", end_d);
891       perror("lseek");
892       uL(fprintf(uH, "record (%s) is corrupt (c)\n", ful_c));
893       u3_lo_bail();
894     }
895 
896     while ( end_d != c3_wiseof(u3_uled) ) {
897       c3_d    tar_d = (end_d - (c3_d)c3_wiseof(u3_ular));
898       u3_ular lar_u;
899       c3_w*   img_w;
900       u3_noun ron;
901 
902       // uL(fprintf(uH, "rest: reading event at %" PRIx64 "\n", end_d));
903 
904       if ( -1 == lseek64(fid_i, 4ULL * tar_d, SEEK_SET) ) {
905         uL(fprintf(uH, "record (%s) is corrupt (d)\n", ful_c));
906         u3_lo_bail();
907       }
908       if ( sizeof(u3_ular) != read(fid_i, &lar_u, sizeof(u3_ular)) ) {
909         uL(fprintf(uH, "record (%s) is corrupt (e)\n", ful_c));
910         u3_lo_bail();
911       }
912 
913       if ( lar_u.syn_w != u3r_mug_d(tar_d) ) {
914         if ( c3n == rup ) {
915           uL(fprintf(uH, "corruption detected; attempting to fix\n"));
916           rup = c3y;
917         }
918         uL(fprintf(uH, "lar:%x mug:%x\n", lar_u.syn_w, u3r_mug_d(tar_d)));
919         end_d--; u3Z->lug_u.len_d--;
920         continue;
921       }
922       else if ( c3y == rup ) {
923         uL(fprintf(uH, "matched at %x\n", lar_u.syn_w));
924         rup = c3n;
925       }
926 
927       if ( lar_u.ent_d == 0 ) {
928         ohh = c3y;
929       }
930 
931 #if 0
932       uL(fprintf(uH, "log: read: at %d, %d: lar ent %" PRIu64 ", len %d, mug %x\n",
933                       (tar_w - lar_u.len_w),
934                       tar_w,
935                       lar_u.ent_d,
936                       lar_u.len_w,
937                       lar_u.mug_w));
938 #endif
939       if ( end_d == u3Z->lug_u.len_d ) {
940         ent_d = las_d = lar_u.ent_d;
941       }
942       else {
943         if ( lar_u.ent_d != (ent_d - 1ULL) ) {
944           uL(fprintf(uH, "record (%s) is corrupt (g)\n", ful_c));
945           uL(fprintf(uH, "lar_u.ent_d %" PRIx64 ", ent_d %" PRIx64 "\n", lar_u.ent_d, ent_d));
946           u3_lo_bail();
947         }
948         ent_d -= 1ULL;
949       }
950       end_d = (tar_d - (c3_d)lar_u.len_w);
951 
952       if ( ent_d < old_d ) {
953         /*  change to continue to check all events  */
954         break;
955       }
956 
957       img_w = c3_malloc(4 * lar_u.len_w);
958 
959       if ( -1 == lseek64(fid_i, 4ULL * end_d, SEEK_SET) ) {
960         uL(fprintf(uH, "record (%s) is corrupt (h)\n", ful_c));
961         u3_lo_bail();
962       }
963       if ( (4 * lar_u.len_w) != read(fid_i, img_w, (4 * lar_u.len_w)) ) {
964         uL(fprintf(uH, "record (%s) is corrupt (i)\n", ful_c));
965         u3_lo_bail();
966       }
967 
968       ron = u3i_words(lar_u.len_w, img_w);
969       free(img_w);
970 
971       if ( lar_u.mug_w !=
972             u3r_mug_both(u3r_mug(ron),
973                            u3r_mug_both(u3r_mug(lar_u.tem_w),
974                                           u3r_mug(lar_u.typ_w))) )
975       {
976         uL(fprintf(uH, "record (%s) is corrupt (j)\n", ful_c));
977         u3_lo_bail();
978       }
979 
980       if ( c3__ov != lar_u.typ_w ) {
981         u3z(ron);
982         continue;
983       }
984 
985 #if 0
986       // disable encryption for now
987       //
988       if ( u3A->key ) {
989         u3_noun dep;
990 
991         dep = u3dc("de:crua", u3k(u3A->key), ron);
992         if ( c3n == u3du(dep) ) {
993           uL(fprintf(uH, "record (%s) is corrupt (k)\n", ful_c));
994           u3_lo_bail();
995         }
996         else {
997           ron = u3k(u3t(dep));
998           u3z(dep);
999         }
1000       }
1001 #endif
1002       roe = u3nc(u3ke_cue(ron), roe);
1003     }
1004     u3A->ent_d = c3_max(las_d + 1ULL, old_d);
1005   }
1006 
1007   if ( u3_nul == roe ) {
1008     //  Nothing in the log that was not also in the checkpoint.
1009     //
1010     c3_assert(u3A->ent_d == old_d);
1011     if ( las_d + 1 != old_d ) {
1012       uL(fprintf(uH, "checkpoint and log disagree! las:%" PRIu64 " old:%" PRIu64 "\n",
1013                      las_d + 1, old_d));
1014       uL(fprintf(uH, "Some events appear to be missing from the log.\n"
1015                      "Please contact the authorities, "
1016                      "and do not delete your pier!\n"));
1017       u3_lo_bail();
1018     }
1019   }
1020   else {
1021     u3_noun rou = roe;
1022     c3_w    xno_w;
1023 
1024     //  Execute the fscking things.  This is pretty much certain to crash.
1025     //
1026     uL(fprintf(uH, "rest: replaying through event %" PRIu64 "\n", las_d));
1027     fprintf(uH, "---------------- playback starting----------------\n");
1028 
1029     xno_w = 0;
1030     while ( u3_nul != roe ) {
1031       u3_noun i_roe = u3h(roe);
1032       u3_noun t_roe = u3t(roe);
1033       u3_noun now = u3h(i_roe);
1034       u3_noun ovo = u3t(i_roe);
1035 
1036       u3v_time(u3k(now));
1037       if ( (c3y == u3_Host.ops_u.vno) &&
1038            ( (c3__veer == u3h(u3t(ovo)) ||
1039              (c3__vega == u3h(u3t(ovo)))) ) )
1040       {
1041         fprintf(stderr, "replay: skipped veer\n");
1042       }
1043       else if ( c3y == u3_Host.ops_u.fog &&
1044                 u3_nul == t_roe ) {
1045         fprintf(stderr, "replay: -Xwtf, skipped last event\n");
1046       }
1047       else {
1048         _sist_sing(u3k(ovo));
1049         fputc('.', stderr);
1050       }
1051 
1052       // fprintf(stderr, "playback: sing: %d\n", xno_w));
1053 
1054       roe = t_roe;
1055       xno_w++;
1056 
1057       if ( 0 == (xno_w % 1000) ) {
1058         uL(fprintf(uH, "{%d}\n", xno_w));
1059         // u3_lo_grab("rest", rou, u3_none);
1060       }
1061     }
1062     u3z(rou);
1063   }
1064   uL(fprintf(stderr, "\n---------------- playback complete----------------\n"));
1065 
1066 #if 0
1067   //  If you see this error, your record is totally fscking broken!
1068   //  Which probably serves you right.  Please consult a consultant.
1069   {
1070     if ( u3_nul == u3A->own ) {
1071       uL(fprintf(uH, "record did not install a master!\n"));
1072       u3_lo_bail();
1073     }
1074     u3A->our = u3k(u3h(u3A->own));
1075     u3A->pod = u3dc("scot", 'p', u3k(u3A->our)));
1076   }
1077 
1078   //  Now, who the fsck are you?  No, really.
1079   {
1080     u3_noun who;
1081     c3_c*   fil_c;
1082     c3_c*   who_c;
1083 
1084     if ( (fil_c = strrchr(u3_Host.dir_c, '/')) ) {
1085       fil_c++;
1086     } else fil_c = u3_Host.dir_c;
1087 
1088     who = u3dc("scot", 'p', u3k(u3A->our)));
1089     who_c = u3r_string(who);
1090     u3z(who);
1091 
1092     if ( strncmp(fil_c, who_c + 1, strlen(fil_c)) ) {
1093       uL(fprintf(uH, "record master (%s) does not match filename!\n", who_c));
1094       u3_lo_bail();
1095     }
1096     free(who_c);
1097   }
1098 #endif
1099 
1100   //  Increment sequence numbers. New logs start at 1.
1101   if ( c3y == ohh ) {
1102     uL(fprintf(uH, "rest: bumping ent_d\n"));
1103     u3_ular lar_u;
1104     c3_d    end_d;
1105     c3_d    tar_d;
1106 
1107     u3A->ent_d++;
1108     end_d = u3Z->lug_u.len_d;
1109     while ( end_d != c3_wiseof(u3_uled) ) {
1110       tar_d = end_d - c3_wiseof(u3_ular);
1111       if ( -1 == lseek64(fid_i, 4ULL * tar_d, SEEK_SET) ) {
1112         uL(fprintf(uH, "bumping sequence numbers failed (a)\n"));
1113         u3_lo_bail();
1114       }
1115       if ( sizeof(lar_u) != read(fid_i, &lar_u, sizeof(lar_u)) ) {
1116         uL(fprintf(uH, "bumping sequence numbers failed (b)\n"));
1117         u3_lo_bail();
1118       }
1119       lar_u.ent_d++;
1120       if ( -1 == lseek64(fid_i, 4ULL * tar_d, SEEK_SET) ) {
1121         uL(fprintf(uH, "bumping sequence numbers failed (c)\n"));
1122         u3_lo_bail();
1123       }
1124       if ( sizeof(lar_u) != write(fid_i, &lar_u, sizeof(lar_u)) ) {
1125         uL(fprintf(uH, "bumping sequence numbers failed (d)\n"));
1126         u3_lo_bail();
1127       }
1128       end_d = tar_d - lar_u.len_w;
1129     }
1130   }
1131 
1132   //  Rewrite the header.  Will probably corrupt the record.
1133   {
1134     u3_uled led_u;
1135 
1136     led_u.mag_l = u3r_mug('g');
1137     led_u.sal_l = sal_l;
1138     led_u.sev_l = u3A->sev_l;
1139     led_u.key_l = u3A->key ? u3r_mug(u3A->key) : 0;
1140     led_u.kno_w = 163;         //  may need actual translation!
1141     led_u.tno_l = 1;
1142 
1143     if ( (-1 == lseek64(fid_i, 0, SEEK_SET)) ||
1144          (sizeof(led_u) != write(fid_i, &led_u, sizeof(led_u))) )
1145     {
1146       uL(fprintf(uH, "record (%s) failed to rewrite\n", ful_c));
1147       u3_lo_bail();
1148     }
1149   }
1150 
1151   //  Hey, fscker!  It worked.
1152   {
1153     u3_term_ef_boil();
1154   }
1155 }
1156 
1157 /* _sist_zen(): get OS entropy.
1158 */
1159 static u3_noun
_sist_zen()1160 _sist_zen()
1161 {
1162   c3_w rad_w[16];
1163 
1164   c3_rand(rad_w);
1165   return u3i_words(16, rad_w);
1166 }
1167 
1168 /* u3_sist_boot(): restore or create.
1169 */
1170 void
u3_sist_boot(void)1171 u3_sist_boot(void)
1172 {
1173   // uL(fprintf(uH, "sist: booting\n"));
1174 
1175   if ( c3y == u3_Host.ops_u.nuu ) {
1176     u3_noun pig = u3_none;
1177 
1178     if ( 0 == u3_Host.ops_u.imp_c ) {
1179       u3_noun ten = _sist_zen();
1180       uL(fprintf(uH, "generating curve25519 key pair...\n"));
1181 
1182       pig = u3nq(c3__make, u3_nul, 11, u3nc(ten, u3_Host.ops_u.fak));
1183     }
1184     else {
1185       u3_noun imp = u3i_string(u3_Host.ops_u.imp_c);
1186       u3_noun whu = u3dc("slaw", 'p', u3k(imp));
1187 
1188       if ( (u3_nul == whu) ) {
1189         fprintf(stderr, "czar: incorrect format\r\n");
1190         u3_lo_bail();
1191       }
1192       else {
1193         u3_noun gen = u3_nul;
1194         u3_noun gun = u3_nul;
1195         if (c3n == u3_Host.ops_u.fak) {
1196           if ( 0 != u3_Host.ops_u.gen_c) {
1197             gen = u3i_string(u3_Host.ops_u.gen_c);
1198           }
1199           else {
1200             gen = _sist_text("generator"); // XX move to main.c
1201           }
1202           gun = u3dc("slaw", c3__uw, gen);
1203 
1204           if ( u3_nul == gun ) {
1205             fprintf(stderr, "czar: incorrect format\r\n");
1206             u3_lo_bail();
1207           }
1208         }
1209         else {
1210           gun = u3nc(u3_nul, u3_nul);
1211         }
1212         pig = u3nq(c3__sith,
1213                    u3k(u3t(whu)),
1214                    u3k(u3t(gun)),
1215                    u3_Host.ops_u.fak);
1216 
1217         u3z(whu); u3z(gun);
1218       }
1219       u3z(imp);
1220     }
1221     _sist_make(pig);
1222   }
1223   else {
1224     _sist_rest();
1225   }
1226 }
1227