// shouldbuild reports whether we should build this file. // It applies the same rules that are used with context tags // in package go/build, except that the GOOS and GOARCH // can appear anywhere in the file name, not just after _. // In particular, they can be the entire file name (like windows.c). // We also allow the special tag cmd_go_bootstrap. // See ../go/bootstrap.go and package go/build. static bool shouldbuild(char *file, char *dir) { char *name, *p; int i, j, ret; Buf b; Vec lines, fields; // On Plan 9, most of the libraries are already present. // The main exception is libmach which has been modified // in various places to support Go object files. if(streq(gohostos, "plan9")) { if(streq(dir, "lib9")) { name = lastelem(file); if(streq(name, "goos.c") || streq(name, "flag.c")) return 1; if(!contains(name, "plan9")) return 0; } if(streq(dir, "libbio")) return 0; } // Check file name for GOOS or GOARCH. name = lastelem(file); for(i=0; i<nelem(okgoos); i++) if(contains(name, okgoos[i]) && !streq(okgoos[i], goos)) return 0; for(i=0; i<nelem(okgoarch); i++) if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch)) return 0; // Omit test files. if(contains(name, "_test")) return 0; // cmd/go/doc.go has a giant /* */ comment before // it gets to the important detail that it is not part of // package main. We don't parse those comments, // so special case that file. if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go")) return 0; if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go")) return 0; // Check file contents for // +build lines. binit(&b); vinit(&lines); vinit(&fields); ret = 1; readfile(&b, file); splitlines(&lines, bstr(&b)); for(i=0; i<lines.len; i++) { p = lines.p[i]; while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++; if(*p == '\0') continue; if(contains(p, "package documentation")) { ret = 0; goto out; } if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) { ret = 0; goto out; } if(!hasprefix(p, "//")) break; if(!contains(p, "+build")) continue; splitfields(&fields, lines.p[i]); if(fields.len < 2 || !streq(fields.p[1], "+build")) continue; for(j=2; j<fields.len; j++) { p = fields.p[j]; if((*p == '!' && !matchfield(p+1)) || matchfield(p)) goto fieldmatch; } ret = 0; goto out; fieldmatch:; } out: bfree(&b); vfree(&lines); vfree(&fields); return ret; }
int do_restore_client_burp1(struct asfd *asfd, struct conf *conf, enum action act, int vss_restore) { int ars=0; int ret=-1; char msg[512]=""; struct sbuf *sb=NULL; // Windows needs to have the VSS data written first, and the actual data // written immediately afterwards. The server is transferring them in two // chunks. So, leave bfd open after a Windows metadata transfer. BFILE bfd; #ifdef HAVE_WIN32 binit(&bfd, 0, conf); #endif logp("doing %s\n", act_str(act)); snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act), conf->backup?conf->backup:"", conf->regex?conf->regex:""); if(asfd->write_str(asfd, CMD_GEN, msg) || asfd->read_expect(asfd, CMD_GEN, "ok")) return -1; logp("doing %s confirmed\n", act_str(act)); if(conf->send_client_cntr) { // FIX THIS // if(cntr_recv(conf)) goto end; } #if defined(HAVE_WIN32) if(act==ACTION_RESTORE) win32_enable_backup_privileges(); #endif if(!(sb=sbuf_alloc(conf))) goto end; while(1) { char *fullpath=NULL; sbuf_free_content(sb); if((ars=sbufl_fill(sb, asfd, NULL, NULL, conf->cntr))) { if(ars<0) goto end; else { // ars==1 means it ended ok. //logp("got %s end\n", act_str(act)); if(asfd->write_str(asfd, CMD_GEN, "restoreend ok")) goto end; } break; } switch(sb->path.cmd) { case CMD_DIRECTORY: case CMD_FILE: case CMD_ENC_FILE: case CMD_SOFT_LINK: case CMD_HARD_LINK: case CMD_SPECIAL: case CMD_METADATA: case CMD_ENC_METADATA: case CMD_VSS: case CMD_ENC_VSS: case CMD_VSS_T: case CMD_ENC_VSS_T: case CMD_EFS_FILE: if(conf->strip) { int s; s=strip_path_components(asfd, sb, &(sb->path.buf), conf); if(s<0) goto end; // error else if(s==0) { // Too many components stripped // - carry on. continue; } // It is OK, sb->path is now stripped. } if(!(fullpath=prepend_s(conf->restoreprefix, sb->path.buf))) { log_and_send_oom(asfd, __func__); goto end; } if(act==ACTION_RESTORE) { strip_invalid_characters(&fullpath); if(!overwrite_ok(sb, conf, &bfd, fullpath)) { char msg[512]=""; // Something exists at that path. snprintf(msg, sizeof(msg), "Path exists: %s", fullpath); if(restore_interrupt(asfd, sb, msg, conf)) goto end; else { if(fullpath) free(fullpath); continue; } } } break; default: break; } switch(sb->path.cmd) { case CMD_WARNING: cntr_add(conf->cntr, sb->path.cmd, 1); printf("\n"); logp("%s", sb->path); break; case CMD_DIRECTORY: if(restore_dir(asfd, sb, fullpath, act, conf)) goto end; break; case CMD_FILE: case CMD_VSS_T: // Have it a separate statement to the // encrypted version so that encrypted and not // encrypted files can be restored at the // same time. if(restore_file_or_get_meta(asfd, &bfd, sb, fullpath, act, NULL, NULL, NULL, vss_restore, conf)) { logp("restore_file error\n"); goto end; } break; case CMD_ENC_FILE: case CMD_ENC_VSS_T: if(restore_file_or_get_meta(asfd, &bfd, sb, fullpath, act, conf->encryption_password, NULL, NULL, vss_restore, conf)) { logp("restore_file error\n"); goto end; } break; case CMD_SOFT_LINK: case CMD_HARD_LINK: if(restore_link(asfd, sb, fullpath, conf->restoreprefix, act, conf)) goto end; break; case CMD_SPECIAL: if(restore_special(asfd, sb, fullpath, act, conf)) goto end; break; case CMD_METADATA: case CMD_VSS: if(restore_metadata(asfd, &bfd, sb, fullpath, act, NULL, vss_restore, conf)) goto end; break; case CMD_ENC_METADATA: case CMD_ENC_VSS: if(restore_metadata(asfd, &bfd, sb, fullpath, act, conf->encryption_password, vss_restore, conf)) goto end; break; case CMD_EFS_FILE: if(restore_file_or_get_meta(asfd, &bfd, sb, fullpath, act, NULL, NULL, NULL, vss_restore, conf)) { logp("restore_file error\n"); goto end; } break; default: logp("unknown cmd: %c\n", sb->path.cmd); goto end; break; } if(fullpath) free(fullpath); } ret=0; end: sbuf_free(sb); #ifdef HAVE_WIN32 // It is possible for a bfd to still be open. bclose(&bfd, asfd); #endif cntr_print_end(conf->cntr); cntr_print(conf->cntr, act); if(!ret) logp("%s finished\n", act_str(act)); else logp("ret: %d\n", ret); return ret; }
void print(struct termios *tp, struct winsize *wp, int ldisc, enum FMT fmt) { struct cchar *p; long tmp; u_char *cc; int cnt, ispeed, ospeed; char buf1[100], buf2[100]; cnt = 0; /* Line discipline. */ if (ldisc != TTYDISC) { switch(ldisc) { case SLIPDISC: cnt += printf("slip disc; "); break; case PPPDISC: cnt += printf("ppp disc; "); break; default: cnt += printf("#%d disc; ", ldisc); break; } } /* Line speed. */ ispeed = cfgetispeed(tp); ospeed = cfgetospeed(tp); if (ispeed != ospeed) cnt += printf("ispeed %d baud; ospeed %d baud;", ispeed, ospeed); else cnt += printf("speed %d baud;", ispeed); if (fmt >= BSD) cnt += printf(" %d rows; %d columns;", wp->ws_row, wp->ws_col); if (cnt) printf("\n"); #define on(f) ((tmp & (f)) != 0) #define put(n, f, d) \ if (fmt >= BSD || on(f) != (d)) \ bput((n) + on(f)); /* "local" flags */ tmp = tp->c_lflag; binit("lflags"); put("-icanon", ICANON, 1); put("-isig", ISIG, 1); put("-iexten", IEXTEN, 1); put("-echo", ECHO, 1); put("-echoe", ECHOE, 0); put("-echok", ECHOK, 0); put("-echoke", ECHOKE, 0); put("-echonl", ECHONL, 0); put("-echoctl", ECHOCTL, 0); put("-echoprt", ECHOPRT, 0); put("-altwerase", ALTWERASE, 0); put("-noflsh", NOFLSH, 0); put("-tostop", TOSTOP, 0); put("-flusho", FLUSHO, 0); put("-pendin", PENDIN, 0); put("-nokerninfo", NOKERNINFO, 0); put("-extproc", EXTPROC, 0); /* input flags */ tmp = tp->c_iflag; binit("iflags"); put("-istrip", ISTRIP, 0); put("-icrnl", ICRNL, 1); put("-inlcr", INLCR, 0); put("-igncr", IGNCR, 0); put("-ixon", IXON, 1); put("-ixoff", IXOFF, 0); put("-ixany", IXANY, 1); put("-imaxbel", IMAXBEL, 1); put("-ignbrk", IGNBRK, 0); put("-brkint", BRKINT, 1); put("-inpck", INPCK, 0); put("-ignpar", IGNPAR, 0); put("-parmrk", PARMRK, 0); /* output flags */ tmp = tp->c_oflag; binit("oflags"); put("-opost", OPOST, 1); put("-onlcr", ONLCR, 1); put("-ocrnl", OCRNL, 0); put("-oxtabs", OXTABS, 1); put("-onocr", OXTABS, 0); put("-onlret", OXTABS, 0); /* control flags (hardware state) */ tmp = tp->c_cflag; binit("cflags"); put("-cread", CREAD, 1); switch(tmp&CSIZE) { case CS5: bput("cs5"); break; case CS6: bput("cs6"); break; case CS7: bput("cs7"); break; case CS8: bput("cs8"); break; } bput("-parenb" + on(PARENB)); put("-parodd", PARODD, 0); put("-hupcl", HUPCL, 1); put("-clocal", CLOCAL, 0); put("-cstopb", CSTOPB, 0); switch(tmp & (CCTS_OFLOW | CRTS_IFLOW)) { case CCTS_OFLOW: bput("ctsflow"); break; case CRTS_IFLOW: bput("rtsflow"); break; default: put("-crtscts", CCTS_OFLOW | CRTS_IFLOW, 0); break; } put("-dsrflow", CDSR_OFLOW, 0); put("-dtrflow", CDTR_IFLOW, 0); put("-mdmbuf", MDMBUF, 0); /* XXX mdmbuf == dtrflow */ /* special control characters */ cc = tp->c_cc; if (fmt == POSIX) { binit("cchars"); for (p = cchars1; p->name; ++p) { snprintf(buf1, sizeof(buf1), "%s = %s;", p->name, ccval(p, cc[p->sub])); bput(buf1); } binit(NULL); } else { binit(NULL); for (p = cchars1, cnt = 0; p->name; ++p) { if (fmt != BSD && cc[p->sub] == p->def) continue; #define WD "%-8s" snprintf(buf1 + cnt * 8, sizeof(buf1) - cnt * 8, WD, p->name); snprintf(buf2 + cnt * 8, sizeof(buf2) - cnt * 8, WD, ccval(p, cc[p->sub])); if (++cnt == LINELENGTH / 8) { cnt = 0; printf("%s\n", buf1); printf("%s\n", buf2); } } if (cnt) { printf("%s\n", buf1); printf("%s\n", buf2); } } }
// init handles initialization of the various global state, like goroot and goarch. void init(void) { char *p; int i; Buf b; binit(&b); xgetenv(&b, "GOROOT"); if(b.len > 0) { // if not "/", then strip trailing path separator if(b.len >= 2 && b.p[b.len - 1] == slash[0]) b.len--; goroot = btake(&b); } xgetenv(&b, "GOBIN"); if(b.len == 0) bprintf(&b, "%s%sbin", goroot, slash); gobin = btake(&b); xgetenv(&b, "GOOS"); if(b.len == 0) bwritestr(&b, gohostos); goos = btake(&b); if(find(goos, okgoos, nelem(okgoos)) < 0) fatal("unknown $GOOS %s", goos); p = bpathf(&b, "%s/include/u.h", goroot); if(!isfile(p)) { fatal("$GOROOT is not set correctly or not exported\n" "\tGOROOT=%s\n" "\t%s does not exist", goroot, p); } xgetenv(&b, "GOHOSTARCH"); if(b.len > 0) gohostarch = btake(&b); i = find(gohostarch, okgoarch, nelem(okgoarch)); if(i < 0) fatal("unknown $GOHOSTARCH %s", gohostarch); bprintf(&b, "%c", gochars[i]); gohostchar = btake(&b); xgetenv(&b, "GOARCH"); if(b.len == 0) bwritestr(&b, gohostarch); goarch = btake(&b); i = find(goarch, okgoarch, nelem(okgoarch)); if(i < 0) fatal("unknown $GOARCH %s", goarch); bprintf(&b, "%c", gochars[i]); gochar = btake(&b); xsetenv("GOROOT", goroot); xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); // Make the environment more predictable. xsetenv("LANG", "C"); xsetenv("LANGUAGE", "en_US.UTF8"); goversion = findgoversion(); workdir = xworkdir(); xatexit(rmworkdir); bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch); tooldir = btake(&b); bfree(&b); }
/* * Initialization code. * Called from cold start routine as * soon as a stack and segmentation * have been established. * Functions: * clear and free user core * turn on clock * hand craft 0th process * call all initialization routines * fork - process 0 to schedule * - process 1 execute bootstrap */ int main() { register struct proc *p; register int i; register struct fs *fs = NULL; char inbuf[4]; char inch; int s __attribute__((unused)); startup(); printf ("\n%s", version); cpuidentify(); cnidentify(); /* * Set up system process 0 (swapper). */ p = &proc[0]; p->p_addr = (size_t) &u; p->p_stat = SRUN; p->p_flag |= SLOAD | SSYS; p->p_nice = NZERO; u.u_procp = p; /* init user structure */ u.u_cmask = CMASK; u.u_lastfile = -1; for (i = 1; i < NGROUPS; i++) u.u_groups[i] = NOGROUP; for (i = 0; i < sizeof(u.u_rlimit)/sizeof(u.u_rlimit[0]); i++) u.u_rlimit[i].rlim_cur = u.u_rlimit[i].rlim_max = RLIM_INFINITY; /* Initialize signal state for process 0 */ siginit (p); /* * Initialize tables, protocols, and set up well-known inodes. */ #ifdef LOG_ENABLED loginit(); #endif coutinit(); cinit(); pqinit(); ihinit(); bhinit(); binit(); nchinit(); clkstart(); s = spl0(); rdisk_init(); pipedev = rootdev = get_boot_device(); swapdev = get_swap_device(); /* Mount a root filesystem. */ for (;;) { if(rootdev!=-1) { fs = mountfs (rootdev, (boothowto & RB_RDONLY) ? MNT_RDONLY : 0, (struct inode*) 0); } if (fs) break; printf ("No root filesystem available!\n"); // rdisk_list_partitions(RDISK_FS); retry: printf ("Please enter device to boot from (press ? to list): "); inch=0; inbuf[0] = inbuf[1] = inbuf[2] = inbuf[3] = 0; while((inch=cngetc()) != '\r') { switch(inch) { case '?': printf("?\n"); rdisk_list_partitions(RDISK_FS); printf ("Please enter device to boot from (press ? to list): "); break; default: printf("%c",inch); inbuf[0] = inbuf[1]; inbuf[1] = inbuf[2]; inbuf[2] = inbuf[3]; inbuf[3] = inch; break; } } inch = 0; if(inbuf[0]=='r' && inbuf[1]=='d') { if(inbuf[2]>='0' && inbuf[2] < '0'+rdisk_num_disks()) { if(inbuf[3]>='a' && inbuf[3]<='d') { rootdev=makedev(inbuf[2]-'0',inbuf[3]-'a'+1); inch = 1; } } } else if(inbuf[1]=='r' && inbuf[2]=='d') { if(inbuf[3]>='0' && inbuf[3] < '0'+rdisk_num_disks()) { rootdev=makedev(inbuf[3]-'0',0); inch = 1; } } else if(inbuf[3] == 0) { inch = 1; } if(inch==0) { printf("\nUnknown device.\n\n"); goto retry; } printf ("\n\n"); } printf ("phys mem = %u kbytes\n", physmem / 1024); printf ("user mem = %u kbytes\n", MAXMEM / 1024); if(minor(rootdev)==0) { printf ("root dev = rd%d (%d,%d)\n", major(rootdev), major(rootdev), minor(rootdev) ); } else { printf ("root dev = rd%d%c (%d,%d)\n", major(rootdev), 'a'+minor(rootdev)-1, major(rootdev), minor(rootdev) ); } printf ("root size = %u kbytes\n", fs->fs_fsize * DEV_BSIZE / 1024); mount[0].m_inodp = (struct inode*) 1; /* XXX */ mount_updname (fs, "/", "root", 1, 4); time.tv_sec = fs->fs_time; boottime = time; /* Find a swap file. */ swapstart = 1; while(swapdev == -1) { printf("Please enter swap device (press ? to list): "); inbuf[0] = inbuf[1] = inbuf[2] = inbuf[3] = 0; while((inch = cngetc())!='\r') { switch(inch) { case '?': printf("?\n"); rdisk_list_partitions(RDISK_SWAP); printf("Please enter swap device (press ? to list): "); break; default: printf("%c",inch); inbuf[0] = inbuf[1]; inbuf[1] = inbuf[2]; inbuf[2] = inbuf[3]; inbuf[3] = inch; break; } } inch = 0; if(inbuf[0]=='r' && inbuf[1]=='d') { if(inbuf[2]>='0' && inbuf[2] < '0'+rdisk_num_disks()) { if(inbuf[3]>='a' && inbuf[3]<='d') { swapdev=makedev(inbuf[2]-'0',inbuf[3]-'a'+1); inch = 1; } } } else if(inbuf[1]=='r' && inbuf[2]=='d') { if(inbuf[3]>='0' && inbuf[3] < '0'+rdisk_num_disks()) { swapdev=makedev(inbuf[3]-'0',0); inch = 1; } } if(minor(swapdev)!=0) { if(partition_type(swapdev)!=RDISK_SWAP) { printf("\nNot a swap partition!\n\n"); swapdev=-1; } } } nswap = rdsize(swapdev); if(minor(swapdev)==0) { printf ("swap dev = rd%d (%d,%d)\n", major(swapdev), major(swapdev), minor(swapdev) ); } else { printf ("swap dev = rd%d%c (%d,%d)\n", major(swapdev), 'a'+minor(swapdev)-1, major(swapdev), minor(swapdev) ); } (*bdevsw[major(swapdev)].d_open)(swapdev, FREAD|FWRITE, S_IFBLK); printf ("swap size = %u kbytes\n", nswap * DEV_BSIZE / 1024); if (nswap <= 0) panic ("zero swap size"); /* don't want to panic, but what ? */ mfree (swapmap, nswap, swapstart); /* Kick off timeout driven events by calling first time. */ schedcpu (0); /* Set up the root file system. */ rootdir = iget (rootdev, &mount[0].m_filsys, (ino_t) ROOTINO); iunlock (rootdir); u.u_cdir = iget (rootdev, &mount[0].m_filsys, (ino_t) ROOTINO); iunlock (u.u_cdir); u.u_rdir = NULL; /* * Make init process. */ if (newproc (0) == 0) { /* Parent process with pid 0: swapper. * No return from sched. */ sched(); } /* Child process with pid 1: init. */ s = splhigh(); p = u.u_procp; p->p_dsize = icodeend - icode; p->p_daddr = USER_DATA_START; p->p_ssize = 1024; /* one kbyte of stack */ p->p_saddr = USER_DATA_END - 1024; bcopy ((caddr_t) icode, (caddr_t) USER_DATA_START, icodeend - icode); /* * return goes to location 0 of user init code * just copied out. */ return 0; }
// setup sets up the tree for the initial build. static void setup(void) { int i; Buf b; char *p; binit(&b); // Create bin directory. p = bpathf(&b, "%s/bin", goroot); if(!isdir(p)) xmkdir(p); // Create package directory. p = bpathf(&b, "%s/pkg", goroot); if(!isdir(p)) xmkdir(p); p = bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch); if(rebuildall) xremoveall(p); xmkdirall(p); if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) { p = bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch); if(rebuildall) xremoveall(p); xmkdirall(p); } // Create object directory. // We keep it in pkg/ so that all the generated binaries // are in one tree. If pkg/obj/libgc.a exists, it is a dreg from // before we used subdirectories of obj. Delete all of obj // to clean up. bpathf(&b, "%s/pkg/obj/libgc.a", goroot); if(isfile(bstr(&b))) xremoveall(bpathf(&b, "%s/pkg/obj", goroot)); p = bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch); if(rebuildall) xremoveall(p); xmkdirall(p); // Create tool directory. // We keep it in pkg/, just like the object directory above. if(rebuildall) xremoveall(tooldir); xmkdirall(tooldir); // Remove tool binaries from before the tool/gohostos_gohostarch xremoveall(bpathf(&b, "%s/bin/tool", goroot)); // Remove old pre-tool binaries. for(i=0; i<nelem(oldtool); i++) xremove(bpathf(&b, "%s/bin/%s", goroot, oldtool[i])); // If $GOBIN is set and has a Go compiler, it must be cleaned. for(i=0; gochars[i]; i++) { if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) { for(i=0; i<nelem(oldtool); i++) xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i])); break; } } // For release, make sure excluded things are excluded. if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) { for(i=0; i<nelem(unreleased); i++) if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i]))) fatal("%s should not exist in release build", bstr(&b)); } bfree(&b); }
// mkanames reads [5689].out.h and writes anames[5689].c // The format is much the same as the Go opcodes above. // It also writes out cnames array for C_* constants and the dnames // array for D_* constants. void mkanames(char *dir, char *file) { int i, j, ch, n, unknown; Buf in, b, out, out2; Vec lines; char *p, *p2; Vec dnames[128]; binit(&b); binit(&in); binit(&out); binit(&out2); vinit(&lines); for(i=0; i<nelem(dnames); i++) vinit(&dnames[i]); ch = file[xstrlen(file)-3]; bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch); readfile(&in, bstr(&b)); splitlines(&lines, bstr(&in)); // Include link.h so that the extern declaration there is // checked against the non-extern declaration we are generating. bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n")); bwritestr(&out, bprintf(&b, "#include <u.h>\n")); bwritestr(&out, bprintf(&b, "#include <libc.h>\n")); bwritestr(&out, bprintf(&b, "#include <bio.h>\n")); bwritestr(&out, bprintf(&b, "#include <link.h>\n")); bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch)); bwritestr(&out, bprintf(&b, "\n")); bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch)); for(i=0; i<lines.len; i++) { if(hasprefix(lines.p[i], "\tA")) { p = xstrstr(lines.p[i], ","); if(p) *p = '\0'; p = xstrstr(lines.p[i], "\n"); if(p) *p = '\0'; p = lines.p[i] + 2; bwritestr(&out, bprintf(&b, "\t\"%s\",\n", p)); } } bwritestr(&out, "};\n"); j=0; bprintf(&out2, "char* cnames%c[] = {\n", ch); for(i=0; i<lines.len; i++) { if(hasprefix(lines.p[i], "\tC_")) { p = xstrstr(lines.p[i], ","); if(p) *p = '\0'; p = xstrstr(lines.p[i], "\n"); if(p) *p = '\0'; p = lines.p[i] + 3; bwritestr(&out2, bprintf(&b, "\t\"%s\",\n", p)); j++; } } bwritestr(&out2, "};\n"); if(j>0) bwriteb(&out, &out2); j=unknown=0; n=-1; for(i=0; i<lines.len; i++) { if(hasprefix(lines.p[i], "\tD_")) { p = xstrstr(lines.p[i], ","); if(p) *p = '\0'; p = xstrstr(lines.p[i], "\n"); if(p) *p = '\0'; // Parse explicit value, if any p = xstrstr(lines.p[i], "="); if(p) { // Skip space after '=' p2 = p + 1; while(*p2 == ' ' || *p2 == '\t') p2++; n = xatoi(p2, &p2); // We can't do anything about // non-numeric values or anything that // follows while(*p2 == ' ' || *p2 == '\t') p2++; if(*p2 != 0) { unknown = 1; continue; } // Truncate space before '=' while(*(p-1) == ' ' || *(p-1) == '\t') p--; *p = '\0'; unknown = 0; } else { n++; } if(unknown || n >= nelem(dnames)) continue; p = lines.p[i] + 3; if(xstrcmp(p, "LAST") == 0) continue; vadd(&dnames[n], p); j++; } } if(j>0){ bwritestr(&out, bprintf(&b, "char* dnames%c[D_LAST] = {\n", ch)); for(i=0; i<nelem(dnames); i++) { if(dnames[i].len == 0) continue; bwritestr(&out, bprintf(&b, "\t[D_%s] = \"", dnames[i].p[0])); for(j=0; j<dnames[i].len; j++) { if(j != 0) bwritestr(&out, "/"); bwritestr(&out, dnames[i].p[j]); } bwritestr(&out, "\",\n"); } bwritestr(&out, "};\n"); } writefile(&out, file, 0); bfree(&b); bfree(&in); bfree(&out); bfree(&out2); vfree(&lines); for(i=0; i<nelem(dnames); i++) vfree(&dnames[i]); }
// Bootstrap processor starts running C code here. // Allocate a real stack and switch to it, first // doing some setup required for memory allocator to work. int main(void) { monitor_clear(); xylos_logo(); kinit1(end, P2V(4 * 1024 * 1024)); // phys page allocator, 16MB for kernel kvmalloc(); // kernel page table mpinit(); // collect info about this machine lapicinit(); seginit(); // set up segments cprintf("Initializing interrupts... "); init_generic_irq_table(); picinit(); // interrupt controller ioapicinit(); // another interrupt controller cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); cprintf("Initializing console and serial... "); consoleinit(); // I/O devices & their interrupts uartinit(); // serial port cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); cprintf("Setting up swap space disk... "); swapinit(); cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); cprintf("Initializing tasking... "); pinit(); // process table tvinit(); // trap vectors binit(); // buffer cache cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); cprintf("Initializing pipe IPC... "); init_pipe_ipc_system(); if(pipe_ipc_sanitycheck() == 0) { cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); } cprintf("Initializing direct IPC... "); init_direct_ipc_table(); if(direct_ipc_sanitycheck() == 0) { cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); } cprintf("Mounting root filesystem... "); fileinit(); // file table ideinit(); // disk cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); if(!ismp) { cprintf("Starting up uniprocessor CPU... "); timerinit(); // uniprocessor timer cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); } if(ismp) { if(ncpu > 1) { cprintf("Starting up %d CPU cores... ", ncpu); } else { cprintf("Starting up %d CPU core... ", ncpu); } } startothers(); // start other processors kinit2(P2V(4 * 1024 * 1024), P2V(PHYSTOP)); // 16MB to PHYSTOP [234MB] if(ismp) { cprintf_color(COLOR_BLACK, COLOR_LIGHT_GREEN, false, "done\n"); } // detects and starts km drivers auto_enable_nic(); // first user process userinit(); // Finish setting up this processor in mpmain. mpmain(); }
// shouldbuild reports whether we should build this file. // It applies the same rules that are used with context tags // in package go/build, except that the GOOS and GOARCH // can appear anywhere in the file name, not just after _. // In particular, they can be the entire file name (like windows.c). // We also allow the special tag cmd_go_bootstrap. // See ../go/bootstrap.go and package go/build. static bool shouldbuild(char *file, char *dir) { char *name, *p; int i, j, ret; Buf b; Vec lines, fields; // Check file name for GOOS or GOARCH. name = lastelem(file); for(i=0; i<nelem(okgoos); i++) { if(streq(okgoos[i], goos)) continue; p = xstrstr(name, okgoos[i]); if(p == nil) continue; p += xstrlen(okgoos[i]); if(*p == '.' || *p == '_' || *p == '\0') return 0; } for(i=0; i<nelem(okgoarch); i++) { if(streq(okgoarch[i], goarch)) continue; p = xstrstr(name, okgoarch[i]); if(p == nil) continue; p += xstrlen(okgoarch[i]); if(*p == '.' || *p == '_' || *p == '\0') return 0; } // Omit test files. if(contains(name, "_test")) return 0; // cmd/go/doc.go has a giant /* */ comment before // it gets to the important detail that it is not part of // package main. We don't parse those comments, // so special case that file. if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go")) return 0; if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go")) return 0; // Check file contents for // +build lines. binit(&b); vinit(&lines); vinit(&fields); ret = 1; readfile(&b, file); splitlines(&lines, bstr(&b)); for(i=0; i<lines.len; i++) { p = lines.p[i]; while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++; if(*p == '\0') continue; if(contains(p, "package documentation")) { ret = 0; goto out; } if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) { ret = 0; goto out; } if(!hasprefix(p, "//")) break; if(!contains(p, "+build")) continue; splitfields(&fields, lines.p[i]); if(fields.len < 2 || !streq(fields.p[1], "+build")) continue; for(j=2; j<fields.len; j++) { p = fields.p[j]; if((*p == '!' && !matchfield(p+1)) || matchfield(p)) goto fieldmatch; } ret = 0; goto out; fieldmatch:; } out: bfree(&b); vfree(&lines); vfree(&fields); return ret; }
// mkzasm writes zasm_$GOOS_$GOARCH.h, // which contains struct offsets for use by // assembly files. It also writes a copy to the work space // under the name zasm_GOOS_GOARCH.h (no expansion). // void mkzasm(char *dir, char *file) { int i, n; char *aggr, *p; Buf in, b, out; Vec argv, lines, fields; binit(&in); binit(&b); binit(&out); vinit(&argv); vinit(&lines); vinit(&fields); bwritestr(&out, "// auto generated by go tool dist\n\n"); for(i=0; i<nelem(zasmhdr); i++) { if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) { bwritestr(&out, zasmhdr[i].hdr); goto ok; } } fatal("unknown $GOOS/$GOARCH in mkzasm"); ok: // Run 6c -DGOOS_goos -DGOARCH_goarch -Iworkdir -a proc.c // to get acid [sic] output. vreset(&argv); vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); vadd(&argv, bprintf(&b, "-DGOOS_%s", goos)); vadd(&argv, bprintf(&b, "-DGOARCH_%s", goarch)); vadd(&argv, bprintf(&b, "-I%s", workdir)); vadd(&argv, "-a"); vadd(&argv, "proc.c"); runv(&in, dir, CheckExit, &argv); // Convert input like // aggr G // { // Gobuf 24 sched; // 'Y' 48 stack0; // } // into output like // #define g_sched 24 // #define g_stack0 48 // aggr = nil; splitlines(&lines, bstr(&in)); for(i=0; i<lines.len; i++) { splitfields(&fields, lines.p[i]); if(fields.len == 2 && streq(fields.p[0], "aggr")) { if(streq(fields.p[1], "G")) aggr = "g"; else if(streq(fields.p[1], "M")) aggr = "m"; else if(streq(fields.p[1], "Gobuf")) aggr = "gobuf"; else if(streq(fields.p[1], "WinCall")) aggr = "wincall"; } if(hasprefix(lines.p[i], "}")) aggr = nil; if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) { n = fields.len; p = fields.p[n-1]; if(p[xstrlen(p)-1] == ';') p[xstrlen(p)-1] = '\0'; bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2])); } } // Write both to file and to workdir/zasm_GOOS_GOARCH.h. writefile(&out, file, 0); writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0); bfree(&in); bfree(&b); bfree(&out); vfree(&argv); vfree(&lines); vfree(&fields); }
// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h, // which contains Go struct definitions equivalent to the C ones. // Mostly we just write the output of 6c -q to the file. // However, we run it on multiple files, so we have to delete // the duplicated definitions, and we don't care about the funcs // and consts, so we delete those too. // void mkzruntimedefs(char *dir, char *file) { int i, skip; char *p; Buf in, b, out; Vec argv, lines, fields, seen; binit(&in); binit(&b); binit(&out); vinit(&argv); vinit(&lines); vinit(&fields); vinit(&seen); bwritestr(&out, "// auto generated by go tool dist\n" "\n" "package runtime\n" "import \"unsafe\"\n" "var _ unsafe.Pointer\n" "\n" ); // Run 6c -DGOOS_goos -DGOARCH_goarch -Iworkdir -q // on each of the runtimedefs C files. vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); vadd(&argv, bprintf(&b, "-DGOOS_%s", goos)); vadd(&argv, bprintf(&b, "-DGOARCH_%s", goarch)); vadd(&argv, bprintf(&b, "-I%s", workdir)); vadd(&argv, "-q"); vadd(&argv, ""); p = argv.p[argv.len-1]; for(i=0; i<nelem(runtimedefs); i++) { argv.p[argv.len-1] = runtimedefs[i]; runv(&b, dir, CheckExit, &argv); bwriteb(&in, &b); } argv.p[argv.len-1] = p; // Process the aggregate output. skip = 0; splitlines(&lines, bstr(&in)); for(i=0; i<lines.len; i++) { p = lines.p[i]; // Drop comment, func, and const lines. if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func")) continue; // Note beginning of type or var decl, which can be multiline. // Remove duplicates. The linear check of seen here makes the // whole processing quadratic in aggregate, but there are only // about 100 declarations, so this is okay (and simple). if(hasprefix(p, "type ") || hasprefix(p, "var ")) { splitfields(&fields, p); if(fields.len < 2) continue; if(find(fields.p[1], seen.p, seen.len) >= 0) { if(streq(fields.p[fields.len-1], "{")) skip = 1; // skip until } continue; } vadd(&seen, fields.p[1]); } if(skip) { if(hasprefix(p, "}")) skip = 0; continue; } bwritestr(&out, p); } writefile(&out, file, 0); bfree(&in); bfree(&b); bfree(&out); vfree(&argv); vfree(&lines); vfree(&fields); vfree(&seen); }
// mkzasm writes zasm_$GOOS_$GOARCH.h, // which contains struct offsets for use by // assembly files. It also writes a copy to the work space // under the name zasm_GOOS_GOARCH.h (no expansion). // void mkzasm(char *dir, char *file) { int i, n; char *aggr, *p; Buf in, b, out, exp; Vec argv, lines, fields; binit(&in); binit(&b); binit(&out); binit(&exp); vinit(&argv); vinit(&lines); vinit(&fields); bwritestr(&out, "// auto generated by go tool dist\n\n"); for(i=0; i<nelem(zasmhdr); i++) { if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) { bwritestr(&out, zasmhdr[i].hdr); goto ok; } } fatal("unknown $GOOS/$GOARCH in mkzasm"); ok: // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c // to get acid [sic] output. vreset(&argv); vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); vadd(&argv, "-D"); vadd(&argv, bprintf(&b, "GOOS_%s", goos)); vadd(&argv, "-D"); vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); vadd(&argv, "-I"); vadd(&argv, bprintf(&b, "%s", workdir)); vadd(&argv, "-a"); vadd(&argv, "-n"); vadd(&argv, "-o"); vadd(&argv, bpathf(&b, "%s/proc.acid", workdir)); vadd(&argv, "proc.c"); runv(nil, dir, CheckExit, &argv); readfile(&in, bpathf(&b, "%s/proc.acid", workdir)); // Convert input like // aggr G // { // Gobuf 24 sched; // 'Y' 48 stack0; // } // StackMin = 128; // into output like // #define g_sched 24 // #define g_stack0 48 // #define const_StackMin 128 aggr = nil; splitlines(&lines, bstr(&in)); for(i=0; i<lines.len; i++) { splitfields(&fields, lines.p[i]); if(fields.len == 2 && streq(fields.p[0], "aggr")) { if(streq(fields.p[1], "G")) aggr = "g"; else if(streq(fields.p[1], "M")) aggr = "m"; else if(streq(fields.p[1], "P")) aggr = "p"; else if(streq(fields.p[1], "Gobuf")) aggr = "gobuf"; else if(streq(fields.p[1], "LibCall")) aggr = "libcall"; else if(streq(fields.p[1], "WinCallbackContext")) aggr = "cbctxt"; else if(streq(fields.p[1], "SEH")) aggr = "seh"; } if(hasprefix(lines.p[i], "}")) aggr = nil; if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) { n = fields.len; p = fields.p[n-1]; if(p[xstrlen(p)-1] == ';') p[xstrlen(p)-1] = '\0'; bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2])); } if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants p = fields.p[2]; if(p[xstrlen(p)-1] == ';') p[xstrlen(p)-1] = '\0'; bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p)); } } // Some #defines that are used for .c files. if(streq(goos, "windows")) { bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB)); } xgetenv(&exp, "GOEXPERIMENT"); bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp))); // Write both to file and to workdir/zasm_GOOS_GOARCH.h. writefile(&out, file, 0); writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0); bfree(&in); bfree(&b); bfree(&out); bfree(&exp); vfree(&argv); vfree(&lines); vfree(&fields); }
// genrun is the generic run implementation. static void genrun(Buf *b, char *dir, int mode, Vec *argv, int wait) { int i, p[2], pid; Buf b1, cmd; char *q; while(nbg >= maxnbg) bgwait1(); binit(&b1); binit(&cmd); if(!isabs(argv->p[0])) { bpathf(&b1, "/bin/%s", argv->p[0]); free(argv->p[0]); argv->p[0] = xstrdup(bstr(&b1)); } // Generate a copy of the command to show in a log. // Substitute $WORK for the work directory. for(i=0; i<argv->len; i++) { if(i > 0) bwritestr(&cmd, " "); q = argv->p[i]; if(workdir != nil && hasprefix(q, workdir)) { bwritestr(&cmd, "$WORK"); q += strlen(workdir); } bwritestr(&cmd, q); } if(vflag > 1) errprintf("%s\n", bstr(&cmd)); if(b != nil) { breset(b); if(pipe(p) < 0) fatal("pipe"); } switch(pid = fork()) { case -1: fatal("fork"); case 0: if(b != nil) { close(0); close(p[0]); dup(p[1], 1); dup(p[1], 2); if(p[1] > 2) close(p[1]); } if(dir != nil) { if(chdir(dir) < 0) { fprint(2, "chdir: %r\n"); _exits("chdir"); } } vadd(argv, nil); exec(argv->p[0], argv->p); fprint(2, "%s\n", bstr(&cmd)); fprint(2, "exec: %r\n"); _exits("exec"); } if(b != nil) { close(p[1]); breadfrom(b, p[0]); close(p[0]); } if(nbg < 0) fatal("bad bookkeeping"); bg[nbg].pid = pid; bg[nbg].mode = mode; bg[nbg].cmd = btake(&cmd); bg[nbg].b = b; nbg++; if(wait) bgwait(); bfree(&cmd); bfree(&b1); }
int main (int argc, char *argv[]) { int ch; FILE *fd; char line[1000]; bool got_inc = false; setlocale(LC_ALL, ""); bindtextdomain("bareos", LOCALEDIR); textdomain("bareos"); init_stack_dump(); lmgr_init_thread(); working_directory = "/tmp"; my_name_is(argc, argv, "bextract"); init_msg(NULL, NULL); /* setup message handler */ OSDependentInit(); ff = init_find_files(); binit(&bfd); while ((ch = getopt(argc, argv, "b:c:D:d:e:i:pvV:?")) != -1) { switch (ch) { case 'b': /* bootstrap file */ bsr = parse_bsr(NULL, optarg); // dump_bsr(bsr, true); break; case 'c': /* specify config file */ if (configfile != NULL) { free(configfile); } configfile = bstrdup(optarg); break; case 'D': /* specify director name */ if (DirectorName != NULL) { free(DirectorName); } DirectorName = bstrdup(optarg); break; case 'd': /* debug level */ if (*optarg == 't') { dbg_timestamp = true; } else { debug_level = atoi(optarg); if (debug_level <= 0) { debug_level = 1; } } break; case 'e': /* exclude list */ if ((fd = fopen(optarg, "rb")) == NULL) { berrno be; Pmsg2(0, _("Could not open exclude file: %s, ERR=%s\n"), optarg, be.bstrerror()); exit(1); } while (fgets(line, sizeof(line), fd) != NULL) { strip_trailing_junk(line); Dmsg1(900, "add_exclude %s\n", line); add_fname_to_exclude_list(ff, line); } fclose(fd); break; case 'i': /* include list */ if ((fd = fopen(optarg, "rb")) == NULL) { berrno be; Pmsg2(0, _("Could not open include file: %s, ERR=%s\n"), optarg, be.bstrerror()); exit(1); } while (fgets(line, sizeof(line), fd) != NULL) { strip_trailing_junk(line); Dmsg1(900, "add_include %s\n", line); add_fname_to_include_list(ff, 0, line); } fclose(fd); got_inc = true; break; case 'p': forge_on = true; break; case 'v': verbose++; break; case 'V': /* Volume name */ VolumeName = optarg; break; case '?': default: usage(); } /* end switch */ } /* end while */ argc -= optind; argv += optind; if (argc != 2) { Pmsg0(0, _("Wrong number of arguments. Make sure the last two parameters are <bareos-archive-device-name> <directory-to-store-files>\n")); usage(); } if (configfile == NULL) { configfile = bstrdup(CONFIG_FILE); } my_config = new_config_parser(); parse_sd_config(my_config, configfile, M_ERROR_TERM); if (DirectorName) { foreach_res(director, R_DIRECTOR) { if (bstrcmp(director->hdr.name, DirectorName)) { break; } } if (!director) { Emsg2(M_ERROR_TERM, 0, _("No Director resource named %s defined in %s. Cannot continue.\n"), DirectorName, configfile); } } load_sd_plugins(me->plugin_directory, me->plugin_names); read_crypto_cache(me->working_directory, "bareos-sd", get_first_port_host_order(me->SDaddrs)); if (!got_inc) { /* If no include file, */ add_fname_to_include_list(ff, 0, "/"); /* include everything */ } where = argv[1]; do_extract(argv[0]); if (bsr) { free_bsr(bsr); } if (prog_name_msg) { Pmsg1(000, _("%d Program Name and/or Program Data Stream records ignored.\n"), prog_name_msg); } if (win32_data_msg) { Pmsg1(000, _("%d Win32 data or Win32 gzip data stream records. Ignored.\n"), win32_data_msg); } term_include_exclude_files(ff); term_find_files(ff); return 0; }
// The bootstrap command runs a build from scratch, // stopping at having installed the go_bootstrap command. void cmdbootstrap(int argc, char **argv) { int i; Buf b; char *oldgoos, *oldgoarch, *oldgochar; binit(&b); ARGBEGIN{ case 'a': rebuildall = 1; break; case 's': sflag++; break; case 'v': vflag++; break; default: usage(); }ARGEND if(argc > 0) usage(); if(rebuildall) clean(); goversion = findgoversion(); setup(); xsetenv("GOROOT", goroot); xsetenv("GOROOT_FINAL", goroot_final); // For the main bootstrap, building for host os/arch. oldgoos = goos; oldgoarch = goarch; oldgochar = gochar; goos = gohostos; goarch = gohostarch; gochar = gohostchar; xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); for(i=0; i<nelem(buildorder); i++) { install(bprintf(&b, buildorder[i], gohostchar)); if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s")) install(bprintf(&b, buildorder[i], oldgochar)); } goos = oldgoos; goarch = oldgoarch; gochar = oldgochar; xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); // Build pkg/runtime for actual goos/goarch too. if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) install("pkg/runtime"); bfree(&b); }
// The bootstrap command runs a build from scratch, // stopping at having installed the go_bootstrap command. void cmdbootstrap(int argc, char **argv) { int i; Buf b; char *oldgoos, *oldgoarch, *oldgochar; binit(&b); ARGBEGIN{ case 'a': rebuildall = 1; break; case 's': sflag++; break; case 'v': vflag++; break; default: usage(); }ARGEND if(argc > 0) usage(); if(isdir(bpathf(&b, "%s/src/pkg", goroot))) { fatal("\n\n" "The Go package sources have moved to $GOROOT/src.\n" "*** %s still exists. ***\n" "It probably contains stale files that may confuse the build.\n" "Please (check what's there and) remove it and try again.\n" "See http://golang.org/s/go14nopkg\n", bpathf(&b, "%s/src/pkg", goroot)); } if(rebuildall) clean(); goversion = findgoversion(); setup(); xsetenv("GOROOT", goroot); xsetenv("GOROOT_FINAL", goroot_final); // For the main bootstrap, building for host os/arch. oldgoos = goos; oldgoarch = goarch; oldgochar = gochar; goos = gohostos; goarch = gohostarch; gochar = gohostchar; xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); for(i=0; i<nelem(buildorder); i++) { install(bprintf(&b, buildorder[i], gohostchar)); if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s")) install(bprintf(&b, buildorder[i], oldgochar)); } goos = oldgoos; goarch = oldgoarch; gochar = oldgochar; xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); // Build runtime for actual goos/goarch too. if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) install("runtime"); bfree(&b); }
// findgoversion determines the Go version to use in the version string. static char* findgoversion(void) { char *tag, *rev, *p; int i, nrev; Buf b, path, bmore, branch; Vec tags; binit(&b); binit(&path); binit(&bmore); binit(&branch); vinit(&tags); // The $GOROOT/VERSION file takes priority, for distributions // without the Mercurial repo. bpathf(&path, "%s/VERSION", goroot); if(isfile(bstr(&path))) { readfile(&b, bstr(&path)); chomp(&b); // Commands such as "dist version > VERSION" will cause // the shell to create an empty VERSION file and set dist's // stdout to its fd. dist in turn looks at VERSION and uses // its content if available, which is empty at this point. if(b.len > 0) goto done; } // The $GOROOT/VERSION.cache file is a cache to avoid invoking // hg every time we run this command. Unlike VERSION, it gets // deleted by the clean command. bpathf(&path, "%s/VERSION.cache", goroot); if(isfile(bstr(&path))) { readfile(&b, bstr(&path)); chomp(&b); goto done; } // Otherwise, use Mercurial. // What is the current branch? run(&branch, goroot, CheckExit, "hg", "identify", "-b", nil); chomp(&branch); // What are the tags along the current branch? tag = "devel"; rev = "."; run(&b, goroot, CheckExit, "hg", "log", "-b", bstr(&branch), "-r", ".:0", "--template", "{tags} + ", nil); splitfields(&tags, bstr(&b)); nrev = 0; for(i=0; i<tags.len; i++) { p = tags.p[i]; if(streq(p, "+")) nrev++; // NOTE: Can reenable the /* */ code when we want to // start reporting versions named 'weekly' again. if(/*hasprefix(p, "weekly.") ||*/ hasprefix(p, "go")) { tag = xstrdup(p); // If this tag matches the current checkout // exactly (no "+" yet), don't show extra // revision information. if(nrev == 0) rev = ""; break; } } if(tag[0] == '\0') { // Did not find a tag; use branch name. bprintf(&b, "branch.%s", bstr(&branch)); tag = btake(&b); } if(rev[0]) { // Tag is before the revision we're building. // Add extra information. run(&bmore, goroot, CheckExit, "hg", "log", "--template", " +{node|short} {date|date}", "-r", rev, nil); chomp(&bmore); } bprintf(&b, "%s", tag); if(bmore.len > 0) bwriteb(&b, &bmore); // Cache version. writefile(&b, bstr(&path), 0); done: p = btake(&b); bfree(&b); bfree(&path); bfree(&bmore); bfree(&branch); vfree(&tags); return p; }
// init handles initialization of the various global state, like goroot and goarch. void init(void) { char *p; int i; Buf b; binit(&b); xgetenv(&b, "GOROOT"); if(b.len > 0) { // if not "/", then strip trailing path separator if(b.len >= 2 && b.p[b.len - 1] == slash[0]) b.len--; goroot = btake(&b); } xgetenv(&b, "GOBIN"); if(b.len == 0) bprintf(&b, "%s%sbin", goroot, slash); gobin = btake(&b); xgetenv(&b, "GOOS"); if(b.len == 0) bwritestr(&b, gohostos); goos = btake(&b); if(find(goos, okgoos, nelem(okgoos)) < 0) fatal("unknown $GOOS %s", goos); xgetenv(&b, "GOARM"); if(b.len == 0) bwritestr(&b, xgetgoarm()); goarm = btake(&b); xgetenv(&b, "GO386"); if(b.len == 0) { if(cansse2()) bwritestr(&b, "sse2"); else bwritestr(&b, "387"); } go386 = btake(&b); p = bpathf(&b, "%s/include/u.h", goroot); if(!isfile(p)) { fatal("$GOROOT is not set correctly or not exported\n" "\tGOROOT=%s\n" "\t%s does not exist", goroot, p); } xgetenv(&b, "GOHOSTARCH"); if(b.len > 0) gohostarch = btake(&b); i = find(gohostarch, okgoarch, nelem(okgoarch)); if(i < 0) fatal("unknown $GOHOSTARCH %s", gohostarch); bprintf(&b, "%c", gochars[i]); gohostchar = btake(&b); xgetenv(&b, "GOARCH"); if(b.len == 0) bwritestr(&b, gohostarch); goarch = btake(&b); i = find(goarch, okgoarch, nelem(okgoarch)); if(i < 0) fatal("unknown $GOARCH %s", goarch); bprintf(&b, "%c", gochars[i]); gochar = btake(&b); xgetenv(&b, "GO_EXTLINK_ENABLED"); if(b.len > 0) { goextlinkenabled = btake(&b); if(!streq(goextlinkenabled, "0") && !streq(goextlinkenabled, "1")) fatal("unknown $GO_EXTLINK_ENABLED %s", goextlinkenabled); } xgetenv(&b, "CC"); if(b.len == 0) { // Use clang on OS X, because gcc is deprecated there. // Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that // actually runs clang. We prepare different command // lines for the two binaries, so it matters what we call it. // See golang.org/issue/5822. if(defaultclang) bprintf(&b, "clang"); else bprintf(&b, "gcc"); } defaultcc = btake(&b); xgetenv(&b, "CFLAGS"); defaultcflags = btake(&b); xgetenv(&b, "LDFLAGS"); defaultldflags = btake(&b); xgetenv(&b, "CC_FOR_TARGET"); if(b.len == 0) { bprintf(&b, defaultcc); } defaultcctarget = btake(&b); xgetenv(&b, "CXX_FOR_TARGET"); if(b.len == 0) { xgetenv(&b, "CXX"); if(b.len == 0) { if(defaultclang) bprintf(&b, "clang++"); else bprintf(&b, "g++"); } } defaultcxxtarget = btake(&b); xsetenv("GOROOT", goroot); xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); xsetenv("GOARM", goarm); xsetenv("GO386", go386); // Make the environment more predictable. xsetenv("LANG", "C"); xsetenv("LANGUAGE", "en_US.UTF8"); goversion = findgoversion(); workdir = xworkdir(); xatexit(rmworkdir); bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch); tooldir = btake(&b); bfree(&b); }
// install installs the library, package, or binary associated with dir, // which is relative to $GOROOT/src. static void install(char *dir) { char *name, *p, *elem, *prefix, *exe; bool islib, ispkg, isgo, stale; Buf b, b1, path; Vec compile, files, link, go, missing, clean, lib, extra; Time ttarg, t; int i, j, k, n, doclean, targ, usecpp; if(vflag) { if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) errprintf("%s (%s/%s)\n", dir, goos, goarch); else errprintf("%s\n", dir); } binit(&b); binit(&b1); binit(&path); vinit(&compile); vinit(&files); vinit(&link); vinit(&go); vinit(&missing); vinit(&clean); vinit(&lib); vinit(&extra); // path = full path to dir. bpathf(&path, "%s/src/%s", goroot, dir); name = lastelem(dir); // For misc/prof, copy into the tool directory and we're done. if(hasprefix(dir, "misc/")) { copy(bpathf(&b, "%s/%s", tooldir, name), bpathf(&b1, "%s/misc/%s", goroot, name), 1); goto out; } // For release, cmd/prof is not included. if((streq(dir, "cmd/prof")) && !isdir(bstr(&path))) { if(vflag > 1) errprintf("skipping %s - does not exist\n", dir); goto out; } // set up gcc command line on first run. if(gccargs.len == 0) { bprintf(&b, "%s", defaultcc); splitfields(&gccargs, bstr(&b)); for(i=0; i<nelem(proto_gccargs); i++) vadd(&gccargs, proto_gccargs[i]); if(contains(gccargs.p[0], "clang")) { // disable ASCII art in clang errors, if possible vadd(&gccargs, "-fno-caret-diagnostics"); // clang is too smart about unused command-line arguments vadd(&gccargs, "-Qunused-arguments"); } if(streq(gohostos, "darwin")) { // golang.org/issue/5261 vadd(&gccargs, "-mmacosx-version-min=10.6"); } } islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc"); ispkg = hasprefix(dir, "pkg"); isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo"); exe = ""; if(streq(gohostos, "windows")) exe = ".exe"; // Start final link command line. // Note: code below knows that link.p[targ] is the target. if(islib) { // C library. vadd(&link, "ar"); if(streq(gohostos, "plan9")) vadd(&link, "rc"); else vadd(&link, "rsc"); prefix = ""; if(!hasprefix(name, "lib")) prefix = "lib"; targ = link.len; vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name)); } else if(ispkg) { // Go library (package). vadd(&link, bpathf(&b, "%s/pack", tooldir)); vadd(&link, "grc"); p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4); *xstrrchr(p, '/') = '\0'; xmkdirall(p); targ = link.len; vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4)); } else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) { // Go command. vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar)); vadd(&link, "-o"); elem = name; if(streq(elem, "go")) elem = "go_bootstrap"; targ = link.len; vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe)); } else { // C command. Use gccargs. if(streq(gohostos, "plan9")) { vadd(&link, bprintf(&b, "%sl", gohostchar)); vadd(&link, "-o"); targ = link.len; vadd(&link, bpathf(&b, "%s/%s", tooldir, name)); } else { vcopy(&link, gccargs.p, gccargs.len); if(sflag) vadd(&link, "-static"); vadd(&link, "-o"); targ = link.len; vadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe)); if(streq(gohostarch, "amd64")) vadd(&link, "-m64"); else if(streq(gohostarch, "386")) vadd(&link, "-m32"); } } ttarg = mtime(link.p[targ]); // Gather files that are sources for this target. // Everything in that directory, and any target-specific // additions. xreaddir(&files, bstr(&path)); // Remove files beginning with . or _, // which are likely to be editor temporary files. // This is the same heuristic build.ScanDir uses. // There do exist real C files beginning with _, // so limit that check to just Go files. n = 0; for(i=0; i<files.len; i++) { p = files.p[i]; if(hasprefix(p, ".") || (hasprefix(p, "_") && hassuffix(p, ".go"))) xfree(p); else files.p[n++] = p; } files.len = n; for(i=0; i<nelem(deptab); i++) { if(hasprefix(dir, deptab[i].prefix)) { for(j=0; (p=deptab[i].dep[j])!=nil; j++) { breset(&b1); bwritestr(&b1, p); bsubst(&b1, "$GOROOT", goroot); bsubst(&b1, "$GOOS", goos); bsubst(&b1, "$GOARCH", goarch); p = bstr(&b1); if(hassuffix(p, ".a")) { if(streq(gohostos, "plan9") && hassuffix(p, "libbio.a")) continue; vadd(&lib, bpathf(&b, "%s", p)); continue; } if(hassuffix(p, "/*")) { bpathf(&b, "%s/%s", bstr(&path), p); b.len -= 2; xreaddir(&extra, bstr(&b)); bprintf(&b, "%s", p); b.len -= 2; for(k=0; k<extra.len; k++) vadd(&files, bpathf(&b1, "%s/%s", bstr(&b), extra.p[k])); continue; } if(hasprefix(p, "-")) { p++; n = 0; for(k=0; k<files.len; k++) { if(hasprefix(files.p[k], p)) xfree(files.p[k]); else files.p[n++] = files.p[k]; } files.len = n; continue; } vadd(&files, p); } } } vuniq(&files); // Convert to absolute paths. for(i=0; i<files.len; i++) { if(!isabs(files.p[i])) { bpathf(&b, "%s/%s", bstr(&path), files.p[i]); xfree(files.p[i]); files.p[i] = btake(&b); } } // Is the target up-to-date? stale = rebuildall; n = 0; for(i=0; i<files.len; i++) { p = files.p[i]; for(j=0; j<nelem(depsuffix); j++) if(hassuffix(p, depsuffix[j])) goto ok; xfree(files.p[i]); continue; ok: t = mtime(p); if(t != 0 && !hassuffix(p, ".a") && !shouldbuild(p, dir)) { xfree(files.p[i]); continue; } if(hassuffix(p, ".go")) vadd(&go, p); if(t > ttarg) stale = 1; if(t == 0) { vadd(&missing, p); files.p[n++] = files.p[i]; continue; } files.p[n++] = files.p[i]; } files.len = n; // If there are no files to compile, we're done. if(files.len == 0) goto out; for(i=0; i<lib.len && !stale; i++) if(mtime(lib.p[i]) > ttarg) stale = 1; if(!stale) goto out; // For package runtime, copy some files into the work space. if(streq(dir, "pkg/runtime")) { copy(bpathf(&b, "%s/arch_GOARCH.h", workdir), bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0); copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir), bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0); p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch); if(isfile(p)) copy(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0); copy(bpathf(&b, "%s/os_GOOS.h", workdir), bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0); copy(bpathf(&b, "%s/signals_GOOS.h", workdir), bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0); } // Generate any missing files; regenerate existing ones. for(i=0; i<files.len; i++) { p = files.p[i]; elem = lastelem(p); for(j=0; j<nelem(gentab); j++) { if(hasprefix(elem, gentab[j].nameprefix)) { if(vflag > 1) errprintf("generate %s\n", p); gentab[j].gen(bstr(&path), p); // Do not add generated file to clean list. // In pkg/runtime, we want to be able to // build the package with the go tool, // and it assumes these generated files already // exist (it does not know how to build them). // The 'clean' command can remove // the generated files. goto built; } } // Did not rebuild p. if(find(p, missing.p, missing.len) >= 0) fatal("missing file %s", p); built:; } // One more copy for package runtime. // The last batch was required for the generators. // This one is generated. if(streq(dir, "pkg/runtime")) { copy(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0); } // Generate .c files from .goc files. if(streq(dir, "pkg/runtime")) { for(i=0; i<files.len; i++) { p = files.p[i]; if(!hassuffix(p, ".goc")) continue; // b = path/zp but with _goos_goarch.c instead of .goc bprintf(&b, "%s%sz%s", bstr(&path), slash, lastelem(p)); b.len -= 4; bwritef(&b, "_%s_%s.c", goos, goarch); goc2c(p, bstr(&b)); vadd(&files, bstr(&b)); } vuniq(&files); } if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) { // We've generated the right files; the go command can do the build. if(vflag > 1) errprintf("skip build for cross-compile %s\n", dir); goto nobuild; } // The files generated by GNU Bison use macros that aren't // supported by the Plan 9 compilers so we have to use the // external preprocessor when compiling. usecpp = 0; if(streq(gohostos, "plan9")) { for(i=0; i<files.len; i++) { p = files.p[i]; if(hassuffix(p, "y.tab.c") || hassuffix(p, "y.tab.h")){ usecpp = 1; break; } } } // Compile the files. for(i=0; i<files.len; i++) { if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s")) continue; name = lastelem(files.p[i]); vreset(&compile); if(!isgo) { // C library or tool. if(streq(gohostos, "plan9")) { vadd(&compile, bprintf(&b, "%sc", gohostchar)); vadd(&compile, "-FTVw"); if(usecpp) vadd(&compile, "-Bp+"); vadd(&compile, bpathf(&b, "-I%s/include/plan9", goroot)); vadd(&compile, bpathf(&b, "-I%s/include/plan9/%s", goroot, gohostarch)); // Work around Plan 9 C compiler's handling of #include with .. path. vadd(&compile, bpathf(&b, "-I%s/src/cmd/ld", goroot)); } else { vcopy(&compile, gccargs.p, gccargs.len); vadd(&compile, "-c"); if(streq(gohostarch, "amd64")) vadd(&compile, "-m64"); else if(streq(gohostarch, "386")) vadd(&compile, "-m32"); if(streq(dir, "lib9")) vadd(&compile, "-DPLAN9PORT"); vadd(&compile, "-I"); vadd(&compile, bpathf(&b, "%s/include", goroot)); } vadd(&compile, "-I"); vadd(&compile, bstr(&path)); // lib9/goos.c gets the default constants hard-coded. if(streq(name, "goos.c")) { vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOOS=\"%s\"", goos)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOARCH=\"%s\"", goarch)); bprintf(&b1, "%s", goroot_final); bsubst(&b1, "\\", "\\\\"); // turn into C string vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOROOT=\"%s\"", bstr(&b1))); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOVERSION=\"%s\"", goversion)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOARM=\"%s\"", goarm)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GO386=\"%s\"", go386)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GO_EXTLINK_ENABLED=\"%s\"", goextlinkenabled)); } // gc/lex.c records the GOEXPERIMENT setting used during the build. if(streq(name, "lex.c")) { xgetenv(&b, "GOEXPERIMENT"); vadd(&compile, "-D"); vadd(&compile, bprintf(&b1, "GOEXPERIMENT=\"%s\"", bstr(&b))); } } else { // Supporting files for a Go package. if(hassuffix(files.p[i], ".s")) vadd(&compile, bpathf(&b, "%s/%sa", tooldir, gochar)); else { vadd(&compile, bpathf(&b, "%s/%sc", tooldir, gochar)); vadd(&compile, "-F"); vadd(&compile, "-V"); vadd(&compile, "-w"); } vadd(&compile, "-I"); vadd(&compile, workdir); vadd(&compile, "-I"); vadd(&compile, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOOS_%s", goos)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOARCH_%s", goarch)); vadd(&compile, "-D"); vadd(&compile, bprintf(&b, "GOOS_GOARCH_%s_%s", goos, goarch)); } bpathf(&b, "%s/%s", workdir, lastelem(files.p[i])); doclean = 1; if(!isgo && streq(gohostos, "darwin")) { // To debug C programs on OS X, it is not enough to say -ggdb // on the command line. You have to leave the object files // lying around too. Leave them in pkg/obj/, which does not // get removed when this tool exits. bpathf(&b1, "%s/pkg/obj/%s", goroot, dir); xmkdirall(bstr(&b1)); bpathf(&b, "%s/%s", bstr(&b1), lastelem(files.p[i])); doclean = 0; } // Change the last character of the output file (which was c or s). if(streq(gohostos, "plan9")) b.p[b.len-1] = gohostchar[0]; else b.p[b.len-1] = 'o'; vadd(&compile, "-o"); vadd(&compile, bstr(&b)); vadd(&compile, files.p[i]); bgrunv(bstr(&path), CheckExit, &compile); vadd(&link, bstr(&b)); if(doclean) vadd(&clean, bstr(&b)); } bgwait(); if(isgo) { // The last loop was compiling individual files. // Hand the Go files to the compiler en masse. vreset(&compile); vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar)); bpathf(&b, "%s/_go_.%s", workdir, gochar); vadd(&compile, "-o"); vadd(&compile, bstr(&b)); vadd(&clean, bstr(&b)); vadd(&link, bstr(&b)); vadd(&compile, "-p"); if(hasprefix(dir, "pkg/")) vadd(&compile, dir+4); else vadd(&compile, "main"); if(streq(dir, "pkg/runtime")) vadd(&compile, "-+"); vcopy(&compile, go.p, go.len); runv(nil, bstr(&path), CheckExit, &compile); } if(!islib && !isgo) { // C binaries need the libraries explicitly, and -lm. vcopy(&link, lib.p, lib.len); if(!streq(gohostos, "plan9")) vadd(&link, "-lm"); } // Remove target before writing it. xremove(link.p[targ]); runv(nil, nil, CheckExit, &link); nobuild: // In package runtime, we install runtime.h and cgocall.h too, // for use by cgo compilation. if(streq(dir, "pkg/runtime")) { copy(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch), bpathf(&b1, "%s/src/pkg/runtime/cgocall.h", goroot), 0); copy(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch), bpathf(&b1, "%s/src/pkg/runtime/runtime.h", goroot), 0); } out: for(i=0; i<clean.len; i++) xremove(clean.p[i]); bfree(&b); bfree(&b1); bfree(&path); vfree(&compile); vfree(&files); vfree(&link); vfree(&go); vfree(&missing); vfree(&clean); vfree(&lib); vfree(&extra); }
/* * Called here by find() for each file included. * This is a callback. The original is find_files() above. * * Send the file and its data to the Storage daemon. * * Returns: 1 if OK * 0 if error * -1 to ignore file/directory (not used here) */ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { bool do_read = false; int stat, data_stream; int rtnstat = 0; DIGEST *digest = NULL; DIGEST *signing_digest = NULL; int digest_stream = STREAM_NONE; SIGNATURE *sig = NULL; bool has_file_data = false; // TODO landonf: Allow the user to specify the digest algorithm #ifdef HAVE_SHA2 crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA256; #else crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA1; #endif BSOCK *sd = jcr->store_bsock; if (job_canceled(jcr)) { return 0; } jcr->num_files_examined++; /* bump total file count */ switch (ff_pkt->type) { case FT_LNKSAVED: /* Hard linked, file already saved */ Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_REGE: Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname); has_file_data = true; break; case FT_REG: Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname); has_file_data = true; break; case FT_LNK: Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_DIRBEGIN: jcr->num_files_examined--; /* correct file count */ return 1; /* not used */ case FT_NORECURSE: Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend from %s into %s\n"), ff_pkt->top_fname, ff_pkt->fname); ff_pkt->type = FT_DIREND; /* Backup only the directory entry */ break; case FT_NOFSCHG: /* Suppress message for /dev filesystems */ if (!is_in_fileset(ff_pkt)) { Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into %s\n"), ff_pkt->fname, ff_pkt->top_fname, ff_pkt->fname); } ff_pkt->type = FT_DIREND; /* Backup only the directory entry */ break; case FT_INVALIDFS: Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend from %s into %s\n"), ff_pkt->top_fname, ff_pkt->fname); ff_pkt->type = FT_DIREND; /* Backup only the directory entry */ break; case FT_INVALIDDT: Jmsg(jcr, M_INFO, 1, _(" Disallowed drive type. Will not descend into %s\n"), ff_pkt->fname); break; case FT_REPARSE: case FT_DIREND: Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link); break; case FT_SPEC: Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname); if (S_ISSOCK(ff_pkt->statp.st_mode)) { Jmsg(jcr, M_SKIPPED, 1, _(" Socket file skipped: %s\n"), ff_pkt->fname); return 1; } break; case FT_RAW: Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname); has_file_data = true; break; case FT_FIFO: Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname); break; case FT_NOACCESS: { berrno be; Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access \"%s\": ERR=%s\n"), ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno)); jcr->JobErrors++; return 1; } case FT_NOFOLLOW: { berrno be; Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link \"%s\": ERR=%s\n"), ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno)); jcr->JobErrors++; return 1; } case FT_NOSTAT: { berrno be; Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat \"%s\": ERR=%s\n"), ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno)); jcr->JobErrors++; return 1; } case FT_DIRNOCHG: case FT_NOCHG: Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname); return 1; case FT_ISARCH: Jmsg(jcr, M_NOTSAVED, 0, _(" Archive file not saved: %s\n"), ff_pkt->fname); return 1; case FT_NOOPEN: { berrno be; Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory \"%s\": ERR=%s\n"), ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno)); jcr->JobErrors++; return 1; } default: Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"), ff_pkt->type, ff_pkt->fname); jcr->JobErrors++; return 1; } Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname); /* Digests and encryption are only useful if there's file data */ if (has_file_data) { /* * Setup for digest handling. If this fails, the digest will be set to NULL * and not used. Note, the digest (file hash) can be any one of the four * algorithms below. * * The signing digest is a single algorithm depending on * whether or not we have SHA2. * ****FIXME**** the signing algoritm should really be * determined a different way!!!!!! What happens if * sha2 was available during backup but not restore? */ if (ff_pkt->flags & FO_MD5) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5); digest_stream = STREAM_MD5_DIGEST; } else if (ff_pkt->flags & FO_SHA1) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1); digest_stream = STREAM_SHA1_DIGEST; } else if (ff_pkt->flags & FO_SHA256) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256); digest_stream = STREAM_SHA256_DIGEST; } else if (ff_pkt->flags & FO_SHA512) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512); digest_stream = STREAM_SHA512_DIGEST; } /* Did digest initialization fail? */ if (digest_stream != STREAM_NONE && digest == NULL) { Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"), stream_to_ascii(digest_stream)); } /* * Set up signature digest handling. If this fails, the signature digest will be set to * NULL and not used. */ // TODO landonf: We should really only calculate the digest once, for both verification and signing. if (jcr->crypto.pki_sign) { signing_digest = crypto_digest_new(jcr, signing_algorithm); /* Full-stop if a failure occurred initializing the signature digest */ if (signing_digest == NULL) { Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"), stream_to_ascii(signing_algorithm)); jcr->JobErrors++; goto good_rtn; } } /* Enable encryption */ if (jcr->crypto.pki_encrypt) { ff_pkt->flags |= FO_ENCRYPT; } } /* Initialize the file descriptor we use for data and other streams. */ binit(&ff_pkt->bfd); if (ff_pkt->flags & FO_PORTABLE) { set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */ } if (ff_pkt->cmd_plugin) { if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) { goto bail_out; } send_plugin_name(jcr, sd, true); /* signal start of plugin data */ } /* Send attributes -- must be done after binit() */ if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) { goto bail_out; } /* Set up the encryption context and send the session data to the SD */ if (has_file_data && jcr->crypto.pki_encrypt) { if (!crypto_session_send(jcr, sd)) { goto bail_out; } } /* * Open any file with data that we intend to save, then save it. * * Note, if is_win32_backup, we must open the Directory so that * the BackupRead will save its permissions and ownership streams. */ if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode)) { #ifdef HAVE_WIN32 do_read = !is_portable_backup(&ff_pkt->bfd) || ff_pkt->statp.st_size > 0; #else do_read = ff_pkt->statp.st_size > 0; #endif } else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO || ff_pkt->type == FT_REPARSE || (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) { do_read = true; } if (ff_pkt->cmd_plugin) { do_read = true; } Dmsg1(400, "do_read=%d\n", do_read); if (do_read) { btimer_t *tid; if (ff_pkt->type == FT_FIFO) { tid = start_thread_timer(jcr, pthread_self(), 60); } else { tid = NULL; } int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0; ff_pkt->bfd.reparse_point = ff_pkt->type == FT_REPARSE; if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) { ff_pkt->ff_errno = errno; berrno be; Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open \"%s\": ERR=%s.\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; if (tid) { stop_thread_timer(tid); tid = NULL; } goto good_rtn; } if (tid) { stop_thread_timer(tid); tid = NULL; } stat = send_data(jcr, data_stream, ff_pkt, digest, signing_digest); if (ff_pkt->flags & FO_CHKCHANGES) { has_file_changed(jcr, ff_pkt); } bclose(&ff_pkt->bfd); if (!stat) { goto bail_out; } } #ifdef HAVE_DARWIN_OS /* Regular files can have resource forks and Finder Info */ if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & FO_HFSPLUS)) { if (ff_pkt->hfsinfo.rsrclength > 0) { int flags; int rsrc_stream; if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { ff_pkt->ff_errno = errno; berrno be; Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; if (is_bopen(&ff_pkt->bfd)) { bclose(&ff_pkt->bfd); } goto good_rtn; } flags = ff_pkt->flags; ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE); if (flags & FO_ENCRYPT) { rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA; } else { rsrc_stream = STREAM_MACOS_FORK_DATA; } stat = send_data(jcr, rsrc_stream, ff_pkt, digest, signing_digest); ff_pkt->flags = flags; bclose(&ff_pkt->bfd); if (!stat) { goto bail_out; } } Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname); sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES); Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32); sd->msglen = 32; if (digest) { crypto_digest_update(digest, (uint8_t *)sd->msg, sd->msglen); } if (signing_digest) { crypto_digest_update(signing_digest, (uint8_t *)sd->msg, sd->msglen); } sd->send(); sd->signal(BNET_EOD); } #endif /* * Save ACLs for anything not being a symlink and not being a plugin. */ if (!ff_pkt->cmd_plugin) { if (ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK) { if (!build_acl_streams(jcr, ff_pkt)) goto bail_out; } } /* * Save Extended Attributes for all files not being a plugin. */ if (!ff_pkt->cmd_plugin) { if (ff_pkt->flags & FO_XATTR) { if (!build_xattr_streams(jcr, ff_pkt)) goto bail_out; } } /* Terminate the signing digest and send it to the Storage daemon */ if (signing_digest) { uint32_t size = 0; if ((sig = crypto_sign_new(jcr)) == NULL) { Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for crypto signature.\n")); goto bail_out; } if (!crypto_sign_add_signer(sig, signing_digest, jcr->crypto.pki_keypair)) { Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n")); goto bail_out; } /* Get signature size */ if (!crypto_sign_encode(sig, NULL, &size)) { Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n")); goto bail_out; } /* Grow the bsock buffer to fit our message if necessary */ if (sizeof_pool_memory(sd->msg) < (int32_t)size) { sd->msg = realloc_pool_memory(sd->msg, size); } /* Send our header */ sd->fsend("%ld %ld 0", jcr->JobFiles, STREAM_SIGNED_DIGEST); Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); /* Encode signature data */ if (!crypto_sign_encode(sig, (uint8_t *)sd->msg, &size)) { Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n")); goto bail_out; } sd->msglen = size; sd->send(); sd->signal(BNET_EOD); /* end of checksum */ } /* Terminate any digest and send it to Storage daemon */ if (digest) { uint32_t size; sd->fsend("%ld %d 0", jcr->JobFiles, digest_stream); Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); size = CRYPTO_DIGEST_MAX_SIZE; /* Grow the bsock buffer to fit our message if necessary */ if (sizeof_pool_memory(sd->msg) < (int32_t)size) { sd->msg = realloc_pool_memory(sd->msg, size); } if (!crypto_digest_finalize(digest, (uint8_t *)sd->msg, &size)) { Jmsg(jcr, M_FATAL, 0, _("An error occurred finalizing signing the stream.\n")); goto bail_out; } sd->msglen = size; sd->send(); sd->signal(BNET_EOD); /* end of checksum */ } if (ff_pkt->cmd_plugin) { send_plugin_name(jcr, sd, false); /* signal end of plugin data */ } good_rtn: rtnstat = 1; /* good return */ bail_out: if (digest) { crypto_digest_free(digest); } if (signing_digest) { crypto_digest_free(signing_digest); } if (sig) { crypto_sign_free(sig); } return rtnstat; }