/* * NB: written in "high-level assembly language" */ #include #include /* for mdconfig */ #include #include /* for nmount */ #include #include /* for fstat */ #include /* for OS interface */ #include #include /* for open */ #include #include #ifndef MDTAB #define MDTAB "/boot/mdtab.conf" #endif int syscall(const int n, ...); #define _exit(a) syscall(SYS_exit, a) #define close(a) syscall(SYS_close, a) #define execve(a, b, c) syscall(SYS_execve, a, b, c) #define getpid() syscall(SYS_getpid) #define ioctl(a, b, c) syscall(SYS_ioctl, a, b, c) #define nmount(a, b, c) syscall(SYS_nmount, a, b, c) #define open(a, b) syscall(SYS_open, a, b) #define read(a, b, c) syscall(SYS_read, a, b, c) #define stat(a, b) syscall(SYS_stat, a, b) #define write(a, b, c) syscall(SYS_write, a, b, c) int errno; void printfilerr(int f, char *e, size_t e_len, char* name, size_t len) { #define TAG "mdtab: " write(f, TAG, sizeof(TAG)-1); write(f, e, e_len); if(len) write(f, name, len); write(f, "\n", 1); #undef TAG } #ifdef VERBOSE #define printmsg(e, name, len) \ printfilerr(/*STDOUT_FILENO*/ 1, e, sizeof(e)-1, name, len) #endif #define printerr(e, name, len) \ printfilerr(/*STDERR_FILENO*/ 2, e, sizeof(e)-1, name, len) /* 32bit unsigned int to decimal ASCII conversion, not zero-terminated */ int toa(char* s, unsigned n) { char *p; char rev[11]; int len = 0; #define BASE 10 p = rev; do { *p++ = (n % BASE) + '0'; len++; } while (n /= BASE); while(p != rev) { *s++ = *--p; } *s = *p; /* *++s = '\0'; */ return len; #undef BASE } void print_errno() { char s[11]; printerr("errno=", s, toa(s, errno)); } int main(int argc, char **argv, char **envp) { int asinit, fd, mfd = -1; ssize_t e; size_t imgname_len = 0, mountpt_len = 0, unitstr_len = 0; struct md_ioctl mdio; struct stat sb; struct iovec iov[8]; /* stack abuse */ char buf[2*(PATH_MAX+1)]; char errmsg[255]; #define MDEV "/dev/md" char unitstr[sizeof(MDEV) + 10 + 5] = MDEV; char c, *mountpt = 0, *p; enum { LINESTART, IMGNAME, MOUNTPTNAME, COMMENT } pstate = LINESTART; /* don't bother loading module */ /* if (!kld_isloaded("g_md") && kld_load("geom_md") == -1) { printerr("failed to load module ", "geom_md", sizeof(geom_md)); print_errno(); goto runinit; } */ asinit = (getpid() == 1); if (asinit) { close(/*STDIN_FILENO*/ 0); close(/*STDOUT_FILENO*/ 1); close(/*STDERR_FILENO*/ 2); open(_PATH_CONSOLE, O_RDWR); /* 0 */ open(_PATH_CONSOLE, O_RDWR); /* 1 */ open(_PATH_CONSOLE, O_RDWR); /* 2 */ } #define MDCTL_FULLNAME "/dev/" MDCTL_NAME if ((mfd = open(MDCTL_FULLNAME, O_RDWR)) < 0) { printerr("cannot open ", MDCTL_FULLNAME, sizeof(MDCTL_FULLNAME) - 1); print_errno(); goto runinit; } #undef MDCTL_FULLNAME iov[0].iov_base = "fstype"; iov[0].iov_len = sizeof("fstype");; iov[1].iov_base = "ufs"; iov[1].iov_len = sizeof("ufs"); iov[2].iov_base = "fspath"; iov[2].iov_len = sizeof("fspath");; iov[4].iov_base = "from"; iov[4].iov_len = sizeof("from"); iov[6].iov_base = "errmsg"; iov[6].iov_len = sizeof("errmsg");; iov[7].iov_base = &errmsg; iov[7].iov_len = sizeof(errmsg);; #define bzero(a,b) do { \ char *_p; \ for(_p = (char*)(&a) + b; _p != (char*) &a;) \ *--_p = '\0'; \ } while(0) bzero(mdio, sizeof(mdio)); mdio.md_version = MDIOVERSION; mdio.md_type = MD_VNODE; mdio.md_file = buf; mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS | MD_READONLY; if ((fd = open(MDTAB, O_RDONLY)) < 0) { printerr("cannot open ", MDTAB, sizeof(MDTAB)-1); print_errno(); goto runinit; } p = buf; /* read and parse MDTAB */ while((p < buf + sizeof(buf)) && (e = read(fd, &c, 1)) == 1) { switch(pstate) { case LINESTART: switch(c) { case '\0': case ' ': case '\t': case '\n': break; /* ignore empty space at line start */ case '#': pstate = COMMENT; break; default: *p++ = c; pstate = IMGNAME; imgname_len = 1; } break; case COMMENT: if(c == '\n') { pstate = LINESTART; p = buf; } break; case IMGNAME: switch(c) { case '\0': case ' ': case '\t': *p++ = '\0'; pstate = MOUNTPTNAME; mountpt_len = 0; mountpt = p; break; case '\n': printerr("two values needed in ", MDTAB, sizeof(MDTAB)-1); pstate = LINESTART; p = buf; break; case '#': printerr("incorrect comment in ", MDTAB, sizeof(MDTAB)-1); pstate = COMMENT; break; default: *p++ = c; imgname_len++; } break; /* case MOUNTPTNAME */ default: switch(c) { case '\0': case ' ': case '\t': /* ignore empty space before and within mount point name */ break; case '#': case '\n': /* ignore rest of line */ if (c == '\n') pstate = LINESTART; else pstate = COMMENT; *p ='\0'; p = buf; if (mountpt_len == 0) { printerr("two values needed in ", MDTAB, sizeof(MDTAB)-1); } else { printmsg("attaching image ", buf, imgname_len); if (stat(buf, &sb) == -1) { printerr("cannot stat ", buf, imgname_len); print_errno(); break; } mdio.md_mediasize = sb.st_size; mdio.md_unit = 0; if (ioctl(mfd, MDIOCATTACH, &mdio) < 0) { printerr("cannot attach ", buf, imgname_len); print_errno(); break; } unitstr_len = toa(unitstr + sizeof(MDEV)-1, mdio.md_unit) + sizeof(MDEV)-1; unitstr[unitstr_len++] = '.'; unitstr[unitstr_len++] = 'u'; unitstr[unitstr_len++] = 'z'; unitstr[unitstr_len++] = 'i'; unitstr[unitstr_len++] = 'p'; unitstr[unitstr_len] = '\0'; if (stat(unitstr, &sb) == -1) { if (errno == 2) { printerr ("node not found: ", unitstr, unitstr_len); printerr ("perhaps, geom_uzip not loaded", "", 0); } else { printerr("cannot stat ", unitstr, unitstr_len); print_errno(); } break; } printmsg("attached to ", unitstr, unitstr_len); /* "fspath" value */ iov[3].iov_base = mountpt; iov[3].iov_len = mountpt_len+1; /* "from" value */ iov[5].iov_base = unitstr; iov[5].iov_len = unitstr_len+1; if (nmount(&iov, sizeof(iov)/sizeof(iov[0]), MNT_RDONLY) < 0) { printerr("cannot mount ", unitstr, unitstr_len); printerr("to ", mountpt, mountpt_len); print_errno(); printerr("fs error: ", iov[7].iov_base, iov[7].iov_len); break; } printmsg("mounted at ", mountpt, mountpt_len); } break; default: *p++ = c; mountpt_len++; } } } if (e < 0) { printerr("error reading ", MDTAB, sizeof(MDTAB) - 1); print_errno(); } close(fd); runinit: if (mfd >= 0) close(mfd); if(asinit) { argv[0] = "init"; execve("/sbin/init", argv, envp); printerr("cannot execve ", "/sbin/init", 10); print_errno(); } /* start of init failed, kernel panic is imminent */ _exit(0); return 0; } typedef void (*fptr)(void); void _start1(fptr cleanup, int argc, char *argv[]) { char **env = argv + argc + 1; main(argc, argv, env); }