clang-format
This commit is contained in:
@@ -36,85 +36,73 @@
|
||||
* Usage: cat [files]
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Print a file that's already been opened. */
|
||||
static
|
||||
void
|
||||
docat(const char *name, int fd)
|
||||
{
|
||||
char buf[1024];
|
||||
int len, wr, wrtot;
|
||||
static void docat(const char *name, int fd) {
|
||||
char buf[1024];
|
||||
int len, wr, wrtot;
|
||||
|
||||
/*
|
||||
* As long as we get more than zero bytes, we haven't hit EOF.
|
||||
* Zero means EOF. Less than zero means an error occurred.
|
||||
* We may read less than we asked for, though, in various cases
|
||||
* for various reasons.
|
||||
*/
|
||||
while ((len = read(fd, buf, sizeof(buf)))>0) {
|
||||
/*
|
||||
* Likewise, we may actually write less than we attempted
|
||||
* to. So loop until we're done.
|
||||
*/
|
||||
wrtot = 0;
|
||||
while (wrtot < len) {
|
||||
wr = write(STDOUT_FILENO, buf+wrtot, len-wrtot);
|
||||
if (wr<0) {
|
||||
err(1, "stdout");
|
||||
}
|
||||
wrtot += wr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got a read error, print it and exit.
|
||||
*/
|
||||
if (len<0) {
|
||||
err(1, "%s", name);
|
||||
}
|
||||
/*
|
||||
* As long as we get more than zero bytes, we haven't hit EOF.
|
||||
* Zero means EOF. Less than zero means an error occurred.
|
||||
* We may read less than we asked for, though, in various cases
|
||||
* for various reasons.
|
||||
*/
|
||||
while ((len = read(fd, buf, sizeof(buf))) > 0) {
|
||||
/*
|
||||
* Likewise, we may actually write less than we attempted
|
||||
* to. So loop until we're done.
|
||||
*/
|
||||
wrtot = 0;
|
||||
while (wrtot < len) {
|
||||
wr = write(STDOUT_FILENO, buf + wrtot, len - wrtot);
|
||||
if (wr < 0) {
|
||||
err(1, "stdout");
|
||||
}
|
||||
wrtot += wr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got a read error, print it and exit.
|
||||
*/
|
||||
if (len < 0) {
|
||||
err(1, "%s", name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a file by name. */
|
||||
static
|
||||
void
|
||||
cat(const char *file)
|
||||
{
|
||||
int fd;
|
||||
static void cat(const char *file) {
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* "-" means print stdin.
|
||||
*/
|
||||
if (!strcmp(file, "-")) {
|
||||
docat("stdin", STDIN_FILENO);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* "-" means print stdin.
|
||||
*/
|
||||
if (!strcmp(file, "-")) {
|
||||
docat("stdin", STDIN_FILENO);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the file, print it, and close it.
|
||||
* Bail out if we can't open it.
|
||||
*/
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, "%s", file);
|
||||
}
|
||||
docat(file, fd);
|
||||
close(fd);
|
||||
/*
|
||||
* Open the file, print it, and close it.
|
||||
* Bail out if we can't open it.
|
||||
*/
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", file);
|
||||
}
|
||||
docat(file, fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc==1) {
|
||||
/* No args - just do stdin */
|
||||
docat("stdin", STDIN_FILENO);
|
||||
}
|
||||
else {
|
||||
/* Print all the files specified on the command line. */
|
||||
int i;
|
||||
for (i=1; i<argc; i++) {
|
||||
cat(argv[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc == 1) {
|
||||
/* No args - just do stdin */
|
||||
docat("stdin", STDIN_FILENO);
|
||||
} else {
|
||||
/* Print all the files specified on the command line. */
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
cat(argv[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,79 +35,73 @@
|
||||
* Usage: cp oldfile newfile
|
||||
*/
|
||||
|
||||
|
||||
/* Copy one file to another. */
|
||||
static
|
||||
void
|
||||
copy(const char *from, const char *to)
|
||||
{
|
||||
int fromfd;
|
||||
int tofd;
|
||||
char buf[1024];
|
||||
int len, wr, wrtot;
|
||||
static void copy(const char *from, const char *to) {
|
||||
int fromfd;
|
||||
int tofd;
|
||||
char buf[1024];
|
||||
int len, wr, wrtot;
|
||||
|
||||
/*
|
||||
* Open the files, and give up if they won't open
|
||||
*/
|
||||
fromfd = open(from, O_RDONLY);
|
||||
if (fromfd<0) {
|
||||
err(1, "%s", from);
|
||||
}
|
||||
tofd = open(to, O_WRONLY|O_CREAT|O_TRUNC);
|
||||
if (tofd<0) {
|
||||
err(1, "%s", to);
|
||||
}
|
||||
/*
|
||||
* Open the files, and give up if they won't open
|
||||
*/
|
||||
fromfd = open(from, O_RDONLY);
|
||||
if (fromfd < 0) {
|
||||
err(1, "%s", from);
|
||||
}
|
||||
tofd = open(to, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (tofd < 0) {
|
||||
err(1, "%s", to);
|
||||
}
|
||||
|
||||
/*
|
||||
* As long as we get more than zero bytes, we haven't hit EOF.
|
||||
* Zero means EOF. Less than zero means an error occurred.
|
||||
* We may read less than we asked for, though, in various cases
|
||||
* for various reasons.
|
||||
*/
|
||||
while ((len = read(fromfd, buf, sizeof(buf)))>0) {
|
||||
/*
|
||||
* Likewise, we may actually write less than we attempted
|
||||
* to. So loop until we're done.
|
||||
*/
|
||||
wrtot = 0;
|
||||
while (wrtot < len) {
|
||||
wr = write(tofd, buf+wrtot, len-wrtot);
|
||||
if (wr<0) {
|
||||
err(1, "%s", to);
|
||||
}
|
||||
wrtot += wr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got a read error, print it and exit.
|
||||
*/
|
||||
if (len<0) {
|
||||
err(1, "%s", from);
|
||||
}
|
||||
/*
|
||||
* As long as we get more than zero bytes, we haven't hit EOF.
|
||||
* Zero means EOF. Less than zero means an error occurred.
|
||||
* We may read less than we asked for, though, in various cases
|
||||
* for various reasons.
|
||||
*/
|
||||
while ((len = read(fromfd, buf, sizeof(buf))) > 0) {
|
||||
/*
|
||||
* Likewise, we may actually write less than we attempted
|
||||
* to. So loop until we're done.
|
||||
*/
|
||||
wrtot = 0;
|
||||
while (wrtot < len) {
|
||||
wr = write(tofd, buf + wrtot, len - wrtot);
|
||||
if (wr < 0) {
|
||||
err(1, "%s", to);
|
||||
}
|
||||
wrtot += wr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we got a read error, print it and exit.
|
||||
*/
|
||||
if (len < 0) {
|
||||
err(1, "%s", from);
|
||||
}
|
||||
|
||||
if (close(fromfd) < 0) {
|
||||
err(1, "%s: close", from);
|
||||
}
|
||||
if (close(fromfd) < 0) {
|
||||
err(1, "%s: close", from);
|
||||
}
|
||||
|
||||
if (close(tofd) < 0) {
|
||||
err(1, "%s: close", to);
|
||||
}
|
||||
if (close(tofd) < 0) {
|
||||
err(1, "%s: close", to);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* Just do it.
|
||||
*
|
||||
* We don't allow the Unix model where you can do
|
||||
* cp file1 file2 file3 destination-directory
|
||||
*
|
||||
* although this would be pretty easy to add.
|
||||
*/
|
||||
if (argc!=3) {
|
||||
errx(1, "Usage: cp OLDFILE NEWFILE");
|
||||
}
|
||||
copy(argv[1], argv[2]);
|
||||
return 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Just do it.
|
||||
*
|
||||
* We don't allow the Unix model where you can do
|
||||
* cp file1 file2 file3 destination-directory
|
||||
*
|
||||
* although this would be pretty easy to add.
|
||||
*/
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: cp OLDFILE NEWFILE");
|
||||
}
|
||||
copy(argv[1], argv[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
* sure does - it fails all the time."
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Just exit with a failure code. */
|
||||
exit(1);
|
||||
int main(void) {
|
||||
/* Just exit with a failure code. */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -39,20 +39,16 @@
|
||||
* ln -s symlinkcontents symlinkfile
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Create a symlink with filename PATH that contains text TEXT.
|
||||
* When fed to ls -l, this produces something that looks like
|
||||
*
|
||||
* lrwxrwxrwx [stuff] PATH -> TEXT
|
||||
*/
|
||||
static
|
||||
void
|
||||
dosymlink(const char *text, const char *path)
|
||||
{
|
||||
if (symlink(text, path)) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
static void dosymlink(const char *text, const char *path) {
|
||||
if (symlink(text, path)) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -60,34 +56,27 @@ dosymlink(const char *text, const char *path)
|
||||
* OLDFILE. Since it's a hard link, the two names for the file
|
||||
* are equal; both are the "real" file.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dohardlink(const char *oldfile, const char *newfile)
|
||||
{
|
||||
if (link(oldfile, newfile)) {
|
||||
err(1, "%s or %s", oldfile, newfile);
|
||||
exit(1);
|
||||
}
|
||||
static void dohardlink(const char *oldfile, const char *newfile) {
|
||||
if (link(oldfile, newfile)) {
|
||||
err(1, "%s or %s", oldfile, newfile);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* Just do whatever was asked for.
|
||||
*
|
||||
* We don't allow the Unix model where you can do
|
||||
* ln [-s] file1 file2 file3 destination-directory
|
||||
*/
|
||||
if (argc==4 && !strcmp(argv[1], "-s")) {
|
||||
dosymlink(argv[2], argv[3]);
|
||||
}
|
||||
else if (argc==3) {
|
||||
dohardlink(argv[1], argv[2]);
|
||||
}
|
||||
else {
|
||||
warnx("Usage: ln oldfile newfile");
|
||||
errx(1, " ln -s symlinkcontents symlinkfile\n");
|
||||
}
|
||||
return 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Just do whatever was asked for.
|
||||
*
|
||||
* We don't allow the Unix model where you can do
|
||||
* ln [-s] file1 file2 file3 destination-directory
|
||||
*/
|
||||
if (argc == 4 && !strcmp(argv[1], "-s")) {
|
||||
dosymlink(argv[2], argv[3]);
|
||||
} else if (argc == 3) {
|
||||
dohardlink(argv[1], argv[2]);
|
||||
} else {
|
||||
warnx("Usage: ln oldfile newfile");
|
||||
errx(1, " ln -s symlinkcontents symlinkfile\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -46,300 +46,274 @@
|
||||
*/
|
||||
|
||||
/* Flags for which options we're using. */
|
||||
static int aopt=0;
|
||||
static int dopt=0;
|
||||
static int lopt=0;
|
||||
static int Ropt=0;
|
||||
static int sopt=0;
|
||||
static int aopt = 0;
|
||||
static int dopt = 0;
|
||||
static int lopt = 0;
|
||||
static int Ropt = 0;
|
||||
static int sopt = 0;
|
||||
|
||||
/* Process an option character. */
|
||||
static
|
||||
void
|
||||
option(int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'a': aopt=1; break;
|
||||
case 'd': dopt=1; break;
|
||||
case 'l': lopt=1; break;
|
||||
case 'R': Ropt=1; break;
|
||||
case 's': sopt=1; break;
|
||||
default:
|
||||
errx(1, "Unknown option -%c", ch);
|
||||
}
|
||||
static void option(int ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
aopt = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dopt = 1;
|
||||
break;
|
||||
case 'l':
|
||||
lopt = 1;
|
||||
break;
|
||||
case 'R':
|
||||
Ropt = 1;
|
||||
break;
|
||||
case 's':
|
||||
sopt = 1;
|
||||
break;
|
||||
default:
|
||||
errx(1, "Unknown option -%c", ch);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to find the non-directory part of a pathname.
|
||||
*/
|
||||
static
|
||||
const char *
|
||||
basename(const char *path)
|
||||
{
|
||||
const char *s;
|
||||
static const char *basename(const char *path) {
|
||||
const char *s;
|
||||
|
||||
s = strrchr(path, '/');
|
||||
if (s) {
|
||||
return s+1;
|
||||
}
|
||||
return path;
|
||||
s = strrchr(path, '/');
|
||||
if (s) {
|
||||
return s + 1;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to check if a name refers to a directory.
|
||||
*/
|
||||
static
|
||||
int
|
||||
isdir(const char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
int fd;
|
||||
static int isdir(const char *path) {
|
||||
struct stat buf;
|
||||
int fd;
|
||||
|
||||
/* Assume stat() may not be implemented; use fstat */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &buf)<0) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
close(fd);
|
||||
/* Assume stat() may not be implemented; use fstat */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &buf) < 0) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return S_ISDIR(buf.st_mode);
|
||||
return S_ISDIR(buf.st_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* When listing one of several subdirectories, show the name of the
|
||||
* directory.
|
||||
*/
|
||||
static
|
||||
void
|
||||
printheader(const char *file)
|
||||
{
|
||||
/* No blank line before the first header */
|
||||
static int first=1;
|
||||
if (first) {
|
||||
first = 0;
|
||||
}
|
||||
else {
|
||||
printf("\n");
|
||||
}
|
||||
printf("%s:\n", file);
|
||||
static void printheader(const char *file) {
|
||||
/* No blank line before the first header */
|
||||
static int first = 1;
|
||||
if (first) {
|
||||
first = 0;
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
printf("%s:\n", file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a single file.
|
||||
* We don't do the neat multicolumn listing that Unix ls does.
|
||||
*/
|
||||
static
|
||||
void
|
||||
print(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
const char *file;
|
||||
int typech;
|
||||
static void print(const char *path) {
|
||||
struct stat statbuf;
|
||||
const char *file;
|
||||
int typech;
|
||||
|
||||
if (lopt || sopt) {
|
||||
int fd;
|
||||
if (lopt || sopt) {
|
||||
int fd;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &statbuf)<0) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &statbuf) < 0) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
file = basename(path);
|
||||
file = basename(path);
|
||||
|
||||
if (sopt) {
|
||||
printf("%3d ", statbuf.st_blocks);
|
||||
}
|
||||
if (sopt) {
|
||||
printf("%3d ", statbuf.st_blocks);
|
||||
}
|
||||
|
||||
if (lopt) {
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
typech = '-';
|
||||
}
|
||||
else if (S_ISDIR(statbuf.st_mode)) {
|
||||
typech = 'd';
|
||||
}
|
||||
else if (S_ISLNK(statbuf.st_mode)) {
|
||||
typech = 'l';
|
||||
}
|
||||
else if (S_ISCHR(statbuf.st_mode)) {
|
||||
typech = 'c';
|
||||
}
|
||||
else if (S_ISBLK(statbuf.st_mode)) {
|
||||
typech = 'b';
|
||||
}
|
||||
else {
|
||||
typech = '?';
|
||||
}
|
||||
if (lopt) {
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
typech = '-';
|
||||
} else if (S_ISDIR(statbuf.st_mode)) {
|
||||
typech = 'd';
|
||||
} else if (S_ISLNK(statbuf.st_mode)) {
|
||||
typech = 'l';
|
||||
} else if (S_ISCHR(statbuf.st_mode)) {
|
||||
typech = 'c';
|
||||
} else if (S_ISBLK(statbuf.st_mode)) {
|
||||
typech = 'b';
|
||||
} else {
|
||||
typech = '?';
|
||||
}
|
||||
|
||||
printf("%crwx------ %2d root %-7llu ",
|
||||
typech,
|
||||
statbuf.st_nlink,
|
||||
statbuf.st_size);
|
||||
}
|
||||
printf("%s\n", file);
|
||||
printf("%crwx------ %2d root %-7llu ", typech, statbuf.st_nlink,
|
||||
statbuf.st_size);
|
||||
}
|
||||
printf("%s\n", file);
|
||||
}
|
||||
|
||||
/*
|
||||
* List a directory.
|
||||
*/
|
||||
static
|
||||
void
|
||||
listdir(const char *path, int showheader)
|
||||
{
|
||||
int fd;
|
||||
char buf[1024];
|
||||
char newpath[1024];
|
||||
ssize_t len;
|
||||
static void listdir(const char *path, int showheader) {
|
||||
int fd;
|
||||
char buf[1024];
|
||||
char newpath[1024];
|
||||
ssize_t len;
|
||||
|
||||
if (showheader) {
|
||||
printheader(path);
|
||||
}
|
||||
if (showheader) {
|
||||
printheader(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open it.
|
||||
*/
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
/*
|
||||
* Open it.
|
||||
*/
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* List the directory.
|
||||
*/
|
||||
while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) {
|
||||
buf[len] = 0;
|
||||
/*
|
||||
* List the directory.
|
||||
*/
|
||||
while ((len = getdirentry(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||
buf[len] = 0;
|
||||
|
||||
/* Assemble the full name of the new item */
|
||||
snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
|
||||
/* Assemble the full name of the new item */
|
||||
snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
|
||||
|
||||
if (aopt || buf[0]!='.') {
|
||||
/* Print it */
|
||||
print(newpath);
|
||||
}
|
||||
}
|
||||
if (len<0) {
|
||||
err(1, "%s: getdirentry", path);
|
||||
}
|
||||
if (aopt || buf[0] != '.') {
|
||||
/* Print it */
|
||||
print(newpath);
|
||||
}
|
||||
}
|
||||
if (len < 0) {
|
||||
err(1, "%s: getdirentry", path);
|
||||
}
|
||||
|
||||
/* Done */
|
||||
close(fd);
|
||||
/* Done */
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
recursedir(const char *path)
|
||||
{
|
||||
int fd;
|
||||
char buf[1024];
|
||||
char newpath[1024];
|
||||
int len;
|
||||
static void recursedir(const char *path) {
|
||||
int fd;
|
||||
char buf[1024];
|
||||
char newpath[1024];
|
||||
int len;
|
||||
|
||||
/*
|
||||
* Open it.
|
||||
*/
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
/*
|
||||
* Open it.
|
||||
*/
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* List the directory.
|
||||
*/
|
||||
while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) {
|
||||
buf[len] = 0;
|
||||
/*
|
||||
* List the directory.
|
||||
*/
|
||||
while ((len = getdirentry(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||
buf[len] = 0;
|
||||
|
||||
/* Assemble the full name of the new item */
|
||||
snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
|
||||
/* Assemble the full name of the new item */
|
||||
snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
|
||||
|
||||
if (!aopt && buf[0]=='.') {
|
||||
/* skip this one */
|
||||
continue;
|
||||
}
|
||||
if (!aopt && buf[0] == '.') {
|
||||
/* skip this one */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
|
||||
/* always skip these */
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
|
||||
/* always skip these */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isdir(newpath)) {
|
||||
continue;
|
||||
}
|
||||
if (!isdir(newpath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
listdir(newpath, 1 /*showheader*/);
|
||||
if (Ropt) {
|
||||
recursedir(newpath);
|
||||
}
|
||||
}
|
||||
if (len<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
listdir(newpath, 1 /*showheader*/);
|
||||
if (Ropt) {
|
||||
recursedir(newpath);
|
||||
}
|
||||
}
|
||||
if (len < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
listitem(const char *path, int showheader)
|
||||
{
|
||||
if (!dopt && isdir(path)) {
|
||||
listdir(path, showheader || Ropt);
|
||||
if (Ropt) {
|
||||
recursedir(path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
print(path);
|
||||
}
|
||||
static void listitem(const char *path, int showheader) {
|
||||
if (!dopt && isdir(path)) {
|
||||
listdir(path, showheader || Ropt);
|
||||
if (Ropt) {
|
||||
recursedir(path);
|
||||
}
|
||||
} else {
|
||||
print(path);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i,j, items=0;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, j, items = 0;
|
||||
|
||||
/*
|
||||
* Go through the arguments and count how many non-option args.
|
||||
*/
|
||||
for (i=1; i<argc; i++) {
|
||||
if (argv[i][0]!='-') {
|
||||
items++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Go through the arguments and count how many non-option args.
|
||||
*/
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] != '-') {
|
||||
items++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now go through the options for real, processing them.
|
||||
*/
|
||||
for (i=1; i<argc; i++) {
|
||||
if (argv[i][0]=='-') {
|
||||
/*
|
||||
* This word is an option.
|
||||
* Process all the option characters in it.
|
||||
*/
|
||||
for (j=1; argv[i][j]; j++) {
|
||||
option(argv[i][j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* This word isn't an option; list it.
|
||||
*/
|
||||
listitem(argv[i], items>1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Now go through the options for real, processing them.
|
||||
*/
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
/*
|
||||
* This word is an option.
|
||||
* Process all the option characters in it.
|
||||
*/
|
||||
for (j = 1; argv[i][j]; j++) {
|
||||
option(argv[i][j]);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This word isn't an option; list it.
|
||||
*/
|
||||
listitem(argv[i], items > 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no filenames were specified to list, list the current
|
||||
* directory.
|
||||
*/
|
||||
if (items==0) {
|
||||
listitem(".", 0);
|
||||
}
|
||||
/*
|
||||
* If no filenames were specified to list, list the current
|
||||
* directory.
|
||||
*/
|
||||
if (items == 0) {
|
||||
listitem(".", 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -39,15 +39,13 @@
|
||||
* Just calls the mkdir() system call.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=2) {
|
||||
errx(1, "Usage: mkdir DIRECTORY");
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
errx(1, "Usage: mkdir DIRECTORY");
|
||||
}
|
||||
|
||||
if (mkdir(argv[1], 0775)) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
return 0;
|
||||
if (mkdir(argv[1], 0775)) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,21 +44,16 @@
|
||||
* mv file1 file2 file3 destination-dir
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
dorename(const char *oldfile, const char *newfile)
|
||||
{
|
||||
if (rename(oldfile, newfile)) {
|
||||
err(1, "%s or %s", oldfile, newfile);
|
||||
}
|
||||
static void dorename(const char *oldfile, const char *newfile) {
|
||||
if (rename(oldfile, newfile)) {
|
||||
err(1, "%s or %s", oldfile, newfile);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=3) {
|
||||
errx(1, "Usage: mv oldfile newfile");
|
||||
}
|
||||
dorename(argv[1], argv[2]);
|
||||
return 0;
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: mv oldfile newfile");
|
||||
}
|
||||
dorename(argv[1], argv[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,15 +41,13 @@
|
||||
* system call.)
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
char buf[PATH_MAX+1], *p;
|
||||
int main(void) {
|
||||
char buf[PATH_MAX + 1], *p;
|
||||
|
||||
p = getcwd(buf, sizeof(buf));
|
||||
if (p == NULL) {
|
||||
err(1, ".");
|
||||
}
|
||||
printf("%s\n", buf);
|
||||
return 0;
|
||||
p = getcwd(buf, sizeof(buf));
|
||||
if (p == NULL) {
|
||||
err(1, ".");
|
||||
}
|
||||
printf("%s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,29 +36,24 @@
|
||||
*/
|
||||
|
||||
/* Delete a single file. */
|
||||
static
|
||||
void
|
||||
doremove(const char *file)
|
||||
{
|
||||
if (remove(file)) {
|
||||
err(1, "%s", file);
|
||||
}
|
||||
static void doremove(const char *file) {
|
||||
if (remove(file)) {
|
||||
err(1, "%s", file);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
if (argc<2) {
|
||||
/* Must have at least one file. */
|
||||
errx(1, "Usage: rm FILES");
|
||||
}
|
||||
if (argc < 2) {
|
||||
/* Must have at least one file. */
|
||||
errx(1, "Usage: rm FILES");
|
||||
}
|
||||
|
||||
/* Just delete everything on the command line. */
|
||||
for (i=1; i<argc; i++) {
|
||||
doremove(argv[i]);
|
||||
}
|
||||
/* Just delete everything on the command line. */
|
||||
for (i = 1; i < argc; i++) {
|
||||
doremove(argv[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,15 +37,13 @@
|
||||
* Just calls the rmdir() system call.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=2) {
|
||||
errx(1, "Usage: rmdir DIRECTORY");
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
errx(1, "Usage: rmdir DIRECTORY");
|
||||
}
|
||||
|
||||
if (rmdir(argv[1])) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
return 0;
|
||||
if (rmdir(argv[1])) {
|
||||
err(1, "%s", argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -60,10 +60,7 @@
|
||||
|
||||
/* struct to (portably) hold exit info */
|
||||
struct exitinfo {
|
||||
unsigned val:8,
|
||||
signaled:1,
|
||||
stopped:1,
|
||||
coredump:1;
|
||||
unsigned val : 8, signaled : 1, stopped : 1, coredump : 1;
|
||||
};
|
||||
|
||||
/* set to nonzero if __time syscall seems to work */
|
||||
@@ -77,19 +74,16 @@ static pid_t bgpids[MAXBG];
|
||||
* can_bg
|
||||
* just checks for an open slot.
|
||||
*/
|
||||
static
|
||||
int
|
||||
can_bg(void)
|
||||
{
|
||||
int i;
|
||||
static int can_bg(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,116 +91,92 @@ can_bg(void)
|
||||
* sticks the pid in an open slot in the background array. note the assert --
|
||||
* better check can_bg before calling this.
|
||||
*/
|
||||
static
|
||||
void
|
||||
remember_bg(pid_t pid)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] == 0) {
|
||||
bgpids[i] = pid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
static void remember_bg(pid_t pid) {
|
||||
int i;
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] == 0) {
|
||||
bgpids[i] = pid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* constructor for exitinfo
|
||||
*/
|
||||
static
|
||||
void
|
||||
exitinfo_exit(struct exitinfo *ei, int code)
|
||||
{
|
||||
ei->val = code;
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
static void exitinfo_exit(struct exitinfo *ei, int code) {
|
||||
ei->val = code;
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* readstatus
|
||||
* unpack results from wait
|
||||
*/
|
||||
static
|
||||
void
|
||||
readstatus(int status, struct exitinfo *ei)
|
||||
{
|
||||
if (WIFEXITED(status)) {
|
||||
ei->val = WEXITSTATUS(status);
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
}
|
||||
else if (WIFSIGNALED(status) && WCOREDUMP(status)) {
|
||||
ei->val = WTERMSIG(status);
|
||||
ei->signaled = 1;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 1;
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
ei->val = WTERMSIG(status);
|
||||
ei->signaled = 1;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
}
|
||||
else if (WIFSTOPPED(status)) {
|
||||
ei->val = WSTOPSIG(status);
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 1;
|
||||
ei->coredump = 0;
|
||||
}
|
||||
else {
|
||||
printf("Invalid status code %d", status);
|
||||
ei->val = status;
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
}
|
||||
|
||||
static void readstatus(int status, struct exitinfo *ei) {
|
||||
if (WIFEXITED(status)) {
|
||||
ei->val = WEXITSTATUS(status);
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
} else if (WIFSIGNALED(status) && WCOREDUMP(status)) {
|
||||
ei->val = WTERMSIG(status);
|
||||
ei->signaled = 1;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 1;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
ei->val = WTERMSIG(status);
|
||||
ei->signaled = 1;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
ei->val = WSTOPSIG(status);
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 1;
|
||||
ei->coredump = 0;
|
||||
} else {
|
||||
printf("Invalid status code %d", status);
|
||||
ei->val = status;
|
||||
ei->signaled = 0;
|
||||
ei->stopped = 0;
|
||||
ei->coredump = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* printstatus
|
||||
* print results from wait
|
||||
*/
|
||||
static
|
||||
void
|
||||
printstatus(const struct exitinfo *ei, int printexitzero)
|
||||
{
|
||||
if (ei->signaled && ei->coredump) {
|
||||
printf("Signal %d (core dumped)\n", ei->val);
|
||||
}
|
||||
else if (ei->signaled) {
|
||||
printf("Signal %d\n", ei->val);
|
||||
}
|
||||
else if (ei->stopped) {
|
||||
printf("Stopped on signal %d\n", ei->val);
|
||||
}
|
||||
else if (printexitzero || ei->val != 0) {
|
||||
printf("Exit %d\n", ei->val);
|
||||
}
|
||||
static void printstatus(const struct exitinfo *ei, int printexitzero) {
|
||||
if (ei->signaled && ei->coredump) {
|
||||
printf("Signal %d (core dumped)\n", ei->val);
|
||||
} else if (ei->signaled) {
|
||||
printf("Signal %d\n", ei->val);
|
||||
} else if (ei->stopped) {
|
||||
printf("Stopped on signal %d\n", ei->val);
|
||||
} else if (printexitzero || ei->val != 0) {
|
||||
printf("Exit %d\n", ei->val);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dowait
|
||||
* just does a waitpid.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dowait(pid_t pid)
|
||||
{
|
||||
struct exitinfo ei;
|
||||
int status;
|
||||
static void dowait(pid_t pid) {
|
||||
struct exitinfo ei;
|
||||
int status;
|
||||
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("pid %d", pid);
|
||||
}
|
||||
else {
|
||||
printf("pid %d: ", pid);
|
||||
readstatus(status, &ei);
|
||||
printstatus(&ei, 1);
|
||||
}
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("pid %d", pid);
|
||||
} else {
|
||||
printf("pid %d: ", pid);
|
||||
readstatus(status, &ei);
|
||||
printstatus(&ei, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WNOHANG
|
||||
@@ -214,43 +184,36 @@ dowait(pid_t pid)
|
||||
* dowaitpoll
|
||||
* like dowait, but uses WNOHANG. returns true if we got something.
|
||||
*/
|
||||
static
|
||||
int
|
||||
dowaitpoll(pid_t pid)
|
||||
{
|
||||
struct exitinfo ei;
|
||||
pid_t foundpid;
|
||||
int status;
|
||||
static int dowaitpoll(pid_t pid) {
|
||||
struct exitinfo ei;
|
||||
pid_t foundpid;
|
||||
int status;
|
||||
|
||||
foundpid = waitpid(pid, &status, WNOHANG);
|
||||
if (foundpid < 0) {
|
||||
warn("pid %d", pid);
|
||||
}
|
||||
else if (foundpid != 0) {
|
||||
printf("pid %d: ", pid);
|
||||
readstatus(status, &ei);
|
||||
printstatus(&ei, 1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
foundpid = waitpid(pid, &status, WNOHANG);
|
||||
if (foundpid < 0) {
|
||||
warn("pid %d", pid);
|
||||
} else if (foundpid != 0) {
|
||||
printf("pid %d: ", pid);
|
||||
readstatus(status, &ei);
|
||||
printstatus(&ei, 1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* waitpoll
|
||||
* poll all background jobs for having exited.
|
||||
*/
|
||||
static
|
||||
void
|
||||
waitpoll(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < MAXBG; i++) {
|
||||
if (bgpids[i] != 0) {
|
||||
if (dowaitpoll(bgpids[i])) {
|
||||
bgpids[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void waitpoll(void) {
|
||||
int i;
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] != 0) {
|
||||
if (dowaitpoll(bgpids[i])) {
|
||||
bgpids[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* WNOHANG */
|
||||
|
||||
@@ -260,36 +223,32 @@ waitpoll(void)
|
||||
* know the pids, this is a little tough to use with an arg, but without an
|
||||
* arg it will wait for all the background jobs.
|
||||
*/
|
||||
static
|
||||
void
|
||||
cmd_wait(int ac, char *av[], struct exitinfo *ei)
|
||||
{
|
||||
int i;
|
||||
pid_t pid;
|
||||
static void cmd_wait(int ac, char *av[], struct exitinfo *ei) {
|
||||
int i;
|
||||
pid_t pid;
|
||||
|
||||
if (ac == 2) {
|
||||
pid = atoi(av[1]);
|
||||
dowait(pid);
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i]==pid) {
|
||||
bgpids[i] = 0;
|
||||
}
|
||||
}
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
else if (ac == 1) {
|
||||
for (i=0; i < MAXBG; i++) {
|
||||
if (bgpids[i] != 0) {
|
||||
dowait(bgpids[i]);
|
||||
bgpids[i] = 0;
|
||||
}
|
||||
}
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
printf("Usage: wait [pid]\n");
|
||||
exitinfo_exit(ei, 1);
|
||||
if (ac == 2) {
|
||||
pid = atoi(av[1]);
|
||||
dowait(pid);
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] == pid) {
|
||||
bgpids[i] = 0;
|
||||
}
|
||||
}
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
} else if (ac == 1) {
|
||||
for (i = 0; i < MAXBG; i++) {
|
||||
if (bgpids[i] != 0) {
|
||||
dowait(bgpids[i]);
|
||||
bgpids[i] = 0;
|
||||
}
|
||||
}
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
printf("Usage: wait [pid]\n");
|
||||
exitinfo_exit(ei, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -297,21 +256,18 @@ cmd_wait(int ac, char *av[], struct exitinfo *ei)
|
||||
* just an interface to the system call. no concept of home directory, so
|
||||
* require the directory.
|
||||
*/
|
||||
static
|
||||
void
|
||||
cmd_chdir(int ac, char *av[], struct exitinfo *ei)
|
||||
{
|
||||
if (ac == 2) {
|
||||
if (chdir(av[1])) {
|
||||
warn("chdir: %s", av[1]);
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
printf("Usage: chdir dir\n");
|
||||
exitinfo_exit(ei, 1);
|
||||
static void cmd_chdir(int ac, char *av[], struct exitinfo *ei) {
|
||||
if (ac == 2) {
|
||||
if (chdir(av[1])) {
|
||||
warn("chdir: %s", av[1]);
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
printf("Usage: chdir dir\n");
|
||||
exitinfo_exit(ei, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -319,25 +275,20 @@ cmd_chdir(int ac, char *av[], struct exitinfo *ei)
|
||||
* pretty simple. allow the user to choose the exit code if they want,
|
||||
* otherwise default to 0 (success).
|
||||
*/
|
||||
static
|
||||
void
|
||||
cmd_exit(int ac, char *av[], struct exitinfo *ei)
|
||||
{
|
||||
int code;
|
||||
static void cmd_exit(int ac, char *av[], struct exitinfo *ei) {
|
||||
int code;
|
||||
|
||||
if (ac == 1) {
|
||||
code = 0;
|
||||
}
|
||||
else if (ac == 2) {
|
||||
code = atoi(av[1]);
|
||||
}
|
||||
else {
|
||||
printf("Usage: exit [code]\n");
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
if (ac == 1) {
|
||||
code = 0;
|
||||
} else if (ac == 2) {
|
||||
code = atoi(av[1]);
|
||||
} else {
|
||||
printf("Usage: exit [code]\n");
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
exit(code);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -345,15 +296,13 @@ cmd_exit(int ac, char *av[], struct exitinfo *ei)
|
||||
* executes it. they must all take an argc and argv.
|
||||
*/
|
||||
static struct {
|
||||
const char *name;
|
||||
void (*func)(int, char **, struct exitinfo *);
|
||||
} builtins[] = {
|
||||
{ "cd", cmd_chdir },
|
||||
{ "chdir", cmd_chdir },
|
||||
{ "exit", cmd_exit },
|
||||
{ "wait", cmd_wait },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
const char *name;
|
||||
void (*func)(int, char **, struct exitinfo *);
|
||||
} builtins[] = {{"cd", cmd_chdir},
|
||||
{"chdir", cmd_chdir},
|
||||
{"exit", cmd_exit},
|
||||
{"wait", cmd_wait},
|
||||
{NULL, NULL}};
|
||||
|
||||
/*
|
||||
* docommand
|
||||
@@ -362,116 +311,112 @@ static struct {
|
||||
* otherwise, it's a standard command. check for the '&', try to background
|
||||
* the job if possible, otherwise just run it and wait on it.
|
||||
*/
|
||||
static
|
||||
void
|
||||
docommand(char *buf, struct exitinfo *ei)
|
||||
{
|
||||
char *args[NARG_MAX + 1];
|
||||
int nargs, i;
|
||||
char *s;
|
||||
pid_t pid;
|
||||
int status;
|
||||
int bg=0;
|
||||
time_t startsecs, endsecs;
|
||||
unsigned long startnsecs, endnsecs;
|
||||
static void docommand(char *buf, struct exitinfo *ei) {
|
||||
char *args[NARG_MAX + 1];
|
||||
int nargs, i;
|
||||
char *s;
|
||||
pid_t pid;
|
||||
int status;
|
||||
int bg = 0;
|
||||
time_t startsecs, endsecs;
|
||||
unsigned long startnsecs, endnsecs;
|
||||
|
||||
nargs = 0;
|
||||
for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) {
|
||||
if (nargs >= NARG_MAX) {
|
||||
printf("%s: Too many arguments "
|
||||
"(exceeds system limit)\n",
|
||||
args[0]);
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
args[nargs++] = s;
|
||||
}
|
||||
args[nargs] = NULL;
|
||||
nargs = 0;
|
||||
for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) {
|
||||
if (nargs >= NARG_MAX) {
|
||||
printf("%s: Too many arguments "
|
||||
"(exceeds system limit)\n",
|
||||
args[0]);
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
args[nargs++] = s;
|
||||
}
|
||||
args[nargs] = NULL;
|
||||
|
||||
if (nargs==0) {
|
||||
/* empty line */
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
if (nargs == 0) {
|
||||
/* empty line */
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0; builtins[i].name; i++) {
|
||||
if (!strcmp(builtins[i].name, args[0])) {
|
||||
builtins[i].func(nargs, args, ei);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; builtins[i].name; i++) {
|
||||
if (!strcmp(builtins[i].name, args[0])) {
|
||||
builtins[i].func(nargs, args, ei);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not a builtin; run it */
|
||||
/* Not a builtin; run it */
|
||||
|
||||
if (nargs > 0 && !strcmp(args[nargs-1], "&")) {
|
||||
/* background */
|
||||
if (!can_bg()) {
|
||||
printf("%s: Too many background jobs; wait for "
|
||||
"some to finish before starting more\n",
|
||||
args[0]);
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
nargs--;
|
||||
args[nargs] = NULL;
|
||||
bg = 1;
|
||||
}
|
||||
if (nargs > 0 && !strcmp(args[nargs - 1], "&")) {
|
||||
/* background */
|
||||
if (!can_bg()) {
|
||||
printf("%s: Too many background jobs; wait for "
|
||||
"some to finish before starting more\n",
|
||||
args[0]);
|
||||
exitinfo_exit(ei, 1);
|
||||
return;
|
||||
}
|
||||
nargs--;
|
||||
args[nargs] = NULL;
|
||||
bg = 1;
|
||||
}
|
||||
|
||||
if (timing) {
|
||||
__time(&startsecs, &startnsecs);
|
||||
}
|
||||
if (timing) {
|
||||
__time(&startsecs, &startnsecs);
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
/* error */
|
||||
warn("fork");
|
||||
exitinfo_exit(ei, 255);
|
||||
return;
|
||||
case 0:
|
||||
/* child */
|
||||
execvp(args[0], args);
|
||||
warn("%s", args[0]);
|
||||
/*
|
||||
* Use _exit() instead of exit() in the child
|
||||
* process to avoid calling atexit() functions,
|
||||
* which would cause hostcompat (if present) to
|
||||
* reset the tty state and mess up our input
|
||||
* handling.
|
||||
*/
|
||||
_exit(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
/* error */
|
||||
warn("fork");
|
||||
exitinfo_exit(ei, 255);
|
||||
return;
|
||||
case 0:
|
||||
/* child */
|
||||
execvp(args[0], args);
|
||||
warn("%s", args[0]);
|
||||
/*
|
||||
* Use _exit() instead of exit() in the child
|
||||
* process to avoid calling atexit() functions,
|
||||
* which would cause hostcompat (if present) to
|
||||
* reset the tty state and mess up our input
|
||||
* handling.
|
||||
*/
|
||||
_exit(1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* parent */
|
||||
if (bg) {
|
||||
/* background this command */
|
||||
remember_bg(pid);
|
||||
printf("[%d] %s ... &\n", pid, args[0]);
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
/* parent */
|
||||
if (bg) {
|
||||
/* background this command */
|
||||
remember_bg(pid);
|
||||
printf("[%d] %s ... &\n", pid, args[0]);
|
||||
exitinfo_exit(ei, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid");
|
||||
exitinfo_exit(ei, 255);
|
||||
}
|
||||
else {
|
||||
readstatus(status, ei);
|
||||
}
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid");
|
||||
exitinfo_exit(ei, 255);
|
||||
} else {
|
||||
readstatus(status, ei);
|
||||
}
|
||||
|
||||
if (timing) {
|
||||
__time(&endsecs, &endnsecs);
|
||||
if (endnsecs < startnsecs) {
|
||||
endnsecs += 1000000000;
|
||||
endsecs--;
|
||||
}
|
||||
endnsecs -= startnsecs;
|
||||
endsecs -= startsecs;
|
||||
warnx("subprocess time: %lu.%09lu seconds",
|
||||
(unsigned long) endsecs, (unsigned long) endnsecs);
|
||||
}
|
||||
if (timing) {
|
||||
__time(&endsecs, &endnsecs);
|
||||
if (endnsecs < startnsecs) {
|
||||
endnsecs += 1000000000;
|
||||
endsecs--;
|
||||
}
|
||||
endnsecs -= startnsecs;
|
||||
endsecs -= startsecs;
|
||||
warnx("subprocess time: %lu.%09lu seconds", (unsigned long)endsecs,
|
||||
(unsigned long)endnsecs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -484,40 +429,34 @@ docommand(char *buf, struct exitinfo *ei)
|
||||
* if there's an invalid character or a backspace when there's nothing
|
||||
* in the buffer, putchars an alert (bell).
|
||||
*/
|
||||
static
|
||||
void
|
||||
getcmd(char *buf, size_t len)
|
||||
{
|
||||
size_t pos = 0;
|
||||
int done=0, ch;
|
||||
static void getcmd(char *buf, size_t len) {
|
||||
size_t pos = 0;
|
||||
int done = 0, ch;
|
||||
|
||||
/*
|
||||
* In the absence of a <ctype.h>, assume input is 7-bit ASCII.
|
||||
*/
|
||||
/*
|
||||
* In the absence of a <ctype.h>, assume input is 7-bit ASCII.
|
||||
*/
|
||||
|
||||
while (!done) {
|
||||
ch = getchar();
|
||||
if ((ch == '\b' || ch == 127) && pos > 0) {
|
||||
putchar('\b');
|
||||
putchar(' ');
|
||||
putchar('\b');
|
||||
pos--;
|
||||
}
|
||||
else if (ch == '\r' || ch == '\n') {
|
||||
putchar('\r');
|
||||
putchar('\n');
|
||||
done = 1;
|
||||
}
|
||||
else if (ch >= 32 && ch < 127 && pos < len-1) {
|
||||
buf[pos++] = ch;
|
||||
putchar(ch);
|
||||
}
|
||||
else {
|
||||
/* alert (bell) character */
|
||||
putchar('\a');
|
||||
}
|
||||
}
|
||||
buf[pos] = 0;
|
||||
while (!done) {
|
||||
ch = getchar();
|
||||
if ((ch == '\b' || ch == 127) && pos > 0) {
|
||||
putchar('\b');
|
||||
putchar(' ');
|
||||
putchar('\b');
|
||||
pos--;
|
||||
} else if (ch == '\r' || ch == '\n') {
|
||||
putchar('\r');
|
||||
putchar('\n');
|
||||
done = 1;
|
||||
} else if (ch >= 32 && ch < 127 && pos < len - 1) {
|
||||
buf[pos++] = ch;
|
||||
putchar(ch);
|
||||
} else {
|
||||
/* alert (bell) character */
|
||||
putchar('\a');
|
||||
}
|
||||
}
|
||||
buf[pos] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -526,34 +465,28 @@ getcmd(char *buf, size_t len)
|
||||
* commands and running them (and printing the exit status if it's not
|
||||
* success.)
|
||||
*/
|
||||
static
|
||||
void
|
||||
interactive(void)
|
||||
{
|
||||
char buf[CMDLINE_MAX];
|
||||
struct exitinfo ei;
|
||||
static void interactive(void) {
|
||||
char buf[CMDLINE_MAX];
|
||||
struct exitinfo ei;
|
||||
|
||||
while (1) {
|
||||
printf("OS/161$ ");
|
||||
getcmd(buf, sizeof(buf));
|
||||
docommand(buf, &ei);
|
||||
printstatus(&ei, 0);
|
||||
while (1) {
|
||||
printf("OS/161$ ");
|
||||
getcmd(buf, sizeof(buf));
|
||||
docommand(buf, &ei);
|
||||
printstatus(&ei, 0);
|
||||
#ifdef WNOHANG
|
||||
waitpoll();
|
||||
waitpoll();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
check_timing(void)
|
||||
{
|
||||
time_t secs;
|
||||
unsigned long nsecs;
|
||||
if (__time(&secs, &nsecs) != -1) {
|
||||
timing = 1;
|
||||
warnx("Timing enabled.");
|
||||
}
|
||||
static void check_timing(void) {
|
||||
time_t secs;
|
||||
unsigned long nsecs;
|
||||
if (__time(&secs, &nsecs) != -1) {
|
||||
timing = 1;
|
||||
warnx("Timing enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -561,31 +494,27 @@ check_timing(void)
|
||||
* if there are no arguments, run interactively, otherwise, run a program
|
||||
* from within the shell, but immediately exit.
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
#ifdef HOST
|
||||
hostcompat_init(argc, argv);
|
||||
hostcompat_init(argc, argv);
|
||||
#endif
|
||||
check_timing();
|
||||
check_timing();
|
||||
|
||||
/*
|
||||
* Allow argc to be 0 in case we're running on a broken kernel,
|
||||
* or one that doesn't set argv when starting the first shell.
|
||||
*/
|
||||
if (argc == 0 || argc == 1) {
|
||||
interactive();
|
||||
}
|
||||
else if (argc == 3 && !strcmp(argv[1], "-c")) {
|
||||
struct exitinfo ei;
|
||||
docommand(argv[2], &ei);
|
||||
printstatus(&ei, 0);
|
||||
if (ei.signaled || ei.stopped || ei.val != 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
errx(1, "Usage: sh [-c command]");
|
||||
}
|
||||
return 0;
|
||||
/*
|
||||
* Allow argc to be 0 in case we're running on a broken kernel,
|
||||
* or one that doesn't set argv when starting the first shell.
|
||||
*/
|
||||
if (argc == 0 || argc == 1) {
|
||||
interactive();
|
||||
} else if (argc == 3 && !strcmp(argv[1], "-c")) {
|
||||
struct exitinfo ei;
|
||||
docommand(argv[2], &ei);
|
||||
printstatus(&ei, 0);
|
||||
if (ei.signaled || ei.stopped || ei.val != 0) {
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
errx(1, "Usage: sh [-c command]");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,9 +35,7 @@
|
||||
* Just calls the sync() system call.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
sync();
|
||||
return 0;
|
||||
int main(void) {
|
||||
sync();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@
|
||||
#include <err.h>
|
||||
|
||||
struct indexentry {
|
||||
off_t pos;
|
||||
off_t len;
|
||||
off_t pos;
|
||||
off_t len;
|
||||
};
|
||||
|
||||
static int datafd = -1, indexfd = -1;
|
||||
@@ -67,226 +67,194 @@ static char buf[4096];
|
||||
// string ops
|
||||
|
||||
/* this is standard and should go into libc */
|
||||
static
|
||||
void *
|
||||
memchr(const void *buf, int ch, size_t buflen)
|
||||
{
|
||||
const unsigned char *ubuf = buf;
|
||||
size_t i;
|
||||
static void *memchr(const void *buf, int ch, size_t buflen) {
|
||||
const unsigned char *ubuf = buf;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<buflen; i++) {
|
||||
if (ubuf[i] == ch) {
|
||||
/* this must launder const */
|
||||
return (void *)(ubuf + i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
for (i = 0; i < buflen; i++) {
|
||||
if (ubuf[i] == ch) {
|
||||
/* this must launder const */
|
||||
return (void *)(ubuf + i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// syscall wrappers
|
||||
|
||||
static
|
||||
size_t
|
||||
doread(int fd, const char *name, void *buf, size_t len)
|
||||
{
|
||||
ssize_t r;
|
||||
static size_t doread(int fd, const char *name, void *buf, size_t len) {
|
||||
ssize_t r;
|
||||
|
||||
r = read(fd, buf, len);
|
||||
if (r == -1) {
|
||||
err(1, "%s: read", name);
|
||||
}
|
||||
return (size_t)r;
|
||||
r = read(fd, buf, len);
|
||||
if (r == -1) {
|
||||
err(1, "%s: read", name);
|
||||
}
|
||||
return (size_t)r;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dowrite(int fd, const char *name, const void *buf, size_t len)
|
||||
{
|
||||
ssize_t r;
|
||||
static void dowrite(int fd, const char *name, const void *buf, size_t len) {
|
||||
ssize_t r;
|
||||
|
||||
r = write(fd, buf, len);
|
||||
if (r == -1) {
|
||||
err(1, "%s: write", name);
|
||||
}
|
||||
else if ((size_t)r != len) {
|
||||
errx(1, "%s: write: Unexpected short count %zd of %zu",
|
||||
r, len);
|
||||
}
|
||||
r = write(fd, buf, len);
|
||||
if (r == -1) {
|
||||
err(1, "%s: write", name);
|
||||
} else if ((size_t)r != len) {
|
||||
errx(1, "%s: write: Unexpected short count %zd of %zu", r, len);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
off_t
|
||||
dolseek(int fd, const char *name, off_t pos, int whence)
|
||||
{
|
||||
off_t ret;
|
||||
static off_t dolseek(int fd, const char *name, off_t pos, int whence) {
|
||||
off_t ret;
|
||||
|
||||
ret = lseek(fd, pos, whence);
|
||||
if (ret == -1) {
|
||||
err(1, "%s: lseek", name);
|
||||
}
|
||||
return ret;
|
||||
ret = lseek(fd, pos, whence);
|
||||
if (ret == -1) {
|
||||
err(1, "%s: lseek", name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// file I/O
|
||||
|
||||
static
|
||||
void
|
||||
readfile(const char *name)
|
||||
{
|
||||
int fd, closefd;
|
||||
struct indexentry x;
|
||||
size_t len, remaining, here;
|
||||
const char *s, *t;
|
||||
|
||||
if (name == NULL || !strcmp(name, "-")) {
|
||||
fd = STDIN_FILENO;
|
||||
closefd = -1;
|
||||
}
|
||||
else {
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", name);
|
||||
}
|
||||
closefd = fd;
|
||||
}
|
||||
static void readfile(const char *name) {
|
||||
int fd, closefd;
|
||||
struct indexentry x;
|
||||
size_t len, remaining, here;
|
||||
const char *s, *t;
|
||||
|
||||
x.pos = 0;
|
||||
x.len = 0;
|
||||
while (1) {
|
||||
len = doread(fd, name, buf, sizeof(buf));
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
if (name == NULL || !strcmp(name, "-")) {
|
||||
fd = STDIN_FILENO;
|
||||
closefd = -1;
|
||||
} else {
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", name);
|
||||
}
|
||||
closefd = fd;
|
||||
}
|
||||
|
||||
remaining = len;
|
||||
for (s = buf; s != NULL; s = t) {
|
||||
t = memchr(s, '\n', remaining);
|
||||
if (t != NULL) {
|
||||
t++;
|
||||
here = (t - s);
|
||||
x.len += here;
|
||||
remaining -= here;
|
||||
dowrite(indexfd, indexname, &x, sizeof(x));
|
||||
x.pos += x.len;
|
||||
x.len = 0;
|
||||
}
|
||||
else {
|
||||
x.len += remaining;
|
||||
}
|
||||
}
|
||||
dowrite(datafd, dataname, buf, len);
|
||||
}
|
||||
if (x.len > 0) {
|
||||
dowrite(indexfd, indexname, &x, sizeof(x));
|
||||
}
|
||||
x.pos = 0;
|
||||
x.len = 0;
|
||||
while (1) {
|
||||
len = doread(fd, name, buf, sizeof(buf));
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (closefd != -1) {
|
||||
close(closefd);
|
||||
}
|
||||
remaining = len;
|
||||
for (s = buf; s != NULL; s = t) {
|
||||
t = memchr(s, '\n', remaining);
|
||||
if (t != NULL) {
|
||||
t++;
|
||||
here = (t - s);
|
||||
x.len += here;
|
||||
remaining -= here;
|
||||
dowrite(indexfd, indexname, &x, sizeof(x));
|
||||
x.pos += x.len;
|
||||
x.len = 0;
|
||||
} else {
|
||||
x.len += remaining;
|
||||
}
|
||||
}
|
||||
dowrite(datafd, dataname, buf, len);
|
||||
}
|
||||
if (x.len > 0) {
|
||||
dowrite(indexfd, indexname, &x, sizeof(x));
|
||||
}
|
||||
|
||||
if (closefd != -1) {
|
||||
close(closefd);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpdata(void)
|
||||
{
|
||||
struct indexentry x;
|
||||
off_t indexsize, pos, done;
|
||||
size_t amount, len;
|
||||
static void dumpdata(void) {
|
||||
struct indexentry x;
|
||||
off_t indexsize, pos, done;
|
||||
size_t amount, len;
|
||||
|
||||
indexsize = dolseek(indexfd, indexname, 0, SEEK_CUR);
|
||||
pos = indexsize;
|
||||
assert(pos % sizeof(x) == 0);
|
||||
while (pos > 0) {
|
||||
pos -= sizeof(x);
|
||||
assert(pos >= 0);
|
||||
dolseek(indexfd, indexname, pos, SEEK_SET);
|
||||
indexsize = dolseek(indexfd, indexname, 0, SEEK_CUR);
|
||||
pos = indexsize;
|
||||
assert(pos % sizeof(x) == 0);
|
||||
while (pos > 0) {
|
||||
pos -= sizeof(x);
|
||||
assert(pos >= 0);
|
||||
dolseek(indexfd, indexname, pos, SEEK_SET);
|
||||
|
||||
len = doread(indexfd, indexname, &x, sizeof(x));
|
||||
if (len != sizeof(x)) {
|
||||
errx(1, "%s: read: Unexpected EOF", indexname);
|
||||
}
|
||||
dolseek(datafd, dataname, x.pos, SEEK_SET);
|
||||
len = doread(indexfd, indexname, &x, sizeof(x));
|
||||
if (len != sizeof(x)) {
|
||||
errx(1, "%s: read: Unexpected EOF", indexname);
|
||||
}
|
||||
dolseek(datafd, dataname, x.pos, SEEK_SET);
|
||||
|
||||
for (done = 0; done < x.len; done += amount) {
|
||||
amount = sizeof(buf);
|
||||
if ((off_t)amount > x.len - done) {
|
||||
amount = x.len - done;
|
||||
}
|
||||
len = doread(datafd, dataname, buf, amount);
|
||||
if (len != amount) {
|
||||
errx(1, "%s: read: Unexpected short count"
|
||||
" %zu of %zu", dataname, len, amount);
|
||||
}
|
||||
dowrite(STDOUT_FILENO, "stdout", buf, len);
|
||||
}
|
||||
}
|
||||
for (done = 0; done < x.len; done += amount) {
|
||||
amount = sizeof(buf);
|
||||
if ((off_t)amount > x.len - done) {
|
||||
amount = x.len - done;
|
||||
}
|
||||
len = doread(datafd, dataname, buf, amount);
|
||||
if (len != amount) {
|
||||
errx(1,
|
||||
"%s: read: Unexpected short count"
|
||||
" %zu of %zu",
|
||||
dataname, len, amount);
|
||||
}
|
||||
dowrite(STDOUT_FILENO, "stdout", buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// main
|
||||
|
||||
static
|
||||
int
|
||||
openscratch(const char *name, int flags, mode_t mode)
|
||||
{
|
||||
int fd;
|
||||
static int openscratch(const char *name, int flags, mode_t mode) {
|
||||
int fd;
|
||||
|
||||
fd = open(name, flags, mode);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", name);
|
||||
}
|
||||
if (remove(name) < 0) {
|
||||
if (errno != ENOSYS) {
|
||||
err(1, "%s: remove", name);
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
fd = open(name, flags, mode);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", name);
|
||||
}
|
||||
if (remove(name) < 0) {
|
||||
if (errno != ENOSYS) {
|
||||
err(1, "%s: remove", name);
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
openfiles(void)
|
||||
{
|
||||
pid_t pid;
|
||||
static void openfiles(void) {
|
||||
pid_t pid;
|
||||
|
||||
pid = getpid();
|
||||
pid = getpid();
|
||||
|
||||
snprintf(dataname, sizeof(dataname), ".tmp.tacdata.%d", (int)pid);
|
||||
datafd = openscratch(dataname, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
snprintf(dataname, sizeof(dataname), ".tmp.tacdata.%d", (int)pid);
|
||||
datafd = openscratch(dataname, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
|
||||
snprintf(indexname, sizeof(indexname), ".tmp.tacindex.%d", (int)pid);
|
||||
indexfd = openscratch(indexname, O_RDWR|O_CREAT|O_TRUNC, 0664);
|
||||
snprintf(indexname, sizeof(indexname), ".tmp.tacindex.%d", (int)pid);
|
||||
indexfd = openscratch(indexname, O_RDWR | O_CREAT | O_TRUNC, 0664);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
closefiles(void)
|
||||
{
|
||||
close(datafd);
|
||||
close(indexfd);
|
||||
indexfd = datafd = -1;
|
||||
static void closefiles(void) {
|
||||
close(datafd);
|
||||
close(indexfd);
|
||||
indexfd = datafd = -1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
openfiles();
|
||||
openfiles();
|
||||
|
||||
if (argc > 1) {
|
||||
for (i=1; i<argc; i++) {
|
||||
readfile(argv[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
readfile(NULL);
|
||||
}
|
||||
if (argc > 1) {
|
||||
for (i = 1; i < argc; i++) {
|
||||
readfile(argv[i]);
|
||||
}
|
||||
} else {
|
||||
readfile(NULL);
|
||||
}
|
||||
|
||||
dumpdata();
|
||||
dumpdata();
|
||||
|
||||
closefiles();
|
||||
return 0;
|
||||
closefiles();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,9 +34,7 @@
|
||||
* true - succeed.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Just exit with success. */
|
||||
exit(0);
|
||||
int main(void) {
|
||||
/* Just exit with success. */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -46,15 +46,14 @@ void __bad_assert(const char *file, int line, const char *msg);
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#if 0 /* not allowed by the C standard */
|
||||
#define assert(x) ((void)(x)) /* retain any side effects of X */
|
||||
#if 0 /* not allowed by the C standard */
|
||||
#define assert(x) ((void)(x)) /* retain any side effects of X */
|
||||
#else
|
||||
#define assert(x) ((void)0) /* mysteriously hide any side effects of X */
|
||||
#define assert(x) ((void)0) /* mysteriously hide any side effects of X */
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define assert(x) ((x) ? (void)0 : __bad_assert(__FILE__, __LINE__, #x))
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ASSERT_H_ */
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#ifndef _ERR_H_
|
||||
#define _ERR_H_
|
||||
|
||||
#include <sys/cdefs.h> /* for __DEAD */
|
||||
#include <kern/types.h> /* for __va_list */
|
||||
#include <sys/cdefs.h> /* for __DEAD */
|
||||
#include <kern/types.h> /* for __va_list */
|
||||
|
||||
/*
|
||||
* 4.4BSD error-printing functions.
|
||||
|
||||
@@ -38,16 +38,15 @@
|
||||
#include <kern/limits.h>
|
||||
|
||||
/* Provide the real names */
|
||||
#define NAME_MAX __NAME_MAX
|
||||
#define PATH_MAX __PATH_MAX
|
||||
#define ARG_MAX __ARG_MAX
|
||||
#define PID_MIN __PID_MIN
|
||||
#define PID_MAX __PID_MAX
|
||||
#define PIPE_BUF __PIPE_BUF
|
||||
#define NGROUPS_MAX __NGROUPS_MAX
|
||||
#define LOGIN_NAME_MAX __LOGIN_NAME_MAX
|
||||
#define OPEN_MAX __OPEN_MAX
|
||||
#define IOV_MAX __IOV_MAX
|
||||
|
||||
#define NAME_MAX __NAME_MAX
|
||||
#define PATH_MAX __PATH_MAX
|
||||
#define ARG_MAX __ARG_MAX
|
||||
#define PID_MIN __PID_MIN
|
||||
#define PID_MAX __PID_MAX
|
||||
#define PIPE_BUF __PIPE_BUF
|
||||
#define NGROUPS_MAX __NGROUPS_MAX
|
||||
#define LOGIN_NAME_MAX __LOGIN_NAME_MAX
|
||||
#define OPEN_MAX __OPEN_MAX
|
||||
#define IOV_MAX __IOV_MAX
|
||||
|
||||
#endif /* _LIMITS_H_ */
|
||||
|
||||
@@ -43,12 +43,12 @@
|
||||
typedef __va_list va_list;
|
||||
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
||||
#define va_start(ap, fmt) __builtin_stdarg_start(ap, fmt)
|
||||
#define va_start(ap, fmt) __builtin_stdarg_start(ap, fmt)
|
||||
#else
|
||||
#define va_start(ap, fmt) __builtin_va_start(ap, fmt)
|
||||
#define va_start(ap, fmt) __builtin_va_start(ap, fmt)
|
||||
#endif
|
||||
#define va_arg(ap,t) __builtin_va_arg(ap,t)
|
||||
#define va_copy(ap1,ap2) __builtin_va_copy(ap1,ap2)
|
||||
#define va_arg(ap, t) __builtin_va_arg(ap, t)
|
||||
#define va_copy(ap1, ap2) __builtin_va_copy(ap1, ap2)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
|
||||
#endif /* _STDARG_H_ */
|
||||
|
||||
@@ -46,9 +46,7 @@
|
||||
* (for libc internal use only)
|
||||
*/
|
||||
int __vprintf(void (*sendfunc)(void *clientdata, const char *, size_t len),
|
||||
void *clientdata,
|
||||
const char *fmt,
|
||||
__va_list ap);
|
||||
void *clientdata, const char *fmt, __va_list ap);
|
||||
|
||||
/* Printf calls for user programs */
|
||||
int printf(const char *fmt, ...);
|
||||
|
||||
@@ -64,7 +64,7 @@ int system(const char *command);
|
||||
/*
|
||||
* Pseudo-random number generator.
|
||||
*/
|
||||
#define RAND_MAX 0x7fffffff
|
||||
#define RAND_MAX 0x7fffffff
|
||||
long random(void);
|
||||
void srandom(unsigned long seed);
|
||||
char *initstate(unsigned long, char *, size_t);
|
||||
@@ -80,6 +80,6 @@ void free(void *ptr);
|
||||
* Sort.
|
||||
*/
|
||||
void qsort(void *data, unsigned num, size_t size,
|
||||
int (*f)(const void *, const void *));
|
||||
int (*f)(const void *, const void *));
|
||||
|
||||
#endif /* _STDLIB_H_ */
|
||||
|
||||
@@ -61,5 +61,4 @@ const char *strerror(int errcode);
|
||||
*/
|
||||
void bzero(void *, size_t);
|
||||
|
||||
|
||||
#endif /* _STRING_H_ */
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#define S_ISDIR(mode) ((mode & _S_IFMT) == _S_IFDIR)
|
||||
#define S_ISLNK(mode) ((mode & _S_IFMT) == _S_IFLNK)
|
||||
#define S_ISIFO(mode) ((mode & _S_IFMT) == _S_IFIFO)
|
||||
#define S_ISSOCK(mode) ((mode & _S_IFMT) ==_S_IFSOCK)
|
||||
#define S_ISSOCK(mode) ((mode & _S_IFMT) == _S_IFSOCK)
|
||||
#define S_ISCHR(mode) ((mode & _S_IFMT) == _S_IFCHR)
|
||||
#define S_ISBLK(mode) ((mode & _S_IFMT) == _S_IFBLK)
|
||||
|
||||
@@ -52,14 +52,14 @@
|
||||
* Provide non-underscore names. These are not actually standard; for
|
||||
* some reason only the test macros are.
|
||||
*/
|
||||
#define S_IFMT _S_IFMT
|
||||
#define S_IFREG _S_IFREG
|
||||
#define S_IFDIR _S_IFDIR
|
||||
#define S_IFLNK _S_IFLNK
|
||||
#define S_IFIFO _S_IFIFO
|
||||
#define S_IFMT _S_IFMT
|
||||
#define S_IFREG _S_IFREG
|
||||
#define S_IFDIR _S_IFDIR
|
||||
#define S_IFLNK _S_IFLNK
|
||||
#define S_IFIFO _S_IFIFO
|
||||
#define S_IFSOCK _S_IFSOCK
|
||||
#define S_IFCHR _S_IFCHR
|
||||
#define S_IFBLK _S_IFBLK
|
||||
#define S_IFCHR _S_IFCHR
|
||||
#define S_IFBLK _S_IFBLK
|
||||
|
||||
/*
|
||||
* stat is the same as fstat, only on a file that isn't already
|
||||
@@ -79,5 +79,4 @@ int lstat(const char *path, struct stat *buf);
|
||||
*/
|
||||
int mkdir(const char *dirname, int ignore);
|
||||
|
||||
|
||||
#endif /* _SYS_STAT_H_ */
|
||||
|
||||
@@ -83,5 +83,4 @@ typedef __socklen_t socklen_t;
|
||||
|
||||
#define CHAR_BIT __CHAR_BIT
|
||||
|
||||
|
||||
#endif /* _SYS_TYPES_H_ */
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include <kern/unistd.h>
|
||||
#include <kern/wait.h>
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes for OS/161 system calls.
|
||||
*
|
||||
@@ -97,7 +96,6 @@
|
||||
* the text of the various assignments for an authoritative list.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* NOTE NOTE NOTE NOTE NOTE
|
||||
*
|
||||
@@ -107,7 +105,6 @@
|
||||
* functions will usually have slightly different signatures.
|
||||
*/
|
||||
|
||||
|
||||
/* Required. */
|
||||
__DEAD void _exit(int code);
|
||||
int execv(const char *prog, char *const *args);
|
||||
@@ -156,7 +153,7 @@ ssize_t __getcwd(char *buf, size_t buflen);
|
||||
*/
|
||||
|
||||
int execvp(const char *prog, char *const *args); /* calls execv */
|
||||
char *getcwd(char *buf, size_t buflen); /* calls __getcwd */
|
||||
time_t time(time_t *seconds); /* calls __time */
|
||||
char *getcwd(char *buf, size_t buflen); /* calls __getcwd */
|
||||
time_t time(time_t *seconds); /* calls __time */
|
||||
|
||||
#endif /* _UNISTD_H_ */
|
||||
|
||||
@@ -48,45 +48,40 @@ extern const char *hostcompat_progname;
|
||||
/*
|
||||
* Common routine for all the *err* and *warn* functions.
|
||||
*/
|
||||
static
|
||||
void
|
||||
hostcompat_printerr(int use_errno, const char *fmt, va_list ap)
|
||||
{
|
||||
const char *errmsg;
|
||||
static void hostcompat_printerr(int use_errno, const char *fmt, va_list ap) {
|
||||
const char *errmsg;
|
||||
|
||||
/*
|
||||
* Get the error message for the current errno.
|
||||
* Do this early, before doing anything that might change the
|
||||
* value in errno.
|
||||
*/
|
||||
errmsg = strerror(errno);
|
||||
/*
|
||||
* Get the error message for the current errno.
|
||||
* Do this early, before doing anything that might change the
|
||||
* value in errno.
|
||||
*/
|
||||
errmsg = strerror(errno);
|
||||
|
||||
/*
|
||||
* Look up the program name.
|
||||
* Strictly speaking we should pull off the rightmost
|
||||
* path component of argv[0] and use that as the program
|
||||
* name (this is how BSD err* prints) but it doesn't make
|
||||
* much difference.
|
||||
*/
|
||||
if (hostcompat_progname != NULL) {
|
||||
fprintf(stderr, "%s: ", hostcompat_progname);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "libhostcompat: hostcompat_init not called\n");
|
||||
fprintf(stderr, "libhostcompat-program: ");
|
||||
}
|
||||
/*
|
||||
* Look up the program name.
|
||||
* Strictly speaking we should pull off the rightmost
|
||||
* path component of argv[0] and use that as the program
|
||||
* name (this is how BSD err* prints) but it doesn't make
|
||||
* much difference.
|
||||
*/
|
||||
if (hostcompat_progname != NULL) {
|
||||
fprintf(stderr, "%s: ", hostcompat_progname);
|
||||
} else {
|
||||
fprintf(stderr, "libhostcompat: hostcompat_init not called\n");
|
||||
fprintf(stderr, "libhostcompat-program: ");
|
||||
}
|
||||
|
||||
/* process the printf format and args */
|
||||
vfprintf(stderr, fmt, ap);
|
||||
/* process the printf format and args */
|
||||
vfprintf(stderr, fmt, ap);
|
||||
|
||||
if (use_errno) {
|
||||
/* if we're using errno, print the error string from above. */
|
||||
fprintf(stderr, ": %s\n", errmsg);
|
||||
}
|
||||
else {
|
||||
/* otherwise, just a newline. */
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if (use_errno) {
|
||||
/* if we're using errno, print the error string from above. */
|
||||
fprintf(stderr, ": %s\n", errmsg);
|
||||
} else {
|
||||
/* otherwise, just a newline. */
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,33 +89,21 @@ hostcompat_printerr(int use_errno, const char *fmt, va_list ap)
|
||||
*/
|
||||
|
||||
/* warn/vwarn: use errno, don't exit */
|
||||
void
|
||||
vwarn(const char *fmt, va_list ap)
|
||||
{
|
||||
hostcompat_printerr(1, fmt, ap);
|
||||
}
|
||||
void vwarn(const char *fmt, va_list ap) { hostcompat_printerr(1, fmt, ap); }
|
||||
|
||||
/* warnx/vwarnx: don't use errno, don't exit */
|
||||
void
|
||||
vwarnx(const char *fmt, va_list ap)
|
||||
{
|
||||
hostcompat_printerr(0, fmt, ap);
|
||||
}
|
||||
void vwarnx(const char *fmt, va_list ap) { hostcompat_printerr(0, fmt, ap); }
|
||||
|
||||
/* err/verr: use errno, then exit */
|
||||
void
|
||||
verr(int exitcode, const char *fmt, va_list ap)
|
||||
{
|
||||
hostcompat_printerr(1, fmt, ap);
|
||||
exit(exitcode);
|
||||
void verr(int exitcode, const char *fmt, va_list ap) {
|
||||
hostcompat_printerr(1, fmt, ap);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/* errx/verrx: don't use errno, but do then exit */
|
||||
void
|
||||
verrx(int exitcode, const char *fmt, va_list ap)
|
||||
{
|
||||
hostcompat_printerr(0, fmt, ap);
|
||||
exit(exitcode);
|
||||
void verrx(int exitcode, const char *fmt, va_list ap) {
|
||||
hostcompat_printerr(0, fmt, ap);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,40 +111,32 @@ verrx(int exitcode, const char *fmt, va_list ap)
|
||||
* Just hand off to the va_list versions.
|
||||
*/
|
||||
|
||||
void
|
||||
warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarn(fmt, ap);
|
||||
va_end(ap);
|
||||
void warn(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarn(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
void warnx(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
err(int exitcode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verr(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
void err(int exitcode, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verr(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
errx(int exitcode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verrx(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
void errx(int exitcode, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verrx(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#endif /* NEED_ERR */
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HOSTCOMPAT_ERR_H
|
||||
#define HOSTCOMPAT_ERR_H
|
||||
|
||||
|
||||
@@ -51,188 +51,168 @@ static struct termios hostcompat_savetios;
|
||||
/*
|
||||
* Put the tty state back the way it was.
|
||||
*/
|
||||
static
|
||||
void
|
||||
hostcompat_ttyreset(void)
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_savetios);
|
||||
static void hostcompat_ttyreset(void) {
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_savetios);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the tty state back to the way we want it for running.
|
||||
*/
|
||||
static
|
||||
void
|
||||
hostcompat_ttyresume(void)
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_runtios);
|
||||
static void hostcompat_ttyresume(void) {
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_runtios);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the tty state stuff.
|
||||
*/
|
||||
static
|
||||
int
|
||||
hostcompat_ttysetup(void)
|
||||
{
|
||||
struct termios tios;
|
||||
static int hostcompat_ttysetup(void) {
|
||||
struct termios tios;
|
||||
|
||||
/* Get the current tty state. */
|
||||
if (tcgetattr(STDIN_FILENO, &tios) < 0) {
|
||||
/* stdin is not a tty */
|
||||
return -1;
|
||||
}
|
||||
/* Get the current tty state. */
|
||||
if (tcgetattr(STDIN_FILENO, &tios) < 0) {
|
||||
/* stdin is not a tty */
|
||||
return -1;
|
||||
}
|
||||
|
||||
hostcompat_savetios = tios;
|
||||
hostcompat_savetios = tios;
|
||||
|
||||
/* Turn off canonical ("cooked") input. */
|
||||
tios.c_lflag &= ~ICANON;
|
||||
/* Turn off canonical ("cooked") input. */
|
||||
tios.c_lflag &= ~ICANON;
|
||||
|
||||
/*
|
||||
* With canonical input off, this says how many characters must be
|
||||
* typed before read() will return.
|
||||
*/
|
||||
tios.c_cc[VMIN] = 1;
|
||||
/*
|
||||
* With canonical input off, this says how many characters must be
|
||||
* typed before read() will return.
|
||||
*/
|
||||
tios.c_cc[VMIN] = 1;
|
||||
|
||||
/* This can be used to set up read timeouts, but we don't need that. */
|
||||
tios.c_cc[VTIME] = 0;
|
||||
/* This can be used to set up read timeouts, but we don't need that. */
|
||||
tios.c_cc[VTIME] = 0;
|
||||
|
||||
/* Turn off echoing of keypresses. */
|
||||
tios.c_lflag &= ~(ECHO|ECHONL|ECHOCTL);
|
||||
/* Turn off echoing of keypresses. */
|
||||
tios.c_lflag &= ~(ECHO | ECHONL | ECHOCTL);
|
||||
|
||||
/* Do not support XON/XOFF flow control. */
|
||||
tios.c_iflag &= ~(IXON|IXOFF);
|
||||
/* Do not support XON/XOFF flow control. */
|
||||
tios.c_iflag &= ~(IXON | IXOFF);
|
||||
|
||||
/* On input, we want no CR/LF translation. */
|
||||
tios.c_iflag &= ~(INLCR|IGNCR|ICRNL);
|
||||
/* On input, we want no CR/LF translation. */
|
||||
tios.c_iflag &= ~(INLCR | IGNCR | ICRNL);
|
||||
|
||||
/* However, on output we want LF ('\n') mapped to CRLF. */
|
||||
#ifdef OCRNL /* missing on OS X */
|
||||
tios.c_oflag &= ~(OCRNL);
|
||||
/* However, on output we want LF ('\n') mapped to CRLF. */
|
||||
#ifdef OCRNL /* missing on OS X */
|
||||
tios.c_oflag &= ~(OCRNL);
|
||||
#endif
|
||||
tios.c_oflag |= OPOST|ONLCR;
|
||||
tios.c_oflag |= OPOST | ONLCR;
|
||||
|
||||
/* Enable keyboard signals (^C, ^Z, etc.) because they're useful. */
|
||||
tios.c_lflag |= ISIG;
|
||||
/* Enable keyboard signals (^C, ^Z, etc.) because they're useful. */
|
||||
tios.c_lflag |= ISIG;
|
||||
|
||||
/* Set the new tty state. */
|
||||
hostcompat_runtios = tios;
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &tios);
|
||||
/* Set the new tty state. */
|
||||
hostcompat_runtios = tios;
|
||||
tcsetattr(STDIN_FILENO, TCSADRAIN, &tios);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler for all the fatal signals (SIGSEGV, SIGTERM, etc.)
|
||||
*/
|
||||
static
|
||||
void
|
||||
hostcompat_die(int sig)
|
||||
{
|
||||
/* Set the tty back to the way we found it */
|
||||
hostcompat_ttyreset();
|
||||
static void hostcompat_die(int sig) {
|
||||
/* Set the tty back to the way we found it */
|
||||
hostcompat_ttyreset();
|
||||
|
||||
/* Make sure the default action will occur when we get another signal*/
|
||||
signal(sig, SIG_DFL);
|
||||
/* Make sure the default action will occur when we get another signal*/
|
||||
signal(sig, SIG_DFL);
|
||||
|
||||
/* Post the signal back to ourselves, to cause the right exit status.*/
|
||||
kill(getpid(), sig);
|
||||
/* Post the signal back to ourselves, to cause the right exit status.*/
|
||||
kill(getpid(), sig);
|
||||
|
||||
/* Just in case. */
|
||||
_exit(255);
|
||||
/* Just in case. */
|
||||
_exit(255);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler for the stop signals (SIGTSTP, SIGTTIN, etc.)
|
||||
*/
|
||||
static
|
||||
void
|
||||
hostcompat_stop(int sig)
|
||||
{
|
||||
/* Set the tty back to the way we found it */
|
||||
hostcompat_ttyreset();
|
||||
static void hostcompat_stop(int sig) {
|
||||
/* Set the tty back to the way we found it */
|
||||
hostcompat_ttyreset();
|
||||
|
||||
/* Make sure the default action will occur when we get another signal*/
|
||||
signal(sig, SIG_DFL);
|
||||
/* Make sure the default action will occur when we get another signal*/
|
||||
signal(sig, SIG_DFL);
|
||||
|
||||
/* Post the signal back to ourselves. */
|
||||
kill(getpid(), sig);
|
||||
/* Post the signal back to ourselves. */
|
||||
kill(getpid(), sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler for SIGCONT.
|
||||
*/
|
||||
static
|
||||
void
|
||||
hostcompat_cont(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
static void hostcompat_cont(int sig) {
|
||||
(void)sig;
|
||||
|
||||
/* Set the tty to the way we want it for running. */
|
||||
hostcompat_ttyresume();
|
||||
/* Set the tty to the way we want it for running. */
|
||||
hostcompat_ttyresume();
|
||||
|
||||
/*
|
||||
* Reload the signal handlers for stop/continue signals, in case
|
||||
* they were set up with one-shot signals.
|
||||
*/
|
||||
signal(SIGTTIN, hostcompat_stop);
|
||||
signal(SIGTTOU, hostcompat_stop);
|
||||
signal(SIGTSTP, hostcompat_stop);
|
||||
signal(SIGCONT, hostcompat_cont);
|
||||
/*
|
||||
* Reload the signal handlers for stop/continue signals, in case
|
||||
* they were set up with one-shot signals.
|
||||
*/
|
||||
signal(SIGTTIN, hostcompat_stop);
|
||||
signal(SIGTTOU, hostcompat_stop);
|
||||
signal(SIGTSTP, hostcompat_stop);
|
||||
signal(SIGCONT, hostcompat_cont);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the hostcompat library.
|
||||
*/
|
||||
void
|
||||
hostcompat_init(int argc, char *argv[])
|
||||
{
|
||||
/* Set the program name */
|
||||
if (argc > 0 && argv[0] != NULL) {
|
||||
hostcompat_progname = argv[0];
|
||||
}
|
||||
void hostcompat_init(int argc, char *argv[]) {
|
||||
/* Set the program name */
|
||||
if (argc > 0 && argv[0] != NULL) {
|
||||
hostcompat_progname = argv[0];
|
||||
}
|
||||
|
||||
/* Set the tty modes */
|
||||
if (hostcompat_ttysetup() < 0) {
|
||||
return;
|
||||
}
|
||||
/* Set the tty modes */
|
||||
if (hostcompat_ttysetup() < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* When exit() is called, clean up */
|
||||
atexit(hostcompat_ttyreset);
|
||||
/* When exit() is called, clean up */
|
||||
atexit(hostcompat_ttyreset);
|
||||
|
||||
/* stdout/stderr should be unbuffered */
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
/* stdout/stderr should be unbuffered */
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
/* Catch all the fatal signals, so we can clean up */
|
||||
signal(SIGHUP, hostcompat_die);
|
||||
signal(SIGINT, hostcompat_die);
|
||||
signal(SIGQUIT, hostcompat_die);
|
||||
signal(SIGILL, hostcompat_die);
|
||||
signal(SIGTRAP, hostcompat_die);
|
||||
signal(SIGABRT, hostcompat_die);
|
||||
/* Catch all the fatal signals, so we can clean up */
|
||||
signal(SIGHUP, hostcompat_die);
|
||||
signal(SIGINT, hostcompat_die);
|
||||
signal(SIGQUIT, hostcompat_die);
|
||||
signal(SIGILL, hostcompat_die);
|
||||
signal(SIGTRAP, hostcompat_die);
|
||||
signal(SIGABRT, hostcompat_die);
|
||||
#ifdef SIGEMT
|
||||
signal(SIGEMT, hostcompat_die);
|
||||
signal(SIGEMT, hostcompat_die);
|
||||
#endif
|
||||
signal(SIGFPE, hostcompat_die);
|
||||
signal(SIGBUS, hostcompat_die);
|
||||
signal(SIGSEGV, hostcompat_die);
|
||||
signal(SIGSYS, hostcompat_die);
|
||||
signal(SIGPIPE, hostcompat_die);
|
||||
signal(SIGALRM, hostcompat_die);
|
||||
signal(SIGTERM, hostcompat_die);
|
||||
signal(SIGXCPU, hostcompat_die);
|
||||
signal(SIGXFSZ, hostcompat_die);
|
||||
signal(SIGVTALRM, hostcompat_die);
|
||||
signal(SIGPROF, hostcompat_die);
|
||||
signal(SIGUSR1, hostcompat_die);
|
||||
signal(SIGUSR2, hostcompat_die);
|
||||
signal(SIGFPE, hostcompat_die);
|
||||
signal(SIGBUS, hostcompat_die);
|
||||
signal(SIGSEGV, hostcompat_die);
|
||||
signal(SIGSYS, hostcompat_die);
|
||||
signal(SIGPIPE, hostcompat_die);
|
||||
signal(SIGALRM, hostcompat_die);
|
||||
signal(SIGTERM, hostcompat_die);
|
||||
signal(SIGXCPU, hostcompat_die);
|
||||
signal(SIGXFSZ, hostcompat_die);
|
||||
signal(SIGVTALRM, hostcompat_die);
|
||||
signal(SIGPROF, hostcompat_die);
|
||||
signal(SIGUSR1, hostcompat_die);
|
||||
signal(SIGUSR2, hostcompat_die);
|
||||
|
||||
/* Catch the stop signals, so we can adjust the tty */
|
||||
signal(SIGTTIN, hostcompat_stop);
|
||||
signal(SIGTTOU, hostcompat_stop);
|
||||
signal(SIGTSTP, hostcompat_stop);
|
||||
/* Catch the stop signals, so we can adjust the tty */
|
||||
signal(SIGTTIN, hostcompat_stop);
|
||||
signal(SIGTTOU, hostcompat_stop);
|
||||
signal(SIGTSTP, hostcompat_stop);
|
||||
|
||||
/* Catch the continue signal, so we can adjust the tty */
|
||||
signal(SIGCONT, hostcompat_cont);
|
||||
/* Catch the continue signal, so we can adjust the tty */
|
||||
signal(SIGCONT, hostcompat_cont);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -34,20 +34,18 @@
|
||||
|
||||
#ifdef NEED_NTOHLL
|
||||
|
||||
uint64_t
|
||||
ntohll(uint64_t x)
|
||||
{
|
||||
uint32_t x0, x1, y0, y1;
|
||||
uint64_t ntohll(uint64_t x) {
|
||||
uint32_t x0, x1, y0, y1;
|
||||
|
||||
if (ntohl(1) == 1) {
|
||||
return x;
|
||||
}
|
||||
if (ntohl(1) == 1) {
|
||||
return x;
|
||||
}
|
||||
|
||||
x0 = x & 0xffffffff;
|
||||
y0 = ntohl(x0);
|
||||
x1 = x >> 32;
|
||||
y1 = ntohl(x1);
|
||||
return ((uint64_t)y0 << 32) | y1;
|
||||
x0 = x & 0xffffffff;
|
||||
y0 = ntohl(x0);
|
||||
x1 = x >> 32;
|
||||
y1 = ntohl(x1);
|
||||
return ((uint64_t)y0 << 32) | y1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,22 +33,20 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h> /* sometimes required for NULL */
|
||||
#include <string.h> /* sometimes required for NULL */
|
||||
|
||||
#include "hostcompat.h"
|
||||
|
||||
time_t
|
||||
__time(time_t *secs, unsigned long *nsecs)
|
||||
{
|
||||
struct timeval tv;
|
||||
if (gettimeofday(&tv, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (secs) {
|
||||
*secs = tv.tv_sec;
|
||||
}
|
||||
if (nsecs) {
|
||||
*nsecs = tv.tv_usec * 1000;
|
||||
}
|
||||
return tv.tv_sec;
|
||||
time_t __time(time_t *secs, unsigned long *nsecs) {
|
||||
struct timeval tv;
|
||||
if (gettimeofday(&tv, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (secs) {
|
||||
*secs = tv.tv_sec;
|
||||
}
|
||||
if (nsecs) {
|
||||
*nsecs = tv.tv_usec * 1000;
|
||||
}
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
@@ -38,16 +38,14 @@
|
||||
* Returns the length of the string printed.
|
||||
*/
|
||||
|
||||
int
|
||||
__puts(const char *str)
|
||||
{
|
||||
size_t len;
|
||||
ssize_t ret;
|
||||
int __puts(const char *str) {
|
||||
size_t len;
|
||||
ssize_t ret;
|
||||
|
||||
len = strlen(str);
|
||||
ret = write(STDOUT_FILENO, str, len);
|
||||
if (ret == -1) {
|
||||
return EOF;
|
||||
}
|
||||
return len;
|
||||
len = strlen(str);
|
||||
ret = write(STDOUT_FILENO, str, len);
|
||||
if (ret == -1) {
|
||||
return EOF;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -35,22 +35,20 @@
|
||||
* and return it or the symbolic constant EOF (-1).
|
||||
*/
|
||||
|
||||
int
|
||||
getchar(void)
|
||||
{
|
||||
char ch;
|
||||
int len;
|
||||
int getchar(void) {
|
||||
char ch;
|
||||
int len;
|
||||
|
||||
len = read(STDIN_FILENO, &ch, 1);
|
||||
if (len<=0) {
|
||||
/* end of file or error */
|
||||
return EOF;
|
||||
}
|
||||
len = read(STDIN_FILENO, &ch, 1);
|
||||
if (len <= 0) {
|
||||
/* end of file or error */
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cast through unsigned char, to prevent sign extension. This
|
||||
* sends back values on the range 0-255, rather than -128 to 127,
|
||||
* so EOF can be distinguished from legal input.
|
||||
*/
|
||||
return (int)(unsigned char)ch;
|
||||
/*
|
||||
* Cast through unsigned char, to prevent sign extension. This
|
||||
* sends back values on the range 0-255, rather than -128 to 127,
|
||||
* so EOF can be distinguished from legal input.
|
||||
*/
|
||||
return (int)(unsigned char)ch;
|
||||
}
|
||||
|
||||
@@ -36,43 +36,35 @@
|
||||
* printf - C standard I/O function.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Function passed to __vprintf to do the actual output.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__printf_send(void *mydata, const char *data, size_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
int *err = mydata;
|
||||
static void __printf_send(void *mydata, const char *data, size_t len) {
|
||||
ssize_t ret;
|
||||
int *err = mydata;
|
||||
|
||||
ret = write(STDOUT_FILENO, data, len);
|
||||
*err = (ret == -1) ? errno : 0;
|
||||
ret = write(STDOUT_FILENO, data, len);
|
||||
*err = (ret == -1) ? errno : 0;
|
||||
}
|
||||
|
||||
/* printf: hand off to vprintf */
|
||||
int
|
||||
printf(const char *fmt, ...)
|
||||
{
|
||||
int chars;
|
||||
va_list ap;
|
||||
int printf(const char *fmt, ...) {
|
||||
int chars;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
chars = vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return chars;
|
||||
va_start(ap, fmt);
|
||||
chars = vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return chars;
|
||||
}
|
||||
|
||||
/* vprintf: call __vprintf to do the work. */
|
||||
int
|
||||
vprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
int chars, err;
|
||||
chars = __vprintf(__printf_send, &err, fmt, ap);
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
return chars;
|
||||
int vprintf(const char *fmt, va_list ap) {
|
||||
int chars, err;
|
||||
chars = __vprintf(__printf_send, &err, fmt, ap);
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
@@ -37,14 +37,12 @@
|
||||
* writing that code is not really worthwhile.
|
||||
*/
|
||||
|
||||
int
|
||||
putchar(int ch)
|
||||
{
|
||||
char c = ch;
|
||||
int len;
|
||||
len = write(STDOUT_FILENO, &c, 1);
|
||||
if (len<=0) {
|
||||
return EOF;
|
||||
}
|
||||
return ch;
|
||||
int putchar(int ch) {
|
||||
char c = ch;
|
||||
int len;
|
||||
len = write(STDOUT_FILENO, &c, 1);
|
||||
if (len <= 0) {
|
||||
return EOF;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,8 @@
|
||||
* C standard I/O function - print a string and a newline.
|
||||
*/
|
||||
|
||||
int
|
||||
puts(const char *s)
|
||||
{
|
||||
__puts(s);
|
||||
putchar('\n');
|
||||
return 0;
|
||||
int puts(const char *s) {
|
||||
__puts(s);
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,4 @@
|
||||
* nonzero exit code, skipping any libc cleanup.
|
||||
*/
|
||||
|
||||
void
|
||||
abort(void)
|
||||
{
|
||||
_exit(255);
|
||||
}
|
||||
void abort(void) { _exit(255); }
|
||||
|
||||
@@ -34,50 +34,49 @@
|
||||
* C standard function: exit process.
|
||||
*/
|
||||
|
||||
void
|
||||
exit(int code)
|
||||
{
|
||||
/*
|
||||
* In a more complicated libc, this would call functions registered
|
||||
* with atexit() before calling the syscall to actually exit.
|
||||
*/
|
||||
void exit(int code) {
|
||||
/*
|
||||
* In a more complicated libc, this would call functions registered
|
||||
* with atexit() before calling the syscall to actually exit.
|
||||
*/
|
||||
|
||||
#ifdef __mips__
|
||||
/*
|
||||
* Because gcc knows that _exit doesn't return, if we call it
|
||||
* directly it will drop any code that follows it. This means
|
||||
* that if _exit *does* return, as happens before it's
|
||||
* implemented, undefined and usually weird behavior ensues.
|
||||
*
|
||||
* As a hack (this is quite gross) do the call by hand in an
|
||||
* asm block. Then gcc doesn't know what it is, and won't
|
||||
* optimize the following code out, and we can make sure
|
||||
* that exit() at least really does not return.
|
||||
*
|
||||
* This asm block violates gcc's asm rules by destroying a
|
||||
* register it doesn't declare ($4, which is a0) but this
|
||||
* hopefully doesn't matter as the only local it can lose
|
||||
* track of is "code" and we don't use it afterwards.
|
||||
*/
|
||||
__asm volatile("jal _exit;" /* call _exit */
|
||||
"move $4, %0" /* put code in a0 (delay slot) */
|
||||
: /* no outputs */
|
||||
: "r" (code)); /* code is an input */
|
||||
/*
|
||||
* Ok, exiting doesn't work; see if we can get our process
|
||||
* killed by making an illegal memory access. Use a magic
|
||||
* number address so the symptoms are recognizable and
|
||||
* unlikely to occur by accident otherwise.
|
||||
*/
|
||||
__asm volatile("li $2, 0xeeeee00f;" /* load magic addr into v0 */
|
||||
"lw $2, 0($2)" /* fetch from it */
|
||||
:: ); /* no args */
|
||||
/*
|
||||
* Because gcc knows that _exit doesn't return, if we call it
|
||||
* directly it will drop any code that follows it. This means
|
||||
* that if _exit *does* return, as happens before it's
|
||||
* implemented, undefined and usually weird behavior ensues.
|
||||
*
|
||||
* As a hack (this is quite gross) do the call by hand in an
|
||||
* asm block. Then gcc doesn't know what it is, and won't
|
||||
* optimize the following code out, and we can make sure
|
||||
* that exit() at least really does not return.
|
||||
*
|
||||
* This asm block violates gcc's asm rules by destroying a
|
||||
* register it doesn't declare ($4, which is a0) but this
|
||||
* hopefully doesn't matter as the only local it can lose
|
||||
* track of is "code" and we don't use it afterwards.
|
||||
*/
|
||||
__asm volatile("jal _exit;" /* call _exit */
|
||||
"move $4, %0" /* put code in a0 (delay slot) */
|
||||
: /* no outputs */
|
||||
: "r"(code)); /* code is an input */
|
||||
/*
|
||||
* Ok, exiting doesn't work; see if we can get our process
|
||||
* killed by making an illegal memory access. Use a magic
|
||||
* number address so the symptoms are recognizable and
|
||||
* unlikely to occur by accident otherwise.
|
||||
*/
|
||||
__asm volatile("li $2, 0xeeeee00f;" /* load magic addr into v0 */
|
||||
"lw $2, 0($2)" /* fetch from it */
|
||||
::); /* no args */
|
||||
#else
|
||||
_exit(code);
|
||||
_exit(code);
|
||||
#endif
|
||||
/*
|
||||
* We can't return; so if we can't exit, the only other choice
|
||||
* is to loop.
|
||||
*/
|
||||
while (1) { }
|
||||
/*
|
||||
* We can't return; so if we can't exit, the only other choice
|
||||
* is to loop.
|
||||
*/
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,34 +45,28 @@ extern char **__environ;
|
||||
* This is what we use by default if the kernel didn't supply an
|
||||
* environment.
|
||||
*/
|
||||
static const char *__default_environ[] = {
|
||||
"PATH=/bin:/sbin:/testbin",
|
||||
"SHELL=/bin/sh",
|
||||
"TERM=vt220",
|
||||
NULL
|
||||
};
|
||||
static const char *__default_environ[] = {"PATH=/bin:/sbin:/testbin",
|
||||
"SHELL=/bin/sh", "TERM=vt220", NULL};
|
||||
|
||||
char *
|
||||
getenv(const char *var)
|
||||
{
|
||||
size_t varlen, thislen;
|
||||
char *s;
|
||||
unsigned i;
|
||||
char *getenv(const char *var) {
|
||||
size_t varlen, thislen;
|
||||
char *s;
|
||||
unsigned i;
|
||||
|
||||
if (__environ == NULL) {
|
||||
__environ = (char **)__default_environ;
|
||||
}
|
||||
varlen = strlen(var);
|
||||
for (i=0; __environ[i] != NULL; i++) {
|
||||
s = strchr(__environ[i], '=');
|
||||
if (s == NULL) {
|
||||
/* ? */
|
||||
continue;
|
||||
}
|
||||
thislen = s - __environ[i];
|
||||
if (thislen == varlen && !memcmp(__environ[i], var, thislen)) {
|
||||
return s + 1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
if (__environ == NULL) {
|
||||
__environ = (char **)__default_environ;
|
||||
}
|
||||
varlen = strlen(var);
|
||||
for (i = 0; __environ[i] != NULL; i++) {
|
||||
s = strchr(__environ[i], '=');
|
||||
if (s == NULL) {
|
||||
/* ? */
|
||||
continue;
|
||||
}
|
||||
thislen = s - __environ[i];
|
||||
if (thislen == varlen && !memcmp(__environ[i], var, thislen)) {
|
||||
return s + 1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h> // for uintptr_t on non-OS/161 platforms
|
||||
#include <stdint.h> // for uintptr_t on non-OS/161 platforms
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
@@ -74,33 +74,33 @@ struct mheader {
|
||||
#define MBLOCKSIZE 8
|
||||
#define MBLOCKSHIFT 3
|
||||
#define MMAGIC 2
|
||||
/*
|
||||
* 32-bit platform. size_t is 32 bits (4 bytes).
|
||||
* Block size is 8 bytes.
|
||||
*/
|
||||
unsigned mh_prevblock:29;
|
||||
unsigned mh_pad:1;
|
||||
unsigned mh_magic1:2;
|
||||
/*
|
||||
* 32-bit platform. size_t is 32 bits (4 bytes).
|
||||
* Block size is 8 bytes.
|
||||
*/
|
||||
unsigned mh_prevblock : 29;
|
||||
unsigned mh_pad : 1;
|
||||
unsigned mh_magic1 : 2;
|
||||
|
||||
unsigned mh_nextblock:29;
|
||||
unsigned mh_inuse:1;
|
||||
unsigned mh_magic2:2;
|
||||
unsigned mh_nextblock : 29;
|
||||
unsigned mh_inuse : 1;
|
||||
unsigned mh_magic2 : 2;
|
||||
|
||||
#elif defined(MALLOC64)
|
||||
#define MBLOCKSIZE 16
|
||||
#define MBLOCKSHIFT 4
|
||||
#define MMAGIC 6
|
||||
/*
|
||||
* 64-bit platform. size_t is 64 bits (8 bytes)
|
||||
* Block size is 16 bytes.
|
||||
*/
|
||||
unsigned mh_prevblock:60;
|
||||
unsigned mh_pad:1;
|
||||
unsigned mh_magic1:3;
|
||||
/*
|
||||
* 64-bit platform. size_t is 64 bits (8 bytes)
|
||||
* Block size is 16 bytes.
|
||||
*/
|
||||
unsigned mh_prevblock : 60;
|
||||
unsigned mh_pad : 1;
|
||||
unsigned mh_magic1 : 3;
|
||||
|
||||
unsigned mh_nextblock:60;
|
||||
unsigned mh_inuse:1;
|
||||
unsigned mh_magic2:3;
|
||||
unsigned mh_nextblock : 60;
|
||||
unsigned mh_inuse : 1;
|
||||
unsigned mh_magic2 : 3;
|
||||
|
||||
#else
|
||||
#error "please fix me"
|
||||
@@ -122,17 +122,17 @@ struct mheader {
|
||||
* (value should include the header size)
|
||||
*/
|
||||
|
||||
#define M_NEXTOFF(mh) ((size_t)(((size_t)((mh)->mh_nextblock))<<MBLOCKSHIFT))
|
||||
#define M_PREVOFF(mh) ((size_t)(((size_t)((mh)->mh_prevblock))<<MBLOCKSHIFT))
|
||||
#define M_NEXT(mh) ((struct mheader *)(((char*)(mh))+M_NEXTOFF(mh)))
|
||||
#define M_PREV(mh) ((struct mheader *)(((char*)(mh))-M_PREVOFF(mh)))
|
||||
#define M_NEXTOFF(mh) ((size_t)(((size_t)((mh)->mh_nextblock)) << MBLOCKSHIFT))
|
||||
#define M_PREVOFF(mh) ((size_t)(((size_t)((mh)->mh_prevblock)) << MBLOCKSHIFT))
|
||||
#define M_NEXT(mh) ((struct mheader *)(((char *)(mh)) + M_NEXTOFF(mh)))
|
||||
#define M_PREV(mh) ((struct mheader *)(((char *)(mh)) - M_PREVOFF(mh)))
|
||||
|
||||
#define M_DATA(mh) ((void *)((mh)+1))
|
||||
#define M_SIZE(mh) (M_NEXTOFF(mh)-MBLOCKSIZE)
|
||||
#define M_DATA(mh) ((void *)((mh) + 1))
|
||||
#define M_SIZE(mh) (M_NEXTOFF(mh) - MBLOCKSIZE)
|
||||
|
||||
#define M_OK(mh) ((mh)->mh_magic1==MMAGIC && (mh)->mh_magic2==MMAGIC)
|
||||
#define M_OK(mh) ((mh)->mh_magic1 == MMAGIC && (mh)->mh_magic2 == MMAGIC)
|
||||
|
||||
#define M_MKFIELD(off) ((off)>>MBLOCKSHIFT)
|
||||
#define M_MKFIELD(off) ((off) >> MBLOCKSHIFT)
|
||||
|
||||
/*
|
||||
* System page size. In POSIX you're supposed to call
|
||||
@@ -157,68 +157,65 @@ static uintptr_t __heapbase, __heaptop;
|
||||
/*
|
||||
* Setup function.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__malloc_init(void)
|
||||
{
|
||||
void *x;
|
||||
static void __malloc_init(void) {
|
||||
void *x;
|
||||
|
||||
/*
|
||||
* Check various assumed properties of the sizes.
|
||||
*/
|
||||
if (sizeof(struct mheader) != MBLOCKSIZE) {
|
||||
errx(1, "malloc: Internal error - MBLOCKSIZE wrong");
|
||||
}
|
||||
if ((MBLOCKSIZE & (MBLOCKSIZE-1))!=0) {
|
||||
errx(1, "malloc: Internal error - MBLOCKSIZE not power of 2");
|
||||
}
|
||||
if (1<<MBLOCKSHIFT != MBLOCKSIZE) {
|
||||
errx(1, "malloc: Internal error - MBLOCKSHIFT wrong");
|
||||
}
|
||||
/*
|
||||
* Check various assumed properties of the sizes.
|
||||
*/
|
||||
if (sizeof(struct mheader) != MBLOCKSIZE) {
|
||||
errx(1, "malloc: Internal error - MBLOCKSIZE wrong");
|
||||
}
|
||||
if ((MBLOCKSIZE & (MBLOCKSIZE - 1)) != 0) {
|
||||
errx(1, "malloc: Internal error - MBLOCKSIZE not power of 2");
|
||||
}
|
||||
if (1 << MBLOCKSHIFT != MBLOCKSIZE) {
|
||||
errx(1, "malloc: Internal error - MBLOCKSHIFT wrong");
|
||||
}
|
||||
|
||||
/* init should only be called once. */
|
||||
if (__heapbase!=0 || __heaptop!=0) {
|
||||
errx(1, "malloc: Internal error - bad init call");
|
||||
}
|
||||
/* init should only be called once. */
|
||||
if (__heapbase != 0 || __heaptop != 0) {
|
||||
errx(1, "malloc: Internal error - bad init call");
|
||||
}
|
||||
|
||||
/* Get the page size, if needed. */
|
||||
/* Get the page size, if needed. */
|
||||
#ifdef _SC_PAGESIZE
|
||||
__malloc_pagesize = sysconf(_SC_PAGESIZE);
|
||||
__malloc_pagesize = sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
|
||||
/* Use sbrk to find the base of the heap. */
|
||||
x = sbrk(0);
|
||||
if (x==(void *)-1) {
|
||||
err(1, "malloc: initial sbrk failed");
|
||||
}
|
||||
if (x==(void *) 0) {
|
||||
errx(1, "malloc: Internal error - heap began at 0");
|
||||
}
|
||||
__heapbase = __heaptop = (uintptr_t)x;
|
||||
/* Use sbrk to find the base of the heap. */
|
||||
x = sbrk(0);
|
||||
if (x == (void *)-1) {
|
||||
err(1, "malloc: initial sbrk failed");
|
||||
}
|
||||
if (x == (void *)0) {
|
||||
errx(1, "malloc: Internal error - heap began at 0");
|
||||
}
|
||||
__heapbase = __heaptop = (uintptr_t)x;
|
||||
|
||||
/*
|
||||
* Make sure the heap base is aligned the way we want it.
|
||||
* (On OS/161, it will begin on a page boundary. But on
|
||||
* an arbitrary Unix, it may not be, as traditionally it
|
||||
* begins at _end.)
|
||||
*/
|
||||
/*
|
||||
* Make sure the heap base is aligned the way we want it.
|
||||
* (On OS/161, it will begin on a page boundary. But on
|
||||
* an arbitrary Unix, it may not be, as traditionally it
|
||||
* begins at _end.)
|
||||
*/
|
||||
|
||||
if (__heapbase % MBLOCKSIZE != 0) {
|
||||
size_t adjust = MBLOCKSIZE - (__heapbase % MBLOCKSIZE);
|
||||
x = sbrk(adjust);
|
||||
if (x==(void *)-1) {
|
||||
err(1, "malloc: sbrk failed aligning heap base");
|
||||
}
|
||||
if ((uintptr_t)x != __heapbase) {
|
||||
err(1, "malloc: heap base moved during init");
|
||||
}
|
||||
if (__heapbase % MBLOCKSIZE != 0) {
|
||||
size_t adjust = MBLOCKSIZE - (__heapbase % MBLOCKSIZE);
|
||||
x = sbrk(adjust);
|
||||
if (x == (void *)-1) {
|
||||
err(1, "malloc: sbrk failed aligning heap base");
|
||||
}
|
||||
if ((uintptr_t)x != __heapbase) {
|
||||
err(1, "malloc: heap base moved during init");
|
||||
}
|
||||
#ifdef MALLOCDEBUG
|
||||
warnx("malloc: adjusted heap base upwards by %lu bytes",
|
||||
(unsigned long) adjust);
|
||||
warnx("malloc: adjusted heap base upwards by %lu bytes",
|
||||
(unsigned long)adjust);
|
||||
#endif
|
||||
__heapbase += adjust;
|
||||
__heaptop = __heapbase;
|
||||
}
|
||||
__heapbase += adjust;
|
||||
__heaptop = __heapbase;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -228,45 +225,41 @@ __malloc_init(void)
|
||||
/*
|
||||
* Debugging print function to iterate and dump the entire heap.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__malloc_dump(void)
|
||||
{
|
||||
struct mheader *mh;
|
||||
uintptr_t i;
|
||||
size_t rightprevblock;
|
||||
static void __malloc_dump(void) {
|
||||
struct mheader *mh;
|
||||
uintptr_t i;
|
||||
size_t rightprevblock;
|
||||
|
||||
warnx("heap: ************************************************");
|
||||
warnx("heap: ************************************************");
|
||||
|
||||
rightprevblock = 0;
|
||||
for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) {
|
||||
mh = (struct mheader *) i;
|
||||
if (!M_OK(mh)) {
|
||||
errx(1, "malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad magic bits",
|
||||
(unsigned long) i);
|
||||
}
|
||||
if (mh->mh_prevblock != rightprevblock) {
|
||||
errx(1, "malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad previous-block size %lu "
|
||||
"(should be %lu)",
|
||||
(unsigned long) i,
|
||||
(unsigned long) mh->mh_prevblock << MBLOCKSHIFT,
|
||||
(unsigned long) rightprevblock << MBLOCKSHIFT);
|
||||
}
|
||||
rightprevblock = mh->mh_nextblock;
|
||||
rightprevblock = 0;
|
||||
for (i = __heapbase; i < __heaptop; i += M_NEXTOFF(mh)) {
|
||||
mh = (struct mheader *)i;
|
||||
if (!M_OK(mh)) {
|
||||
errx(1,
|
||||
"malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad magic bits",
|
||||
(unsigned long)i);
|
||||
}
|
||||
if (mh->mh_prevblock != rightprevblock) {
|
||||
errx(1,
|
||||
"malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad previous-block size %lu "
|
||||
"(should be %lu)",
|
||||
(unsigned long)i, (unsigned long)mh->mh_prevblock << MBLOCKSHIFT,
|
||||
(unsigned long)rightprevblock << MBLOCKSHIFT);
|
||||
}
|
||||
rightprevblock = mh->mh_nextblock;
|
||||
|
||||
warnx("heap: 0x%lx 0x%-6lx (next: 0x%lx) %s",
|
||||
(unsigned long) i + MBLOCKSIZE,
|
||||
(unsigned long) M_SIZE(mh),
|
||||
(unsigned long) (i+M_NEXTOFF(mh)),
|
||||
mh->mh_inuse ? "INUSE" : "FREE");
|
||||
}
|
||||
if (i!=__heaptop) {
|
||||
errx(1, "malloc: Heap corrupt; ran off end");
|
||||
}
|
||||
warnx("heap: 0x%lx 0x%-6lx (next: 0x%lx) %s", (unsigned long)i + MBLOCKSIZE,
|
||||
(unsigned long)M_SIZE(mh), (unsigned long)(i + M_NEXTOFF(mh)),
|
||||
mh->mh_inuse ? "INUSE" : "FREE");
|
||||
}
|
||||
if (i != __heaptop) {
|
||||
errx(1, "malloc: Heap corrupt; ran off end");
|
||||
}
|
||||
|
||||
warnx("heap: ************************************************");
|
||||
warnx("heap: ************************************************");
|
||||
}
|
||||
|
||||
#endif /* MALLOCDEBUG */
|
||||
@@ -277,25 +270,22 @@ __malloc_dump(void)
|
||||
* Get more memory (at the top of the heap) using sbrk, and
|
||||
* return a pointer to it.
|
||||
*/
|
||||
static
|
||||
void *
|
||||
__malloc_sbrk(size_t size)
|
||||
{
|
||||
void *x;
|
||||
static void *__malloc_sbrk(size_t size) {
|
||||
void *x;
|
||||
|
||||
x = sbrk(size);
|
||||
if (x == (void *)-1) {
|
||||
return NULL;
|
||||
}
|
||||
x = sbrk(size);
|
||||
if (x == (void *)-1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((uintptr_t)x != __heaptop) {
|
||||
errx(1, "malloc: Internal error - "
|
||||
"heap top moved itself from 0x%lx to 0x%lx",
|
||||
(unsigned long) __heaptop,
|
||||
(unsigned long) (uintptr_t) x);
|
||||
}
|
||||
__heaptop += size;
|
||||
return x;
|
||||
if ((uintptr_t)x != __heaptop) {
|
||||
errx(1,
|
||||
"malloc: Internal error - "
|
||||
"heap top moved itself from 0x%lx to 0x%lx",
|
||||
(unsigned long)__heaptop, (unsigned long)(uintptr_t)x);
|
||||
}
|
||||
__heaptop += size;
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -306,177 +296,171 @@ __malloc_sbrk(size_t size)
|
||||
* Only split if the excess space is at least twice the blocksize -
|
||||
* one blocksize to hold a header and one for data.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__malloc_split(struct mheader *mh, size_t size)
|
||||
{
|
||||
struct mheader *mhnext, *mhnew;
|
||||
size_t oldsize;
|
||||
static void __malloc_split(struct mheader *mh, size_t size) {
|
||||
struct mheader *mhnext, *mhnew;
|
||||
size_t oldsize;
|
||||
|
||||
if (size % MBLOCKSIZE != 0) {
|
||||
errx(1, "malloc: Internal error (size %lu passed to split)",
|
||||
(unsigned long) size);
|
||||
}
|
||||
if (size % MBLOCKSIZE != 0) {
|
||||
errx(1, "malloc: Internal error (size %lu passed to split)",
|
||||
(unsigned long)size);
|
||||
}
|
||||
|
||||
if (M_SIZE(mh) - size < 2*MBLOCKSIZE) {
|
||||
/* no room */
|
||||
return;
|
||||
}
|
||||
if (M_SIZE(mh) - size < 2 * MBLOCKSIZE) {
|
||||
/* no room */
|
||||
return;
|
||||
}
|
||||
|
||||
mhnext = M_NEXT(mh);
|
||||
mhnext = M_NEXT(mh);
|
||||
|
||||
oldsize = M_SIZE(mh);
|
||||
mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE);
|
||||
oldsize = M_SIZE(mh);
|
||||
mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE);
|
||||
|
||||
mhnew = M_NEXT(mh);
|
||||
if (mhnew==mhnext) {
|
||||
errx(1, "malloc: Internal error (split screwed up?)");
|
||||
}
|
||||
mhnew = M_NEXT(mh);
|
||||
if (mhnew == mhnext) {
|
||||
errx(1, "malloc: Internal error (split screwed up?)");
|
||||
}
|
||||
|
||||
mhnew->mh_prevblock = M_MKFIELD(size + MBLOCKSIZE);
|
||||
mhnew->mh_pad = 0;
|
||||
mhnew->mh_magic1 = MMAGIC;
|
||||
mhnew->mh_nextblock = M_MKFIELD(oldsize - size);
|
||||
mhnew->mh_inuse = 0;
|
||||
mhnew->mh_magic2 = MMAGIC;
|
||||
mhnew->mh_prevblock = M_MKFIELD(size + MBLOCKSIZE);
|
||||
mhnew->mh_pad = 0;
|
||||
mhnew->mh_magic1 = MMAGIC;
|
||||
mhnew->mh_nextblock = M_MKFIELD(oldsize - size);
|
||||
mhnew->mh_inuse = 0;
|
||||
mhnew->mh_magic2 = MMAGIC;
|
||||
|
||||
if (mhnext != (struct mheader *) __heaptop) {
|
||||
mhnext->mh_prevblock = mhnew->mh_nextblock;
|
||||
}
|
||||
if (mhnext != (struct mheader *)__heaptop) {
|
||||
mhnext->mh_prevblock = mhnew->mh_nextblock;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* malloc itself.
|
||||
*/
|
||||
void *
|
||||
malloc(size_t size)
|
||||
{
|
||||
struct mheader *mh;
|
||||
uintptr_t i;
|
||||
size_t rightprevblock;
|
||||
size_t morespace;
|
||||
void *p;
|
||||
void *malloc(size_t size) {
|
||||
struct mheader *mh;
|
||||
uintptr_t i;
|
||||
size_t rightprevblock;
|
||||
size_t morespace;
|
||||
void *p;
|
||||
|
||||
if (__heapbase==0) {
|
||||
__malloc_init();
|
||||
}
|
||||
if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) {
|
||||
warnx("malloc: Internal error - local data corrupt");
|
||||
errx(1, "malloc: heapbase 0x%lx; heaptop 0x%lx",
|
||||
(unsigned long) __heapbase, (unsigned long) __heaptop);
|
||||
}
|
||||
if (__heapbase == 0) {
|
||||
__malloc_init();
|
||||
}
|
||||
if (__heapbase == 0 || __heaptop == 0 || __heapbase > __heaptop) {
|
||||
warnx("malloc: Internal error - local data corrupt");
|
||||
errx(1, "malloc: heapbase 0x%lx; heaptop 0x%lx", (unsigned long)__heapbase,
|
||||
(unsigned long)__heaptop);
|
||||
}
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
warnx("malloc: about to allocate %lu (0x%lx) bytes",
|
||||
(unsigned long) size, (unsigned long) size);
|
||||
__malloc_dump();
|
||||
warnx("malloc: about to allocate %lu (0x%lx) bytes", (unsigned long)size,
|
||||
(unsigned long)size);
|
||||
__malloc_dump();
|
||||
#endif
|
||||
|
||||
/* Round size up to an integral number of blocks. */
|
||||
size = ((size + MBLOCKSIZE - 1) & ~(size_t)(MBLOCKSIZE-1));
|
||||
/* Round size up to an integral number of blocks. */
|
||||
size = ((size + MBLOCKSIZE - 1) & ~(size_t)(MBLOCKSIZE - 1));
|
||||
|
||||
/*
|
||||
* First-fit search algorithm for available blocks.
|
||||
* Check to make sure the next/previous sizes all agree.
|
||||
*/
|
||||
rightprevblock = 0;
|
||||
mh = NULL;
|
||||
for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) {
|
||||
mh = (struct mheader *) i;
|
||||
if (!M_OK(mh)) {
|
||||
errx(1, "malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad magic bits",
|
||||
(unsigned long) i);
|
||||
}
|
||||
if (mh->mh_prevblock != rightprevblock) {
|
||||
errx(1, "malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad previous-block size %lu "
|
||||
"(should be %lu)",
|
||||
(unsigned long) i,
|
||||
(unsigned long) mh->mh_prevblock << MBLOCKSHIFT,
|
||||
(unsigned long) rightprevblock << MBLOCKSHIFT);
|
||||
}
|
||||
rightprevblock = mh->mh_nextblock;
|
||||
/*
|
||||
* First-fit search algorithm for available blocks.
|
||||
* Check to make sure the next/previous sizes all agree.
|
||||
*/
|
||||
rightprevblock = 0;
|
||||
mh = NULL;
|
||||
for (i = __heapbase; i < __heaptop; i += M_NEXTOFF(mh)) {
|
||||
mh = (struct mheader *)i;
|
||||
if (!M_OK(mh)) {
|
||||
errx(1,
|
||||
"malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad magic bits",
|
||||
(unsigned long)i);
|
||||
}
|
||||
if (mh->mh_prevblock != rightprevblock) {
|
||||
errx(1,
|
||||
"malloc: Heap corrupt; header at 0x%lx"
|
||||
" has bad previous-block size %lu "
|
||||
"(should be %lu)",
|
||||
(unsigned long)i, (unsigned long)mh->mh_prevblock << MBLOCKSHIFT,
|
||||
(unsigned long)rightprevblock << MBLOCKSHIFT);
|
||||
}
|
||||
rightprevblock = mh->mh_nextblock;
|
||||
|
||||
/* Can't allocate a block that's in use. */
|
||||
if (mh->mh_inuse) {
|
||||
continue;
|
||||
}
|
||||
/* Can't allocate a block that's in use. */
|
||||
if (mh->mh_inuse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Can't allocate a block that isn't big enough. */
|
||||
if (M_SIZE(mh) < size) {
|
||||
continue;
|
||||
}
|
||||
/* Can't allocate a block that isn't big enough. */
|
||||
if (M_SIZE(mh) < size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try splitting block. */
|
||||
__malloc_split(mh, size);
|
||||
/* Try splitting block. */
|
||||
__malloc_split(mh, size);
|
||||
|
||||
/*
|
||||
* Now, allocate.
|
||||
*/
|
||||
mh->mh_inuse = 1;
|
||||
/*
|
||||
* Now, allocate.
|
||||
*/
|
||||
mh->mh_inuse = 1;
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
warnx("malloc: allocating at %p", M_DATA(mh));
|
||||
__malloc_dump();
|
||||
warnx("malloc: allocating at %p", M_DATA(mh));
|
||||
__malloc_dump();
|
||||
#endif
|
||||
return M_DATA(mh);
|
||||
}
|
||||
if (i!=__heaptop) {
|
||||
errx(1, "malloc: Heap corrupt; ran off end");
|
||||
}
|
||||
return M_DATA(mh);
|
||||
}
|
||||
if (i != __heaptop) {
|
||||
errx(1, "malloc: Heap corrupt; ran off end");
|
||||
}
|
||||
|
||||
/*
|
||||
* Didn't find anything. Expand the heap.
|
||||
*
|
||||
* If the heap is nonempty and the top block (the one mh is
|
||||
* left pointing to after the above loop) is free, we can
|
||||
* expand it. Otherwise we need a new block.
|
||||
*/
|
||||
if (mh != NULL && !mh->mh_inuse) {
|
||||
assert(size > M_SIZE(mh));
|
||||
morespace = size - M_SIZE(mh);
|
||||
}
|
||||
else {
|
||||
morespace = MBLOCKSIZE + size;
|
||||
}
|
||||
/*
|
||||
* Didn't find anything. Expand the heap.
|
||||
*
|
||||
* If the heap is nonempty and the top block (the one mh is
|
||||
* left pointing to after the above loop) is free, we can
|
||||
* expand it. Otherwise we need a new block.
|
||||
*/
|
||||
if (mh != NULL && !mh->mh_inuse) {
|
||||
assert(size > M_SIZE(mh));
|
||||
morespace = size - M_SIZE(mh);
|
||||
} else {
|
||||
morespace = MBLOCKSIZE + size;
|
||||
}
|
||||
|
||||
/* Round the amount of space we ask for up to a whole page. */
|
||||
morespace = PAGE_SIZE * ((morespace + PAGE_SIZE - 1) / PAGE_SIZE);
|
||||
/* Round the amount of space we ask for up to a whole page. */
|
||||
morespace = PAGE_SIZE * ((morespace + PAGE_SIZE - 1) / PAGE_SIZE);
|
||||
|
||||
p = __malloc_sbrk(morespace);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
p = __malloc_sbrk(morespace);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mh != NULL && !mh->mh_inuse) {
|
||||
/* update old header */
|
||||
mh->mh_nextblock = M_MKFIELD(M_NEXTOFF(mh) + morespace);
|
||||
mh->mh_inuse = 1;
|
||||
}
|
||||
else {
|
||||
/* fill out new header */
|
||||
mh = p;
|
||||
mh->mh_prevblock = rightprevblock;
|
||||
mh->mh_magic1 = MMAGIC;
|
||||
mh->mh_magic2 = MMAGIC;
|
||||
mh->mh_pad = 0;
|
||||
mh->mh_inuse = 1;
|
||||
mh->mh_nextblock = M_MKFIELD(morespace);
|
||||
}
|
||||
if (mh != NULL && !mh->mh_inuse) {
|
||||
/* update old header */
|
||||
mh->mh_nextblock = M_MKFIELD(M_NEXTOFF(mh) + morespace);
|
||||
mh->mh_inuse = 1;
|
||||
} else {
|
||||
/* fill out new header */
|
||||
mh = p;
|
||||
mh->mh_prevblock = rightprevblock;
|
||||
mh->mh_magic1 = MMAGIC;
|
||||
mh->mh_magic2 = MMAGIC;
|
||||
mh->mh_pad = 0;
|
||||
mh->mh_inuse = 1;
|
||||
mh->mh_nextblock = M_MKFIELD(morespace);
|
||||
}
|
||||
|
||||
/*
|
||||
* Either way, try splitting the block we got as because of
|
||||
* the page rounding it might be quite a bit bigger than we
|
||||
* needed.
|
||||
*/
|
||||
__malloc_split(mh, size);
|
||||
/*
|
||||
* Either way, try splitting the block we got as because of
|
||||
* the page rounding it might be quite a bit bigger than we
|
||||
* needed.
|
||||
*/
|
||||
__malloc_split(mh, size);
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
warnx("malloc: allocating at %p", M_DATA(mh));
|
||||
__malloc_dump();
|
||||
warnx("malloc: allocating at %p", M_DATA(mh));
|
||||
__malloc_dump();
|
||||
#endif
|
||||
return M_DATA(mh);
|
||||
return M_DATA(mh);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -485,107 +469,98 @@ malloc(size_t size)
|
||||
* Clear a range of memory with 0xdeadbeef.
|
||||
* ptr must be suitably aligned.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__malloc_deadbeef(void *ptr, size_t size)
|
||||
{
|
||||
uint32_t *x = ptr;
|
||||
size_t i, n = size/sizeof(uint32_t);
|
||||
for (i=0; i<n; i++) {
|
||||
x[i] = 0xdeadbeef;
|
||||
}
|
||||
static void __malloc_deadbeef(void *ptr, size_t size) {
|
||||
uint32_t *x = ptr;
|
||||
size_t i, n = size / sizeof(uint32_t);
|
||||
for (i = 0; i < n; i++) {
|
||||
x[i] = 0xdeadbeef;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to merge two adjacent blocks (mh below mhnext).
|
||||
*/
|
||||
static
|
||||
void
|
||||
__malloc_trymerge(struct mheader *mh, struct mheader *mhnext)
|
||||
{
|
||||
struct mheader *mhnextnext;
|
||||
static void __malloc_trymerge(struct mheader *mh, struct mheader *mhnext) {
|
||||
struct mheader *mhnextnext;
|
||||
|
||||
if (mh->mh_nextblock != mhnext->mh_prevblock) {
|
||||
errx(1, "free: Heap corrupt (%p and %p inconsistent)",
|
||||
mh, mhnext);
|
||||
}
|
||||
if (mh->mh_inuse || mhnext->mh_inuse) {
|
||||
/* can't merge */
|
||||
return;
|
||||
}
|
||||
if (mh->mh_nextblock != mhnext->mh_prevblock) {
|
||||
errx(1, "free: Heap corrupt (%p and %p inconsistent)", mh, mhnext);
|
||||
}
|
||||
if (mh->mh_inuse || mhnext->mh_inuse) {
|
||||
/* can't merge */
|
||||
return;
|
||||
}
|
||||
|
||||
mhnextnext = M_NEXT(mhnext);
|
||||
mhnextnext = M_NEXT(mhnext);
|
||||
|
||||
mh->mh_nextblock = M_MKFIELD(MBLOCKSIZE + M_SIZE(mh) +
|
||||
MBLOCKSIZE + M_SIZE(mhnext));
|
||||
mh->mh_nextblock =
|
||||
M_MKFIELD(MBLOCKSIZE + M_SIZE(mh) + MBLOCKSIZE + M_SIZE(mhnext));
|
||||
|
||||
if (mhnextnext != (struct mheader *)__heaptop) {
|
||||
mhnextnext->mh_prevblock = mh->mh_nextblock;
|
||||
}
|
||||
if (mhnextnext != (struct mheader *)__heaptop) {
|
||||
mhnextnext->mh_prevblock = mh->mh_nextblock;
|
||||
}
|
||||
|
||||
/* Deadbeef out the memory used by the now-obsolete header */
|
||||
__malloc_deadbeef(mhnext, sizeof(struct mheader));
|
||||
/* Deadbeef out the memory used by the now-obsolete header */
|
||||
__malloc_deadbeef(mhnext, sizeof(struct mheader));
|
||||
}
|
||||
|
||||
/*
|
||||
* The actual free() implementation.
|
||||
*/
|
||||
void
|
||||
free(void *x)
|
||||
{
|
||||
struct mheader *mh, *mhnext, *mhprev;
|
||||
void free(void *x) {
|
||||
struct mheader *mh, *mhnext, *mhprev;
|
||||
|
||||
if (x==NULL) {
|
||||
/* safest practice */
|
||||
return;
|
||||
}
|
||||
if (x == NULL) {
|
||||
/* safest practice */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Consistency check. */
|
||||
if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) {
|
||||
warnx("free: Internal error - local data corrupt");
|
||||
errx(1, "free: heapbase 0x%lx; heaptop 0x%lx",
|
||||
(unsigned long) __heapbase, (unsigned long) __heaptop);
|
||||
}
|
||||
/* Consistency check. */
|
||||
if (__heapbase == 0 || __heaptop == 0 || __heapbase > __heaptop) {
|
||||
warnx("free: Internal error - local data corrupt");
|
||||
errx(1, "free: heapbase 0x%lx; heaptop 0x%lx", (unsigned long)__heapbase,
|
||||
(unsigned long)__heaptop);
|
||||
}
|
||||
|
||||
/* Don't allow freeing pointers that aren't on the heap. */
|
||||
if ((uintptr_t)x < __heapbase || (uintptr_t)x >= __heaptop) {
|
||||
errx(1, "free: Invalid pointer %p freed (out of range)", x);
|
||||
}
|
||||
/* Don't allow freeing pointers that aren't on the heap. */
|
||||
if ((uintptr_t)x < __heapbase || (uintptr_t)x >= __heaptop) {
|
||||
errx(1, "free: Invalid pointer %p freed (out of range)", x);
|
||||
}
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
warnx("free: about to free %p", x);
|
||||
__malloc_dump();
|
||||
warnx("free: about to free %p", x);
|
||||
__malloc_dump();
|
||||
#endif
|
||||
|
||||
mh = ((struct mheader *)x)-1;
|
||||
if (!M_OK(mh)) {
|
||||
errx(1, "free: Invalid pointer %p freed (corrupt header)", x);
|
||||
}
|
||||
mh = ((struct mheader *)x) - 1;
|
||||
if (!M_OK(mh)) {
|
||||
errx(1, "free: Invalid pointer %p freed (corrupt header)", x);
|
||||
}
|
||||
|
||||
if (!mh->mh_inuse) {
|
||||
errx(1, "free: Invalid pointer %p freed (already free)", x);
|
||||
}
|
||||
if (!mh->mh_inuse) {
|
||||
errx(1, "free: Invalid pointer %p freed (already free)", x);
|
||||
}
|
||||
|
||||
/* mark it free */
|
||||
mh->mh_inuse = 0;
|
||||
/* mark it free */
|
||||
mh->mh_inuse = 0;
|
||||
|
||||
/* wipe it */
|
||||
__malloc_deadbeef(M_DATA(mh), M_SIZE(mh));
|
||||
/* wipe it */
|
||||
__malloc_deadbeef(M_DATA(mh), M_SIZE(mh));
|
||||
|
||||
/* Try merging with the block above (but not if we're at the top) */
|
||||
mhnext = M_NEXT(mh);
|
||||
if (mhnext != (struct mheader *)__heaptop) {
|
||||
__malloc_trymerge(mh, mhnext);
|
||||
}
|
||||
/* Try merging with the block above (but not if we're at the top) */
|
||||
mhnext = M_NEXT(mh);
|
||||
if (mhnext != (struct mheader *)__heaptop) {
|
||||
__malloc_trymerge(mh, mhnext);
|
||||
}
|
||||
|
||||
/* Try merging with the block below (but not if we're at the bottom) */
|
||||
if (mh != (struct mheader *)__heapbase) {
|
||||
mhprev = M_PREV(mh);
|
||||
__malloc_trymerge(mhprev, mh);
|
||||
}
|
||||
/* Try merging with the block below (but not if we're at the bottom) */
|
||||
if (mh != (struct mheader *)__heapbase) {
|
||||
mhprev = M_PREV(mh);
|
||||
__malloc_trymerge(mhprev, mh);
|
||||
}
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
warnx("free: freed %p", x);
|
||||
__malloc_dump();
|
||||
warnx("free: freed %p", x);
|
||||
__malloc_dump();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -34,112 +34,106 @@
|
||||
/*
|
||||
* qsort() for OS/161, where it isn't in libc.
|
||||
*/
|
||||
void
|
||||
qsort(void *vdata, unsigned num, size_t size,
|
||||
int (*f)(const void *, const void *))
|
||||
{
|
||||
unsigned pivot, head, tail;
|
||||
char *data = vdata;
|
||||
char tmp[size];
|
||||
void qsort(void *vdata, unsigned num, size_t size,
|
||||
int (*f)(const void *, const void *)) {
|
||||
unsigned pivot, head, tail;
|
||||
char *data = vdata;
|
||||
char tmp[size];
|
||||
|
||||
#define COMPARE(aa, bb) \
|
||||
((aa) == (bb) ? 0 : f(data + (aa) * size, data + (bb) * size))
|
||||
#define EXCHANGE(aa, bb) \
|
||||
memcpy(tmp, data + (aa) * size, size); \
|
||||
memcpy(data + (aa) * size, data + (bb) * size, size); \
|
||||
memcpy(data + (bb) * size, tmp, size)
|
||||
#define COMPARE(aa, bb) \
|
||||
((aa) == (bb) ? 0 : f(data + (aa) * size, data + (bb) * size))
|
||||
#define EXCHANGE(aa, bb) \
|
||||
memcpy(tmp, data + (aa) * size, size); \
|
||||
memcpy(data + (aa) * size, data + (bb) * size, size); \
|
||||
memcpy(data + (bb) * size, tmp, size)
|
||||
|
||||
if (num <= 1) {
|
||||
return;
|
||||
}
|
||||
if (num == 2) {
|
||||
if (COMPARE(0, 1) > 0) {
|
||||
EXCHANGE(0, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (num <= 1) {
|
||||
return;
|
||||
}
|
||||
if (num == 2) {
|
||||
if (COMPARE(0, 1) > 0) {
|
||||
EXCHANGE(0, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 1. Pick a pivot value. For simplicity, always use the
|
||||
* middle of the array.
|
||||
*/
|
||||
pivot = num / 2;
|
||||
|
||||
/*
|
||||
* 1. Pick a pivot value. For simplicity, always use the
|
||||
* middle of the array.
|
||||
*/
|
||||
pivot = num / 2;
|
||||
/*
|
||||
* 2. Shift all values less than or equal to the pivot value
|
||||
* to the front of the array.
|
||||
*/
|
||||
head = 0;
|
||||
tail = num - 1;
|
||||
|
||||
/*
|
||||
* 2. Shift all values less than or equal to the pivot value
|
||||
* to the front of the array.
|
||||
*/
|
||||
head = 0;
|
||||
tail = num - 1;
|
||||
while (head < tail) {
|
||||
if (COMPARE(head, pivot) <= 0) {
|
||||
head++;
|
||||
} else if (COMPARE(tail, pivot) > 0) {
|
||||
tail--;
|
||||
} else {
|
||||
EXCHANGE(head, tail);
|
||||
if (pivot == head) {
|
||||
pivot = tail;
|
||||
} else if (pivot == tail) {
|
||||
pivot = head;
|
||||
}
|
||||
head++;
|
||||
tail--;
|
||||
}
|
||||
}
|
||||
|
||||
while (head < tail) {
|
||||
if (COMPARE(head, pivot) <= 0) {
|
||||
head++;
|
||||
}
|
||||
else if (COMPARE(tail, pivot) > 0) {
|
||||
tail--;
|
||||
}
|
||||
else {
|
||||
EXCHANGE(head, tail);
|
||||
if (pivot == head) {
|
||||
pivot = tail;
|
||||
}
|
||||
else if (pivot == tail) {
|
||||
pivot = head;
|
||||
}
|
||||
head++;
|
||||
tail--;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 3. If there's an even number of elements and we swapped the
|
||||
* last two, the head and tail indexes will cross. In this
|
||||
* case the first entry on the tail side is tail+1. If there's
|
||||
* an odd number of elements, we stop with head == tail, and
|
||||
* the first entry on the tail side is this value (hence,
|
||||
* tail) if it's is greater than the pivot value, and the next
|
||||
* element (hence, tail+1) if it's less than or equal to the
|
||||
* pivot value.
|
||||
*
|
||||
* Henceforth use "tail" to hold the index of the first entry
|
||||
* of the back portion of the array.
|
||||
*/
|
||||
if (head > tail || COMPARE(head, pivot) <= 0) {
|
||||
tail++;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. If there's an even number of elements and we swapped the
|
||||
* last two, the head and tail indexes will cross. In this
|
||||
* case the first entry on the tail side is tail+1. If there's
|
||||
* an odd number of elements, we stop with head == tail, and
|
||||
* the first entry on the tail side is this value (hence,
|
||||
* tail) if it's is greater than the pivot value, and the next
|
||||
* element (hence, tail+1) if it's less than or equal to the
|
||||
* pivot value.
|
||||
*
|
||||
* Henceforth use "tail" to hold the index of the first entry
|
||||
* of the back portion of the array.
|
||||
*/
|
||||
if (head > tail || COMPARE(head, pivot) <= 0) {
|
||||
tail++;
|
||||
}
|
||||
/*
|
||||
* 4. If we got a bad pivot that gave us only one partition,
|
||||
* because of the order of the advances in the loop above it
|
||||
* will always put everything in the front portion of the
|
||||
* array (so tail == num). This happens if we picked the
|
||||
* largest value. Move the pivot to the end, if necessary, lop
|
||||
* off all values equal to it, and recurse on the rest. (If
|
||||
* there is no rest, the array is already sorted and we're
|
||||
* done.)
|
||||
*/
|
||||
if (tail == num) {
|
||||
if (pivot < num - 1) {
|
||||
if (COMPARE(pivot, num - 1) > 0) {
|
||||
EXCHANGE(pivot, num - 1);
|
||||
}
|
||||
}
|
||||
tail = num - 1;
|
||||
while (tail > 0 && COMPARE(tail - 1, tail) == 0) {
|
||||
tail--;
|
||||
}
|
||||
if (tail > 0) {
|
||||
qsort(vdata, tail, size, f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(tail > 0 && tail < num);
|
||||
|
||||
/*
|
||||
* 4. If we got a bad pivot that gave us only one partition,
|
||||
* because of the order of the advances in the loop above it
|
||||
* will always put everything in the front portion of the
|
||||
* array (so tail == num). This happens if we picked the
|
||||
* largest value. Move the pivot to the end, if necessary, lop
|
||||
* off all values equal to it, and recurse on the rest. (If
|
||||
* there is no rest, the array is already sorted and we're
|
||||
* done.)
|
||||
*/
|
||||
if (tail == num) {
|
||||
if (pivot < num - 1) {
|
||||
if (COMPARE(pivot, num - 1) > 0) {
|
||||
EXCHANGE(pivot, num - 1);
|
||||
}
|
||||
}
|
||||
tail = num - 1;
|
||||
while (tail > 0 && COMPARE(tail - 1, tail) == 0) {
|
||||
tail--;
|
||||
}
|
||||
if (tail > 0) {
|
||||
qsort(vdata, tail, size, f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(tail > 0 && tail < num);
|
||||
|
||||
/*
|
||||
* 5. Recurse on each subpart of the array.
|
||||
*/
|
||||
qsort(vdata, tail, size, f);
|
||||
qsort((char *)vdata + tail * size, num - tail, size, f);
|
||||
/*
|
||||
* 5. Recurse on each subpart of the array.
|
||||
*/
|
||||
qsort(vdata, tail, size, f);
|
||||
qsort((char *)vdata + tail * size, num - tail, size, f);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
static void srandom_unlocked(unsigned long);
|
||||
static long random_unlocked(void);
|
||||
|
||||
|
||||
/*
|
||||
* random.c:
|
||||
*
|
||||
@@ -119,39 +118,39 @@ static long random_unlocked(void);
|
||||
* for the polynomial (actually a trinomial) that the R.N.G. is based on, and
|
||||
* the separation between the two lower order coefficients of the trinomial.
|
||||
*/
|
||||
#define TYPE_0 0 /* linear congruential */
|
||||
#define BREAK_0 8
|
||||
#define DEG_0 0
|
||||
#define SEP_0 0
|
||||
#define TYPE_0 0 /* linear congruential */
|
||||
#define BREAK_0 8
|
||||
#define DEG_0 0
|
||||
#define SEP_0 0
|
||||
|
||||
#define TYPE_1 1 /* x**7 + x**3 + 1 */
|
||||
#define BREAK_1 32
|
||||
#define DEG_1 7
|
||||
#define SEP_1 3
|
||||
#define TYPE_1 1 /* x**7 + x**3 + 1 */
|
||||
#define BREAK_1 32
|
||||
#define DEG_1 7
|
||||
#define SEP_1 3
|
||||
|
||||
#define TYPE_2 2 /* x**15 + x + 1 */
|
||||
#define BREAK_2 64
|
||||
#define DEG_2 15
|
||||
#define SEP_2 1
|
||||
#define TYPE_2 2 /* x**15 + x + 1 */
|
||||
#define BREAK_2 64
|
||||
#define DEG_2 15
|
||||
#define SEP_2 1
|
||||
|
||||
#define TYPE_3 3 /* x**31 + x**3 + 1 */
|
||||
#define BREAK_3 128
|
||||
#define DEG_3 31
|
||||
#define SEP_3 3
|
||||
#define TYPE_3 3 /* x**31 + x**3 + 1 */
|
||||
#define BREAK_3 128
|
||||
#define DEG_3 31
|
||||
#define SEP_3 3
|
||||
|
||||
#define TYPE_4 4 /* x**63 + x + 1 */
|
||||
#define BREAK_4 256
|
||||
#define DEG_4 63
|
||||
#define SEP_4 1
|
||||
#define TYPE_4 4 /* x**63 + x + 1 */
|
||||
#define BREAK_4 256
|
||||
#define DEG_4 63
|
||||
#define SEP_4 1
|
||||
|
||||
/*
|
||||
* Array versions of the above information to make code run faster --
|
||||
* relies on fact that TYPE_i == i.
|
||||
*/
|
||||
#define MAX_TYPES 5 /* max number of types above */
|
||||
#define MAX_TYPES 5 /* max number of types above */
|
||||
|
||||
static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
|
||||
static const int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
|
||||
static const int degrees[MAX_TYPES] = {DEG_0, DEG_1, DEG_2, DEG_3, DEG_4};
|
||||
static const int seps[MAX_TYPES] = {SEP_0, SEP_1, SEP_2, SEP_3, SEP_4};
|
||||
|
||||
/*
|
||||
* Initially, everything is set up as if from:
|
||||
@@ -168,18 +167,38 @@ static const int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
|
||||
*/
|
||||
|
||||
static long randtbl[DEG_3 + 1] = {
|
||||
TYPE_3,
|
||||
(long)0x9a319039L, (long)0x32d9c024L, (long)0x9b663182L,
|
||||
(long)0x5da1f342L, (long)0xde3b81e0L, (long)0xdf0a6fb5L,
|
||||
(long)0xf103bc02L, (long)0x48f340fbL, (long)0x7449e56bL,
|
||||
(long)0xbeb1dbb0L, (long)0xab5c5918L, (long)0x946554fdL,
|
||||
(long)0x8c2e680fL, (long)0xeb3d799fL, (long)0xb11ee0b7L,
|
||||
(long)0x2d436b86L, (long)0xda672e2aL, (long)0x1588ca88L,
|
||||
(long)0xe369735dL, (long)0x904f35f7L, (long)0xd7158fd6L,
|
||||
(long)0x6fa6f051L, (long)0x616e6b96L, (long)0xac94efdcL,
|
||||
(long)0x36413f93L, (long)0xc622c298L, (long)0xf5a42ab8L,
|
||||
(long)0x8a88d77bL, (long)0xf5ad9d0eL, (long)0x8999220bL,
|
||||
(long)0x27fb47b9L,
|
||||
TYPE_3,
|
||||
(long)0x9a319039L,
|
||||
(long)0x32d9c024L,
|
||||
(long)0x9b663182L,
|
||||
(long)0x5da1f342L,
|
||||
(long)0xde3b81e0L,
|
||||
(long)0xdf0a6fb5L,
|
||||
(long)0xf103bc02L,
|
||||
(long)0x48f340fbL,
|
||||
(long)0x7449e56bL,
|
||||
(long)0xbeb1dbb0L,
|
||||
(long)0xab5c5918L,
|
||||
(long)0x946554fdL,
|
||||
(long)0x8c2e680fL,
|
||||
(long)0xeb3d799fL,
|
||||
(long)0xb11ee0b7L,
|
||||
(long)0x2d436b86L,
|
||||
(long)0xda672e2aL,
|
||||
(long)0x1588ca88L,
|
||||
(long)0xe369735dL,
|
||||
(long)0x904f35f7L,
|
||||
(long)0xd7158fd6L,
|
||||
(long)0x6fa6f051L,
|
||||
(long)0x616e6b96L,
|
||||
(long)0xac94efdcL,
|
||||
(long)0x36413f93L,
|
||||
(long)0xc622c298L,
|
||||
(long)0xf5a42ab8L,
|
||||
(long)0x8a88d77bL,
|
||||
(long)0xf5ad9d0eL,
|
||||
(long)0x8999220bL,
|
||||
(long)0x27fb47b9L,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -227,32 +246,27 @@ static long *end_ptr = &randtbl[DEG_3 + 1];
|
||||
* introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
|
||||
* for default usage relies on values produced by this routine.
|
||||
*/
|
||||
static
|
||||
void
|
||||
srandom_unlocked(unsigned long x)
|
||||
{
|
||||
int i;
|
||||
static void srandom_unlocked(unsigned long x) {
|
||||
int i;
|
||||
|
||||
if (rand_type == TYPE_0)
|
||||
state[0] = x;
|
||||
else {
|
||||
state[0] = x;
|
||||
for (i = 1; i < rand_deg; i++)
|
||||
state[i] = 1103515245L * state[i - 1] + 12345L;
|
||||
fptr = &state[rand_sep];
|
||||
rptr = &state[0];
|
||||
for (i = 0; i < 10 * rand_deg; i++)
|
||||
(void)random_unlocked();
|
||||
}
|
||||
if (rand_type == TYPE_0)
|
||||
state[0] = x;
|
||||
else {
|
||||
state[0] = x;
|
||||
for (i = 1; i < rand_deg; i++)
|
||||
state[i] = 1103515245L * state[i - 1] + 12345L;
|
||||
fptr = &state[rand_sep];
|
||||
rptr = &state[0];
|
||||
for (i = 0; i < 10 * rand_deg; i++)
|
||||
(void)random_unlocked();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
srandom(unsigned long x)
|
||||
{
|
||||
void srandom(unsigned long x) {
|
||||
|
||||
LOCKME();
|
||||
srandom_unlocked(x);
|
||||
UNLOCKME();
|
||||
LOCKME();
|
||||
srandom_unlocked(x);
|
||||
UNLOCKME();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -278,57 +292,55 @@ srandom(unsigned long x)
|
||||
* word boundary; otherwise a bus error will occur. Even so, lint will
|
||||
* complain about mis-alignment, but you should disregard these messages.
|
||||
*/
|
||||
char *
|
||||
initstate(
|
||||
unsigned long seed, /* seed for R.N.G. */
|
||||
char *arg_state, /* pointer to state array */
|
||||
size_t n) /* # bytes of state info */
|
||||
char *initstate(unsigned long seed, /* seed for R.N.G. */
|
||||
char *arg_state, /* pointer to state array */
|
||||
size_t n) /* # bytes of state info */
|
||||
{
|
||||
void *ostate = (void *)(&state[-1]);
|
||||
long *long_arg_state;
|
||||
void *ostate = (void *)(&state[-1]);
|
||||
long *long_arg_state;
|
||||
|
||||
assert(arg_state != NULL);
|
||||
assert(arg_state != NULL);
|
||||
|
||||
long_arg_state = (long *)(void *)arg_state;
|
||||
long_arg_state = (long *)(void *)arg_state;
|
||||
|
||||
LOCKME();
|
||||
if (rand_type == TYPE_0)
|
||||
state[-1] = rand_type;
|
||||
else
|
||||
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
if (n < BREAK_0) {
|
||||
UNLOCKME();
|
||||
return (NULL);
|
||||
} else if (n < BREAK_1) {
|
||||
rand_type = TYPE_0;
|
||||
rand_deg = DEG_0;
|
||||
rand_sep = SEP_0;
|
||||
} else if (n < BREAK_2) {
|
||||
rand_type = TYPE_1;
|
||||
rand_deg = DEG_1;
|
||||
rand_sep = SEP_1;
|
||||
} else if (n < BREAK_3) {
|
||||
rand_type = TYPE_2;
|
||||
rand_deg = DEG_2;
|
||||
rand_sep = SEP_2;
|
||||
} else if (n < BREAK_4) {
|
||||
rand_type = TYPE_3;
|
||||
rand_deg = DEG_3;
|
||||
rand_sep = SEP_3;
|
||||
} else {
|
||||
rand_type = TYPE_4;
|
||||
rand_deg = DEG_4;
|
||||
rand_sep = SEP_4;
|
||||
}
|
||||
state = (long *) (long_arg_state + 1); /* first location */
|
||||
end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
|
||||
srandom_unlocked(seed);
|
||||
if (rand_type == TYPE_0)
|
||||
long_arg_state[0] = rand_type;
|
||||
else
|
||||
long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
UNLOCKME();
|
||||
return((char *)ostate);
|
||||
LOCKME();
|
||||
if (rand_type == TYPE_0)
|
||||
state[-1] = rand_type;
|
||||
else
|
||||
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
if (n < BREAK_0) {
|
||||
UNLOCKME();
|
||||
return (NULL);
|
||||
} else if (n < BREAK_1) {
|
||||
rand_type = TYPE_0;
|
||||
rand_deg = DEG_0;
|
||||
rand_sep = SEP_0;
|
||||
} else if (n < BREAK_2) {
|
||||
rand_type = TYPE_1;
|
||||
rand_deg = DEG_1;
|
||||
rand_sep = SEP_1;
|
||||
} else if (n < BREAK_3) {
|
||||
rand_type = TYPE_2;
|
||||
rand_deg = DEG_2;
|
||||
rand_sep = SEP_2;
|
||||
} else if (n < BREAK_4) {
|
||||
rand_type = TYPE_3;
|
||||
rand_deg = DEG_3;
|
||||
rand_sep = SEP_3;
|
||||
} else {
|
||||
rand_type = TYPE_4;
|
||||
rand_deg = DEG_4;
|
||||
rand_sep = SEP_4;
|
||||
}
|
||||
state = (long *)(long_arg_state + 1); /* first location */
|
||||
end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
|
||||
srandom_unlocked(seed);
|
||||
if (rand_type == TYPE_0)
|
||||
long_arg_state[0] = rand_type;
|
||||
else
|
||||
long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
UNLOCKME();
|
||||
return ((char *)ostate);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -350,47 +362,46 @@ initstate(
|
||||
* word boundary; otherwise a bus error will occur. Even so, lint will
|
||||
* complain about mis-alignment, but you should disregard these messages.
|
||||
*/
|
||||
char *
|
||||
setstate(char *arg_state) /* pointer to state array */
|
||||
char *setstate(char *arg_state) /* pointer to state array */
|
||||
{
|
||||
long *new_state;
|
||||
int type;
|
||||
int rear;
|
||||
void *ostate = (void *)(&state[-1]);
|
||||
long *new_state;
|
||||
int type;
|
||||
int rear;
|
||||
void *ostate = (void *)(&state[-1]);
|
||||
|
||||
assert(arg_state != NULL);
|
||||
assert(arg_state != NULL);
|
||||
|
||||
new_state = (long *)(void *)arg_state;
|
||||
type = (int)(new_state[0] % MAX_TYPES);
|
||||
rear = (int)(new_state[0] / MAX_TYPES);
|
||||
new_state = (long *)(void *)arg_state;
|
||||
type = (int)(new_state[0] % MAX_TYPES);
|
||||
rear = (int)(new_state[0] / MAX_TYPES);
|
||||
|
||||
LOCKME();
|
||||
if (rand_type == TYPE_0)
|
||||
state[-1] = rand_type;
|
||||
else
|
||||
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
switch(type) {
|
||||
case TYPE_0:
|
||||
case TYPE_1:
|
||||
case TYPE_2:
|
||||
case TYPE_3:
|
||||
case TYPE_4:
|
||||
rand_type = type;
|
||||
rand_deg = degrees[type];
|
||||
rand_sep = seps[type];
|
||||
break;
|
||||
default:
|
||||
UNLOCKME();
|
||||
return (NULL);
|
||||
}
|
||||
state = (long *) (new_state + 1);
|
||||
if (rand_type != TYPE_0) {
|
||||
rptr = &state[rear];
|
||||
fptr = &state[(rear + rand_sep) % rand_deg];
|
||||
}
|
||||
end_ptr = &state[rand_deg]; /* set end_ptr too */
|
||||
UNLOCKME();
|
||||
return((char *)ostate);
|
||||
LOCKME();
|
||||
if (rand_type == TYPE_0)
|
||||
state[-1] = rand_type;
|
||||
else
|
||||
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
|
||||
switch (type) {
|
||||
case TYPE_0:
|
||||
case TYPE_1:
|
||||
case TYPE_2:
|
||||
case TYPE_3:
|
||||
case TYPE_4:
|
||||
rand_type = type;
|
||||
rand_deg = degrees[type];
|
||||
rand_sep = seps[type];
|
||||
break;
|
||||
default:
|
||||
UNLOCKME();
|
||||
return (NULL);
|
||||
}
|
||||
state = (long *)(new_state + 1);
|
||||
if (rand_type != TYPE_0) {
|
||||
rptr = &state[rear];
|
||||
fptr = &state[(rear + rand_sep) % rand_deg];
|
||||
}
|
||||
end_ptr = &state[rand_deg]; /* set end_ptr too */
|
||||
UNLOCKME();
|
||||
return ((char *)ostate);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -410,44 +421,40 @@ setstate(char *arg_state) /* pointer to state array */
|
||||
*
|
||||
* Returns a 31-bit random number.
|
||||
*/
|
||||
static
|
||||
long
|
||||
random_unlocked(void)
|
||||
{
|
||||
long i;
|
||||
long *f, *r;
|
||||
static long random_unlocked(void) {
|
||||
long i;
|
||||
long *f, *r;
|
||||
|
||||
if (rand_type == TYPE_0) {
|
||||
i = state[0];
|
||||
state[0] = i = (i * 1103515245L + 12345L) & 0x7fffffff;
|
||||
} else {
|
||||
/*
|
||||
* Use local variables rather than static variables for speed.
|
||||
*/
|
||||
f = fptr; r = rptr;
|
||||
*f += *r;
|
||||
/* chucking least random bit */
|
||||
i = ((unsigned long)*f >> 1) & 0x7fffffff;
|
||||
if (++f >= end_ptr) {
|
||||
f = state;
|
||||
++r;
|
||||
}
|
||||
else if (++r >= end_ptr) {
|
||||
r = state;
|
||||
}
|
||||
if (rand_type == TYPE_0) {
|
||||
i = state[0];
|
||||
state[0] = i = (i * 1103515245L + 12345L) & 0x7fffffff;
|
||||
} else {
|
||||
/*
|
||||
* Use local variables rather than static variables for speed.
|
||||
*/
|
||||
f = fptr;
|
||||
r = rptr;
|
||||
*f += *r;
|
||||
/* chucking least random bit */
|
||||
i = ((unsigned long)*f >> 1) & 0x7fffffff;
|
||||
if (++f >= end_ptr) {
|
||||
f = state;
|
||||
++r;
|
||||
} else if (++r >= end_ptr) {
|
||||
r = state;
|
||||
}
|
||||
|
||||
fptr = f; rptr = r;
|
||||
}
|
||||
return(i);
|
||||
fptr = f;
|
||||
rptr = r;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
long
|
||||
random(void)
|
||||
{
|
||||
long r;
|
||||
long random(void) {
|
||||
long r;
|
||||
|
||||
LOCKME();
|
||||
r = random_unlocked();
|
||||
UNLOCKME();
|
||||
return (r);
|
||||
LOCKME();
|
||||
r = random_unlocked();
|
||||
UNLOCKME();
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -39,53 +39,50 @@
|
||||
*/
|
||||
|
||||
#define MAXCMDSIZE 2048
|
||||
#define MAXARGS 128
|
||||
#define MAXARGS 128
|
||||
|
||||
int
|
||||
system(const char *cmd)
|
||||
{
|
||||
/*
|
||||
* Ordinarily, you call the shell to process the command.
|
||||
* But we don't know that the shell can do that. So, do it
|
||||
* ourselves.
|
||||
*/
|
||||
int system(const char *cmd) {
|
||||
/*
|
||||
* Ordinarily, you call the shell to process the command.
|
||||
* But we don't know that the shell can do that. So, do it
|
||||
* ourselves.
|
||||
*/
|
||||
|
||||
char tmp[MAXCMDSIZE];
|
||||
char *argv[MAXARGS+1];
|
||||
int nargs=0;
|
||||
char *s;
|
||||
int pid, status;
|
||||
char tmp[MAXCMDSIZE];
|
||||
char *argv[MAXARGS + 1];
|
||||
int nargs = 0;
|
||||
char *s;
|
||||
int pid, status;
|
||||
|
||||
if (strlen(cmd) >= sizeof(tmp)) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
strcpy(tmp, cmd);
|
||||
if (strlen(cmd) >= sizeof(tmp)) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
strcpy(tmp, cmd);
|
||||
|
||||
for (s = strtok(tmp, " \t"); s; s = strtok(NULL, " \t")) {
|
||||
if (nargs < MAXARGS) {
|
||||
argv[nargs++] = s;
|
||||
}
|
||||
else {
|
||||
errno = E2BIG;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (s = strtok(tmp, " \t"); s; s = strtok(NULL, " \t")) {
|
||||
if (nargs < MAXARGS) {
|
||||
argv[nargs++] = s;
|
||||
} else {
|
||||
errno = E2BIG;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
argv[nargs] = NULL;
|
||||
argv[nargs] = NULL;
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
/* child */
|
||||
execv(argv[0], argv);
|
||||
/* exec only returns if it fails */
|
||||
_exit(255);
|
||||
default:
|
||||
/* parent */
|
||||
waitpid(pid, &status, 0);
|
||||
return status;
|
||||
}
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
/* child */
|
||||
execv(argv[0], argv);
|
||||
/* exec only returns if it fails */
|
||||
_exit(255);
|
||||
default:
|
||||
/* parent */
|
||||
waitpid(pid, &status, 0);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,17 +34,15 @@
|
||||
* their sort order.
|
||||
*/
|
||||
|
||||
int
|
||||
memcmp(const void *av, const void *bv, size_t len)
|
||||
{
|
||||
const unsigned char *a = av;
|
||||
const unsigned char *b = bv;
|
||||
size_t i;
|
||||
int memcmp(const void *av, const void *bv, size_t len) {
|
||||
const unsigned char *a = av;
|
||||
const unsigned char *b = bv;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
return (int)(a[i] - b[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
return (int)(a[i] - b[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,11 +33,9 @@
|
||||
/*
|
||||
* Standard C function to return a string for a given errno.
|
||||
*/
|
||||
const char *
|
||||
strerror(int errcode)
|
||||
{
|
||||
if (errcode>=0 && errcode < sys_nerr) {
|
||||
return sys_errlist[errcode];
|
||||
}
|
||||
return "Unknown error number";
|
||||
const char *strerror(int errcode) {
|
||||
if (errcode >= 0 && errcode < sys_nerr) {
|
||||
return sys_errlist[errcode];
|
||||
}
|
||||
return "Unknown error number";
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
|
||||
static char *__strtok_context;
|
||||
|
||||
char *
|
||||
strtok(char *str, const char *seps)
|
||||
{
|
||||
return strtok_r(str, seps, &__strtok_context);
|
||||
char *strtok(char *str, const char *seps) {
|
||||
return strtok_r(str, seps, &__strtok_context);
|
||||
}
|
||||
|
||||
@@ -35,8 +35,4 @@
|
||||
* but also returns nanoseconds.
|
||||
*/
|
||||
|
||||
time_t
|
||||
time(time_t *t)
|
||||
{
|
||||
return __time(t, NULL);
|
||||
}
|
||||
time_t time(time_t *t) { return __time(t, NULL); }
|
||||
|
||||
@@ -38,13 +38,11 @@
|
||||
* Print a message to stderr and bail out of the program.
|
||||
*/
|
||||
|
||||
void
|
||||
__bad_assert(const char *file, int line, const char *expr)
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Assertion failed: %s (%s line %d)\n",
|
||||
expr, file, line);
|
||||
void __bad_assert(const char *file, int line, const char *expr) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Assertion failed: %s (%s line %d)\n", expr, file,
|
||||
line);
|
||||
|
||||
write(STDERR_FILENO, buf, strlen(buf));
|
||||
abort();
|
||||
write(STDERR_FILENO, buf, strlen(buf));
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -47,72 +47,60 @@ extern char **__argv;
|
||||
/*
|
||||
* Routine to print error message text to stderr.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__senderr(void *junk, const char *data, size_t len)
|
||||
{
|
||||
(void)junk; /* not needed or used */
|
||||
static void __senderr(void *junk, const char *data, size_t len) {
|
||||
(void)junk; /* not needed or used */
|
||||
|
||||
write(STDERR_FILENO, data, len);
|
||||
write(STDERR_FILENO, data, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shortcut to call __senderr on a null-terminated string.
|
||||
* (__senderr is set up to be called by __vprintf.)
|
||||
*/
|
||||
static
|
||||
void
|
||||
__senderrstr(const char *str)
|
||||
{
|
||||
__senderr(NULL, str, strlen(str));
|
||||
}
|
||||
static void __senderrstr(const char *str) { __senderr(NULL, str, strlen(str)); }
|
||||
|
||||
/*
|
||||
* Common routine for all the *err* and *warn* functions.
|
||||
*/
|
||||
static
|
||||
void
|
||||
__printerr(int use_errno, const char *fmt, va_list ap)
|
||||
{
|
||||
const char *errmsg;
|
||||
const char *prog;
|
||||
static void __printerr(int use_errno, const char *fmt, va_list ap) {
|
||||
const char *errmsg;
|
||||
const char *prog;
|
||||
|
||||
/*
|
||||
* Get the error message for the current errno.
|
||||
* Do this early, before doing anything that might change the
|
||||
* value in errno.
|
||||
*/
|
||||
errmsg = strerror(errno);
|
||||
/*
|
||||
* Get the error message for the current errno.
|
||||
* Do this early, before doing anything that might change the
|
||||
* value in errno.
|
||||
*/
|
||||
errmsg = strerror(errno);
|
||||
|
||||
/*
|
||||
* Look up the program name.
|
||||
* Strictly speaking we should pull off the rightmost
|
||||
* path component of argv[0] and use that as the program
|
||||
* name (this is how BSD err* prints) but it doesn't make
|
||||
* much difference.
|
||||
*/
|
||||
if (__argv!=NULL && __argv[0]!=NULL) {
|
||||
prog = __argv[0];
|
||||
}
|
||||
else {
|
||||
prog = "(program name unknown)";
|
||||
}
|
||||
/*
|
||||
* Look up the program name.
|
||||
* Strictly speaking we should pull off the rightmost
|
||||
* path component of argv[0] and use that as the program
|
||||
* name (this is how BSD err* prints) but it doesn't make
|
||||
* much difference.
|
||||
*/
|
||||
if (__argv != NULL && __argv[0] != NULL) {
|
||||
prog = __argv[0];
|
||||
} else {
|
||||
prog = "(program name unknown)";
|
||||
}
|
||||
|
||||
/* print the program name */
|
||||
__senderrstr(prog);
|
||||
__senderrstr(": ");
|
||||
/* print the program name */
|
||||
__senderrstr(prog);
|
||||
__senderrstr(": ");
|
||||
|
||||
/* process the printf format and args */
|
||||
__vprintf(__senderr, NULL, fmt, ap);
|
||||
/* process the printf format and args */
|
||||
__vprintf(__senderr, NULL, fmt, ap);
|
||||
|
||||
/* if we're using errno, print the error string from above. */
|
||||
if (use_errno) {
|
||||
__senderrstr(": ");
|
||||
__senderrstr(errmsg);
|
||||
}
|
||||
/* if we're using errno, print the error string from above. */
|
||||
if (use_errno) {
|
||||
__senderrstr(": ");
|
||||
__senderrstr(errmsg);
|
||||
}
|
||||
|
||||
/* and always add a newline. */
|
||||
__senderrstr("\n");
|
||||
/* and always add a newline. */
|
||||
__senderrstr("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,33 +108,21 @@ __printerr(int use_errno, const char *fmt, va_list ap)
|
||||
*/
|
||||
|
||||
/* warn/vwarn: use errno, don't exit */
|
||||
void
|
||||
vwarn(const char *fmt, va_list ap)
|
||||
{
|
||||
__printerr(1, fmt, ap);
|
||||
}
|
||||
void vwarn(const char *fmt, va_list ap) { __printerr(1, fmt, ap); }
|
||||
|
||||
/* warnx/vwarnx: don't use errno, don't exit */
|
||||
void
|
||||
vwarnx(const char *fmt, va_list ap)
|
||||
{
|
||||
__printerr(0, fmt, ap);
|
||||
}
|
||||
void vwarnx(const char *fmt, va_list ap) { __printerr(0, fmt, ap); }
|
||||
|
||||
/* err/verr: use errno, then exit */
|
||||
void
|
||||
verr(int exitcode, const char *fmt, va_list ap)
|
||||
{
|
||||
__printerr(1, fmt, ap);
|
||||
exit(exitcode);
|
||||
void verr(int exitcode, const char *fmt, va_list ap) {
|
||||
__printerr(1, fmt, ap);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/* errx/verrx: don't use errno, but do then exit */
|
||||
void
|
||||
verrx(int exitcode, const char *fmt, va_list ap)
|
||||
{
|
||||
__printerr(0, fmt, ap);
|
||||
exit(exitcode);
|
||||
void verrx(int exitcode, const char *fmt, va_list ap) {
|
||||
__printerr(0, fmt, ap);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -154,38 +130,30 @@ verrx(int exitcode, const char *fmt, va_list ap)
|
||||
* Just hand off to the va_list versions.
|
||||
*/
|
||||
|
||||
void
|
||||
warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarn(fmt, ap);
|
||||
va_end(ap);
|
||||
void warn(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarn(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
void warnx(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
err(int exitcode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verr(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
void err(int exitcode, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verr(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
errx(int exitcode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verrx(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
void errx(int exitcode, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verrx(exitcode, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -38,54 +38,51 @@
|
||||
* POSIX C function: exec a program on the search path. Tries
|
||||
* execv() repeatedly until one of the choices works.
|
||||
*/
|
||||
int
|
||||
execvp(const char *prog, char *const *args)
|
||||
{
|
||||
const char *searchpath, *s, *t;
|
||||
char progpath[PATH_MAX];
|
||||
size_t len;
|
||||
int execvp(const char *prog, char *const *args) {
|
||||
const char *searchpath, *s, *t;
|
||||
char progpath[PATH_MAX];
|
||||
size_t len;
|
||||
|
||||
if (strchr(prog, '/') != NULL) {
|
||||
execv(prog, args);
|
||||
return -1;
|
||||
}
|
||||
if (strchr(prog, '/') != NULL) {
|
||||
execv(prog, args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
searchpath = getenv("PATH");
|
||||
if (searchpath == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
searchpath = getenv("PATH");
|
||||
if (searchpath == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (s = searchpath; s != NULL; s = t) {
|
||||
t = strchr(s, ':');
|
||||
if (t != NULL) {
|
||||
len = t - s;
|
||||
/* advance past the colon */
|
||||
t++;
|
||||
}
|
||||
else {
|
||||
len = strlen(s);
|
||||
}
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
if (len >= sizeof(progpath)) {
|
||||
continue;
|
||||
}
|
||||
memcpy(progpath, s, len);
|
||||
snprintf(progpath + len, sizeof(progpath) - len, "/%s", prog);
|
||||
execv(progpath, args);
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
case ENOEXEC:
|
||||
/* routine errors, try next dir */
|
||||
break;
|
||||
default:
|
||||
/* oops, let's fail */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
for (s = searchpath; s != NULL; s = t) {
|
||||
t = strchr(s, ':');
|
||||
if (t != NULL) {
|
||||
len = t - s;
|
||||
/* advance past the colon */
|
||||
t++;
|
||||
} else {
|
||||
len = strlen(s);
|
||||
}
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
if (len >= sizeof(progpath)) {
|
||||
continue;
|
||||
}
|
||||
memcpy(progpath, s, len);
|
||||
snprintf(progpath + len, sizeof(progpath) - len, "/%s", prog);
|
||||
execv(progpath, args);
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
case ENOEXEC:
|
||||
/* routine errors, try next dir */
|
||||
break;
|
||||
default:
|
||||
/* oops, let's fail */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -36,21 +36,19 @@
|
||||
* all the work.
|
||||
*/
|
||||
|
||||
char *
|
||||
getcwd(char *buf, size_t buflen)
|
||||
{
|
||||
int r;
|
||||
char *getcwd(char *buf, size_t buflen) {
|
||||
int r;
|
||||
|
||||
if (buflen < 1) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (buflen < 1) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = __getcwd(buf, buflen-1);
|
||||
if (r < 0) {
|
||||
return NULL;
|
||||
}
|
||||
r = __getcwd(buf, buflen - 1);
|
||||
if (r < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf[r] = 0;
|
||||
return buf;
|
||||
buf[r] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -38,74 +38,60 @@
|
||||
#include <err.h>
|
||||
#include <test/triple.h>
|
||||
|
||||
static
|
||||
pid_t
|
||||
spawnv(const char *prog, char **argv)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
err(1, "fork");
|
||||
case 0:
|
||||
/* child */
|
||||
execv(prog, argv);
|
||||
err(1, "%s: execv", prog);
|
||||
default:
|
||||
/* parent */
|
||||
break;
|
||||
}
|
||||
return pid;
|
||||
static pid_t spawnv(const char *prog, char **argv) {
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
err(1, "fork");
|
||||
case 0:
|
||||
/* child */
|
||||
execv(prog, argv);
|
||||
err(1, "%s: execv", prog);
|
||||
default:
|
||||
/* parent */
|
||||
break;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
dowait(int index, int pid)
|
||||
{
|
||||
int status;
|
||||
static int dowait(int index, int pid) {
|
||||
int status;
|
||||
|
||||
if (waitpid(pid, &status, 0)<0) {
|
||||
warn("waitpid for copy #%d (pid %d)", index, pid);
|
||||
return 1;
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
warnx("copy #%d (pid %d): signal %d", index, pid,
|
||||
WTERMSIG(status));
|
||||
return 1;
|
||||
}
|
||||
else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("copy #%d (pid %d): exit %d", index, pid,
|
||||
WEXITSTATUS(status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid for copy #%d (pid %d)", index, pid);
|
||||
return 1;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("copy #%d (pid %d): signal %d", index, pid, WTERMSIG(status));
|
||||
return 1;
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
warnx("copy #%d (pid %d): exit %d", index, pid, WEXITSTATUS(status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
triple(const char *prog)
|
||||
{
|
||||
pid_t pids[3];
|
||||
int i, failures = 0;
|
||||
char *args[2];
|
||||
void triple(const char *prog) {
|
||||
pid_t pids[3];
|
||||
int i, failures = 0;
|
||||
char *args[2];
|
||||
|
||||
/* set up the argv */
|
||||
args[0]=(char *)prog;
|
||||
args[1]=NULL;
|
||||
/* set up the argv */
|
||||
args[0] = (char *)prog;
|
||||
args[1] = NULL;
|
||||
|
||||
warnx("Starting: running three copies of %s...", prog);
|
||||
warnx("Starting: running three copies of %s...", prog);
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
pids[i]=spawnv(args[0], args);
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
pids[i] = spawnv(args[0], args);
|
||||
}
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
failures += dowait(i, pids[i]);
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
failures += dowait(i, pids[i]);
|
||||
}
|
||||
|
||||
if (failures > 0) {
|
||||
warnx("%d failures", failures);
|
||||
}
|
||||
else {
|
||||
warnx("Congratulations! You passed.");
|
||||
}
|
||||
if (failures > 0) {
|
||||
warnx("%d failures", failures);
|
||||
} else {
|
||||
warnx("Congratulations! You passed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include "support.h"
|
||||
#include "kern/sfs.h"
|
||||
|
||||
|
||||
#ifdef HOST
|
||||
/*
|
||||
* OS/161 runs natively on a big-endian platform, so we can
|
||||
@@ -78,53 +77,44 @@ static bool recurse;
|
||||
|
||||
static unsigned dumppos;
|
||||
|
||||
static
|
||||
void
|
||||
dumpval(const char *desc, const char *val)
|
||||
{
|
||||
size_t dlen, vlen, used;
|
||||
static void dumpval(const char *desc, const char *val) {
|
||||
size_t dlen, vlen, used;
|
||||
|
||||
dlen = strlen(desc);
|
||||
vlen = strlen(val);
|
||||
dlen = strlen(desc);
|
||||
vlen = strlen(val);
|
||||
|
||||
printf(" ");
|
||||
printf(" ");
|
||||
|
||||
printf("%s: %s", desc, val);
|
||||
printf("%s: %s", desc, val);
|
||||
|
||||
used = dlen + 2 + vlen;
|
||||
for (; used < 36; used++) {
|
||||
putchar(' ');
|
||||
}
|
||||
used = dlen + 2 + vlen;
|
||||
for (; used < 36; used++) {
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
if (dumppos % 2 == 1) {
|
||||
printf("\n");
|
||||
}
|
||||
dumppos++;
|
||||
if (dumppos % 2 == 1) {
|
||||
printf("\n");
|
||||
}
|
||||
dumppos++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpvalf(const char *desc, const char *valf, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[128];
|
||||
static void dumpvalf(const char *desc, const char *valf, ...) {
|
||||
va_list ap;
|
||||
char buf[128];
|
||||
|
||||
va_start(ap, valf);
|
||||
vsnprintf(buf, sizeof(buf), valf, ap);
|
||||
va_end(ap);
|
||||
dumpval(desc, buf);
|
||||
va_start(ap, valf);
|
||||
vsnprintf(buf, sizeof(buf), valf, ap);
|
||||
va_end(ap);
|
||||
dumpval(desc, buf);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumplval(const char *desc, const char *lval)
|
||||
{
|
||||
if (dumppos % 2 == 1) {
|
||||
printf("\n");
|
||||
dumppos++;
|
||||
}
|
||||
printf(" %s: %s\n", desc, lval);
|
||||
dumppos += 2;
|
||||
static void dumplval(const char *desc, const char *lval) {
|
||||
if (dumppos % 2 == 1) {
|
||||
printf("\n");
|
||||
dumppos++;
|
||||
}
|
||||
printf(" %s: %s\n", desc, lval);
|
||||
dumppos += 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -132,476 +122,437 @@ dumplval(const char *desc, const char *lval)
|
||||
|
||||
static void dumpinode(uint32_t ino, const char *name);
|
||||
|
||||
static
|
||||
uint32_t
|
||||
readsb(void)
|
||||
{
|
||||
struct sfs_superblock sb;
|
||||
static uint32_t readsb(void) {
|
||||
struct sfs_superblock sb;
|
||||
|
||||
diskread(&sb, SFS_SUPER_BLOCK);
|
||||
if (SWAP32(sb.sb_magic) != SFS_MAGIC) {
|
||||
errx(1, "Not an sfs filesystem");
|
||||
}
|
||||
return SWAP32(sb.sb_nblocks);
|
||||
diskread(&sb, SFS_SUPER_BLOCK);
|
||||
if (SWAP32(sb.sb_magic) != SFS_MAGIC) {
|
||||
errx(1, "Not an sfs filesystem");
|
||||
}
|
||||
return SWAP32(sb.sb_nblocks);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpsb(void)
|
||||
{
|
||||
struct sfs_superblock sb;
|
||||
unsigned i;
|
||||
static void dumpsb(void) {
|
||||
struct sfs_superblock sb;
|
||||
unsigned i;
|
||||
|
||||
diskread(&sb, SFS_SUPER_BLOCK);
|
||||
sb.sb_volname[sizeof(sb.sb_volname)-1] = 0;
|
||||
diskread(&sb, SFS_SUPER_BLOCK);
|
||||
sb.sb_volname[sizeof(sb.sb_volname) - 1] = 0;
|
||||
|
||||
printf("Superblock\n");
|
||||
printf("----------\n");
|
||||
dumpvalf("Magic", "0x%8x", SWAP32(sb.sb_magic));
|
||||
dumpvalf("Size", "%u blocks", SWAP32(sb.sb_nblocks));
|
||||
dumpvalf("Freemap size", "%u blocks",
|
||||
SFS_FREEMAPBLOCKS(SWAP32(sb.sb_nblocks)));
|
||||
dumpvalf("Block size", "%u bytes", SFS_BLOCKSIZE);
|
||||
dumplval("Volume name", sb.sb_volname);
|
||||
printf("Superblock\n");
|
||||
printf("----------\n");
|
||||
dumpvalf("Magic", "0x%8x", SWAP32(sb.sb_magic));
|
||||
dumpvalf("Size", "%u blocks", SWAP32(sb.sb_nblocks));
|
||||
dumpvalf("Freemap size", "%u blocks",
|
||||
SFS_FREEMAPBLOCKS(SWAP32(sb.sb_nblocks)));
|
||||
dumpvalf("Block size", "%u bytes", SFS_BLOCKSIZE);
|
||||
dumplval("Volume name", sb.sb_volname);
|
||||
|
||||
for (i=0; i<ARRAYCOUNT(sb.reserved); i++) {
|
||||
if (sb.reserved[i] != 0) {
|
||||
printf(" Word %u in reserved area: 0x%x\n",
|
||||
i, SWAP32(sb.reserved[i]));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < ARRAYCOUNT(sb.reserved); i++) {
|
||||
if (sb.reserved[i] != 0) {
|
||||
printf(" Word %u in reserved area: 0x%x\n", i, SWAP32(sb.reserved[i]));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpfreemap(uint32_t fsblocks)
|
||||
{
|
||||
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
uint32_t i, j, k, bn;
|
||||
uint8_t data[SFS_BLOCKSIZE], mask;
|
||||
char tmp[16];
|
||||
static void dumpfreemap(uint32_t fsblocks) {
|
||||
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
uint32_t i, j, k, bn;
|
||||
uint8_t data[SFS_BLOCKSIZE], mask;
|
||||
char tmp[16];
|
||||
|
||||
printf("Free block bitmap\n");
|
||||
printf("-----------------\n");
|
||||
for (i=0; i<freemapblocks; i++) {
|
||||
diskread(data, SFS_FREEMAP_START+i);
|
||||
printf(" Freemap block #%u in disk block %u: blocks %u - %u"
|
||||
" (0x%x - 0x%x)\n",
|
||||
i, SFS_FREEMAP_START+i,
|
||||
i*SFS_BITSPERBLOCK, (i+1)*SFS_BITSPERBLOCK - 1,
|
||||
i*SFS_BITSPERBLOCK, (i+1)*SFS_BITSPERBLOCK - 1);
|
||||
for (j=0; j<SFS_BLOCKSIZE; j++) {
|
||||
if (j % 8 == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "0x%x",
|
||||
i*SFS_BITSPERBLOCK + j*8);
|
||||
printf("%-7s ", tmp);
|
||||
}
|
||||
for (k=0; k<8; k++) {
|
||||
bn = i*SFS_BITSPERBLOCK + j*8 + k;
|
||||
mask = 1U << k;
|
||||
if (bn >= fsblocks) {
|
||||
if (data[j] & mask) {
|
||||
putchar('x');
|
||||
}
|
||||
else {
|
||||
putchar('!');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (data[j] & mask) {
|
||||
putchar('*');
|
||||
}
|
||||
else {
|
||||
putchar('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j % 8 == 7) {
|
||||
printf("\n");
|
||||
}
|
||||
else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("Free block bitmap\n");
|
||||
printf("-----------------\n");
|
||||
for (i = 0; i < freemapblocks; i++) {
|
||||
diskread(data, SFS_FREEMAP_START + i);
|
||||
printf(" Freemap block #%u in disk block %u: blocks %u - %u"
|
||||
" (0x%x - 0x%x)\n",
|
||||
i, SFS_FREEMAP_START + i, i * SFS_BITSPERBLOCK,
|
||||
(i + 1) * SFS_BITSPERBLOCK - 1, i * SFS_BITSPERBLOCK,
|
||||
(i + 1) * SFS_BITSPERBLOCK - 1);
|
||||
for (j = 0; j < SFS_BLOCKSIZE; j++) {
|
||||
if (j % 8 == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "0x%x", i * SFS_BITSPERBLOCK + j * 8);
|
||||
printf("%-7s ", tmp);
|
||||
}
|
||||
for (k = 0; k < 8; k++) {
|
||||
bn = i * SFS_BITSPERBLOCK + j * 8 + k;
|
||||
mask = 1U << k;
|
||||
if (bn >= fsblocks) {
|
||||
if (data[j] & mask) {
|
||||
putchar('x');
|
||||
} else {
|
||||
putchar('!');
|
||||
}
|
||||
} else {
|
||||
if (data[j] & mask) {
|
||||
putchar('*');
|
||||
} else {
|
||||
putchar('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j % 8 == 7) {
|
||||
printf("\n");
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpindirect(uint32_t block)
|
||||
{
|
||||
uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)];
|
||||
char tmp[128];
|
||||
unsigned i;
|
||||
static void dumpindirect(uint32_t block) {
|
||||
uint32_t ib[SFS_BLOCKSIZE / sizeof(uint32_t)];
|
||||
char tmp[128];
|
||||
unsigned i;
|
||||
|
||||
if (block == 0) {
|
||||
return;
|
||||
}
|
||||
printf("Indirect block %u\n", block);
|
||||
if (block == 0) {
|
||||
return;
|
||||
}
|
||||
printf("Indirect block %u\n", block);
|
||||
|
||||
diskread(ib, block);
|
||||
for (i=0; i<ARRAYCOUNT(ib); i++) {
|
||||
if (i % 4 == 0) {
|
||||
printf("@%-3u ", i);
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), "%u (0x%x)",
|
||||
SWAP32(ib[i]), SWAP32(ib[i]));
|
||||
printf(" %-16s", tmp);
|
||||
if (i % 4 == 3) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
diskread(ib, block);
|
||||
for (i = 0; i < ARRAYCOUNT(ib); i++) {
|
||||
if (i % 4 == 0) {
|
||||
printf("@%-3u ", i);
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), "%u (0x%x)", SWAP32(ib[i]), SWAP32(ib[i]));
|
||||
printf(" %-16s", tmp);
|
||||
if (i % 4 == 3) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
uint32_t
|
||||
traverse_ib(uint32_t fileblock, uint32_t numblocks, uint32_t block,
|
||||
void (*doblock)(uint32_t, uint32_t))
|
||||
{
|
||||
uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)];
|
||||
unsigned i;
|
||||
static uint32_t traverse_ib(uint32_t fileblock, uint32_t numblocks,
|
||||
uint32_t block,
|
||||
void (*doblock)(uint32_t, uint32_t)) {
|
||||
uint32_t ib[SFS_BLOCKSIZE / sizeof(uint32_t)];
|
||||
unsigned i;
|
||||
|
||||
if (block == 0) {
|
||||
memset(ib, 0, sizeof(ib));
|
||||
}
|
||||
else {
|
||||
diskread(ib, block);
|
||||
}
|
||||
for (i=0; i<ARRAYCOUNT(ib) && fileblock < numblocks; i++) {
|
||||
doblock(fileblock++, SWAP32(ib[i]));
|
||||
}
|
||||
return fileblock;
|
||||
if (block == 0) {
|
||||
memset(ib, 0, sizeof(ib));
|
||||
} else {
|
||||
diskread(ib, block);
|
||||
}
|
||||
for (i = 0; i < ARRAYCOUNT(ib) && fileblock < numblocks; i++) {
|
||||
doblock(fileblock++, SWAP32(ib[i]));
|
||||
}
|
||||
return fileblock;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
traverse(const struct sfs_dinode *sfi, void (*doblock)(uint32_t, uint32_t))
|
||||
{
|
||||
uint32_t fileblock;
|
||||
uint32_t numblocks;
|
||||
unsigned i;
|
||||
static void traverse(const struct sfs_dinode *sfi,
|
||||
void (*doblock)(uint32_t, uint32_t)) {
|
||||
uint32_t fileblock;
|
||||
uint32_t numblocks;
|
||||
unsigned i;
|
||||
|
||||
numblocks = DIVROUNDUP(SWAP32(sfi->sfi_size), SFS_BLOCKSIZE);
|
||||
numblocks = DIVROUNDUP(SWAP32(sfi->sfi_size), SFS_BLOCKSIZE);
|
||||
|
||||
fileblock = 0;
|
||||
for (i=0; i<SFS_NDIRECT && fileblock < numblocks; i++) {
|
||||
doblock(fileblock++, SWAP32(sfi->sfi_direct[i]));
|
||||
}
|
||||
if (fileblock < numblocks) {
|
||||
fileblock = traverse_ib(fileblock, numblocks,
|
||||
SWAP32(sfi->sfi_indirect), doblock);
|
||||
}
|
||||
assert(fileblock == numblocks);
|
||||
fileblock = 0;
|
||||
for (i = 0; i < SFS_NDIRECT && fileblock < numblocks; i++) {
|
||||
doblock(fileblock++, SWAP32(sfi->sfi_direct[i]));
|
||||
}
|
||||
if (fileblock < numblocks) {
|
||||
fileblock =
|
||||
traverse_ib(fileblock, numblocks, SWAP32(sfi->sfi_indirect), doblock);
|
||||
}
|
||||
assert(fileblock == numblocks);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpdirblock(uint32_t fileblock, uint32_t diskblock)
|
||||
{
|
||||
struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)];
|
||||
int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
int i;
|
||||
static void dumpdirblock(uint32_t fileblock, uint32_t diskblock) {
|
||||
struct sfs_direntry sds[SFS_BLOCKSIZE / sizeof(struct sfs_direntry)];
|
||||
int nsds = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
|
||||
int i;
|
||||
|
||||
(void)fileblock;
|
||||
if (diskblock == 0) {
|
||||
printf(" [block %u - empty]\n", diskblock);
|
||||
return;
|
||||
}
|
||||
diskread(&sds, diskblock);
|
||||
(void)fileblock;
|
||||
if (diskblock == 0) {
|
||||
printf(" [block %u - empty]\n", diskblock);
|
||||
return;
|
||||
}
|
||||
diskread(&sds, diskblock);
|
||||
|
||||
printf(" [block %u]\n", diskblock);
|
||||
for (i=0; i<nsds; i++) {
|
||||
uint32_t ino = SWAP32(sds[i].sfd_ino);
|
||||
if (ino==SFS_NOINO) {
|
||||
printf(" [free entry]\n");
|
||||
}
|
||||
else {
|
||||
sds[i].sfd_name[SFS_NAMELEN-1] = 0; /* just in case */
|
||||
printf(" %u %s\n", ino, sds[i].sfd_name);
|
||||
}
|
||||
}
|
||||
printf(" [block %u]\n", diskblock);
|
||||
for (i = 0; i < nsds; i++) {
|
||||
uint32_t ino = SWAP32(sds[i].sfd_ino);
|
||||
if (ino == SFS_NOINO) {
|
||||
printf(" [free entry]\n");
|
||||
} else {
|
||||
sds[i].sfd_name[SFS_NAMELEN - 1] = 0; /* just in case */
|
||||
printf(" %u %s\n", ino, sds[i].sfd_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpdir(uint32_t ino, const struct sfs_dinode *sfi)
|
||||
{
|
||||
int nentries;
|
||||
static void dumpdir(uint32_t ino, const struct sfs_dinode *sfi) {
|
||||
int nentries;
|
||||
|
||||
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
|
||||
if (SWAP32(sfi->sfi_size) % sizeof(struct sfs_direntry) != 0) {
|
||||
warnx("Warning: dir size is not a multiple of dir entry size");
|
||||
}
|
||||
printf("Directory contents for inode %u: %d entries\n", ino, nentries);
|
||||
traverse(sfi, dumpdirblock);
|
||||
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
|
||||
if (SWAP32(sfi->sfi_size) % sizeof(struct sfs_direntry) != 0) {
|
||||
warnx("Warning: dir size is not a multiple of dir entry size");
|
||||
}
|
||||
printf("Directory contents for inode %u: %d entries\n", ino, nentries);
|
||||
traverse(sfi, dumpdirblock);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
recursedirblock(uint32_t fileblock, uint32_t diskblock)
|
||||
{
|
||||
struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)];
|
||||
int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
int i;
|
||||
static void recursedirblock(uint32_t fileblock, uint32_t diskblock) {
|
||||
struct sfs_direntry sds[SFS_BLOCKSIZE / sizeof(struct sfs_direntry)];
|
||||
int nsds = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
|
||||
int i;
|
||||
|
||||
(void)fileblock;
|
||||
if (diskblock == 0) {
|
||||
return;
|
||||
}
|
||||
diskread(&sds, diskblock);
|
||||
(void)fileblock;
|
||||
if (diskblock == 0) {
|
||||
return;
|
||||
}
|
||||
diskread(&sds, diskblock);
|
||||
|
||||
for (i=0; i<nsds; i++) {
|
||||
uint32_t ino = SWAP32(sds[i].sfd_ino);
|
||||
if (ino==SFS_NOINO) {
|
||||
continue;
|
||||
}
|
||||
sds[i].sfd_name[SFS_NAMELEN-1] = 0; /* just in case */
|
||||
dumpinode(ino, sds[i].sfd_name);
|
||||
}
|
||||
for (i = 0; i < nsds; i++) {
|
||||
uint32_t ino = SWAP32(sds[i].sfd_ino);
|
||||
if (ino == SFS_NOINO) {
|
||||
continue;
|
||||
}
|
||||
sds[i].sfd_name[SFS_NAMELEN - 1] = 0; /* just in case */
|
||||
dumpinode(ino, sds[i].sfd_name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
recursedir(uint32_t ino, const struct sfs_dinode *sfi)
|
||||
{
|
||||
int nentries;
|
||||
static void recursedir(uint32_t ino, const struct sfs_dinode *sfi) {
|
||||
int nentries;
|
||||
|
||||
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
|
||||
printf("Reading files in directory %u: %d entries\n", ino, nentries);
|
||||
traverse(sfi, recursedirblock);
|
||||
printf("Done with directory %u\n", ino);
|
||||
nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
|
||||
printf("Reading files in directory %u: %d entries\n", ino, nentries);
|
||||
traverse(sfi, recursedirblock);
|
||||
printf("Done with directory %u\n", ino);
|
||||
}
|
||||
|
||||
static
|
||||
void dumpfileblock(uint32_t fileblock, uint32_t diskblock)
|
||||
{
|
||||
uint8_t data[SFS_BLOCKSIZE];
|
||||
unsigned i, j;
|
||||
char tmp[128];
|
||||
static void dumpfileblock(uint32_t fileblock, uint32_t diskblock) {
|
||||
uint8_t data[SFS_BLOCKSIZE];
|
||||
unsigned i, j;
|
||||
char tmp[128];
|
||||
|
||||
if (diskblock == 0) {
|
||||
printf(" 0x%6x [sparse]\n", fileblock * SFS_BLOCKSIZE);
|
||||
return;
|
||||
}
|
||||
if (diskblock == 0) {
|
||||
printf(" 0x%6x [sparse]\n", fileblock * SFS_BLOCKSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
diskread(data, diskblock);
|
||||
for (i=0; i<SFS_BLOCKSIZE; i++) {
|
||||
if (i % 16 == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "0x%x",
|
||||
fileblock * SFS_BLOCKSIZE + i);
|
||||
printf("%8s", tmp);
|
||||
}
|
||||
if (i % 8 == 0) {
|
||||
printf(" ");
|
||||
}
|
||||
else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%02x", data[i]);
|
||||
if (i % 16 == 15) {
|
||||
printf(" ");
|
||||
for (j = i-15; j<=i; j++) {
|
||||
if (data[j] < 32 || data[j] > 126) {
|
||||
putchar('.');
|
||||
}
|
||||
else {
|
||||
putchar(data[j]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
diskread(data, diskblock);
|
||||
for (i = 0; i < SFS_BLOCKSIZE; i++) {
|
||||
if (i % 16 == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "0x%x", fileblock * SFS_BLOCKSIZE + i);
|
||||
printf("%8s", tmp);
|
||||
}
|
||||
if (i % 8 == 0) {
|
||||
printf(" ");
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%02x", data[i]);
|
||||
if (i % 16 == 15) {
|
||||
printf(" ");
|
||||
for (j = i - 15; j <= i; j++) {
|
||||
if (data[j] < 32 || data[j] > 126) {
|
||||
putchar('.');
|
||||
} else {
|
||||
putchar(data[j]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpfile(uint32_t ino, const struct sfs_dinode *sfi)
|
||||
{
|
||||
printf("File contents for inode %u:\n", ino);
|
||||
traverse(sfi, dumpfileblock);
|
||||
static void dumpfile(uint32_t ino, const struct sfs_dinode *sfi) {
|
||||
printf("File contents for inode %u:\n", ino);
|
||||
traverse(sfi, dumpfileblock);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dumpinode(uint32_t ino, const char *name)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
const char *typename;
|
||||
char tmp[128];
|
||||
unsigned i;
|
||||
static void dumpinode(uint32_t ino, const char *name) {
|
||||
struct sfs_dinode sfi;
|
||||
const char *typename;
|
||||
char tmp[128];
|
||||
unsigned i;
|
||||
|
||||
diskread(&sfi, ino);
|
||||
diskread(&sfi, ino);
|
||||
|
||||
printf("Inode %u", ino);
|
||||
if (name != NULL) {
|
||||
printf(" (%s)", name);
|
||||
}
|
||||
printf("\n");
|
||||
printf("--------------\n");
|
||||
printf("Inode %u", ino);
|
||||
if (name != NULL) {
|
||||
printf(" (%s)", name);
|
||||
}
|
||||
printf("\n");
|
||||
printf("--------------\n");
|
||||
|
||||
switch (SWAP16(sfi.sfi_type)) {
|
||||
case SFS_TYPE_FILE: typename = "regular file"; break;
|
||||
case SFS_TYPE_DIR: typename = "directory"; break;
|
||||
default: typename = "invalid"; break;
|
||||
}
|
||||
dumpvalf("Type", "%u (%s)", SWAP16(sfi.sfi_type), typename);
|
||||
dumpvalf("Size", "%u", SWAP32(sfi.sfi_size));
|
||||
dumpvalf("Link count", "%u", SWAP16(sfi.sfi_linkcount));
|
||||
printf("\n");
|
||||
switch (SWAP16(sfi.sfi_type)) {
|
||||
case SFS_TYPE_FILE:
|
||||
typename = "regular file";
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
typename = "directory";
|
||||
break;
|
||||
default:
|
||||
typename = "invalid";
|
||||
break;
|
||||
}
|
||||
dumpvalf("Type", "%u (%s)", SWAP16(sfi.sfi_type), typename);
|
||||
dumpvalf("Size", "%u", SWAP32(sfi.sfi_size));
|
||||
dumpvalf("Link count", "%u", SWAP16(sfi.sfi_linkcount));
|
||||
printf("\n");
|
||||
|
||||
printf(" Direct blocks:\n");
|
||||
for (i=0; i<SFS_NDIRECT; i++) {
|
||||
if (i % 4 == 0) {
|
||||
printf("@%-2u ", i);
|
||||
}
|
||||
/*
|
||||
* Assume the disk size might be > 64K sectors (which
|
||||
* would be 32M) but is < 1024K sectors (512M) so we
|
||||
* need up to 5 hex digits for a block number. And
|
||||
* assume it's actually < 1 million sectors so we need
|
||||
* only up to 6 decimal digits. The complete block
|
||||
* number print then needs up to 16 digits.
|
||||
*/
|
||||
snprintf(tmp, sizeof(tmp), "%u (0x%x)",
|
||||
SWAP32(sfi.sfi_direct[i]), SWAP32(sfi.sfi_direct[i]));
|
||||
printf(" %-16s", tmp);
|
||||
if (i % 4 == 3) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (i % 4 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Indirect block: %u (0x%x)\n",
|
||||
SWAP32(sfi.sfi_indirect), SWAP32(sfi.sfi_indirect));
|
||||
for (i=0; i<ARRAYCOUNT(sfi.sfi_waste); i++) {
|
||||
if (sfi.sfi_waste[i] != 0) {
|
||||
printf(" Word %u in waste area: 0x%x\n",
|
||||
i, SWAP32(sfi.sfi_waste[i]));
|
||||
}
|
||||
}
|
||||
printf(" Direct blocks:\n");
|
||||
for (i = 0; i < SFS_NDIRECT; i++) {
|
||||
if (i % 4 == 0) {
|
||||
printf("@%-2u ", i);
|
||||
}
|
||||
/*
|
||||
* Assume the disk size might be > 64K sectors (which
|
||||
* would be 32M) but is < 1024K sectors (512M) so we
|
||||
* need up to 5 hex digits for a block number. And
|
||||
* assume it's actually < 1 million sectors so we need
|
||||
* only up to 6 decimal digits. The complete block
|
||||
* number print then needs up to 16 digits.
|
||||
*/
|
||||
snprintf(tmp, sizeof(tmp), "%u (0x%x)", SWAP32(sfi.sfi_direct[i]),
|
||||
SWAP32(sfi.sfi_direct[i]));
|
||||
printf(" %-16s", tmp);
|
||||
if (i % 4 == 3) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (i % 4 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Indirect block: %u (0x%x)\n", SWAP32(sfi.sfi_indirect),
|
||||
SWAP32(sfi.sfi_indirect));
|
||||
for (i = 0; i < ARRAYCOUNT(sfi.sfi_waste); i++) {
|
||||
if (sfi.sfi_waste[i] != 0) {
|
||||
printf(" Word %u in waste area: 0x%x\n", i, SWAP32(sfi.sfi_waste[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (doindirect) {
|
||||
dumpindirect(SWAP32(sfi.sfi_indirect));
|
||||
}
|
||||
if (doindirect) {
|
||||
dumpindirect(SWAP32(sfi.sfi_indirect));
|
||||
}
|
||||
|
||||
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && dodirs) {
|
||||
dumpdir(ino, &sfi);
|
||||
}
|
||||
if (SWAP16(sfi.sfi_type) == SFS_TYPE_FILE && dofiles) {
|
||||
dumpfile(ino, &sfi);
|
||||
}
|
||||
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && recurse) {
|
||||
recursedir(ino, &sfi);
|
||||
}
|
||||
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && dodirs) {
|
||||
dumpdir(ino, &sfi);
|
||||
}
|
||||
if (SWAP16(sfi.sfi_type) == SFS_TYPE_FILE && dofiles) {
|
||||
dumpfile(ino, &sfi);
|
||||
}
|
||||
if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && recurse) {
|
||||
recursedir(ino, &sfi);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// main
|
||||
|
||||
static
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
warnx("Usage: dumpsfs [options] device/diskfile");
|
||||
warnx(" -s: dump superblock");
|
||||
warnx(" -b: dump free block bitmap");
|
||||
warnx(" -i ino: dump specified inode");
|
||||
warnx(" -I: dump indirect blocks");
|
||||
warnx(" -f: dump file contents");
|
||||
warnx(" -d: dump directory contents");
|
||||
warnx(" -r: recurse into directory contents");
|
||||
warnx(" -a: equivalent to -sbdfr -i 1");
|
||||
errx(1, " Default is -i 1");
|
||||
static void usage(void) {
|
||||
warnx("Usage: dumpsfs [options] device/diskfile");
|
||||
warnx(" -s: dump superblock");
|
||||
warnx(" -b: dump free block bitmap");
|
||||
warnx(" -i ino: dump specified inode");
|
||||
warnx(" -I: dump indirect blocks");
|
||||
warnx(" -f: dump file contents");
|
||||
warnx(" -d: dump directory contents");
|
||||
warnx(" -r: recurse into directory contents");
|
||||
warnx(" -a: equivalent to -sbdfr -i 1");
|
||||
errx(1, " Default is -i 1");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
bool dosb = false;
|
||||
bool dofreemap = false;
|
||||
uint32_t dumpino = 0;
|
||||
const char *dumpdisk = NULL;
|
||||
int main(int argc, char **argv) {
|
||||
bool dosb = false;
|
||||
bool dofreemap = false;
|
||||
uint32_t dumpino = 0;
|
||||
const char *dumpdisk = NULL;
|
||||
|
||||
int i, j;
|
||||
uint32_t nblocks;
|
||||
int i, j;
|
||||
uint32_t nblocks;
|
||||
|
||||
#ifdef HOST
|
||||
/* Don't do this; it frobs the tty and you can't pipe to less */
|
||||
/*hostcompat_init(argc, argv);*/
|
||||
hostcompat_progname = argv[0];
|
||||
/* Don't do this; it frobs the tty and you can't pipe to less */
|
||||
/*hostcompat_init(argc, argv);*/
|
||||
hostcompat_progname = argv[0];
|
||||
#endif
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
for (j=1; argv[i][j]; j++) {
|
||||
switch (argv[i][j]) {
|
||||
case 's': dosb = true; break;
|
||||
case 'b': dofreemap = true; break;
|
||||
case 'i':
|
||||
if (argv[i][j+1] == 0) {
|
||||
dumpino = atoi(argv[++i]);
|
||||
}
|
||||
else {
|
||||
dumpino = atoi(argv[i]+j+1);
|
||||
j = strlen(argv[i]);
|
||||
}
|
||||
/* XXX ugly */
|
||||
goto nextarg;
|
||||
case 'I': doindirect = true; break;
|
||||
case 'f': dofiles = true; break;
|
||||
case 'd': dodirs = true; break;
|
||||
case 'r': recurse = true; break;
|
||||
case 'a':
|
||||
dosb = true;
|
||||
dofreemap = true;
|
||||
if (dumpino == 0) {
|
||||
dumpino = SFS_ROOTDIR_INO;
|
||||
}
|
||||
doindirect = true;
|
||||
dofiles = true;
|
||||
dodirs = true;
|
||||
recurse = true;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dumpdisk != NULL) {
|
||||
usage();
|
||||
}
|
||||
dumpdisk = argv[i];
|
||||
}
|
||||
nextarg:
|
||||
;
|
||||
}
|
||||
if (dumpdisk == NULL) {
|
||||
usage();
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
for (j = 1; argv[i][j]; j++) {
|
||||
switch (argv[i][j]) {
|
||||
case 's':
|
||||
dosb = true;
|
||||
break;
|
||||
case 'b':
|
||||
dofreemap = true;
|
||||
break;
|
||||
case 'i':
|
||||
if (argv[i][j + 1] == 0) {
|
||||
dumpino = atoi(argv[++i]);
|
||||
} else {
|
||||
dumpino = atoi(argv[i] + j + 1);
|
||||
j = strlen(argv[i]);
|
||||
}
|
||||
/* XXX ugly */
|
||||
goto nextarg;
|
||||
case 'I':
|
||||
doindirect = true;
|
||||
break;
|
||||
case 'f':
|
||||
dofiles = true;
|
||||
break;
|
||||
case 'd':
|
||||
dodirs = true;
|
||||
break;
|
||||
case 'r':
|
||||
recurse = true;
|
||||
break;
|
||||
case 'a':
|
||||
dosb = true;
|
||||
dofreemap = true;
|
||||
if (dumpino == 0) {
|
||||
dumpino = SFS_ROOTDIR_INO;
|
||||
}
|
||||
doindirect = true;
|
||||
dofiles = true;
|
||||
dodirs = true;
|
||||
recurse = true;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dumpdisk != NULL) {
|
||||
usage();
|
||||
}
|
||||
dumpdisk = argv[i];
|
||||
}
|
||||
nextarg:;
|
||||
}
|
||||
if (dumpdisk == NULL) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (!dosb && !dofreemap && dumpino == 0) {
|
||||
dumpino = SFS_ROOTDIR_INO;
|
||||
}
|
||||
if (!dosb && !dofreemap && dumpino == 0) {
|
||||
dumpino = SFS_ROOTDIR_INO;
|
||||
}
|
||||
|
||||
opendisk(dumpdisk);
|
||||
nblocks = readsb();
|
||||
opendisk(dumpdisk);
|
||||
nblocks = readsb();
|
||||
|
||||
if (dosb) {
|
||||
dumpsb();
|
||||
}
|
||||
if (dofreemap) {
|
||||
dumpfreemap(nblocks);
|
||||
}
|
||||
if (dumpino != 0) {
|
||||
dumpinode(dumpino, NULL);
|
||||
}
|
||||
if (dosb) {
|
||||
dumpsb();
|
||||
}
|
||||
if (dofreemap) {
|
||||
dumpfreemap(nblocks);
|
||||
}
|
||||
if (dumpino != 0) {
|
||||
dumpinode(dumpino, NULL);
|
||||
}
|
||||
|
||||
closedisk();
|
||||
closedisk();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,7 @@
|
||||
* Just calls reboot() with the RB_HALT flag.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
reboot(RB_HALT);
|
||||
return 0;
|
||||
int main(void) {
|
||||
reboot(RB_HALT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,160 +41,148 @@
|
||||
#include "disk.h"
|
||||
|
||||
#define HOSTSTRING "System/161 Disk Image"
|
||||
#define BLOCKSIZE 512
|
||||
#define BLOCKSIZE 512
|
||||
|
||||
#ifndef EINTR
|
||||
#define EINTR 0
|
||||
#endif
|
||||
|
||||
static int fd=-1;
|
||||
static int fd = -1;
|
||||
static uint32_t nblocks;
|
||||
|
||||
/*
|
||||
* Open a disk. If we're built for the host OS, check that it's a
|
||||
* System/161 disk image, and then ignore the header block.
|
||||
*/
|
||||
void
|
||||
opendisk(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
void opendisk(const char *path) {
|
||||
struct stat statbuf;
|
||||
|
||||
assert(fd<0);
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &statbuf)) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
assert(fd < 0);
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &statbuf)) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
|
||||
nblocks = statbuf.st_size / BLOCKSIZE;
|
||||
nblocks = statbuf.st_size / BLOCKSIZE;
|
||||
|
||||
#ifdef HOST
|
||||
nblocks--;
|
||||
nblocks--;
|
||||
|
||||
{
|
||||
char buf[64];
|
||||
int len;
|
||||
{
|
||||
char buf[64];
|
||||
int len;
|
||||
|
||||
do {
|
||||
len = read(fd, buf, sizeof(buf)-1);
|
||||
if (len < 0 && (errno==EINTR || errno==EAGAIN)) {
|
||||
continue;
|
||||
}
|
||||
} while (0);
|
||||
do {
|
||||
len = read(fd, buf, sizeof(buf) - 1);
|
||||
if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
|
||||
continue;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
buf[len] = 0;
|
||||
buf[strlen(HOSTSTRING)] = 0;
|
||||
buf[len] = 0;
|
||||
buf[strlen(HOSTSTRING)] = 0;
|
||||
|
||||
if (strcmp(buf, HOSTSTRING)) {
|
||||
errx(1, "%s: Not a System/161 disk image", path);
|
||||
}
|
||||
}
|
||||
if (strcmp(buf, HOSTSTRING)) {
|
||||
errx(1, "%s: Not a System/161 disk image", path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the block size. (This is fixed, but still...)
|
||||
*/
|
||||
uint32_t
|
||||
diskblocksize(void)
|
||||
{
|
||||
assert(fd>=0);
|
||||
return BLOCKSIZE;
|
||||
uint32_t diskblocksize(void) {
|
||||
assert(fd >= 0);
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the device/image size in blocks.
|
||||
*/
|
||||
uint32_t
|
||||
diskblocks(void)
|
||||
{
|
||||
assert(fd>=0);
|
||||
return nblocks;
|
||||
uint32_t diskblocks(void) {
|
||||
assert(fd >= 0);
|
||||
return nblocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a block.
|
||||
*/
|
||||
void
|
||||
diskwrite(const void *data, uint32_t block)
|
||||
{
|
||||
const char *cdata = data;
|
||||
uint32_t tot=0;
|
||||
int len;
|
||||
void diskwrite(const void *data, uint32_t block) {
|
||||
const char *cdata = data;
|
||||
uint32_t tot = 0;
|
||||
int len;
|
||||
|
||||
assert(fd>=0);
|
||||
assert(fd >= 0);
|
||||
|
||||
#ifdef HOST
|
||||
// skip over disk file header
|
||||
block++;
|
||||
// skip over disk file header
|
||||
block++;
|
||||
#endif
|
||||
|
||||
if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
if (lseek(fd, block * BLOCKSIZE, SEEK_SET) < 0) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
|
||||
while (tot < BLOCKSIZE) {
|
||||
len = write(fd, cdata + tot, BLOCKSIZE - tot);
|
||||
if (len < 0) {
|
||||
if (errno==EINTR || errno==EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
err(1, "write");
|
||||
}
|
||||
if (len==0) {
|
||||
err(1, "write returned 0?");
|
||||
}
|
||||
tot += len;
|
||||
}
|
||||
while (tot < BLOCKSIZE) {
|
||||
len = write(fd, cdata + tot, BLOCKSIZE - tot);
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
err(1, "write");
|
||||
}
|
||||
if (len == 0) {
|
||||
err(1, "write returned 0?");
|
||||
}
|
||||
tot += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a block.
|
||||
*/
|
||||
void
|
||||
diskread(void *data, uint32_t block)
|
||||
{
|
||||
char *cdata = data;
|
||||
uint32_t tot=0;
|
||||
int len;
|
||||
void diskread(void *data, uint32_t block) {
|
||||
char *cdata = data;
|
||||
uint32_t tot = 0;
|
||||
int len;
|
||||
|
||||
assert(fd>=0);
|
||||
assert(fd >= 0);
|
||||
|
||||
#ifdef HOST
|
||||
// skip over disk file header
|
||||
block++;
|
||||
// skip over disk file header
|
||||
block++;
|
||||
#endif
|
||||
|
||||
if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
if (lseek(fd, block * BLOCKSIZE, SEEK_SET) < 0) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
|
||||
while (tot < BLOCKSIZE) {
|
||||
len = read(fd, cdata + tot, BLOCKSIZE - tot);
|
||||
if (len < 0) {
|
||||
if (errno==EINTR || errno==EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
err(1, "read");
|
||||
}
|
||||
if (len==0) {
|
||||
err(1, "unexpected EOF in mid-sector");
|
||||
}
|
||||
tot += len;
|
||||
}
|
||||
while (tot < BLOCKSIZE) {
|
||||
len = read(fd, cdata + tot, BLOCKSIZE - tot);
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
err(1, "read");
|
||||
}
|
||||
if (len == 0) {
|
||||
err(1, "unexpected EOF in mid-sector");
|
||||
}
|
||||
tot += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the disk.
|
||||
*/
|
||||
void
|
||||
closedisk(void)
|
||||
{
|
||||
assert(fd>=0);
|
||||
if (close(fd)) {
|
||||
err(1, "close");
|
||||
}
|
||||
fd = -1;
|
||||
void closedisk(void) {
|
||||
assert(fd >= 0);
|
||||
if (close(fd)) {
|
||||
err(1, "close");
|
||||
}
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "support.h"
|
||||
#include "kern/sfs.h"
|
||||
|
||||
|
||||
#ifdef HOST
|
||||
|
||||
#include <netinet/in.h> // for arpa/inet.h
|
||||
@@ -66,175 +65,155 @@ static char freemapbuf[MAXFREEMAPBLOCKS * SFS_BLOCKSIZE];
|
||||
/*
|
||||
* Assert that the on-disk data structures are correctly sized.
|
||||
*/
|
||||
static
|
||||
void
|
||||
check(void)
|
||||
{
|
||||
assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
|
||||
assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
|
||||
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
|
||||
static void check(void) {
|
||||
assert(sizeof(struct sfs_superblock) == SFS_BLOCKSIZE);
|
||||
assert(sizeof(struct sfs_dinode) == SFS_BLOCKSIZE);
|
||||
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark a block allocated.
|
||||
*/
|
||||
static
|
||||
void
|
||||
allocblock(uint32_t block)
|
||||
{
|
||||
uint32_t mapbyte = block/CHAR_BIT;
|
||||
unsigned char mask = (1<<(block % CHAR_BIT));
|
||||
static void allocblock(uint32_t block) {
|
||||
uint32_t mapbyte = block / CHAR_BIT;
|
||||
unsigned char mask = (1 << (block % CHAR_BIT));
|
||||
|
||||
assert((freemapbuf[mapbyte] & mask) == 0);
|
||||
freemapbuf[mapbyte] |= mask;
|
||||
assert((freemapbuf[mapbyte] & mask) == 0);
|
||||
freemapbuf[mapbyte] |= mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the free block bitmap.
|
||||
*/
|
||||
static
|
||||
void
|
||||
initfreemap(uint32_t fsblocks)
|
||||
{
|
||||
uint32_t freemapbits = SFS_FREEMAPBITS(fsblocks);
|
||||
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
uint32_t i;
|
||||
static void initfreemap(uint32_t fsblocks) {
|
||||
uint32_t freemapbits = SFS_FREEMAPBITS(fsblocks);
|
||||
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
uint32_t i;
|
||||
|
||||
if (freemapblocks > MAXFREEMAPBLOCKS) {
|
||||
errx(1, "Filesystem too large -- "
|
||||
"increase MAXFREEMAPBLOCKS and recompile");
|
||||
}
|
||||
if (freemapblocks > MAXFREEMAPBLOCKS) {
|
||||
errx(1, "Filesystem too large -- "
|
||||
"increase MAXFREEMAPBLOCKS and recompile");
|
||||
}
|
||||
|
||||
/* mark the superblock and root inode in use */
|
||||
allocblock(SFS_SUPER_BLOCK);
|
||||
allocblock(SFS_ROOTDIR_INO);
|
||||
/* mark the superblock and root inode in use */
|
||||
allocblock(SFS_SUPER_BLOCK);
|
||||
allocblock(SFS_ROOTDIR_INO);
|
||||
|
||||
/* the freemap blocks must be in use */
|
||||
for (i=0; i<freemapblocks; i++) {
|
||||
allocblock(SFS_FREEMAP_START + i);
|
||||
}
|
||||
/* the freemap blocks must be in use */
|
||||
for (i = 0; i < freemapblocks; i++) {
|
||||
allocblock(SFS_FREEMAP_START + i);
|
||||
}
|
||||
|
||||
/* all blocks in the freemap but past the volume end are "in use" */
|
||||
for (i=fsblocks; i<freemapbits; i++) {
|
||||
allocblock(i);
|
||||
}
|
||||
/* all blocks in the freemap but past the volume end are "in use" */
|
||||
for (i = fsblocks; i < freemapbits; i++) {
|
||||
allocblock(i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize and write out the superblock.
|
||||
*/
|
||||
static
|
||||
void
|
||||
writesuper(const char *volname, uint32_t nblocks)
|
||||
{
|
||||
struct sfs_superblock sb;
|
||||
static void writesuper(const char *volname, uint32_t nblocks) {
|
||||
struct sfs_superblock sb;
|
||||
|
||||
/* The cast is required on some outdated host systems. */
|
||||
bzero((void *)&sb, sizeof(sb));
|
||||
/* The cast is required on some outdated host systems. */
|
||||
bzero((void *)&sb, sizeof(sb));
|
||||
|
||||
if (strlen(volname) >= SFS_VOLNAME_SIZE) {
|
||||
errx(1, "Volume name %s too long", volname);
|
||||
}
|
||||
if (strlen(volname) >= SFS_VOLNAME_SIZE) {
|
||||
errx(1, "Volume name %s too long", volname);
|
||||
}
|
||||
|
||||
/* Initialize the superblock structure */
|
||||
sb.sb_magic = SWAP32(SFS_MAGIC);
|
||||
sb.sb_nblocks = SWAP32(nblocks);
|
||||
strcpy(sb.sb_volname, volname);
|
||||
/* Initialize the superblock structure */
|
||||
sb.sb_magic = SWAP32(SFS_MAGIC);
|
||||
sb.sb_nblocks = SWAP32(nblocks);
|
||||
strcpy(sb.sb_volname, volname);
|
||||
|
||||
/* and write it out. */
|
||||
diskwrite(&sb, SFS_SUPER_BLOCK);
|
||||
/* and write it out. */
|
||||
diskwrite(&sb, SFS_SUPER_BLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the free block bitmap.
|
||||
*/
|
||||
static
|
||||
void
|
||||
writefreemap(uint32_t fsblocks)
|
||||
{
|
||||
uint32_t freemapblocks;
|
||||
char *ptr;
|
||||
uint32_t i;
|
||||
static void writefreemap(uint32_t fsblocks) {
|
||||
uint32_t freemapblocks;
|
||||
char *ptr;
|
||||
uint32_t i;
|
||||
|
||||
/* Write out each of the blocks in the free block bitmap. */
|
||||
freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
for (i=0; i<freemapblocks; i++) {
|
||||
ptr = freemapbuf + i*SFS_BLOCKSIZE;
|
||||
diskwrite(ptr, SFS_FREEMAP_START+i);
|
||||
}
|
||||
/* Write out each of the blocks in the free block bitmap. */
|
||||
freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
for (i = 0; i < freemapblocks; i++) {
|
||||
ptr = freemapbuf + i * SFS_BLOCKSIZE;
|
||||
diskwrite(ptr, SFS_FREEMAP_START + i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the root directory inode.
|
||||
*/
|
||||
static
|
||||
void
|
||||
writerootdir(void)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
static void writerootdir(void) {
|
||||
struct sfs_dinode sfi;
|
||||
|
||||
/* Initialize the dinode */
|
||||
bzero((void *)&sfi, sizeof(sfi));
|
||||
sfi.sfi_size = SWAP32(0);
|
||||
sfi.sfi_type = SWAP16(SFS_TYPE_DIR);
|
||||
sfi.sfi_linkcount = SWAP16(1);
|
||||
/* Initialize the dinode */
|
||||
bzero((void *)&sfi, sizeof(sfi));
|
||||
sfi.sfi_size = SWAP32(0);
|
||||
sfi.sfi_type = SWAP16(SFS_TYPE_DIR);
|
||||
sfi.sfi_linkcount = SWAP16(1);
|
||||
|
||||
/* Write it out */
|
||||
diskwrite(&sfi, SFS_ROOTDIR_INO);
|
||||
/* Write it out */
|
||||
diskwrite(&sfi, SFS_ROOTDIR_INO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
uint32_t size, blocksize;
|
||||
char *volname, *s;
|
||||
int main(int argc, char **argv) {
|
||||
uint32_t size, blocksize;
|
||||
char *volname, *s;
|
||||
|
||||
#ifdef HOST
|
||||
hostcompat_init(argc, argv);
|
||||
hostcompat_init(argc, argv);
|
||||
#endif
|
||||
|
||||
if (argc!=3) {
|
||||
errx(1, "Usage: mksfs device/diskfile volume-name");
|
||||
}
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: mksfs device/diskfile volume-name");
|
||||
}
|
||||
|
||||
check();
|
||||
check();
|
||||
|
||||
volname = argv[2];
|
||||
volname = argv[2];
|
||||
|
||||
/* Remove one trailing colon from volname, if present */
|
||||
s = strchr(volname, ':');
|
||||
if (s != NULL) {
|
||||
if (strlen(s)!=1) {
|
||||
errx(1, "Illegal volume name %s", volname);
|
||||
}
|
||||
*s = 0;
|
||||
}
|
||||
/* Remove one trailing colon from volname, if present */
|
||||
s = strchr(volname, ':');
|
||||
if (s != NULL) {
|
||||
if (strlen(s) != 1) {
|
||||
errx(1, "Illegal volume name %s", volname);
|
||||
}
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
/* Don't allow slashes */
|
||||
s = strchr(volname, '/');
|
||||
if (s != NULL) {
|
||||
errx(1, "Illegal volume name %s", volname);
|
||||
}
|
||||
/* Don't allow slashes */
|
||||
s = strchr(volname, '/');
|
||||
if (s != NULL) {
|
||||
errx(1, "Illegal volume name %s", volname);
|
||||
}
|
||||
|
||||
opendisk(argv[1]);
|
||||
blocksize = diskblocksize();
|
||||
opendisk(argv[1]);
|
||||
blocksize = diskblocksize();
|
||||
|
||||
if (blocksize!=SFS_BLOCKSIZE) {
|
||||
errx(1, "Device has wrong blocksize %u (should be %u)\n",
|
||||
blocksize, SFS_BLOCKSIZE);
|
||||
}
|
||||
size = diskblocks();
|
||||
if (blocksize != SFS_BLOCKSIZE) {
|
||||
errx(1, "Device has wrong blocksize %u (should be %u)\n", blocksize,
|
||||
SFS_BLOCKSIZE);
|
||||
}
|
||||
size = diskblocks();
|
||||
|
||||
/* Write out the on-disk structures */
|
||||
initfreemap(size);
|
||||
writesuper(volname, size);
|
||||
writefreemap(size);
|
||||
writerootdir();
|
||||
/* Write out the on-disk structures */
|
||||
initfreemap(size);
|
||||
writesuper(volname, size);
|
||||
writefreemap(size);
|
||||
writerootdir();
|
||||
|
||||
closedisk();
|
||||
closedisk();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __osf__
|
||||
/* Digital Unix (aka Compaq Tru64) */
|
||||
#define HAS_NO_SIZED_TYPES
|
||||
|
||||
@@ -36,9 +36,7 @@
|
||||
* Just calls reboot() with the RB_POWEROFF flag.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
reboot(RB_POWEROFF);
|
||||
return 0;
|
||||
int main(void) {
|
||||
reboot(RB_POWEROFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,7 @@
|
||||
* Just calls reboot() with the RB_REBOOT flag.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
reboot(RB_REBOOT);
|
||||
return 0;
|
||||
int main(void) {
|
||||
reboot(RB_REBOOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* for CHAR_BIT */
|
||||
#include <limits.h> /* also for CHAR_BIT */
|
||||
#include <sys/types.h> /* for CHAR_BIT */
|
||||
#include <limits.h> /* also for CHAR_BIT */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
@@ -52,69 +52,62 @@ static uint8_t *tofreedata;
|
||||
* called after the superblock is loaded so we can ask how big the
|
||||
* volume is.
|
||||
*/
|
||||
void
|
||||
freemap_setup(void)
|
||||
{
|
||||
size_t i, mapbytes;
|
||||
uint32_t fsblocks, mapblocks;
|
||||
void freemap_setup(void) {
|
||||
size_t i, mapbytes;
|
||||
uint32_t fsblocks, mapblocks;
|
||||
|
||||
fsblocks = sb_totalblocks();
|
||||
mapblocks = sb_freemapblocks();
|
||||
mapbytes = mapblocks * SFS_BLOCKSIZE;
|
||||
fsblocks = sb_totalblocks();
|
||||
mapblocks = sb_freemapblocks();
|
||||
mapbytes = mapblocks * SFS_BLOCKSIZE;
|
||||
|
||||
freemapdata = domalloc(mapbytes * sizeof(uint8_t));
|
||||
tofreedata = domalloc(mapbytes * sizeof(uint8_t));
|
||||
for (i=0; i<mapbytes; i++) {
|
||||
freemapdata[i] = tofreedata[i] = 0;
|
||||
}
|
||||
freemapdata = domalloc(mapbytes * sizeof(uint8_t));
|
||||
tofreedata = domalloc(mapbytes * sizeof(uint8_t));
|
||||
for (i = 0; i < mapbytes; i++) {
|
||||
freemapdata[i] = tofreedata[i] = 0;
|
||||
}
|
||||
|
||||
/* Mark off what's in the freemap but past the volume end. */
|
||||
for (i=fsblocks; i < mapblocks*SFS_BITSPERBLOCK; i++) {
|
||||
freemap_blockinuse(i, B_PASTEND, 0);
|
||||
}
|
||||
/* Mark off what's in the freemap but past the volume end. */
|
||||
for (i = fsblocks; i < mapblocks * SFS_BITSPERBLOCK; i++) {
|
||||
freemap_blockinuse(i, B_PASTEND, 0);
|
||||
}
|
||||
|
||||
/* Mark the superblock block and the freemap blocks in use */
|
||||
freemap_blockinuse(SFS_SUPER_BLOCK, B_SUPERBLOCK, 0);
|
||||
for (i=0; i < mapblocks; i++) {
|
||||
freemap_blockinuse(SFS_FREEMAP_START+i, B_FREEMAPBLOCK, i);
|
||||
}
|
||||
/* Mark the superblock block and the freemap blocks in use */
|
||||
freemap_blockinuse(SFS_SUPER_BLOCK, B_SUPERBLOCK, 0);
|
||||
for (i = 0; i < mapblocks; i++) {
|
||||
freemap_blockinuse(SFS_FREEMAP_START + i, B_FREEMAPBLOCK, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string for a blockusage; used for printing errors.
|
||||
*/
|
||||
static
|
||||
const char *
|
||||
blockusagestr(blockusage_t how, uint32_t howdesc)
|
||||
{
|
||||
static char rv[256];
|
||||
switch (how) {
|
||||
case B_SUPERBLOCK:
|
||||
return "superblock";
|
||||
case B_FREEMAPBLOCK:
|
||||
snprintf(rv, sizeof(rv), "freemap block %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_INODE:
|
||||
snprintf(rv, sizeof(rv), "inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_IBLOCK:
|
||||
snprintf(rv, sizeof(rv), "indirect block of inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_DIRDATA:
|
||||
snprintf(rv, sizeof(rv), "directory data from inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_DATA:
|
||||
snprintf(rv, sizeof(rv), "file data from inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_PASTEND:
|
||||
return "past the end of the fs";
|
||||
}
|
||||
return rv;
|
||||
static const char *blockusagestr(blockusage_t how, uint32_t howdesc) {
|
||||
static char rv[256];
|
||||
switch (how) {
|
||||
case B_SUPERBLOCK:
|
||||
return "superblock";
|
||||
case B_FREEMAPBLOCK:
|
||||
snprintf(rv, sizeof(rv), "freemap block %lu", (unsigned long)howdesc);
|
||||
break;
|
||||
case B_INODE:
|
||||
snprintf(rv, sizeof(rv), "inode %lu", (unsigned long)howdesc);
|
||||
break;
|
||||
case B_IBLOCK:
|
||||
snprintf(rv, sizeof(rv), "indirect block of inode %lu",
|
||||
(unsigned long)howdesc);
|
||||
break;
|
||||
case B_DIRDATA:
|
||||
snprintf(rv, sizeof(rv), "directory data from inode %lu",
|
||||
(unsigned long)howdesc);
|
||||
break;
|
||||
case B_DATA:
|
||||
snprintf(rv, sizeof(rv), "file data from inode %lu",
|
||||
(unsigned long)howdesc);
|
||||
break;
|
||||
case B_PASTEND:
|
||||
return "past the end of the fs";
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -123,28 +116,26 @@ blockusagestr(blockusage_t how, uint32_t howdesc)
|
||||
*
|
||||
* FUTURE: this should not produce unrecoverable errors.
|
||||
*/
|
||||
void
|
||||
freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc)
|
||||
{
|
||||
unsigned index = block/8;
|
||||
uint8_t mask = ((uint8_t)1)<<(block%8);
|
||||
void freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc) {
|
||||
unsigned index = block / 8;
|
||||
uint8_t mask = ((uint8_t)1) << (block % 8);
|
||||
|
||||
if (tofreedata[index] & mask) {
|
||||
/* really using the block, don't free it */
|
||||
tofreedata[index] &= ~mask;
|
||||
}
|
||||
if (tofreedata[index] & mask) {
|
||||
/* really using the block, don't free it */
|
||||
tofreedata[index] &= ~mask;
|
||||
}
|
||||
|
||||
if (freemapdata[index] & mask) {
|
||||
warnx("Block %lu (used as %s) already in use! (NOT FIXED)",
|
||||
(unsigned long) block, blockusagestr(how, howdesc));
|
||||
setbadness(EXIT_UNRECOV);
|
||||
}
|
||||
if (freemapdata[index] & mask) {
|
||||
warnx("Block %lu (used as %s) already in use! (NOT FIXED)",
|
||||
(unsigned long)block, blockusagestr(how, howdesc));
|
||||
setbadness(EXIT_UNRECOV);
|
||||
}
|
||||
|
||||
freemapdata[index] |= mask;
|
||||
freemapdata[index] |= mask;
|
||||
|
||||
if (how != B_PASTEND) {
|
||||
blocksinuse++;
|
||||
}
|
||||
if (how != B_PASTEND) {
|
||||
blocksinuse++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -158,37 +149,33 @@ freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc)
|
||||
* original usage to be something we are dropping, e.g. if a truncate
|
||||
* (to a nonzero length > INOMAX_D) got partially completed.
|
||||
*/
|
||||
void
|
||||
freemap_blockfree(uint32_t block)
|
||||
{
|
||||
unsigned index = block/8;
|
||||
uint8_t mask = ((uint8_t)1)<<(block%8);
|
||||
void freemap_blockfree(uint32_t block) {
|
||||
unsigned index = block / 8;
|
||||
uint8_t mask = ((uint8_t)1) << (block % 8);
|
||||
|
||||
if (tofreedata[index] & mask) {
|
||||
/* already marked to free once, ignore */
|
||||
return;
|
||||
}
|
||||
if (freemapdata[index] & mask) {
|
||||
/* block is used elsewhere, ignore */
|
||||
return;
|
||||
}
|
||||
tofreedata[index] |= mask;
|
||||
if (tofreedata[index] & mask) {
|
||||
/* already marked to free once, ignore */
|
||||
return;
|
||||
}
|
||||
if (freemapdata[index] & mask) {
|
||||
/* block is used elsewhere, ignore */
|
||||
return;
|
||||
}
|
||||
tofreedata[index] |= mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of bits set.
|
||||
*/
|
||||
static
|
||||
int
|
||||
countbits(uint8_t val)
|
||||
{
|
||||
uint8_t x;
|
||||
int ct=0;
|
||||
static int countbits(uint8_t val) {
|
||||
uint8_t x;
|
||||
int ct = 0;
|
||||
|
||||
for (x=1; x; x<<=1) {
|
||||
if (val & x) ct++;
|
||||
}
|
||||
return ct;
|
||||
for (x = 1; x; x <<= 1) {
|
||||
if (val & x)
|
||||
ct++;
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -198,21 +185,18 @@ countbits(uint8_t val)
|
||||
* byte offset within that block; VAL is the byte value; WHAT is a
|
||||
* string indicating what happened.
|
||||
*/
|
||||
static
|
||||
void
|
||||
reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val, const char *what)
|
||||
{
|
||||
uint8_t x, y;
|
||||
uint32_t blocknum;
|
||||
static void reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val,
|
||||
const char *what) {
|
||||
uint8_t x, y;
|
||||
uint32_t blocknum;
|
||||
|
||||
for (x=1, y=0; x; x<<=1, y++) {
|
||||
if (val & x) {
|
||||
blocknum = mapblock*SFS_BITSPERBLOCK +
|
||||
byte*CHAR_BIT + y;
|
||||
warnx("Block %lu erroneously shown %s in freemap",
|
||||
(unsigned long) blocknum, what);
|
||||
}
|
||||
}
|
||||
for (x = 1, y = 0; x; x <<= 1, y++) {
|
||||
if (val & x) {
|
||||
blocknum = mapblock * SFS_BITSPERBLOCK + byte * CHAR_BIT + y;
|
||||
warnx("Block %lu erroneously shown %s in freemap",
|
||||
(unsigned long)blocknum, what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -221,90 +205,84 @@ reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val, const char *what)
|
||||
* This is called after (at the end of) pass 1, when we've recursively
|
||||
* found all the reachable blocks and marked them.
|
||||
*/
|
||||
void
|
||||
freemap_check(void)
|
||||
{
|
||||
uint8_t actual[SFS_BLOCKSIZE], *expected, *tofree, tmp;
|
||||
uint32_t alloccount=0, freecount=0, i, j;
|
||||
int bchanged;
|
||||
uint32_t bitblocks;
|
||||
void freemap_check(void) {
|
||||
uint8_t actual[SFS_BLOCKSIZE], *expected, *tofree, tmp;
|
||||
uint32_t alloccount = 0, freecount = 0, i, j;
|
||||
int bchanged;
|
||||
uint32_t bitblocks;
|
||||
|
||||
bitblocks = sb_freemapblocks();
|
||||
bitblocks = sb_freemapblocks();
|
||||
|
||||
for (i=0; i<bitblocks; i++) {
|
||||
sfs_readfreemapblock(i, actual);
|
||||
expected = freemapdata + i*SFS_BLOCKSIZE;
|
||||
tofree = tofreedata + i*SFS_BLOCKSIZE;
|
||||
bchanged = 0;
|
||||
for (i = 0; i < bitblocks; i++) {
|
||||
sfs_readfreemapblock(i, actual);
|
||||
expected = freemapdata + i * SFS_BLOCKSIZE;
|
||||
tofree = tofreedata + i * SFS_BLOCKSIZE;
|
||||
bchanged = 0;
|
||||
|
||||
for (j=0; j<SFS_BLOCKSIZE; j++) {
|
||||
/* we shouldn't have blocks marked both ways */
|
||||
assert((expected[j] & tofree[j])==0);
|
||||
for (j = 0; j < SFS_BLOCKSIZE; j++) {
|
||||
/* we shouldn't have blocks marked both ways */
|
||||
assert((expected[j] & tofree[j]) == 0);
|
||||
|
||||
/* what's there is what should be there */
|
||||
if (actual[j] == expected[j]) {
|
||||
continue;
|
||||
}
|
||||
/* what's there is what should be there */
|
||||
if (actual[j] == expected[j]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* what's there is what should be there modulo frees */
|
||||
if (actual[j] == (expected[j] | tofree[j])) {
|
||||
actual[j] = expected[j];
|
||||
bchanged = 1;
|
||||
continue;
|
||||
}
|
||||
/* what's there is what should be there modulo frees */
|
||||
if (actual[j] == (expected[j] | tofree[j])) {
|
||||
actual[j] = expected[j];
|
||||
bchanged = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* oops, it doesn't match... */
|
||||
/* oops, it doesn't match... */
|
||||
|
||||
/* free the ones we're freeing (don't report these) */
|
||||
actual[j] &= ~tofree[j];
|
||||
/* free the ones we're freeing (don't report these) */
|
||||
actual[j] &= ~tofree[j];
|
||||
|
||||
/* are we short any? */
|
||||
if ((actual[j] & expected[j]) != expected[j]) {
|
||||
tmp = expected[j] & ~actual[j];
|
||||
alloccount += countbits(tmp);
|
||||
if (tmp != 0) {
|
||||
reportfreemap(i, j, tmp, "free");
|
||||
}
|
||||
}
|
||||
/* are we short any? */
|
||||
if ((actual[j] & expected[j]) != expected[j]) {
|
||||
tmp = expected[j] & ~actual[j];
|
||||
alloccount += countbits(tmp);
|
||||
if (tmp != 0) {
|
||||
reportfreemap(i, j, tmp, "free");
|
||||
}
|
||||
}
|
||||
|
||||
/* do we have any extra? */
|
||||
if ((actual[j] & expected[j]) != actual[j]) {
|
||||
tmp = actual[j] & ~expected[j];
|
||||
freecount += countbits(tmp);
|
||||
if (tmp != 0) {
|
||||
reportfreemap(i, j, tmp, "allocated");
|
||||
}
|
||||
}
|
||||
/* do we have any extra? */
|
||||
if ((actual[j] & expected[j]) != actual[j]) {
|
||||
tmp = actual[j] & ~expected[j];
|
||||
freecount += countbits(tmp);
|
||||
if (tmp != 0) {
|
||||
reportfreemap(i, j, tmp, "allocated");
|
||||
}
|
||||
}
|
||||
|
||||
/* set it to what it should be */
|
||||
actual[j] = expected[j];
|
||||
bchanged = 1;
|
||||
}
|
||||
/* set it to what it should be */
|
||||
actual[j] = expected[j];
|
||||
bchanged = 1;
|
||||
}
|
||||
|
||||
/* write the block back if necessary */
|
||||
if (bchanged) {
|
||||
sfs_writefreemapblock(i, actual);
|
||||
}
|
||||
}
|
||||
/* write the block back if necessary */
|
||||
if (bchanged) {
|
||||
sfs_writefreemapblock(i, actual);
|
||||
}
|
||||
}
|
||||
|
||||
if (alloccount > 0) {
|
||||
warnx("%lu blocks erroneously shown free in freemap (fixed)",
|
||||
(unsigned long) alloccount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
if (freecount > 0) {
|
||||
warnx("%lu blocks erroneously shown used in freemap (fixed)",
|
||||
(unsigned long) freecount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
if (alloccount > 0) {
|
||||
warnx("%lu blocks erroneously shown free in freemap (fixed)",
|
||||
(unsigned long)alloccount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
if (freecount > 0) {
|
||||
warnx("%lu blocks erroneously shown used in freemap (fixed)",
|
||||
(unsigned long)freecount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total number of blocks in use, which we count during
|
||||
* pass 1.
|
||||
*/
|
||||
unsigned long
|
||||
freemap_blocksused(void)
|
||||
{
|
||||
return blocksinuse;
|
||||
}
|
||||
unsigned long freemap_blocksused(void) { return blocksinuse; }
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
B_SUPERBLOCK, /* Block that is the superblock */
|
||||
B_FREEMAPBLOCK, /* Block used by free-block bitmap */
|
||||
B_INODE, /* Block that is an inode */
|
||||
B_IBLOCK, /* Indirect (or doubly-indirect etc.) block */
|
||||
B_DIRDATA, /* Data block of a directory */
|
||||
B_DATA, /* Data block */
|
||||
B_PASTEND, /* Block off the end of the fs */
|
||||
B_SUPERBLOCK, /* Block that is the superblock */
|
||||
B_FREEMAPBLOCK, /* Block used by free-block bitmap */
|
||||
B_INODE, /* Block that is an inode */
|
||||
B_IBLOCK, /* Indirect (or doubly-indirect etc.) block */
|
||||
B_DIRDATA, /* Data block of a directory */
|
||||
B_DATA, /* Data block */
|
||||
B_PASTEND, /* Block off the end of the fs */
|
||||
} blockusage_t;
|
||||
|
||||
/* Call this after loading the superblock but before doing any checks. */
|
||||
@@ -63,5 +63,4 @@ void freemap_check(void);
|
||||
/* Return the number of blocks in use. Valid after freemap_check(). */
|
||||
unsigned long freemap_blocksused(void);
|
||||
|
||||
|
||||
#endif /* FREEMAP_H */
|
||||
|
||||
@@ -80,80 +80,79 @@
|
||||
|
||||
/* numbers */
|
||||
|
||||
#define NUM_D SFS_NDIRECT
|
||||
#define NUM_I SFS_NINDIRECT
|
||||
#define NUM_II SFS_NDINDIRECT
|
||||
#define NUM_III SFS_NTINDIRECT
|
||||
#define NUM_D SFS_NDIRECT
|
||||
#define NUM_I SFS_NINDIRECT
|
||||
#define NUM_II SFS_NDINDIRECT
|
||||
#define NUM_III SFS_NTINDIRECT
|
||||
|
||||
/* blocks */
|
||||
|
||||
#if NUM_D == 0
|
||||
#define GET_D(sfi, i) GET0_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SET0_x(sfi, sfi_direct, i)
|
||||
#define GET_D(sfi, i) GET0_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SET0_x(sfi, sfi_direct, i)
|
||||
#elif NUM_D == 1
|
||||
#define GET_D(sfi, i) GET1_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SET1_x(sfi, sfi_direct, i)
|
||||
#define GET_D(sfi, i) GET1_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SET1_x(sfi, sfi_direct, i)
|
||||
#else
|
||||
#define GET_D(sfi, i) GETN_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SETN_x(sfi, sfi_direct, i)
|
||||
#define GET_D(sfi, i) GETN_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SETN_x(sfi, sfi_direct, i)
|
||||
#endif
|
||||
|
||||
#if NUM_I == 0
|
||||
#define GET_I(sfi, i) GET0_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SET0_x(sfi, sfi_indirect, i)
|
||||
#define GET_I(sfi, i) GET0_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SET0_x(sfi, sfi_indirect, i)
|
||||
#elif NUM_I == 1
|
||||
#define GET_I(sfi, i) GET1_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SET1_x(sfi, sfi_indirect, i)
|
||||
#define GET_I(sfi, i) GET1_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SET1_x(sfi, sfi_indirect, i)
|
||||
#else
|
||||
#define GET_I(sfi, i) GETN_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SETN_x(sfi, sfi_indirect, i)
|
||||
#define GET_I(sfi, i) GETN_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SETN_x(sfi, sfi_indirect, i)
|
||||
#endif
|
||||
|
||||
#if NUM_II == 0
|
||||
#define GET_II(sfi, i) GET0_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SET0_x(sfi, sfi_dindirect, i)
|
||||
#define GET_II(sfi, i) GET0_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SET0_x(sfi, sfi_dindirect, i)
|
||||
#elif NUM_II == 1
|
||||
#define GET_II(sfi, i) GET1_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SET1_x(sfi, sfi_dindirect, i)
|
||||
#define GET_II(sfi, i) GET1_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SET1_x(sfi, sfi_dindirect, i)
|
||||
#else
|
||||
#define GET_II(sfi, i) GETN_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SETN_x(sfi, sfi_dindirect, i)
|
||||
#define GET_II(sfi, i) GETN_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SETN_x(sfi, sfi_dindirect, i)
|
||||
#endif
|
||||
|
||||
#if NUM_III == 0
|
||||
#define GET_III(sfi, i) GET0_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SET0_x(sfi, sfi_tindirect, i)
|
||||
#define GET_III(sfi, i) GET0_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SET0_x(sfi, sfi_tindirect, i)
|
||||
#elif NUM_III == 1
|
||||
#define GET_III(sfi, i) GET1_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SET1_x(sfi, sfi_tindirect, i)
|
||||
#define GET_III(sfi, i) GET1_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SET1_x(sfi, sfi_tindirect, i)
|
||||
#else
|
||||
#define GET_III(sfi, i) GETN_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SETN_x(sfi, sfi_tindirect, i)
|
||||
#define GET_III(sfi, i) GETN_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SETN_x(sfi, sfi_tindirect, i)
|
||||
#endif
|
||||
|
||||
/* the generic forms of the block macros */
|
||||
|
||||
#define GET0_x(sfi, field, i) ((void)(i), (void)(sfi), 0)
|
||||
#define GET1_x(sfi, field, i) ((void)(i), (sfi)->field)
|
||||
#define GETN_x(sfi, field, i) ((sfi)->field[(i)])
|
||||
#define GET0_x(sfi, field, i) ((void)(i), (void)(sfi), 0)
|
||||
#define GET1_x(sfi, field, i) ((void)(i), (sfi)->field)
|
||||
#define GETN_x(sfi, field, i) ((sfi)->field[(i)])
|
||||
|
||||
#define SET0_x(sfi, field, i) (*((void)(i), (void)(sfi), (uint32_t *)NULL))
|
||||
#define SET1_x(sfi, field, i) (*((void)(i), &(sfi)->field))
|
||||
#define SETN_x(sfi, field, i) ((sfi)->field[(i)])
|
||||
#define SET0_x(sfi, field, i) (*((void)(i), (void)(sfi), (uint32_t *)NULL))
|
||||
#define SET1_x(sfi, field, i) (*((void)(i), &(sfi)->field))
|
||||
#define SETN_x(sfi, field, i) ((sfi)->field[(i)])
|
||||
|
||||
/* region sizes */
|
||||
|
||||
#define RANGE_D 1
|
||||
#define RANGE_I (RANGE_D * SFS_DBPERIDB)
|
||||
#define RANGE_II (RANGE_I * SFS_DBPERIDB)
|
||||
#define RANGE_III (RANGE_II * SFS_DBPERIDB)
|
||||
#define RANGE_D 1
|
||||
#define RANGE_I (RANGE_D * SFS_DBPERIDB)
|
||||
#define RANGE_II (RANGE_I * SFS_DBPERIDB)
|
||||
#define RANGE_III (RANGE_II * SFS_DBPERIDB)
|
||||
|
||||
/* max blocks */
|
||||
|
||||
#define INOMAX_D NUM_D
|
||||
#define INOMAX_I (INOMAX_D + SFS_DBPERIDB * NUM_I)
|
||||
#define INOMAX_II (INOMAX_I + SFS_DBPERIDB * NUM_II)
|
||||
#define INOMAX_III (INOMAX_II + SFS_DBPERIDB * NUM_III)
|
||||
|
||||
#define INOMAX_D NUM_D
|
||||
#define INOMAX_I (INOMAX_D + SFS_DBPERIDB * NUM_I)
|
||||
#define INOMAX_II (INOMAX_I + SFS_DBPERIDB * NUM_II)
|
||||
#define INOMAX_III (INOMAX_II + SFS_DBPERIDB * NUM_III)
|
||||
|
||||
#endif /* IBMACROS_H */
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
* FUTURE: should count the number of blocks allocated to this inode
|
||||
*/
|
||||
struct inodeinfo {
|
||||
uint32_t ino;
|
||||
uint32_t linkcount; /* files only */
|
||||
int visited; /* dirs only */
|
||||
int type;
|
||||
uint32_t ino;
|
||||
uint32_t linkcount; /* files only */
|
||||
int visited; /* dirs only */
|
||||
int type;
|
||||
};
|
||||
|
||||
/* Table of inodes found. */
|
||||
@@ -66,61 +66,53 @@ static int inodes_sorted = 0;
|
||||
/*
|
||||
* Add an entry to the inode table, realloc'ing it if needed.
|
||||
*/
|
||||
static
|
||||
void
|
||||
inode_addtable(uint32_t ino, int type)
|
||||
{
|
||||
unsigned newmax;
|
||||
static void inode_addtable(uint32_t ino, int type) {
|
||||
unsigned newmax;
|
||||
|
||||
assert(ninodes <= maxinodes);
|
||||
if (ninodes == maxinodes) {
|
||||
newmax = maxinodes ? maxinodes * 2 : 4;
|
||||
inodes = dorealloc(inodes, maxinodes * sizeof(inodes[0]),
|
||||
newmax * sizeof(inodes[0]));
|
||||
maxinodes = newmax;
|
||||
}
|
||||
inodes[ninodes].ino = ino;
|
||||
inodes[ninodes].linkcount = 0;
|
||||
inodes[ninodes].visited = 0;
|
||||
inodes[ninodes].type = type;
|
||||
ninodes++;
|
||||
inodes_sorted = 0;
|
||||
assert(ninodes <= maxinodes);
|
||||
if (ninodes == maxinodes) {
|
||||
newmax = maxinodes ? maxinodes * 2 : 4;
|
||||
inodes = dorealloc(inodes, maxinodes * sizeof(inodes[0]),
|
||||
newmax * sizeof(inodes[0]));
|
||||
maxinodes = newmax;
|
||||
}
|
||||
inodes[ninodes].ino = ino;
|
||||
inodes[ninodes].linkcount = 0;
|
||||
inodes[ninodes].visited = 0;
|
||||
inodes[ninodes].type = type;
|
||||
ninodes++;
|
||||
inodes_sorted = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare function for inodes.
|
||||
*/
|
||||
static
|
||||
int
|
||||
inode_compare(const void *av, const void *bv)
|
||||
{
|
||||
const struct inodeinfo *a = av;
|
||||
const struct inodeinfo *b = bv;
|
||||
static int inode_compare(const void *av, const void *bv) {
|
||||
const struct inodeinfo *a = av;
|
||||
const struct inodeinfo *b = bv;
|
||||
|
||||
if (a->ino < b->ino) {
|
||||
return -1;
|
||||
}
|
||||
if (a->ino > b->ino) {
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* There should be no duplicates in the table! But C99 makes
|
||||
* no guarantees about whether the implementation of qsort can
|
||||
* ask us to compare an element to itself. Assert that this is
|
||||
* what happened.
|
||||
*/
|
||||
assert(av == bv);
|
||||
return 0;
|
||||
if (a->ino < b->ino) {
|
||||
return -1;
|
||||
}
|
||||
if (a->ino > b->ino) {
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* There should be no duplicates in the table! But C99 makes
|
||||
* no guarantees about whether the implementation of qsort can
|
||||
* ask us to compare an element to itself. Assert that this is
|
||||
* what happened.
|
||||
*/
|
||||
assert(av == bv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* After pass1, we sort the inode table for faster access.
|
||||
*/
|
||||
void
|
||||
inode_sorttable(void)
|
||||
{
|
||||
qsort(inodes, ninodes, sizeof(inodes[0]), inode_compare);
|
||||
inodes_sorted = 1;
|
||||
void inode_sorttable(void) {
|
||||
qsort(inodes, ninodes, sizeof(inodes[0]), inode_compare);
|
||||
inodes_sorted = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -132,35 +124,30 @@ inode_sorttable(void)
|
||||
* pass2.c, we'll need to be able to ask if an inode number is valid
|
||||
* and names a directory.)
|
||||
*/
|
||||
static
|
||||
struct inodeinfo *
|
||||
inode_find(uint32_t ino)
|
||||
{
|
||||
unsigned min, max, i;
|
||||
static struct inodeinfo *inode_find(uint32_t ino) {
|
||||
unsigned min, max, i;
|
||||
|
||||
assert(inodes_sorted);
|
||||
assert(ninodes > 0);
|
||||
assert(inodes_sorted);
|
||||
assert(ninodes > 0);
|
||||
|
||||
min = 0;
|
||||
max = ninodes;
|
||||
while (1) {
|
||||
assert(min <= max);
|
||||
if (min == max) {
|
||||
errx(EXIT_UNRECOV, "FATAL: inode %u wasn't found in my inode table", ino);
|
||||
}
|
||||
i = min + (max - min)/2;
|
||||
if (inodes[i].ino < ino) {
|
||||
min = i + 1;
|
||||
}
|
||||
else if (inodes[i].ino > ino) {
|
||||
max = i;
|
||||
}
|
||||
else {
|
||||
assert(inodes[i].ino == ino);
|
||||
return &inodes[i];
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
min = 0;
|
||||
max = ninodes;
|
||||
while (1) {
|
||||
assert(min <= max);
|
||||
if (min == max) {
|
||||
errx(EXIT_UNRECOV, "FATAL: inode %u wasn't found in my inode table", ino);
|
||||
}
|
||||
i = min + (max - min) / 2;
|
||||
if (inodes[i].ino < ino) {
|
||||
min = i + 1;
|
||||
} else if (inodes[i].ino > ino) {
|
||||
max = i;
|
||||
} else {
|
||||
assert(inodes[i].ino == ino);
|
||||
return &inodes[i];
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -173,22 +160,20 @@ inode_find(uint32_t ino)
|
||||
* after all inodes have been added. In the FUTURE this could be
|
||||
* changed to a better data structure.
|
||||
*/
|
||||
int
|
||||
inode_add(uint32_t ino, int type)
|
||||
{
|
||||
unsigned i;
|
||||
int inode_add(uint32_t ino, int type) {
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<ninodes; i++) {
|
||||
if (inodes[i].ino==ino) {
|
||||
assert(inodes[i].linkcount == 0);
|
||||
assert(inodes[i].type == type);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ninodes; i++) {
|
||||
if (inodes[i].ino == ino) {
|
||||
assert(inodes[i].linkcount == 0);
|
||||
assert(inodes[i].type == type);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inode_addtable(ino, type);
|
||||
inode_addtable(ino, type);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -198,19 +183,17 @@ inode_add(uint32_t ino, int type)
|
||||
* Note that there is no way to clear the visited flag for now because
|
||||
* it's only used once (by pass2).
|
||||
*/
|
||||
int
|
||||
inode_visitdir(uint32_t ino)
|
||||
{
|
||||
struct inodeinfo *inf;
|
||||
int inode_visitdir(uint32_t ino) {
|
||||
struct inodeinfo *inf;
|
||||
|
||||
inf = inode_find(ino);
|
||||
assert(inf->type == SFS_TYPE_DIR);
|
||||
assert(inf->linkcount == 0);
|
||||
if (inf->visited) {
|
||||
return 1;
|
||||
}
|
||||
inf->visited = 1;
|
||||
return 0;
|
||||
inf = inode_find(ino);
|
||||
assert(inf->type == SFS_TYPE_DIR);
|
||||
assert(inf->linkcount == 0);
|
||||
if (inf->visited) {
|
||||
return 1;
|
||||
}
|
||||
inf->visited = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -218,49 +201,43 @@ inode_visitdir(uint32_t ino)
|
||||
* does. (And that, in turn, is because the link count of a directory
|
||||
* is a local property.)
|
||||
*/
|
||||
void
|
||||
inode_addlink(uint32_t ino)
|
||||
{
|
||||
struct inodeinfo *inf;
|
||||
void inode_addlink(uint32_t ino) {
|
||||
struct inodeinfo *inf;
|
||||
|
||||
inf = inode_find(ino);
|
||||
assert(inf->type == SFS_TYPE_FILE);
|
||||
assert(inf->visited == 0);
|
||||
inf->linkcount++;
|
||||
inf = inode_find(ino);
|
||||
assert(inf->type == SFS_TYPE_FILE);
|
||||
assert(inf->visited == 0);
|
||||
inf->linkcount++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Correct link counts. This is effectively pass3. (FUTURE: change the
|
||||
* name accordingly.)
|
||||
*/
|
||||
void
|
||||
inode_adjust_filelinks(void)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
unsigned i;
|
||||
void inode_adjust_filelinks(void) {
|
||||
struct sfs_dinode sfi;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<ninodes; i++) {
|
||||
if (inodes[i].type == SFS_TYPE_DIR) {
|
||||
/* directory */
|
||||
continue;
|
||||
}
|
||||
assert(inodes[i].type == SFS_TYPE_FILE);
|
||||
for (i = 0; i < ninodes; i++) {
|
||||
if (inodes[i].type == SFS_TYPE_DIR) {
|
||||
/* directory */
|
||||
continue;
|
||||
}
|
||||
assert(inodes[i].type == SFS_TYPE_FILE);
|
||||
|
||||
/* because we've seen it, there must be at least one link */
|
||||
assert(inodes[i].linkcount > 0);
|
||||
/* because we've seen it, there must be at least one link */
|
||||
assert(inodes[i].linkcount > 0);
|
||||
|
||||
sfs_readinode(inodes[i].ino, &sfi);
|
||||
assert(sfi.sfi_type == SFS_TYPE_FILE);
|
||||
sfs_readinode(inodes[i].ino, &sfi);
|
||||
assert(sfi.sfi_type == SFS_TYPE_FILE);
|
||||
|
||||
if (sfi.sfi_linkcount != inodes[i].linkcount) {
|
||||
warnx("File %lu link count %lu should be %lu (fixed)",
|
||||
(unsigned long) inodes[i].ino,
|
||||
(unsigned long) sfi.sfi_linkcount,
|
||||
(unsigned long) inodes[i].linkcount);
|
||||
sfi.sfi_linkcount = inodes[i].linkcount;
|
||||
setbadness(EXIT_RECOV);
|
||||
sfs_writeinode(inodes[i].ino, &sfi);
|
||||
}
|
||||
}
|
||||
if (sfi.sfi_linkcount != inodes[i].linkcount) {
|
||||
warnx("File %lu link count %lu should be %lu (fixed)",
|
||||
(unsigned long)inodes[i].ino, (unsigned long)sfi.sfi_linkcount,
|
||||
(unsigned long)inodes[i].linkcount);
|
||||
sfi.sfi_linkcount = inodes[i].linkcount;
|
||||
setbadness(EXIT_RECOV);
|
||||
sfs_writeinode(inodes[i].ino, &sfi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,5 +61,4 @@ void inode_addlink(uint32_t ino);
|
||||
*/
|
||||
void inode_adjust_filelinks(void);
|
||||
|
||||
|
||||
#endif /* INODE_H */
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "passes.h"
|
||||
#include "main.h"
|
||||
|
||||
static int badness=0;
|
||||
static int badness = 0;
|
||||
|
||||
/*
|
||||
* Update the badness state. (codes are in main.h)
|
||||
@@ -50,69 +50,65 @@ static int badness=0;
|
||||
* The badness state only gets worse, and is ultimately the process
|
||||
* exit code.
|
||||
*/
|
||||
void
|
||||
setbadness(int code)
|
||||
{
|
||||
if (badness < code) {
|
||||
badness = code;
|
||||
}
|
||||
void setbadness(int code) {
|
||||
if (badness < code) {
|
||||
badness = code;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
#ifdef HOST
|
||||
hostcompat_init(argc, argv);
|
||||
hostcompat_init(argc, argv);
|
||||
#endif
|
||||
|
||||
/* FUTURE: add -n option */
|
||||
if (argc!=2) {
|
||||
errx(EXIT_USAGE, "Usage: sfsck device/diskfile");
|
||||
}
|
||||
/* FUTURE: add -n option */
|
||||
if (argc != 2) {
|
||||
errx(EXIT_USAGE, "Usage: sfsck device/diskfile");
|
||||
}
|
||||
|
||||
opendisk(argv[1]);
|
||||
opendisk(argv[1]);
|
||||
|
||||
sfs_setup();
|
||||
sb_load();
|
||||
sb_check();
|
||||
freemap_setup();
|
||||
sfs_setup();
|
||||
sb_load();
|
||||
sb_check();
|
||||
freemap_setup();
|
||||
|
||||
printf("Phase 1 -- check blocks and sizes\n");
|
||||
pass1();
|
||||
freemap_check();
|
||||
printf("Phase 1 -- check blocks and sizes\n");
|
||||
pass1();
|
||||
freemap_check();
|
||||
|
||||
printf("Phase 2 -- check directory tree\n");
|
||||
inode_sorttable();
|
||||
pass2();
|
||||
printf("Phase 2 -- check directory tree\n");
|
||||
inode_sorttable();
|
||||
pass2();
|
||||
|
||||
printf("Phase 3 -- check reference counts\n");
|
||||
inode_adjust_filelinks();
|
||||
printf("Phase 3 -- check reference counts\n");
|
||||
inode_adjust_filelinks();
|
||||
|
||||
closedisk();
|
||||
closedisk();
|
||||
|
||||
warnx("%lu blocks used (of %lu); %lu directories; %lu files",
|
||||
freemap_blocksused(), (unsigned long)sb_totalblocks(),
|
||||
pass1_founddirs(), pass1_foundfiles());
|
||||
warnx("%lu blocks used (of %lu); %lu directories; %lu files",
|
||||
freemap_blocksused(), (unsigned long)sb_totalblocks(),
|
||||
pass1_founddirs(), pass1_foundfiles());
|
||||
|
||||
switch (badness) {
|
||||
case EXIT_USAGE:
|
||||
case EXIT_FATAL:
|
||||
default:
|
||||
/* not supposed to happen here */
|
||||
assert(0);
|
||||
break;
|
||||
case EXIT_UNRECOV:
|
||||
warnx("WARNING - unrecoverable errors. Maybe try again?");
|
||||
break;
|
||||
case EXIT_RECOV:
|
||||
warnx("Caution - filesystem modified. Run again for luck.");
|
||||
break;
|
||||
case EXIT_CLEAN:
|
||||
break;
|
||||
}
|
||||
switch (badness) {
|
||||
case EXIT_USAGE:
|
||||
case EXIT_FATAL:
|
||||
default:
|
||||
/* not supposed to happen here */
|
||||
assert(0);
|
||||
break;
|
||||
case EXIT_UNRECOV:
|
||||
warnx("WARNING - unrecoverable errors. Maybe try again?");
|
||||
break;
|
||||
case EXIT_RECOV:
|
||||
warnx("Caution - filesystem modified. Run again for luck.");
|
||||
break;
|
||||
case EXIT_CLEAN:
|
||||
break;
|
||||
}
|
||||
|
||||
return badness;
|
||||
return badness;
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
* the ultimate exit code of sfsck.
|
||||
*/
|
||||
|
||||
#define EXIT_USAGE 4
|
||||
#define EXIT_FATAL 3
|
||||
#define EXIT_UNRECOV 2
|
||||
#define EXIT_RECOV 1
|
||||
#define EXIT_CLEAN 0
|
||||
#define EXIT_USAGE 4
|
||||
#define EXIT_FATAL 3
|
||||
#define EXIT_UNRECOV 2
|
||||
#define EXIT_RECOV 1
|
||||
#define EXIT_CLEAN 0
|
||||
|
||||
void setbadness(int code);
|
||||
|
||||
|
||||
@@ -47,18 +47,18 @@
|
||||
#include "passes.h"
|
||||
#include "main.h"
|
||||
|
||||
static unsigned long count_dirs=0, count_files=0;
|
||||
static unsigned long count_dirs = 0, count_files = 0;
|
||||
|
||||
/*
|
||||
* State for checking indirect blocks.
|
||||
*/
|
||||
struct ibstate {
|
||||
uint32_t ino; /* inode we're doing (constant) */
|
||||
uint32_t curfileblock; /* current block offset in the file */
|
||||
uint32_t fileblocks; /* file size in blocks (constant) */
|
||||
uint32_t volblocks; /* volume size in blocks (constant) */
|
||||
unsigned pasteofcount; /* number of blocks found past eof */
|
||||
blockusage_t usagetype; /* how to call freemap_blockinuse() */
|
||||
uint32_t ino; /* inode we're doing (constant) */
|
||||
uint32_t curfileblock; /* current block offset in the file */
|
||||
uint32_t fileblocks; /* file size in blocks (constant) */
|
||||
uint32_t volblocks; /* volume size in blocks (constant) */
|
||||
unsigned pasteofcount; /* number of blocks found past eof */
|
||||
blockusage_t usagetype; /* how to call freemap_blockinuse() */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -76,100 +76,88 @@ struct ibstate {
|
||||
* scanning. IECHANGEDP should be set to 1 if *IENTRY is changed.
|
||||
* INDIRECTION is the indirection level of this block (1, 2, or 3).
|
||||
*/
|
||||
static
|
||||
void
|
||||
check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
|
||||
int indirection)
|
||||
{
|
||||
uint32_t entries[SFS_DBPERIDB];
|
||||
uint32_t i, ct;
|
||||
uint32_t coveredblocks;
|
||||
int localchanged = 0;
|
||||
int j;
|
||||
static void check_indirect_block(struct ibstate *ibs, uint32_t *ientry,
|
||||
int *iechangedp, int indirection) {
|
||||
uint32_t entries[SFS_DBPERIDB];
|
||||
uint32_t i, ct;
|
||||
uint32_t coveredblocks;
|
||||
int localchanged = 0;
|
||||
int j;
|
||||
|
||||
if (*ientry > 0 && *ientry < ibs->volblocks) {
|
||||
sfs_readindirect(*ientry, entries);
|
||||
freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
|
||||
}
|
||||
else {
|
||||
if (*ientry >= ibs->volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: indirect block pointer (level %d) "
|
||||
"for block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs->ino, indirection,
|
||||
(unsigned long)ibs->curfileblock,
|
||||
(unsigned long)*ientry);
|
||||
*ientry = 0;
|
||||
*iechangedp = 1;
|
||||
}
|
||||
coveredblocks = 1;
|
||||
for (j=0; j<indirection; j++) {
|
||||
coveredblocks *= SFS_DBPERIDB;
|
||||
}
|
||||
ibs->curfileblock += coveredblocks;
|
||||
return;
|
||||
}
|
||||
if (*ientry > 0 && *ientry < ibs->volblocks) {
|
||||
sfs_readindirect(*ientry, entries);
|
||||
freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
|
||||
} else {
|
||||
if (*ientry >= ibs->volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: indirect block pointer (level %d) "
|
||||
"for block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs->ino, indirection,
|
||||
(unsigned long)ibs->curfileblock, (unsigned long)*ientry);
|
||||
*ientry = 0;
|
||||
*iechangedp = 1;
|
||||
}
|
||||
coveredblocks = 1;
|
||||
for (j = 0; j < indirection; j++) {
|
||||
coveredblocks *= SFS_DBPERIDB;
|
||||
}
|
||||
ibs->curfileblock += coveredblocks;
|
||||
return;
|
||||
}
|
||||
|
||||
if (indirection > 1) {
|
||||
for (i=0; i<SFS_DBPERIDB; i++) {
|
||||
check_indirect_block(ibs, &entries[i], &localchanged,
|
||||
indirection-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(indirection==1);
|
||||
if (indirection > 1) {
|
||||
for (i = 0; i < SFS_DBPERIDB; i++) {
|
||||
check_indirect_block(ibs, &entries[i], &localchanged, indirection - 1);
|
||||
}
|
||||
} else {
|
||||
assert(indirection == 1);
|
||||
|
||||
for (i=0; i<SFS_DBPERIDB; i++) {
|
||||
if (entries[i] >= ibs->volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: direct block pointer for "
|
||||
"block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs->ino,
|
||||
(unsigned long)ibs->curfileblock,
|
||||
(unsigned long)entries[i]);
|
||||
entries[i] = 0;
|
||||
localchanged = 1;
|
||||
}
|
||||
else if (entries[i] != 0) {
|
||||
if (ibs->curfileblock < ibs->fileblocks) {
|
||||
freemap_blockinuse(entries[i],
|
||||
ibs->usagetype,
|
||||
ibs->ino);
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_RECOV);
|
||||
ibs->pasteofcount++;
|
||||
freemap_blockfree(entries[i]);
|
||||
entries[i] = 0;
|
||||
localchanged = 1;
|
||||
}
|
||||
}
|
||||
ibs->curfileblock++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < SFS_DBPERIDB; i++) {
|
||||
if (entries[i] >= ibs->volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: direct block pointer for "
|
||||
"block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs->ino, (unsigned long)ibs->curfileblock,
|
||||
(unsigned long)entries[i]);
|
||||
entries[i] = 0;
|
||||
localchanged = 1;
|
||||
} else if (entries[i] != 0) {
|
||||
if (ibs->curfileblock < ibs->fileblocks) {
|
||||
freemap_blockinuse(entries[i], ibs->usagetype, ibs->ino);
|
||||
} else {
|
||||
setbadness(EXIT_RECOV);
|
||||
ibs->pasteofcount++;
|
||||
freemap_blockfree(entries[i]);
|
||||
entries[i] = 0;
|
||||
localchanged = 1;
|
||||
}
|
||||
}
|
||||
ibs->curfileblock++;
|
||||
}
|
||||
}
|
||||
|
||||
ct=0;
|
||||
for (i=ct=0; i<SFS_DBPERIDB; i++) {
|
||||
if (entries[i]!=0) ct++;
|
||||
}
|
||||
if (ct==0) {
|
||||
if (*ientry != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
/* this is not necessarily correct */
|
||||
/*ibs->pasteofcount++;*/
|
||||
*iechangedp = 1;
|
||||
freemap_blockfree(*ientry);
|
||||
*ientry = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(*ientry != 0);
|
||||
if (localchanged) {
|
||||
sfs_writeindirect(*ientry, entries);
|
||||
}
|
||||
}
|
||||
ct = 0;
|
||||
for (i = ct = 0; i < SFS_DBPERIDB; i++) {
|
||||
if (entries[i] != 0)
|
||||
ct++;
|
||||
}
|
||||
if (ct == 0) {
|
||||
if (*ientry != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
/* this is not necessarily correct */
|
||||
/*ibs->pasteofcount++;*/
|
||||
*iechangedp = 1;
|
||||
freemap_blockfree(*ientry);
|
||||
*ientry = 0;
|
||||
}
|
||||
} else {
|
||||
assert(*ientry != 0);
|
||||
if (localchanged) {
|
||||
sfs_writeindirect(*ientry, entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -180,71 +168,64 @@ check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
|
||||
* Returns nonzero if SFI has been modified and needs to be written
|
||||
* back.
|
||||
*/
|
||||
static
|
||||
int
|
||||
check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
|
||||
{
|
||||
struct ibstate ibs;
|
||||
uint32_t size, datablock;
|
||||
int changed;
|
||||
int i;
|
||||
static int check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir) {
|
||||
struct ibstate ibs;
|
||||
uint32_t size, datablock;
|
||||
int changed;
|
||||
int i;
|
||||
|
||||
size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
|
||||
size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
|
||||
|
||||
ibs.ino = ino;
|
||||
/*ibs.curfileblock = 0;*/
|
||||
ibs.fileblocks = size/SFS_BLOCKSIZE;
|
||||
ibs.volblocks = sb_totalblocks();
|
||||
ibs.pasteofcount = 0;
|
||||
ibs.usagetype = isdir ? B_DIRDATA : B_DATA;
|
||||
ibs.ino = ino;
|
||||
/*ibs.curfileblock = 0;*/
|
||||
ibs.fileblocks = size / SFS_BLOCKSIZE;
|
||||
ibs.volblocks = sb_totalblocks();
|
||||
ibs.pasteofcount = 0;
|
||||
ibs.usagetype = isdir ? B_DIRDATA : B_DATA;
|
||||
|
||||
changed = 0;
|
||||
changed = 0;
|
||||
|
||||
for (ibs.curfileblock=0; ibs.curfileblock<NUM_D; ibs.curfileblock++) {
|
||||
datablock = GET_D(sfi, ibs.curfileblock);
|
||||
if (datablock >= ibs.volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: direct block pointer for "
|
||||
"block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs.ino,
|
||||
(unsigned long)ibs.curfileblock,
|
||||
(unsigned long)datablock);
|
||||
SET_D(sfi, ibs.curfileblock) = 0;
|
||||
changed = 1;
|
||||
}
|
||||
else if (datablock > 0) {
|
||||
if (ibs.curfileblock < ibs.fileblocks) {
|
||||
freemap_blockinuse(datablock, ibs.usagetype,
|
||||
ibs.ino);
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_RECOV);
|
||||
ibs.pasteofcount++;
|
||||
changed = 1;
|
||||
freemap_blockfree(datablock);
|
||||
SET_D(sfi, ibs.curfileblock) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ibs.curfileblock = 0; ibs.curfileblock < NUM_D; ibs.curfileblock++) {
|
||||
datablock = GET_D(sfi, ibs.curfileblock);
|
||||
if (datablock >= ibs.volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: direct block pointer for "
|
||||
"block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs.ino, (unsigned long)ibs.curfileblock,
|
||||
(unsigned long)datablock);
|
||||
SET_D(sfi, ibs.curfileblock) = 0;
|
||||
changed = 1;
|
||||
} else if (datablock > 0) {
|
||||
if (ibs.curfileblock < ibs.fileblocks) {
|
||||
freemap_blockinuse(datablock, ibs.usagetype, ibs.ino);
|
||||
} else {
|
||||
setbadness(EXIT_RECOV);
|
||||
ibs.pasteofcount++;
|
||||
changed = 1;
|
||||
freemap_blockfree(datablock);
|
||||
SET_D(sfi, ibs.curfileblock) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_I; i++) {
|
||||
check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
|
||||
}
|
||||
for (i=0; i<NUM_II; i++) {
|
||||
check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
|
||||
}
|
||||
for (i=0; i<NUM_III; i++) {
|
||||
check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
|
||||
}
|
||||
for (i = 0; i < NUM_I; i++) {
|
||||
check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
|
||||
}
|
||||
for (i = 0; i < NUM_II; i++) {
|
||||
check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
|
||||
}
|
||||
for (i = 0; i < NUM_III; i++) {
|
||||
check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
|
||||
}
|
||||
|
||||
if (ibs.pasteofcount > 0) {
|
||||
warnx("Inode %lu: %u blocks after EOF (freed)",
|
||||
(unsigned long) ibs.ino, ibs.pasteofcount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
if (ibs.pasteofcount > 0) {
|
||||
warnx("Inode %lu: %u blocks after EOF (freed)", (unsigned long)ibs.ino,
|
||||
ibs.pasteofcount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
|
||||
return changed;
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -255,99 +236,90 @@ check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
|
||||
* Returns nonzero if SFI has been modified and needs to be written
|
||||
* back.
|
||||
*/
|
||||
static
|
||||
int
|
||||
pass1_inode(uint32_t ino, struct sfs_dinode *sfi, int alreadychanged)
|
||||
{
|
||||
int changed = alreadychanged;
|
||||
int isdir = sfi->sfi_type == SFS_TYPE_DIR;
|
||||
static int pass1_inode(uint32_t ino, struct sfs_dinode *sfi,
|
||||
int alreadychanged) {
|
||||
int changed = alreadychanged;
|
||||
int isdir = sfi->sfi_type == SFS_TYPE_DIR;
|
||||
|
||||
if (inode_add(ino, sfi->sfi_type)) {
|
||||
/* Already been here. */
|
||||
assert(changed == 0);
|
||||
return 1;
|
||||
}
|
||||
if (inode_add(ino, sfi->sfi_type)) {
|
||||
/* Already been here. */
|
||||
assert(changed == 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
freemap_blockinuse(ino, B_INODE, ino);
|
||||
freemap_blockinuse(ino, B_INODE, ino);
|
||||
|
||||
if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) {
|
||||
warnx("Inode %lu: sfi_waste section not zeroed (fixed)",
|
||||
(unsigned long) ino);
|
||||
setbadness(EXIT_RECOV);
|
||||
changed = 1;
|
||||
}
|
||||
if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) {
|
||||
warnx("Inode %lu: sfi_waste section not zeroed (fixed)",
|
||||
(unsigned long)ino);
|
||||
setbadness(EXIT_RECOV);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (check_inode_blocks(ino, sfi, isdir)) {
|
||||
changed = 1;
|
||||
}
|
||||
if (check_inode_blocks(ino, sfi, isdir)) {
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
sfs_writeinode(ino, sfi);
|
||||
}
|
||||
return 0;
|
||||
if (changed) {
|
||||
sfs_writeinode(ino, sfi);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the directory entry in SFD. INDEX is its offset, and PATH is
|
||||
* its name; these are used for printing messages.
|
||||
*/
|
||||
static
|
||||
int
|
||||
pass1_direntry(const char *path, uint32_t index, struct sfs_direntry *sfd)
|
||||
{
|
||||
int dchanged = 0;
|
||||
uint32_t nblocks;
|
||||
static int pass1_direntry(const char *path, uint32_t index,
|
||||
struct sfs_direntry *sfd) {
|
||||
int dchanged = 0;
|
||||
uint32_t nblocks;
|
||||
|
||||
nblocks = sb_totalblocks();
|
||||
nblocks = sb_totalblocks();
|
||||
|
||||
if (sfd->sfd_ino == SFS_NOINO) {
|
||||
if (sfd->sfd_name[0] != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has name but no file",
|
||||
path, (unsigned long) index);
|
||||
sfd->sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
else if (sfd->sfd_ino >= nblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has out of range "
|
||||
"inode (cleared)",
|
||||
path, (unsigned long) index);
|
||||
sfd->sfd_ino = SFS_NOINO;
|
||||
sfd->sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
else {
|
||||
if (sfd->sfd_name[0] == 0) {
|
||||
/* XXX: what happens if FSCK.n.m already exists? */
|
||||
snprintf(sfd->sfd_name, sizeof(sfd->sfd_name),
|
||||
"FSCK.%lu.%lu",
|
||||
(unsigned long) sfd->sfd_ino,
|
||||
(unsigned long) uniqueid());
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has file but "
|
||||
"no name (fixed: %s)",
|
||||
path, (unsigned long) index,
|
||||
sfd->sfd_name);
|
||||
dchanged = 1;
|
||||
}
|
||||
if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu not "
|
||||
"null-terminated (fixed)",
|
||||
path, (unsigned long) index);
|
||||
dchanged = 1;
|
||||
}
|
||||
if (checkbadstring(sfd->sfd_name)) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu contains invalid "
|
||||
"characters (fixed)",
|
||||
path, (unsigned long) index);
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
return dchanged;
|
||||
if (sfd->sfd_ino == SFS_NOINO) {
|
||||
if (sfd->sfd_name[0] != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has name but no file", path,
|
||||
(unsigned long)index);
|
||||
sfd->sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
} else if (sfd->sfd_ino >= nblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has out of range "
|
||||
"inode (cleared)",
|
||||
path, (unsigned long)index);
|
||||
sfd->sfd_ino = SFS_NOINO;
|
||||
sfd->sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
} else {
|
||||
if (sfd->sfd_name[0] == 0) {
|
||||
/* XXX: what happens if FSCK.n.m already exists? */
|
||||
snprintf(sfd->sfd_name, sizeof(sfd->sfd_name), "FSCK.%lu.%lu",
|
||||
(unsigned long)sfd->sfd_ino, (unsigned long)uniqueid());
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has file but "
|
||||
"no name (fixed: %s)",
|
||||
path, (unsigned long)index, sfd->sfd_name);
|
||||
dchanged = 1;
|
||||
}
|
||||
if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu not "
|
||||
"null-terminated (fixed)",
|
||||
path, (unsigned long)index);
|
||||
dchanged = 1;
|
||||
}
|
||||
if (checkbadstring(sfd->sfd_name)) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu contains invalid "
|
||||
"characters (fixed)",
|
||||
path, (unsigned long)index);
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
return dchanged;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -355,142 +327,120 @@ pass1_direntry(const char *path, uint32_t index, struct sfs_direntry *sfd)
|
||||
* to this directory. This traverses the volume directory tree
|
||||
* recursively.
|
||||
*/
|
||||
static
|
||||
void
|
||||
pass1_dir(uint32_t ino, const char *pathsofar)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
struct sfs_direntry *direntries;
|
||||
uint32_t ndirentries, i;
|
||||
int ichanged=0, dchanged=0;
|
||||
static void pass1_dir(uint32_t ino, const char *pathsofar) {
|
||||
struct sfs_dinode sfi;
|
||||
struct sfs_direntry *direntries;
|
||||
uint32_t ndirentries, i;
|
||||
int ichanged = 0, dchanged = 0;
|
||||
|
||||
sfs_readinode(ino, &sfi);
|
||||
sfs_readinode(ino, &sfi);
|
||||
|
||||
if (sfi.sfi_size % sizeof(struct sfs_direntry) != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s has illegal size %lu (fixed)",
|
||||
pathsofar, (unsigned long) sfi.sfi_size);
|
||||
sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
|
||||
sizeof(struct sfs_direntry));
|
||||
ichanged = 1;
|
||||
}
|
||||
count_dirs++;
|
||||
if (sfi.sfi_size % sizeof(struct sfs_direntry) != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s has illegal size %lu (fixed)", pathsofar,
|
||||
(unsigned long)sfi.sfi_size);
|
||||
sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size, sizeof(struct sfs_direntry));
|
||||
ichanged = 1;
|
||||
}
|
||||
count_dirs++;
|
||||
|
||||
if (pass1_inode(ino, &sfi, ichanged)) {
|
||||
/* been here before; crosslinked dir, sort it out in pass 2 */
|
||||
return;
|
||||
}
|
||||
if (pass1_inode(ino, &sfi, ichanged)) {
|
||||
/* been here before; crosslinked dir, sort it out in pass 2 */
|
||||
return;
|
||||
}
|
||||
|
||||
ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry);
|
||||
direntries = domalloc(sfi.sfi_size);
|
||||
ndirentries = sfi.sfi_size / sizeof(struct sfs_direntry);
|
||||
direntries = domalloc(sfi.sfi_size);
|
||||
|
||||
sfs_readdir(&sfi, direntries, ndirentries);
|
||||
sfs_readdir(&sfi, direntries, ndirentries);
|
||||
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (pass1_direntry(pathsofar, i, &direntries[i])) {
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ndirentries; i++) {
|
||||
if (pass1_direntry(pathsofar, i, &direntries[i])) {
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (direntries[i].sfd_ino == SFS_NOINO) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
/* nothing */
|
||||
}
|
||||
else {
|
||||
char path[strlen(pathsofar)+SFS_NAMELEN+1];
|
||||
struct sfs_dinode subsfi;
|
||||
uint32_t subino;
|
||||
for (i = 0; i < ndirentries; i++) {
|
||||
if (direntries[i].sfd_ino == SFS_NOINO) {
|
||||
/* nothing */
|
||||
} else if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
/* nothing */
|
||||
} else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
/* nothing */
|
||||
} else {
|
||||
char path[strlen(pathsofar) + SFS_NAMELEN + 1];
|
||||
struct sfs_dinode subsfi;
|
||||
uint32_t subino;
|
||||
|
||||
subino = direntries[i].sfd_ino;
|
||||
sfs_readinode(subino, &subsfi);
|
||||
snprintf(path, sizeof(path), "%s/%s",
|
||||
pathsofar, direntries[i].sfd_name);
|
||||
subino = direntries[i].sfd_ino;
|
||||
sfs_readinode(subino, &subsfi);
|
||||
snprintf(path, sizeof(path), "%s/%s", pathsofar, direntries[i].sfd_name);
|
||||
|
||||
switch (subsfi.sfi_type) {
|
||||
case SFS_TYPE_FILE:
|
||||
if (pass1_inode(subino, &subsfi, 0)) {
|
||||
/* been here before */
|
||||
break;
|
||||
}
|
||||
count_files++;
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
pass1_dir(subino, path);
|
||||
break;
|
||||
default:
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Object %s: Invalid inode type %u "
|
||||
"(removed)", path, subsfi.sfi_type);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (subsfi.sfi_type) {
|
||||
case SFS_TYPE_FILE:
|
||||
if (pass1_inode(subino, &subsfi, 0)) {
|
||||
/* been here before */
|
||||
break;
|
||||
}
|
||||
count_files++;
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
pass1_dir(subino, path);
|
||||
break;
|
||||
default:
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Object %s: Invalid inode type %u "
|
||||
"(removed)",
|
||||
path, subsfi.sfi_type);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dchanged) {
|
||||
sfs_writedir(&sfi, direntries, ndirentries);
|
||||
}
|
||||
if (dchanged) {
|
||||
sfs_writedir(&sfi, direntries, ndirentries);
|
||||
}
|
||||
|
||||
free(direntries);
|
||||
free(direntries);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the root directory, and implicitly everything under it.
|
||||
*/
|
||||
static
|
||||
void
|
||||
pass1_rootdir(void)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
char path[SFS_VOLNAME_SIZE + 2];
|
||||
static void pass1_rootdir(void) {
|
||||
struct sfs_dinode sfi;
|
||||
char path[SFS_VOLNAME_SIZE + 2];
|
||||
|
||||
sfs_readinode(SFS_ROOTDIR_INO, &sfi);
|
||||
sfs_readinode(SFS_ROOTDIR_INO, &sfi);
|
||||
|
||||
switch (sfi.sfi_type) {
|
||||
case SFS_TYPE_DIR:
|
||||
break;
|
||||
case SFS_TYPE_FILE:
|
||||
warnx("Root directory inode is a regular file (fixed)");
|
||||
goto fix;
|
||||
default:
|
||||
warnx("Root directory inode has invalid type %lu (fixed)",
|
||||
(unsigned long) sfi.sfi_type);
|
||||
fix:
|
||||
setbadness(EXIT_RECOV);
|
||||
sfi.sfi_type = SFS_TYPE_DIR;
|
||||
sfs_writeinode(SFS_ROOTDIR_INO, &sfi);
|
||||
break;
|
||||
}
|
||||
switch (sfi.sfi_type) {
|
||||
case SFS_TYPE_DIR:
|
||||
break;
|
||||
case SFS_TYPE_FILE:
|
||||
warnx("Root directory inode is a regular file (fixed)");
|
||||
goto fix;
|
||||
default:
|
||||
warnx("Root directory inode has invalid type %lu (fixed)",
|
||||
(unsigned long)sfi.sfi_type);
|
||||
fix:
|
||||
setbadness(EXIT_RECOV);
|
||||
sfi.sfi_type = SFS_TYPE_DIR;
|
||||
sfs_writeinode(SFS_ROOTDIR_INO, &sfi);
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path), "%s:", sb_volname());
|
||||
pass1_dir(SFS_ROOTDIR_INO, path);
|
||||
snprintf(path, sizeof(path), "%s:", sb_volname());
|
||||
pass1_dir(SFS_ROOTDIR_INO, path);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// public interface
|
||||
|
||||
void
|
||||
pass1(void)
|
||||
{
|
||||
pass1_rootdir();
|
||||
}
|
||||
void pass1(void) { pass1_rootdir(); }
|
||||
|
||||
unsigned long
|
||||
pass1_founddirs(void)
|
||||
{
|
||||
return count_dirs;
|
||||
}
|
||||
unsigned long pass1_founddirs(void) { return count_dirs; }
|
||||
|
||||
unsigned long
|
||||
pass1_foundfiles(void)
|
||||
{
|
||||
return count_files;
|
||||
}
|
||||
unsigned long pass1_foundfiles(void) { return count_files; }
|
||||
|
||||
@@ -58,268 +58,241 @@
|
||||
* instead of the first entry we recursively find. Beware of course
|
||||
* that the .. entry might not point to anywhere valid at all...
|
||||
*/
|
||||
static
|
||||
int
|
||||
pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
struct sfs_direntry *direntries;
|
||||
int *sortvector;
|
||||
uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
|
||||
int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;
|
||||
static int pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar) {
|
||||
struct sfs_dinode sfi;
|
||||
struct sfs_direntry *direntries;
|
||||
int *sortvector;
|
||||
uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
|
||||
int ichanged = 0, dchanged = 0, dotseen = 0, dotdotseen = 0;
|
||||
|
||||
if (inode_visitdir(ino)) {
|
||||
/* crosslinked dir; tell parent to remove the entry */
|
||||
return 1;
|
||||
}
|
||||
if (inode_visitdir(ino)) {
|
||||
/* crosslinked dir; tell parent to remove the entry */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load the inode. */
|
||||
sfs_readinode(ino, &sfi);
|
||||
/* Load the inode. */
|
||||
sfs_readinode(ino, &sfi);
|
||||
|
||||
/*
|
||||
* Load the directory. If there is any leftover room in the
|
||||
* last block, allocate space for it in case we want to insert
|
||||
* entries.
|
||||
*/
|
||||
/*
|
||||
* Load the directory. If there is any leftover room in the
|
||||
* last block, allocate space for it in case we want to insert
|
||||
* entries.
|
||||
*/
|
||||
|
||||
ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry);
|
||||
maxdirentries = SFS_ROUNDUP(ndirentries,
|
||||
SFS_BLOCKSIZE/sizeof(struct sfs_direntry));
|
||||
dirsize = maxdirentries * sizeof(struct sfs_direntry);
|
||||
direntries = domalloc(dirsize);
|
||||
ndirentries = sfi.sfi_size / sizeof(struct sfs_direntry);
|
||||
maxdirentries =
|
||||
SFS_ROUNDUP(ndirentries, SFS_BLOCKSIZE / sizeof(struct sfs_direntry));
|
||||
dirsize = maxdirentries * sizeof(struct sfs_direntry);
|
||||
direntries = domalloc(dirsize);
|
||||
|
||||
sortvector = domalloc(ndirentries * sizeof(int));
|
||||
sortvector = domalloc(ndirentries * sizeof(int));
|
||||
|
||||
sfs_readdir(&sfi, direntries, ndirentries);
|
||||
for (i=ndirentries; i<maxdirentries; i++) {
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
|
||||
}
|
||||
sfs_readdir(&sfi, direntries, ndirentries);
|
||||
for (i = ndirentries; i < maxdirentries; i++) {
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort by name and check for duplicate names.
|
||||
*/
|
||||
/*
|
||||
* Sort by name and check for duplicate names.
|
||||
*/
|
||||
|
||||
sfsdir_sort(direntries, ndirentries, sortvector);
|
||||
sfsdir_sort(direntries, ndirentries, sortvector);
|
||||
|
||||
/* don't use ndirentries-1 here, in case ndirentries == 0 */
|
||||
for (i=0; i+1<ndirentries; i++) {
|
||||
struct sfs_direntry *d1 = &direntries[sortvector[i]];
|
||||
struct sfs_direntry *d2 = &direntries[sortvector[i+1]];
|
||||
assert(d1 != d2);
|
||||
/* don't use ndirentries-1 here, in case ndirentries == 0 */
|
||||
for (i = 0; i + 1 < ndirentries; i++) {
|
||||
struct sfs_direntry *d1 = &direntries[sortvector[i]];
|
||||
struct sfs_direntry *d2 = &direntries[sortvector[i + 1]];
|
||||
assert(d1 != d2);
|
||||
|
||||
if (d1->sfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) {
|
||||
/* sfsdir_sort puts these last */
|
||||
continue;
|
||||
}
|
||||
if (d1->sfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) {
|
||||
/* sfsdir_sort puts these last */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(d1->sfd_name, d2->sfd_name)) {
|
||||
if (d1->sfd_ino == d2->sfd_ino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Duplicate entries for "
|
||||
"%s (merged)",
|
||||
pathsofar, d1->sfd_name);
|
||||
d1->sfd_ino = SFS_NOINO;
|
||||
d1->sfd_name[0] = 0;
|
||||
}
|
||||
else {
|
||||
/* XXX: what if FSCK.n.m already exists? */
|
||||
snprintf(d1->sfd_name, sizeof(d1->sfd_name),
|
||||
"FSCK.%lu.%lu",
|
||||
(unsigned long) d1->sfd_ino,
|
||||
(unsigned long) uniqueid());
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Duplicate names %s "
|
||||
"(one renamed: %s)",
|
||||
pathsofar, d2->sfd_name, d1->sfd_name);
|
||||
}
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
if (!strcmp(d1->sfd_name, d2->sfd_name)) {
|
||||
if (d1->sfd_ino == d2->sfd_ino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Duplicate entries for "
|
||||
"%s (merged)",
|
||||
pathsofar, d1->sfd_name);
|
||||
d1->sfd_ino = SFS_NOINO;
|
||||
d1->sfd_name[0] = 0;
|
||||
} else {
|
||||
/* XXX: what if FSCK.n.m already exists? */
|
||||
snprintf(d1->sfd_name, sizeof(d1->sfd_name), "FSCK.%lu.%lu",
|
||||
(unsigned long)d1->sfd_ino, (unsigned long)uniqueid());
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Duplicate names %s "
|
||||
"(one renamed: %s)",
|
||||
pathsofar, d2->sfd_name, d1->sfd_name);
|
||||
}
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for the . and .. entries.
|
||||
*/
|
||||
/*
|
||||
* Look for the . and .. entries.
|
||||
*/
|
||||
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
if (direntries[i].sfd_ino != ino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Incorrect `.' entry "
|
||||
"(fixed)", pathsofar);
|
||||
direntries[i].sfd_ino = ino;
|
||||
dchanged = 1;
|
||||
}
|
||||
/* duplicates are checked above -> only one . here */
|
||||
assert(dotseen==0);
|
||||
dotseen = 1;
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
if (direntries[i].sfd_ino != parentino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Incorrect `..' entry "
|
||||
"(fixed)", pathsofar);
|
||||
direntries[i].sfd_ino = parentino;
|
||||
dchanged = 1;
|
||||
}
|
||||
/* duplicates are checked above -> only one .. here */
|
||||
assert(dotdotseen==0);
|
||||
dotdotseen = 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ndirentries; i++) {
|
||||
if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
if (direntries[i].sfd_ino != ino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Incorrect `.' entry "
|
||||
"(fixed)",
|
||||
pathsofar);
|
||||
direntries[i].sfd_ino = ino;
|
||||
dchanged = 1;
|
||||
}
|
||||
/* duplicates are checked above -> only one . here */
|
||||
assert(dotseen == 0);
|
||||
dotseen = 1;
|
||||
} else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
if (direntries[i].sfd_ino != parentino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Incorrect `..' entry "
|
||||
"(fixed)",
|
||||
pathsofar);
|
||||
direntries[i].sfd_ino = parentino;
|
||||
dchanged = 1;
|
||||
}
|
||||
/* duplicates are checked above -> only one .. here */
|
||||
assert(dotdotseen == 0);
|
||||
dotdotseen = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no . entry, try to insert one.
|
||||
*/
|
||||
/*
|
||||
* If no . entry, try to insert one.
|
||||
*/
|
||||
|
||||
if (!dotseen) {
|
||||
if (sfsdir_tryadd(direntries, ndirentries, ".", ino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `.' entry (added)",
|
||||
pathsofar);
|
||||
dchanged = 1;
|
||||
}
|
||||
else if (sfsdir_tryadd(direntries, maxdirentries, ".",
|
||||
ino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `.' entry (added)",
|
||||
pathsofar);
|
||||
ndirentries++;
|
||||
dchanged = 1;
|
||||
sfi.sfi_size += sizeof(struct sfs_direntry);
|
||||
ichanged = 1;
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_UNRECOV);
|
||||
warnx("Directory %s: No `.' entry (NOT FIXED)",
|
||||
pathsofar);
|
||||
}
|
||||
}
|
||||
if (!dotseen) {
|
||||
if (sfsdir_tryadd(direntries, ndirentries, ".", ino) == 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `.' entry (added)", pathsofar);
|
||||
dchanged = 1;
|
||||
} else if (sfsdir_tryadd(direntries, maxdirentries, ".", ino) == 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `.' entry (added)", pathsofar);
|
||||
ndirentries++;
|
||||
dchanged = 1;
|
||||
sfi.sfi_size += sizeof(struct sfs_direntry);
|
||||
ichanged = 1;
|
||||
} else {
|
||||
setbadness(EXIT_UNRECOV);
|
||||
warnx("Directory %s: No `.' entry (NOT FIXED)", pathsofar);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no .. entry, try to insert one.
|
||||
*/
|
||||
/*
|
||||
* If no .. entry, try to insert one.
|
||||
*/
|
||||
|
||||
if (!dotdotseen) {
|
||||
if (sfsdir_tryadd(direntries, ndirentries, "..",
|
||||
parentino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `..' entry (added)",
|
||||
pathsofar);
|
||||
dchanged = 1;
|
||||
}
|
||||
else if (sfsdir_tryadd(direntries, maxdirentries, "..",
|
||||
parentino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `..' entry (added)",
|
||||
pathsofar);
|
||||
ndirentries++;
|
||||
dchanged = 1;
|
||||
sfi.sfi_size += sizeof(struct sfs_direntry);
|
||||
ichanged = 1;
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_UNRECOV);
|
||||
warnx("Directory %s: No `..' entry (NOT FIXED)",
|
||||
pathsofar);
|
||||
}
|
||||
}
|
||||
if (!dotdotseen) {
|
||||
if (sfsdir_tryadd(direntries, ndirentries, "..", parentino) == 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `..' entry (added)", pathsofar);
|
||||
dchanged = 1;
|
||||
} else if (sfsdir_tryadd(direntries, maxdirentries, "..", parentino) == 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `..' entry (added)", pathsofar);
|
||||
ndirentries++;
|
||||
dchanged = 1;
|
||||
sfi.sfi_size += sizeof(struct sfs_direntry);
|
||||
ichanged = 1;
|
||||
} else {
|
||||
setbadness(EXIT_UNRECOV);
|
||||
warnx("Directory %s: No `..' entry (NOT FIXED)", pathsofar);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now load each inode in the directory.
|
||||
*
|
||||
* For regular files, count the number of links we see; for
|
||||
* directories, recurse. Count the number of subdirs seen
|
||||
* so we can correct our own link count if necessary.
|
||||
*/
|
||||
/*
|
||||
* Now load each inode in the directory.
|
||||
*
|
||||
* For regular files, count the number of links we see; for
|
||||
* directories, recurse. Count the number of subdirs seen
|
||||
* so we can correct our own link count if necessary.
|
||||
*/
|
||||
|
||||
subdircount=0;
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (direntries[i].sfd_ino == SFS_NOINO) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
/* nothing */
|
||||
}
|
||||
else {
|
||||
char path[strlen(pathsofar)+SFS_NAMELEN+1];
|
||||
struct sfs_dinode subsfi;
|
||||
subdircount = 0;
|
||||
for (i = 0; i < ndirentries; i++) {
|
||||
if (direntries[i].sfd_ino == SFS_NOINO) {
|
||||
/* nothing */
|
||||
} else if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
/* nothing */
|
||||
} else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
/* nothing */
|
||||
} else {
|
||||
char path[strlen(pathsofar) + SFS_NAMELEN + 1];
|
||||
struct sfs_dinode subsfi;
|
||||
|
||||
sfs_readinode(direntries[i].sfd_ino, &subsfi);
|
||||
snprintf(path, sizeof(path), "%s/%s",
|
||||
pathsofar, direntries[i].sfd_name);
|
||||
sfs_readinode(direntries[i].sfd_ino, &subsfi);
|
||||
snprintf(path, sizeof(path), "%s/%s", pathsofar, direntries[i].sfd_name);
|
||||
|
||||
switch (subsfi.sfi_type) {
|
||||
case SFS_TYPE_FILE:
|
||||
inode_addlink(direntries[i].sfd_ino);
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
if (pass2_dir(direntries[i].sfd_ino,
|
||||
ino,
|
||||
path)) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Crosslink to "
|
||||
"other directory (removed)",
|
||||
path);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
else {
|
||||
subdircount++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Object %s: Invalid inode type %u "
|
||||
"(removed)", path, subsfi.sfi_type);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (subsfi.sfi_type) {
|
||||
case SFS_TYPE_FILE:
|
||||
inode_addlink(direntries[i].sfd_ino);
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
if (pass2_dir(direntries[i].sfd_ino, ino, path)) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Crosslink to "
|
||||
"other directory (removed)",
|
||||
path);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
} else {
|
||||
subdircount++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Object %s: Invalid inode type %u "
|
||||
"(removed)",
|
||||
path, subsfi.sfi_type);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix up the link count if needed.
|
||||
*/
|
||||
/*
|
||||
* Fix up the link count if needed.
|
||||
*/
|
||||
|
||||
if (sfi.sfi_linkcount != subdircount+2) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Link count %lu should be %lu (fixed)",
|
||||
pathsofar, (unsigned long) sfi.sfi_linkcount,
|
||||
(unsigned long) subdircount+2);
|
||||
sfi.sfi_linkcount = subdircount+2;
|
||||
ichanged = 1;
|
||||
}
|
||||
if (sfi.sfi_linkcount != subdircount + 2) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Link count %lu should be %lu (fixed)", pathsofar,
|
||||
(unsigned long)sfi.sfi_linkcount, (unsigned long)subdircount + 2);
|
||||
sfi.sfi_linkcount = subdircount + 2;
|
||||
ichanged = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write back anything that changed, clean up, and return.
|
||||
*/
|
||||
/*
|
||||
* Write back anything that changed, clean up, and return.
|
||||
*/
|
||||
|
||||
if (dchanged) {
|
||||
sfs_writedir(&sfi, direntries, ndirentries);
|
||||
}
|
||||
if (dchanged) {
|
||||
sfs_writedir(&sfi, direntries, ndirentries);
|
||||
}
|
||||
|
||||
if (ichanged) {
|
||||
sfs_writeinode(ino, &sfi);
|
||||
}
|
||||
if (ichanged) {
|
||||
sfs_writeinode(ino, &sfi);
|
||||
}
|
||||
|
||||
free(direntries);
|
||||
free(sortvector);
|
||||
free(direntries);
|
||||
free(sortvector);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pass2(void)
|
||||
{
|
||||
char path[SFS_VOLNAME_SIZE + 2];
|
||||
void pass2(void) {
|
||||
char path[SFS_VOLNAME_SIZE + 2];
|
||||
|
||||
snprintf(path, sizeof(path), "%s:", sb_volname());
|
||||
pass2_dir(SFS_ROOTDIR_INO, SFS_ROOTDIR_INO, path);
|
||||
snprintf(path, sizeof(path), "%s:", sb_volname());
|
||||
pass2_dir(SFS_ROOTDIR_INO, SFS_ROOTDIR_INO, path);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* for CHAR_BIT */
|
||||
#include <limits.h> /* also for CHAR_BIT */
|
||||
#include <sys/types.h> /* for CHAR_BIT */
|
||||
#include <limits.h> /* also for CHAR_BIT */
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
@@ -47,78 +47,62 @@ static struct sfs_superblock sb;
|
||||
/*
|
||||
* Load the superblock.
|
||||
*/
|
||||
void
|
||||
sb_load(void)
|
||||
{
|
||||
sfs_readsb(SFS_SUPER_BLOCK, &sb);
|
||||
if (sb.sb_magic != SFS_MAGIC) {
|
||||
errx(EXIT_FATAL, "Not an sfs filesystem");
|
||||
}
|
||||
void sb_load(void) {
|
||||
sfs_readsb(SFS_SUPER_BLOCK, &sb);
|
||||
if (sb.sb_magic != SFS_MAGIC) {
|
||||
errx(EXIT_FATAL, "Not an sfs filesystem");
|
||||
}
|
||||
|
||||
assert(sb.sb_nblocks > 0);
|
||||
assert(SFS_FREEMAPBLOCKS(sb.sb_nblocks) > 0);
|
||||
assert(sb.sb_nblocks > 0);
|
||||
assert(SFS_FREEMAPBLOCKS(sb.sb_nblocks) > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the superblock.
|
||||
*/
|
||||
void
|
||||
sb_check(void)
|
||||
{
|
||||
int schanged=0;
|
||||
void sb_check(void) {
|
||||
int schanged = 0;
|
||||
|
||||
/*
|
||||
* FUTURE: should we check sb.sb_nblocks against diskblocks()?
|
||||
*/
|
||||
/*
|
||||
* FUTURE: should we check sb.sb_nblocks against diskblocks()?
|
||||
*/
|
||||
|
||||
/* Check the superblock fields */
|
||||
/* Check the superblock fields */
|
||||
|
||||
if (checknullstring(sb.sb_volname, sizeof(sb.sb_volname))) {
|
||||
warnx("Volume name not null-terminated (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checkbadstring(sb.sb_volname)) {
|
||||
warnx("Volume name contains illegal characters (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checkzeroed(sb.reserved, sizeof(sb.reserved))) {
|
||||
warnx("Reserved section of superblock not zeroed (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checknullstring(sb.sb_volname, sizeof(sb.sb_volname))) {
|
||||
warnx("Volume name not null-terminated (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checkbadstring(sb.sb_volname)) {
|
||||
warnx("Volume name contains illegal characters (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checkzeroed(sb.reserved, sizeof(sb.reserved))) {
|
||||
warnx("Reserved section of superblock not zeroed (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
|
||||
/* Write the superblock back if necessary */
|
||||
if (schanged) {
|
||||
sfs_writesb(SFS_SUPER_BLOCK, &sb);
|
||||
}
|
||||
/* Write the superblock back if necessary */
|
||||
if (schanged) {
|
||||
sfs_writesb(SFS_SUPER_BLOCK, &sb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total number of blocks in the volume.
|
||||
*/
|
||||
uint32_t
|
||||
sb_totalblocks(void)
|
||||
{
|
||||
return sb.sb_nblocks;
|
||||
}
|
||||
uint32_t sb_totalblocks(void) { return sb.sb_nblocks; }
|
||||
|
||||
/*
|
||||
* Return the number of freemap blocks.
|
||||
* (this function probably ought to go away)
|
||||
*/
|
||||
uint32_t
|
||||
sb_freemapblocks(void)
|
||||
{
|
||||
return SFS_FREEMAPBLOCKS(sb.sb_nblocks);
|
||||
}
|
||||
uint32_t sb_freemapblocks(void) { return SFS_FREEMAPBLOCKS(sb.sb_nblocks); }
|
||||
|
||||
/*
|
||||
* Return the volume name.
|
||||
*/
|
||||
const char *
|
||||
sb_volname(void)
|
||||
{
|
||||
return sb.sb_volname;
|
||||
}
|
||||
const char *sb_volname(void) { return sb.sb_volname; }
|
||||
|
||||
@@ -45,75 +45,58 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// global setup
|
||||
|
||||
void
|
||||
sfs_setup(void)
|
||||
{
|
||||
assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
|
||||
assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
|
||||
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
|
||||
void sfs_setup(void) {
|
||||
assert(sizeof(struct sfs_superblock) == SFS_BLOCKSIZE);
|
||||
assert(sizeof(struct sfs_dinode) == SFS_BLOCKSIZE);
|
||||
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// byte-swap functions
|
||||
|
||||
static
|
||||
void
|
||||
swapsb(struct sfs_superblock *sb)
|
||||
{
|
||||
sb->sb_magic = SWAP32(sb->sb_magic);
|
||||
sb->sb_nblocks = SWAP32(sb->sb_nblocks);
|
||||
static void swapsb(struct sfs_superblock *sb) {
|
||||
sb->sb_magic = SWAP32(sb->sb_magic);
|
||||
sb->sb_nblocks = SWAP32(sb->sb_nblocks);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapbits(uint8_t *bits)
|
||||
{
|
||||
/* nothing to do */
|
||||
(void)bits;
|
||||
static void swapbits(uint8_t *bits) {
|
||||
/* nothing to do */
|
||||
(void)bits;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapinode(struct sfs_dinode *sfi)
|
||||
{
|
||||
int i;
|
||||
static void swapinode(struct sfs_dinode *sfi) {
|
||||
int i;
|
||||
|
||||
sfi->sfi_size = SWAP32(sfi->sfi_size);
|
||||
sfi->sfi_type = SWAP16(sfi->sfi_type);
|
||||
sfi->sfi_linkcount = SWAP16(sfi->sfi_linkcount);
|
||||
sfi->sfi_size = SWAP32(sfi->sfi_size);
|
||||
sfi->sfi_type = SWAP16(sfi->sfi_type);
|
||||
sfi->sfi_linkcount = SWAP16(sfi->sfi_linkcount);
|
||||
|
||||
for (i=0; i<NUM_D; i++) {
|
||||
SET_D(sfi, i) = SWAP32(GET_D(sfi, i));
|
||||
}
|
||||
for (i = 0; i < NUM_D; i++) {
|
||||
SET_D(sfi, i) = SWAP32(GET_D(sfi, i));
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_I; i++) {
|
||||
SET_I(sfi, i) = SWAP32(GET_I(sfi, i));
|
||||
}
|
||||
for (i = 0; i < NUM_I; i++) {
|
||||
SET_I(sfi, i) = SWAP32(GET_I(sfi, i));
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_II; i++) {
|
||||
SET_II(sfi, i) = SWAP32(GET_II(sfi, i));
|
||||
}
|
||||
for (i = 0; i < NUM_II; i++) {
|
||||
SET_II(sfi, i) = SWAP32(GET_II(sfi, i));
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_III; i++) {
|
||||
SET_III(sfi, i) = SWAP32(GET_III(sfi, i));
|
||||
}
|
||||
for (i = 0; i < NUM_III; i++) {
|
||||
SET_III(sfi, i) = SWAP32(GET_III(sfi, i));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapdir(struct sfs_direntry *sfd)
|
||||
{
|
||||
sfd->sfd_ino = SWAP32(sfd->sfd_ino);
|
||||
static void swapdir(struct sfs_direntry *sfd) {
|
||||
sfd->sfd_ino = SWAP32(sfd->sfd_ino);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapindir(uint32_t *entries)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<SFS_DBPERIDB; i++) {
|
||||
entries[i] = SWAP32(entries[i]);
|
||||
}
|
||||
static void swapindir(uint32_t *entries) {
|
||||
int i;
|
||||
for (i = 0; i < SFS_DBPERIDB; i++) {
|
||||
entries[i] = SWAP32(entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -128,28 +111,24 @@ swapindir(uint32_t *entries)
|
||||
* singly-indirect block this is 1. For a multiply-indirect block,
|
||||
* it is more than 1; in this case recurse.
|
||||
*/
|
||||
static
|
||||
uint32_t
|
||||
ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize)
|
||||
{
|
||||
uint32_t entries[SFS_DBPERIDB];
|
||||
static uint32_t ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize) {
|
||||
uint32_t entries[SFS_DBPERIDB];
|
||||
|
||||
if (iblock == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (iblock == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
diskread(entries, iblock);
|
||||
swapindir(entries);
|
||||
diskread(entries, iblock);
|
||||
swapindir(entries);
|
||||
|
||||
if (entrysize > 1) {
|
||||
uint32_t index = offset / entrysize;
|
||||
offset %= entrysize;
|
||||
return ibmap(entries[index], offset, entrysize/SFS_DBPERIDB);
|
||||
}
|
||||
else {
|
||||
assert(offset < SFS_DBPERIDB);
|
||||
return entries[offset];
|
||||
}
|
||||
if (entrysize > 1) {
|
||||
uint32_t index = offset / entrysize;
|
||||
offset %= entrysize;
|
||||
return ibmap(entries[index], offset, entrysize / SFS_DBPERIDB);
|
||||
} else {
|
||||
assert(offset < SFS_DBPERIDB);
|
||||
return entries[offset];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -157,31 +136,25 @@ ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize)
|
||||
*
|
||||
* Given an inode and a file block, returns a disk block.
|
||||
*/
|
||||
static
|
||||
uint32_t
|
||||
bmap(const struct sfs_dinode *sfi, uint32_t fileblock)
|
||||
{
|
||||
uint32_t iblock, offset;
|
||||
static uint32_t bmap(const struct sfs_dinode *sfi, uint32_t fileblock) {
|
||||
uint32_t iblock, offset;
|
||||
|
||||
if (fileblock < INOMAX_D) {
|
||||
return GET_D(sfi, fileblock);
|
||||
}
|
||||
else if (fileblock < INOMAX_I) {
|
||||
iblock = (fileblock - INOMAX_D) / RANGE_I;
|
||||
offset = (fileblock - INOMAX_D) % RANGE_I;
|
||||
return ibmap(GET_I(sfi, iblock), offset, RANGE_D);
|
||||
}
|
||||
else if (fileblock < INOMAX_II) {
|
||||
iblock = (fileblock - INOMAX_I) / RANGE_II;
|
||||
offset = (fileblock - INOMAX_I) % RANGE_II;
|
||||
return ibmap(GET_II(sfi, iblock), offset, RANGE_I);
|
||||
}
|
||||
else if (fileblock < INOMAX_III) {
|
||||
iblock = (fileblock - INOMAX_II) / RANGE_III;
|
||||
offset = (fileblock - INOMAX_II) % RANGE_III;
|
||||
return ibmap(GET_III(sfi, iblock), offset, RANGE_II);
|
||||
}
|
||||
return 0;
|
||||
if (fileblock < INOMAX_D) {
|
||||
return GET_D(sfi, fileblock);
|
||||
} else if (fileblock < INOMAX_I) {
|
||||
iblock = (fileblock - INOMAX_D) / RANGE_I;
|
||||
offset = (fileblock - INOMAX_D) % RANGE_I;
|
||||
return ibmap(GET_I(sfi, iblock), offset, RANGE_D);
|
||||
} else if (fileblock < INOMAX_II) {
|
||||
iblock = (fileblock - INOMAX_I) / RANGE_II;
|
||||
offset = (fileblock - INOMAX_I) % RANGE_II;
|
||||
return ibmap(GET_II(sfi, iblock), offset, RANGE_I);
|
||||
} else if (fileblock < INOMAX_III) {
|
||||
iblock = (fileblock - INOMAX_II) / RANGE_III;
|
||||
offset = (fileblock - INOMAX_II) % RANGE_III;
|
||||
return ibmap(GET_III(sfi, iblock), offset, RANGE_II);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -191,19 +164,15 @@ bmap(const struct sfs_dinode *sfi, uint32_t fileblock)
|
||||
* superblock - blocknum is a disk block number.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb)
|
||||
{
|
||||
diskread(sb, blocknum);
|
||||
swapsb(sb);
|
||||
void sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb) {
|
||||
diskread(sb, blocknum);
|
||||
swapsb(sb);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb)
|
||||
{
|
||||
swapsb(sb);
|
||||
diskwrite(sb, blocknum);
|
||||
swapsb(sb);
|
||||
void sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb) {
|
||||
swapsb(sb);
|
||||
diskwrite(sb, blocknum);
|
||||
swapsb(sb);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -211,57 +180,45 @@ sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb)
|
||||
* bitmap.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits)
|
||||
{
|
||||
diskread(bits, SFS_FREEMAP_START + whichblock);
|
||||
swapbits(bits);
|
||||
void sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits) {
|
||||
diskread(bits, SFS_FREEMAP_START + whichblock);
|
||||
swapbits(bits);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits)
|
||||
{
|
||||
swapbits(bits);
|
||||
diskwrite(bits, SFS_FREEMAP_START + whichblock);
|
||||
swapbits(bits);
|
||||
void sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits) {
|
||||
swapbits(bits);
|
||||
diskwrite(bits, SFS_FREEMAP_START + whichblock);
|
||||
swapbits(bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* inodes - ino is an inode number, which is a disk block number.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readinode(uint32_t ino, struct sfs_dinode *sfi)
|
||||
{
|
||||
diskread(sfi, ino);
|
||||
swapinode(sfi);
|
||||
void sfs_readinode(uint32_t ino, struct sfs_dinode *sfi) {
|
||||
diskread(sfi, ino);
|
||||
swapinode(sfi);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writeinode(uint32_t ino, struct sfs_dinode *sfi)
|
||||
{
|
||||
swapinode(sfi);
|
||||
diskwrite(sfi, ino);
|
||||
swapinode(sfi);
|
||||
void sfs_writeinode(uint32_t ino, struct sfs_dinode *sfi) {
|
||||
swapinode(sfi);
|
||||
diskwrite(sfi, ino);
|
||||
swapinode(sfi);
|
||||
}
|
||||
|
||||
/*
|
||||
* indirect blocks - blocknum is a disk block number.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readindirect(uint32_t blocknum, uint32_t *entries)
|
||||
{
|
||||
diskread(entries, blocknum);
|
||||
swapindir(entries);
|
||||
void sfs_readindirect(uint32_t blocknum, uint32_t *entries) {
|
||||
diskread(entries, blocknum);
|
||||
swapindir(entries);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writeindirect(uint32_t blocknum, uint32_t *entries)
|
||||
{
|
||||
swapindir(entries);
|
||||
diskwrite(entries, blocknum);
|
||||
swapindir(entries);
|
||||
void sfs_writeindirect(uint32_t blocknum, uint32_t *entries) {
|
||||
swapindir(entries);
|
||||
diskwrite(entries, blocknum);
|
||||
swapindir(entries);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -270,23 +227,19 @@ sfs_writeindirect(uint32_t blocknum, uint32_t *entries)
|
||||
/*
|
||||
* Read the directory block at DISKBLOCK into D.
|
||||
*/
|
||||
static
|
||||
void
|
||||
sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned j;
|
||||
static void sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock) {
|
||||
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
|
||||
unsigned j;
|
||||
|
||||
if (diskblock != 0) {
|
||||
diskread(d, diskblock);
|
||||
for (j=0; j<atonce; j++) {
|
||||
swapdir(&d[j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnx("Warning: sparse directory found");
|
||||
bzero(d, SFS_BLOCKSIZE);
|
||||
}
|
||||
if (diskblock != 0) {
|
||||
diskread(d, diskblock);
|
||||
for (j = 0; j < atonce; j++) {
|
||||
swapdir(&d[j]);
|
||||
}
|
||||
} else {
|
||||
warnx("Warning: sparse directory found");
|
||||
bzero(d, SFS_BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -294,64 +247,56 @@ sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock)
|
||||
* with ND slots. The caller is assumed to have figured out the right
|
||||
* number of slots.
|
||||
*/
|
||||
void
|
||||
sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
|
||||
unsigned i, j;
|
||||
unsigned left, thismany;
|
||||
struct sfs_direntry buffer[atonce];
|
||||
uint32_t diskblock;
|
||||
void sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd) {
|
||||
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
|
||||
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
|
||||
unsigned i, j;
|
||||
unsigned left, thismany;
|
||||
struct sfs_direntry buffer[atonce];
|
||||
uint32_t diskblock;
|
||||
|
||||
left = nd;
|
||||
for (i=0; i<nblocks; i++) {
|
||||
diskblock = bmap(sfi, i);
|
||||
if (left < atonce) {
|
||||
thismany = left;
|
||||
sfs_readdirblock(buffer, diskblock);
|
||||
for (j=0; j<thismany; j++) {
|
||||
d[i*atonce + j] = buffer[j];
|
||||
}
|
||||
}
|
||||
else {
|
||||
thismany = atonce;
|
||||
sfs_readdirblock(d + i*atonce, diskblock);
|
||||
}
|
||||
left -= thismany;
|
||||
}
|
||||
assert(left == 0);
|
||||
left = nd;
|
||||
for (i = 0; i < nblocks; i++) {
|
||||
diskblock = bmap(sfi, i);
|
||||
if (left < atonce) {
|
||||
thismany = left;
|
||||
sfs_readdirblock(buffer, diskblock);
|
||||
for (j = 0; j < thismany; j++) {
|
||||
d[i * atonce + j] = buffer[j];
|
||||
}
|
||||
} else {
|
||||
thismany = atonce;
|
||||
sfs_readdirblock(d + i * atonce, diskblock);
|
||||
}
|
||||
left -= thismany;
|
||||
}
|
||||
assert(left == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the directory block D to DISKBLOCK.
|
||||
*/
|
||||
static
|
||||
void
|
||||
sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned j, bad;
|
||||
static void sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock) {
|
||||
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
|
||||
unsigned j, bad;
|
||||
|
||||
if (diskblock != 0) {
|
||||
for (j=0; j<atonce; j++) {
|
||||
swapdir(&d[j]);
|
||||
}
|
||||
diskwrite(d, diskblock);
|
||||
}
|
||||
else {
|
||||
for (j=bad=0; j<atonce; j++) {
|
||||
if (d[j].sfd_ino != SFS_NOINO ||
|
||||
d[j].sfd_name[0] != 0) {
|
||||
bad = 1;
|
||||
}
|
||||
}
|
||||
if (bad) {
|
||||
warnx("Cannot write to missing block in "
|
||||
"sparse directory (ERROR)");
|
||||
setbadness(EXIT_UNRECOV);
|
||||
}
|
||||
}
|
||||
if (diskblock != 0) {
|
||||
for (j = 0; j < atonce; j++) {
|
||||
swapdir(&d[j]);
|
||||
}
|
||||
diskwrite(d, diskblock);
|
||||
} else {
|
||||
for (j = bad = 0; j < atonce; j++) {
|
||||
if (d[j].sfd_ino != SFS_NOINO || d[j].sfd_name[0] != 0) {
|
||||
bad = 1;
|
||||
}
|
||||
}
|
||||
if (bad) {
|
||||
warnx("Cannot write to missing block in "
|
||||
"sparse directory (ERROR)");
|
||||
setbadness(EXIT_UNRECOV);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -359,36 +304,34 @@ sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock)
|
||||
* buffer with ND slots. The caller is assumed to have set the inode
|
||||
* size accordingly.
|
||||
*/
|
||||
void
|
||||
sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
|
||||
unsigned i, j;
|
||||
unsigned left, thismany;
|
||||
struct sfs_direntry buffer[atonce];
|
||||
uint32_t diskblock;
|
||||
void sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d,
|
||||
unsigned nd) {
|
||||
const unsigned atonce = SFS_BLOCKSIZE / sizeof(struct sfs_direntry);
|
||||
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
|
||||
unsigned i, j;
|
||||
unsigned left, thismany;
|
||||
struct sfs_direntry buffer[atonce];
|
||||
uint32_t diskblock;
|
||||
|
||||
left = nd;
|
||||
for (i=0; i<nblocks; i++) {
|
||||
diskblock = bmap(sfi, i);
|
||||
if (left < atonce) {
|
||||
thismany = left;
|
||||
for (j=0; j<thismany; j++) {
|
||||
buffer[j] = d[i*atonce + j];
|
||||
}
|
||||
for (; j<atonce; j++) {
|
||||
memset(&buffer[j], 0, sizeof(buffer[j]));
|
||||
}
|
||||
sfs_writedirblock(buffer, diskblock);
|
||||
}
|
||||
else {
|
||||
thismany = atonce;
|
||||
sfs_writedirblock(d + i*atonce, diskblock);
|
||||
}
|
||||
left -= thismany;
|
||||
}
|
||||
assert(left == 0);
|
||||
left = nd;
|
||||
for (i = 0; i < nblocks; i++) {
|
||||
diskblock = bmap(sfi, i);
|
||||
if (left < atonce) {
|
||||
thismany = left;
|
||||
for (j = 0; j < thismany; j++) {
|
||||
buffer[j] = d[i * atonce + j];
|
||||
}
|
||||
for (; j < atonce; j++) {
|
||||
memset(&buffer[j], 0, sizeof(buffer[j]));
|
||||
}
|
||||
sfs_writedirblock(buffer, diskblock);
|
||||
} else {
|
||||
thismany = atonce;
|
||||
sfs_writedirblock(d + i * atonce, diskblock);
|
||||
}
|
||||
left -= thismany;
|
||||
}
|
||||
assert(left == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -401,27 +344,24 @@ static struct sfs_direntry *global_sortdirs;
|
||||
* Compare function for the permutation vector produced by
|
||||
* sfsdir_sort().
|
||||
*/
|
||||
static
|
||||
int
|
||||
dirsortfunc(const void *aa, const void *bb)
|
||||
{
|
||||
const int *a = (const int *)aa;
|
||||
const int *b = (const int *)bb;
|
||||
const struct sfs_direntry *ad = &global_sortdirs[*a];
|
||||
const struct sfs_direntry *bd = &global_sortdirs[*b];
|
||||
static int dirsortfunc(const void *aa, const void *bb) {
|
||||
const int *a = (const int *)aa;
|
||||
const int *b = (const int *)bb;
|
||||
const struct sfs_direntry *ad = &global_sortdirs[*a];
|
||||
const struct sfs_direntry *bd = &global_sortdirs[*b];
|
||||
|
||||
/* Sort unallocated entries last */
|
||||
if (ad->sfd_ino == SFS_NOINO && bd->sfd_ino == SFS_NOINO) {
|
||||
return 0;
|
||||
}
|
||||
if (ad->sfd_ino == SFS_NOINO) {
|
||||
return 1;
|
||||
}
|
||||
if (bd->sfd_ino == SFS_NOINO) {
|
||||
return -1;
|
||||
}
|
||||
/* Sort unallocated entries last */
|
||||
if (ad->sfd_ino == SFS_NOINO && bd->sfd_ino == SFS_NOINO) {
|
||||
return 0;
|
||||
}
|
||||
if (ad->sfd_ino == SFS_NOINO) {
|
||||
return 1;
|
||||
}
|
||||
if (bd->sfd_ino == SFS_NOINO) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return strcmp(ad->sfd_name, bd->sfd_name);
|
||||
return strcmp(ad->sfd_name, bd->sfd_name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -429,17 +369,15 @@ dirsortfunc(const void *aa, const void *bb)
|
||||
* permutation vector into VECTOR, which should be allocated to hold
|
||||
* ND ints.
|
||||
*/
|
||||
void
|
||||
sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector)
|
||||
{
|
||||
unsigned i;
|
||||
void sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector) {
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<nd; i++) {
|
||||
vector[i] = i;
|
||||
}
|
||||
for (i = 0; i < nd; i++) {
|
||||
vector[i] = i;
|
||||
}
|
||||
|
||||
global_sortdirs = d;
|
||||
qsort(vector, nd, sizeof(int), dirsortfunc);
|
||||
global_sortdirs = d;
|
||||
qsort(vector, nd, sizeof(int), dirsortfunc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -448,17 +386,16 @@ sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector)
|
||||
*
|
||||
* Returns 0 on success and nonzero on failure.
|
||||
*/
|
||||
int
|
||||
sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name, uint32_t ino)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<nd; i++) {
|
||||
if (d[i].sfd_ino==SFS_NOINO) {
|
||||
d[i].sfd_ino = ino;
|
||||
assert(strlen(name) < sizeof(d[i].sfd_name));
|
||||
strcpy(d[i].sfd_name, name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
int sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name,
|
||||
uint32_t ino) {
|
||||
int i;
|
||||
for (i = 0; i < nd; i++) {
|
||||
if (d[i].sfd_ino == SFS_NOINO) {
|
||||
d[i].sfd_ino = ino;
|
||||
assert(strlen(name) < sizeof(d[i].sfd_name));
|
||||
strcpy(d[i].sfd_name, name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -67,15 +67,14 @@ void sfs_writeindirect(uint32_t blocknum, uint32_t *entries);
|
||||
|
||||
/* directory - ND should be the number of directory entries D points to */
|
||||
void sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd);
|
||||
void sfs_writedir(const struct sfs_dinode *sfi,
|
||||
struct sfs_direntry *d, unsigned nd);
|
||||
void sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d,
|
||||
unsigned nd);
|
||||
|
||||
/* Try to add an entry to a directory. */
|
||||
int sfsdir_tryadd(struct sfs_direntry *d, int nd,
|
||||
const char *name, uint32_t ino);
|
||||
int sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name,
|
||||
uint32_t ino);
|
||||
|
||||
/* Sort a directory by creating a permutation vector. */
|
||||
void sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector);
|
||||
|
||||
|
||||
#endif /* SFS_H */
|
||||
|
||||
@@ -39,106 +39,94 @@
|
||||
/*
|
||||
* Wrapper around malloc.
|
||||
*/
|
||||
void *
|
||||
domalloc(size_t len)
|
||||
{
|
||||
void *x;
|
||||
x = malloc(len);
|
||||
if (x==NULL) {
|
||||
errx(EXIT_FATAL, "Out of memory");
|
||||
}
|
||||
return x;
|
||||
void *domalloc(size_t len) {
|
||||
void *x;
|
||||
x = malloc(len);
|
||||
if (x == NULL) {
|
||||
errx(EXIT_FATAL, "Out of memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around realloc. OSZ is the old block size, which we need if
|
||||
* we're going to emulate realloc with malloc.
|
||||
*/
|
||||
void *
|
||||
dorealloc(void *op, size_t osz, size_t nsz)
|
||||
{
|
||||
void *np;
|
||||
void *dorealloc(void *op, size_t osz, size_t nsz) {
|
||||
void *np;
|
||||
#ifdef NO_REALLOC
|
||||
size_t copysz;
|
||||
size_t copysz;
|
||||
|
||||
np = domalloc(nsz);
|
||||
if (op != NULL) {
|
||||
copysz = osz < nsz ? osz : nsz;
|
||||
memcpy(np, op, copysz);
|
||||
free(op);
|
||||
}
|
||||
np = domalloc(nsz);
|
||||
if (op != NULL) {
|
||||
copysz = osz < nsz ? osz : nsz;
|
||||
memcpy(np, op, copysz);
|
||||
free(op);
|
||||
}
|
||||
#else
|
||||
(void)osz;
|
||||
np = realloc(op, nsz);
|
||||
if (np == NULL) {
|
||||
errx(EXIT_FATAL, "Out of memory");
|
||||
}
|
||||
(void)osz;
|
||||
np = realloc(op, nsz);
|
||||
if (np == NULL) {
|
||||
errx(EXIT_FATAL, "Out of memory");
|
||||
}
|
||||
#endif
|
||||
return np;
|
||||
return np;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a unique id number. (unique as in for this run of sfsck...)
|
||||
*/
|
||||
uint32_t
|
||||
uniqueid(void)
|
||||
{
|
||||
static uint32_t uniquecounter;
|
||||
uint32_t uniqueid(void) {
|
||||
static uint32_t uniquecounter;
|
||||
|
||||
return uniquecounter++;
|
||||
return uniquecounter++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if BUF, a string field of length MAXLEN, contains a null
|
||||
* terminator. If not, slam one in and return 1.
|
||||
*/
|
||||
int
|
||||
checknullstring(char *buf, size_t maxlen)
|
||||
{
|
||||
size_t i;
|
||||
for (i=0; i<maxlen; i++) {
|
||||
if (buf[i]==0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
buf[maxlen-1] = 0;
|
||||
return 1;
|
||||
int checknullstring(char *buf, size_t maxlen) {
|
||||
size_t i;
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
if (buf[i] == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
buf[maxlen - 1] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if BUF contains characters not allowed in file and volume
|
||||
* names. If so, stomp them and return 1.
|
||||
*/
|
||||
int
|
||||
checkbadstring(char *buf)
|
||||
{
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
int checkbadstring(char *buf) {
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
|
||||
for (i=0; buf[i]; i++) {
|
||||
if (buf[i]==':' || buf[i]=='/') {
|
||||
buf[i] = '_';
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
for (i = 0; buf[i]; i++) {
|
||||
if (buf[i] == ':' || buf[i] == '/') {
|
||||
buf[i] = '_';
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if BUF, of size LEN, is zeroed. If not, zero it and return 1.
|
||||
*/
|
||||
int
|
||||
checkzeroed(void *vbuf, size_t len)
|
||||
{
|
||||
char *buf = vbuf;
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
int checkzeroed(void *vbuf, size_t len) {
|
||||
char *buf = vbuf;
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
if (buf[i] != 0) {
|
||||
buf[i] = 0;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (buf[i] != 0) {
|
||||
buf[i] = 0;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <sys/types.h> /* for size_t */
|
||||
#include <stdint.h> /* for uint32_t */
|
||||
#include <sys/types.h> /* for size_t */
|
||||
#include <stdint.h> /* for uint32_t */
|
||||
|
||||
/* non-failing wrapper around malloc */
|
||||
void *domalloc(size_t len);
|
||||
|
||||
@@ -39,19 +39,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, j;
|
||||
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: add num1 num2");
|
||||
}
|
||||
if (argc != 3) {
|
||||
errx(1, "Usage: add num1 num2");
|
||||
}
|
||||
|
||||
i = atoi(argv[1]);
|
||||
j = atoi(argv[2]);
|
||||
i = atoi(argv[1]);
|
||||
j = atoi(argv[2]);
|
||||
|
||||
printf("Answer: %d\n", i+j);
|
||||
printf("Answer: %d\n", i + j);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,21 +37,19 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *tmp;
|
||||
int i;
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *tmp;
|
||||
int i;
|
||||
|
||||
printf("argc: %d\n", argc);
|
||||
printf("argc: %d\n", argc);
|
||||
|
||||
for (i=0; i<=argc; i++) {
|
||||
tmp = argv[i];
|
||||
if (tmp==NULL) {
|
||||
tmp = "[NULL]";
|
||||
}
|
||||
printf("argv[%d]: %s\n", i, tmp);
|
||||
}
|
||||
for (i = 0; i <= argc; i++) {
|
||||
tmp = argv[i];
|
||||
if (tmp == NULL) {
|
||||
tmp = "[NULL]";
|
||||
}
|
||||
printf("argv[%d]: %s\n", i, tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,25 +37,19 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
chdir_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void chdir_empty(void) {
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* This is actually valid by some interpretations.
|
||||
*/
|
||||
/*
|
||||
* This is actually valid by some interpretations.
|
||||
*/
|
||||
|
||||
report_begin("chdir to empty string");
|
||||
rv = chdir("");
|
||||
report_check2(rv, errno, EINVAL, 0);
|
||||
report_begin("chdir to empty string");
|
||||
rv = chdir("");
|
||||
report_check2(rv, errno, EINVAL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
test_chdir(void)
|
||||
{
|
||||
test_chdir_path();
|
||||
chdir_empty();
|
||||
void test_chdir(void) {
|
||||
test_chdir_path();
|
||||
chdir_empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,4 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_close(void)
|
||||
{
|
||||
test_close_fd();
|
||||
}
|
||||
void test_close(void) { test_close_fd(); }
|
||||
|
||||
@@ -44,99 +44,86 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
dup2_fd2(int fd, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void dup2_fd2(int fd, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = dup2(STDIN_FILENO, fd);
|
||||
report_check(rv, errno, EBADF);
|
||||
report_begin("%s", desc);
|
||||
rv = dup2(STDIN_FILENO, fd);
|
||||
report_check(rv, errno, EBADF);
|
||||
|
||||
if (rv != -1) {
|
||||
close(fd); /* just in case */
|
||||
}
|
||||
if (rv != -1) {
|
||||
close(fd); /* just in case */
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dup2_self(void)
|
||||
{
|
||||
struct stat sb;
|
||||
int rv;
|
||||
int testfd;
|
||||
static void dup2_self(void) {
|
||||
struct stat sb;
|
||||
int rv;
|
||||
int testfd;
|
||||
|
||||
/* use fd that isn't in use */
|
||||
testfd = CLOSED_FD;
|
||||
/* use fd that isn't in use */
|
||||
testfd = CLOSED_FD;
|
||||
|
||||
report_begin("copying stdin to test with");
|
||||
report_begin("copying stdin to test with");
|
||||
|
||||
rv = dup2(STDIN_FILENO, testfd);
|
||||
if (rv == -1) {
|
||||
report_result(rv, errno);
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
rv = dup2(STDIN_FILENO, testfd);
|
||||
if (rv == -1) {
|
||||
report_result(rv, errno);
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin("dup2 to same fd");
|
||||
rv = dup2(testfd, testfd);
|
||||
if (rv == testfd) {
|
||||
report_passed();
|
||||
}
|
||||
else if (rv<0) {
|
||||
report_result(rv, errno);
|
||||
report_failure();
|
||||
}
|
||||
else {
|
||||
report_warnx("returned %d instead", rv);
|
||||
report_failure();
|
||||
}
|
||||
report_begin("dup2 to same fd");
|
||||
rv = dup2(testfd, testfd);
|
||||
if (rv == testfd) {
|
||||
report_passed();
|
||||
} else if (rv < 0) {
|
||||
report_result(rv, errno);
|
||||
report_failure();
|
||||
} else {
|
||||
report_warnx("returned %d instead", rv);
|
||||
report_failure();
|
||||
}
|
||||
|
||||
report_begin("fstat fd after dup2 to itself");
|
||||
rv = fstat(testfd, &sb);
|
||||
if (errno == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_result(rv, errno);
|
||||
if (rv==0) {
|
||||
report_passed();
|
||||
}
|
||||
else if (errno != ENOSYS) {
|
||||
report_failure();
|
||||
}
|
||||
else {
|
||||
report_skipped();
|
||||
/* no support for fstat; try lseek */
|
||||
report_begin("lseek fd after dup2 to itself");
|
||||
rv = lseek(testfd, 0, SEEK_CUR);
|
||||
report_result(rv, errno);
|
||||
if (rv==0 || (rv==-1 && errno==ESPIPE)) {
|
||||
report_passed();
|
||||
}
|
||||
else {
|
||||
report_failure();
|
||||
}
|
||||
}
|
||||
report_begin("fstat fd after dup2 to itself");
|
||||
rv = fstat(testfd, &sb);
|
||||
if (errno == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_result(rv, errno);
|
||||
if (rv == 0) {
|
||||
report_passed();
|
||||
} else if (errno != ENOSYS) {
|
||||
report_failure();
|
||||
} else {
|
||||
report_skipped();
|
||||
/* no support for fstat; try lseek */
|
||||
report_begin("lseek fd after dup2 to itself");
|
||||
rv = lseek(testfd, 0, SEEK_CUR);
|
||||
report_result(rv, errno);
|
||||
if (rv == 0 || (rv == -1 && errno == ESPIPE)) {
|
||||
report_passed();
|
||||
} else {
|
||||
report_failure();
|
||||
}
|
||||
}
|
||||
|
||||
close(testfd);
|
||||
close(testfd);
|
||||
}
|
||||
|
||||
void
|
||||
test_dup2(void)
|
||||
{
|
||||
/* This does the first fd. */
|
||||
test_dup2_fd();
|
||||
void test_dup2(void) {
|
||||
/* This does the first fd. */
|
||||
test_dup2_fd();
|
||||
|
||||
/* Any interesting cases added here should also go in common_fds.c */
|
||||
dup2_fd2(-1, "dup2 to -1");
|
||||
dup2_fd2(-5, "dup2 to -5");
|
||||
dup2_fd2(IMPOSSIBLE_FD, "dup2 to impossible fd");
|
||||
/* Any interesting cases added here should also go in common_fds.c */
|
||||
dup2_fd2(-1, "dup2 to -1");
|
||||
dup2_fd2(-5, "dup2 to -5");
|
||||
dup2_fd2(IMPOSSIBLE_FD, "dup2 to impossible fd");
|
||||
#ifdef OPEN_MAX
|
||||
dup2_fd2(OPEN_MAX, "dup2 to OPEN_MAX");
|
||||
dup2_fd2(OPEN_MAX, "dup2 to OPEN_MAX");
|
||||
#else
|
||||
warnx("Warning: OPEN_MAX not defined - test skipped");
|
||||
warnx("Warning: OPEN_MAX not defined - test skipped");
|
||||
#endif
|
||||
|
||||
dup2_self();
|
||||
dup2_self();
|
||||
}
|
||||
|
||||
@@ -40,142 +40,124 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
int
|
||||
exec_common_fork(void)
|
||||
{
|
||||
int pid, rv, status, err;
|
||||
static int exec_common_fork(void) {
|
||||
int pid, rv, status, err;
|
||||
|
||||
/*
|
||||
* This does not happen in a test context (from the point of
|
||||
* view of report.c) so we have to fiddle a bit.
|
||||
*/
|
||||
/*
|
||||
* This does not happen in a test context (from the point of
|
||||
* view of report.c) so we have to fiddle a bit.
|
||||
*/
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
err = errno;
|
||||
report_begin("forking for test");
|
||||
report_result(pid, err);
|
||||
report_aborted();
|
||||
return -1;
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
err = errno;
|
||||
report_begin("forking for test");
|
||||
report_result(pid, err);
|
||||
report_aborted();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid==0) {
|
||||
/* child */
|
||||
return 0;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv == -1) {
|
||||
err = errno;
|
||||
report_begin("waiting for test subprocess");
|
||||
report_result(rv, err);
|
||||
report_failure();
|
||||
return -1;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == MAGIC_STATUS) {
|
||||
return 1;
|
||||
}
|
||||
/* Oops... */
|
||||
report_begin("exit code of subprocess; should be %d", MAGIC_STATUS);
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("signal %d", WTERMSIG(status));
|
||||
}
|
||||
else {
|
||||
report_warnx("exit %d", WEXITSTATUS(status));
|
||||
}
|
||||
report_failure();
|
||||
return -1;
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv == -1) {
|
||||
err = errno;
|
||||
report_begin("waiting for test subprocess");
|
||||
report_result(rv, err);
|
||||
report_failure();
|
||||
return -1;
|
||||
}
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == MAGIC_STATUS) {
|
||||
return 1;
|
||||
}
|
||||
/* Oops... */
|
||||
report_begin("exit code of subprocess; should be %d", MAGIC_STATUS);
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("signal %d", WTERMSIG(status));
|
||||
} else {
|
||||
report_warnx("exit %d", WEXITSTATUS(status));
|
||||
}
|
||||
report_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_badprog(const void *prog, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
static void exec_badprog(const void *prog, const char *desc) {
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin(desc);
|
||||
rv = execv(prog, args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin(desc);
|
||||
rv = execv(prog, args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_emptyprog(void)
|
||||
{
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
static void exec_emptyprog(void) {
|
||||
int rv;
|
||||
char *args[2];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = NULL;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin("exec the empty string");
|
||||
rv = execv("", args);
|
||||
report_check2(rv, errno, EINVAL, EISDIR);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin("exec the empty string");
|
||||
rv = execv("", args);
|
||||
report_check2(rv, errno, EINVAL, EISDIR);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_badargs(void *args, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void exec_badargs(void *args, const char *desc) {
|
||||
int rv;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
exec_onearg(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void exec_onearg(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
char *args[3];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = (char *)ptr;
|
||||
args[2] = NULL;
|
||||
char *args[3];
|
||||
args[0] = (char *)"foo";
|
||||
args[1] = (char *)ptr;
|
||||
args[2] = NULL;
|
||||
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
if (exec_common_fork() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
report_begin(desc);
|
||||
rv = execv("/bin/true", args);
|
||||
report_check(rv, errno, EFAULT);
|
||||
exit(MAGIC_STATUS);
|
||||
}
|
||||
|
||||
void
|
||||
test_execv(void)
|
||||
{
|
||||
exec_badprog(NULL, "exec with NULL program");
|
||||
exec_badprog(INVAL_PTR, "exec with invalid pointer program");
|
||||
exec_badprog(KERN_PTR, "exec with kernel pointer program");
|
||||
void test_execv(void) {
|
||||
exec_badprog(NULL, "exec with NULL program");
|
||||
exec_badprog(INVAL_PTR, "exec with invalid pointer program");
|
||||
exec_badprog(KERN_PTR, "exec with kernel pointer program");
|
||||
|
||||
exec_emptyprog();
|
||||
exec_emptyprog();
|
||||
|
||||
exec_badargs(NULL, "exec with NULL arglist");
|
||||
exec_badargs(INVAL_PTR, "exec with invalid pointer arglist");
|
||||
exec_badargs(KERN_PTR, "exec with kernel pointer arglist");
|
||||
exec_badargs(NULL, "exec with NULL arglist");
|
||||
exec_badargs(INVAL_PTR, "exec with invalid pointer arglist");
|
||||
exec_badargs(KERN_PTR, "exec with kernel pointer arglist");
|
||||
|
||||
exec_onearg(INVAL_PTR, "exec with invalid pointer arg");
|
||||
exec_onearg(KERN_PTR, "exec with kernel pointer arg");
|
||||
exec_onearg(INVAL_PTR, "exec with invalid pointer arg");
|
||||
exec_onearg(KERN_PTR, "exec with kernel pointer arg");
|
||||
}
|
||||
|
||||
@@ -33,9 +33,4 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_fsync(void)
|
||||
{
|
||||
test_fsync_fd();
|
||||
}
|
||||
|
||||
void test_fsync(void) { test_fsync_fd(); }
|
||||
|
||||
@@ -43,53 +43,45 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
ftruncate_fd_device(void)
|
||||
{
|
||||
int rv, fd;
|
||||
static void ftruncate_fd_device(void) {
|
||||
int rv, fd;
|
||||
|
||||
report_begin("ftruncate on device");
|
||||
report_begin("ftruncate on device");
|
||||
|
||||
fd = open("null:", O_RDWR);
|
||||
if (fd<0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open("null:", O_RDWR);
|
||||
if (fd < 0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = ftruncate(fd, 6);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = ftruncate(fd, 6);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ftruncate_size_neg(void)
|
||||
{
|
||||
int rv, fd;
|
||||
static void ftruncate_size_neg(void) {
|
||||
int rv, fd;
|
||||
|
||||
report_begin("ftruncate to negative size");
|
||||
report_begin("ftruncate to negative size");
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = ftruncate(fd, -60);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = ftruncate(fd, -60);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
void
|
||||
test_ftruncate(void)
|
||||
{
|
||||
test_ftruncate_fd();
|
||||
void test_ftruncate(void) {
|
||||
test_ftruncate_fd();
|
||||
|
||||
ftruncate_fd_device();
|
||||
ftruncate_size_neg();
|
||||
ftruncate_fd_device();
|
||||
ftruncate_size_neg();
|
||||
}
|
||||
|
||||
@@ -33,8 +33,4 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_getcwd(void)
|
||||
{
|
||||
test_getcwd_buf();
|
||||
}
|
||||
void test_getcwd(void) { test_getcwd_buf(); }
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_getdirentry(void)
|
||||
{
|
||||
test_getdirentry_fd();
|
||||
test_getdirentry_buf();
|
||||
void test_getdirentry(void) {
|
||||
test_getdirentry_fd();
|
||||
test_getdirentry_buf();
|
||||
}
|
||||
|
||||
@@ -40,64 +40,49 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
one_ioctl_badbuf(int fd, int code, const char *codename,
|
||||
void *ptr, const char *ptrdesc)
|
||||
{
|
||||
int rv;
|
||||
static void one_ioctl_badbuf(int fd, int code, const char *codename, void *ptr,
|
||||
const char *ptrdesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("ioctl %s with %s", codename, ptrdesc);
|
||||
rv = ioctl(fd, code, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("ioctl %s with %s", codename, ptrdesc);
|
||||
rv = ioctl(fd, code, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
any_ioctl_badbuf(int fd, int code, const char *codename)
|
||||
{
|
||||
one_ioctl_badbuf(fd, code, codename, NULL, "NULL pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, INVAL_PTR, "invalid pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, KERN_PTR, "kernel pointer");
|
||||
static void any_ioctl_badbuf(int fd, int code, const char *codename) {
|
||||
one_ioctl_badbuf(fd, code, codename, NULL, "NULL pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, INVAL_PTR, "invalid pointer");
|
||||
one_ioctl_badbuf(fd, code, codename, KERN_PTR, "kernel pointer");
|
||||
}
|
||||
|
||||
#define IOCTL(fd, sym) any_ioctl_badbuf(fd, sym, #sym)
|
||||
|
||||
static
|
||||
void
|
||||
ioctl_badbuf(void)
|
||||
{
|
||||
/*
|
||||
* Since we don't actually define any ioctls, this code won't
|
||||
* actually run. But if you do define ioctls, turn these tests
|
||||
* on for those that actually use the data buffer argument for
|
||||
* anything.
|
||||
*/
|
||||
static void ioctl_badbuf(void) {
|
||||
/*
|
||||
* Since we don't actually define any ioctls, this code won't
|
||||
* actually run. But if you do define ioctls, turn these tests
|
||||
* on for those that actually use the data buffer argument for
|
||||
* anything.
|
||||
*/
|
||||
|
||||
/* IOCTL(STDIN_FILENO, TIOCGETA); */
|
||||
/* IOCTL(STDIN_FILENO, TIOCGETA); */
|
||||
|
||||
|
||||
/* suppress gcc warning */
|
||||
(void)any_ioctl_badbuf;
|
||||
/* suppress gcc warning */
|
||||
(void)any_ioctl_badbuf;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ioctl_badcode(void)
|
||||
{
|
||||
int rv;
|
||||
static void ioctl_badcode(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("invalid ioctl");
|
||||
rv = ioctl(STDIN_FILENO, NONEXIST_IOCTL, NULL);
|
||||
report_check(rv, errno, EIOCTL);
|
||||
report_begin("invalid ioctl");
|
||||
rv = ioctl(STDIN_FILENO, NONEXIST_IOCTL, NULL);
|
||||
report_check(rv, errno, EIOCTL);
|
||||
}
|
||||
|
||||
void
|
||||
test_ioctl(void)
|
||||
{
|
||||
test_ioctl_fd();
|
||||
void test_ioctl(void) {
|
||||
test_ioctl_fd();
|
||||
|
||||
/* Since we don't actually define any ioctls, this is not meaningful */
|
||||
ioctl_badcode();
|
||||
ioctl_badbuf();
|
||||
/* Since we don't actually define any ioctls, this is not meaningful */
|
||||
ioctl_badcode();
|
||||
ioctl_badbuf();
|
||||
}
|
||||
|
||||
@@ -36,53 +36,42 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
link_dir(void)
|
||||
{
|
||||
int rv;
|
||||
static void link_dir(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("hard link of .");
|
||||
rv = link(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv==0) {
|
||||
/* this might help recover... maybe */
|
||||
remove(TESTDIR);
|
||||
}
|
||||
report_begin("hard link of .");
|
||||
rv = link(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* this might help recover... maybe */
|
||||
remove(TESTDIR);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
link_empty1(void)
|
||||
{
|
||||
int rv;
|
||||
static void link_empty1(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("hard link of empty string");
|
||||
rv = link("", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("hard link of empty string");
|
||||
rv = link("", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
link_empty2(void)
|
||||
{
|
||||
int rv;
|
||||
static void link_empty2(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("hard link to empty string");
|
||||
if (create_testdir()<0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = link(TESTDIR, "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
report_begin("hard link to empty string");
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = link(TESTDIR, "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
void
|
||||
test_link(void)
|
||||
{
|
||||
test_link_paths();
|
||||
link_dir();
|
||||
link_empty1();
|
||||
link_empty2();
|
||||
void test_link(void) {
|
||||
test_link_paths();
|
||||
link_dir();
|
||||
link_empty1();
|
||||
link_empty2();
|
||||
}
|
||||
|
||||
@@ -43,236 +43,213 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
lseek_fd_device(void)
|
||||
{
|
||||
int fd, rv;
|
||||
static void lseek_fd_device(void) {
|
||||
int fd, rv;
|
||||
|
||||
report_begin("lseek on device");
|
||||
report_begin("lseek on device");
|
||||
|
||||
fd = open("null:", O_RDONLY);
|
||||
if (fd<0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open("null:", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
report_warn("opening null: failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = lseek(fd, 309, SEEK_SET);
|
||||
report_check(rv, errno, ESPIPE);
|
||||
rv = lseek(fd, 309, SEEK_SET);
|
||||
report_check(rv, errno, ESPIPE);
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_file_stdin(void)
|
||||
{
|
||||
int fd, fd2, rv, status;
|
||||
const char slogan[] = "There ain't no such thing as a free lunch";
|
||||
size_t len = strlen(slogan);
|
||||
pid_t pid;
|
||||
static void lseek_file_stdin(void) {
|
||||
int fd, fd2, rv, status;
|
||||
const char slogan[] = "There ain't no such thing as a free lunch";
|
||||
size_t len = strlen(slogan);
|
||||
pid_t pid;
|
||||
|
||||
report_begin("lseek stdin when open on file");
|
||||
report_begin("lseek stdin when open on file");
|
||||
|
||||
/* fork so we don't affect our own stdin */
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
else if (pid!=0) {
|
||||
/* parent */
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv<0) {
|
||||
report_warn("waitpid failed");
|
||||
report_aborted();
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("subprocess exited with signal %d",
|
||||
WTERMSIG(status));
|
||||
report_aborted();
|
||||
}
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
report_warnx("subprocess exited with code %d",
|
||||
WEXITSTATUS(status));
|
||||
report_aborted();
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* fork so we don't affect our own stdin */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
} else if (pid != 0) {
|
||||
/* parent */
|
||||
rv = waitpid(pid, &status, 0);
|
||||
if (rv < 0) {
|
||||
report_warn("waitpid failed");
|
||||
report_aborted();
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
report_warnx("subprocess exited with signal %d", WTERMSIG(status));
|
||||
report_aborted();
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
report_warnx("subprocess exited with code %d", WEXITSTATUS(status));
|
||||
report_aborted();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* child */
|
||||
/* child */
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
_exit(0);
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move file to stdin.
|
||||
* Use stdin (rather than stdout or stderr) to maximize the
|
||||
* chances of detecting any special-case handling of fds 0-2.
|
||||
* (Writing to stdin is fine as long as it's open for write,
|
||||
* and it will be.)
|
||||
*/
|
||||
fd2 = dup2(fd, STDIN_FILENO);
|
||||
if (fd2<0) {
|
||||
report_warn("dup2 to stdin failed");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
if (fd2 != STDIN_FILENO) {
|
||||
report_warn("dup2 returned wrong file handle");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
close(fd);
|
||||
/*
|
||||
* Move file to stdin.
|
||||
* Use stdin (rather than stdout or stderr) to maximize the
|
||||
* chances of detecting any special-case handling of fds 0-2.
|
||||
* (Writing to stdin is fine as long as it's open for write,
|
||||
* and it will be.)
|
||||
*/
|
||||
fd2 = dup2(fd, STDIN_FILENO);
|
||||
if (fd2 < 0) {
|
||||
report_warn("dup2 to stdin failed");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
if (fd2 != STDIN_FILENO) {
|
||||
report_warn("dup2 returned wrong file handle");
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
rv = write(STDIN_FILENO, slogan, len);
|
||||
if (rv<0) {
|
||||
report_warn("write to %s (via stdin) failed", TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
rv = write(STDIN_FILENO, slogan, len);
|
||||
if (rv < 0) {
|
||||
report_warn("write to %s (via stdin) failed", TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if ((unsigned)rv != len) {
|
||||
report_warnx("write to %s (via stdin) got short count",
|
||||
TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
if ((unsigned)rv != len) {
|
||||
report_warnx("write to %s (via stdin) got short count", TESTFILE);
|
||||
remove(TESTFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* blah */
|
||||
report_skipped();
|
||||
/* blah */
|
||||
report_skipped();
|
||||
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_SET);
|
||||
report_begin("try 1: SEEK_SET");
|
||||
report_check(rv, errno, 0);
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_SET);
|
||||
report_begin("try 1: SEEK_SET");
|
||||
report_check(rv, errno, 0);
|
||||
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_END);
|
||||
report_begin("try 2: SEEK_END");
|
||||
report_check(rv, errno, 0);
|
||||
rv = lseek(STDIN_FILENO, 0, SEEK_END);
|
||||
report_begin("try 2: SEEK_END");
|
||||
report_check(rv, errno, 0);
|
||||
|
||||
remove(TESTFILE);
|
||||
_exit(0);
|
||||
remove(TESTFILE);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_loc_negative(void)
|
||||
{
|
||||
int fd, rv;
|
||||
static void lseek_loc_negative(void) {
|
||||
int fd, rv;
|
||||
|
||||
report_begin("lseek to negative offset");
|
||||
report_begin("lseek to negative offset");
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = lseek(fd, -309, SEEK_SET);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = lseek(fd, -309, SEEK_SET);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_whence_inval(void)
|
||||
{
|
||||
int fd, rv;
|
||||
static void lseek_whence_inval(void) {
|
||||
int fd, rv;
|
||||
|
||||
report_begin("lseek with invalid whence code");
|
||||
report_begin("lseek with invalid whence code");
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
rv = lseek(fd, 0, 3594);
|
||||
report_check(rv, errno, EINVAL);
|
||||
rv = lseek(fd, 0, 3594);
|
||||
report_check(rv, errno, EINVAL);
|
||||
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
lseek_loc_pasteof(void)
|
||||
{
|
||||
const char *message = "blahblah";
|
||||
int fd;
|
||||
off_t pos;
|
||||
static void lseek_loc_pasteof(void) {
|
||||
const char *message = "blahblah";
|
||||
int fd;
|
||||
off_t pos;
|
||||
|
||||
report_begin("seek past/to EOF");
|
||||
report_begin("seek past/to EOF");
|
||||
|
||||
fd = open_testfile(message);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(message);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
pos = lseek(fd, 5340, SEEK_SET);
|
||||
if (pos == -1) {
|
||||
report_warn("lseek past EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5340) {
|
||||
report_warnx("lseek to 5340 got offset %lld", (long long) pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
pos = lseek(fd, 5340, SEEK_SET);
|
||||
if (pos == -1) {
|
||||
report_warn("lseek past EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5340) {
|
||||
report_warnx("lseek to 5340 got offset %lld", (long long)pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos = lseek(fd, -50, SEEK_CUR);
|
||||
if (pos == -1) {
|
||||
report_warn("small seek beyond EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5290) {
|
||||
report_warnx("SEEK_CUR to 5290 got offset %lld",
|
||||
(long long) pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
pos = lseek(fd, -50, SEEK_CUR);
|
||||
if (pos == -1) {
|
||||
report_warn("small seek beyond EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != 5290) {
|
||||
report_warnx("SEEK_CUR to 5290 got offset %lld", (long long)pos);
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos = lseek(fd, 0, SEEK_END);
|
||||
if (pos == -1) {
|
||||
report_warn("seek to EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
pos = lseek(fd, 0, SEEK_END);
|
||||
if (pos == -1) {
|
||||
report_warn("seek to EOF failed");
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pos != (off_t) strlen(message)) {
|
||||
report_warnx("seek to EOF got %lld (should be %zu)",
|
||||
(long long) pos, strlen(message));
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
if (pos != (off_t)strlen(message)) {
|
||||
report_warnx("seek to EOF got %lld (should be %zu)", (long long)pos,
|
||||
strlen(message));
|
||||
report_failure();
|
||||
goto out;
|
||||
}
|
||||
|
||||
report_passed();
|
||||
report_passed();
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return;
|
||||
out:
|
||||
close(fd);
|
||||
remove(TESTFILE);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
test_lseek(void)
|
||||
{
|
||||
test_lseek_fd();
|
||||
void test_lseek(void) {
|
||||
test_lseek_fd();
|
||||
|
||||
lseek_fd_device();
|
||||
lseek_file_stdin();
|
||||
lseek_loc_negative();
|
||||
lseek_loc_pasteof();
|
||||
lseek_whence_inval();
|
||||
lseek_fd_device();
|
||||
lseek_file_stdin();
|
||||
lseek_loc_negative();
|
||||
lseek_loc_pasteof();
|
||||
lseek_whence_inval();
|
||||
}
|
||||
|
||||
@@ -43,45 +43,34 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void mkdir_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("mkdir .");
|
||||
rv = mkdir(".", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
report_begin("mkdir .");
|
||||
rv = mkdir(".", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void mkdir_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("mkdir ..");
|
||||
rv = mkdir("..", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
report_begin("mkdir ..");
|
||||
rv = mkdir("..", 0775);
|
||||
report_check(rv, errno, EEXIST);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
mkdir_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void mkdir_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("mkdir of empty string");
|
||||
rv = mkdir("", 0775);
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("mkdir of empty string");
|
||||
rv = mkdir("", 0775);
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_mkdir(void)
|
||||
{
|
||||
test_mkdir_path();
|
||||
void test_mkdir(void) {
|
||||
test_mkdir_path();
|
||||
|
||||
mkdir_dot();
|
||||
mkdir_dotdot();
|
||||
mkdir_empty();
|
||||
mkdir_dot();
|
||||
mkdir_dotdot();
|
||||
mkdir_empty();
|
||||
}
|
||||
|
||||
@@ -43,36 +43,28 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
open_badflags(void)
|
||||
{
|
||||
int fd;
|
||||
static void open_badflags(void) {
|
||||
int fd;
|
||||
|
||||
report_begin("open null: with bad flags");
|
||||
fd = open("null:", 309842);
|
||||
report_check(fd, errno, EINVAL);
|
||||
report_begin("open null: with bad flags");
|
||||
fd = open("null:", 309842);
|
||||
report_check(fd, errno, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
open_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void open_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("open empty string");
|
||||
rv = open("", O_RDONLY);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv>=0) {
|
||||
close(rv);
|
||||
}
|
||||
report_begin("open empty string");
|
||||
rv = open("", O_RDONLY);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv >= 0) {
|
||||
close(rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_open(void)
|
||||
{
|
||||
test_open_path();
|
||||
void test_open(void) {
|
||||
test_open_path();
|
||||
|
||||
open_badflags();
|
||||
open_empty();
|
||||
open_badflags();
|
||||
open_empty();
|
||||
}
|
||||
|
||||
@@ -43,44 +43,36 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
pipe_badptr(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void pipe_badptr(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = pipe(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("%s", desc);
|
||||
rv = pipe(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
pipe_unaligned(void)
|
||||
{
|
||||
int fds[3], rv;
|
||||
char *ptr;
|
||||
static void pipe_unaligned(void) {
|
||||
int fds[3], rv;
|
||||
char *ptr;
|
||||
|
||||
report_begin("pipe with unaligned pointer");
|
||||
report_begin("pipe with unaligned pointer");
|
||||
|
||||
ptr = (char *)&fds[0];
|
||||
ptr++;
|
||||
ptr = (char *)&fds[0];
|
||||
ptr++;
|
||||
|
||||
rv = pipe((int *)ptr);
|
||||
report_survival(rv, errno);
|
||||
if (rv == 0) {
|
||||
memmove(fds, ptr, 2*sizeof(int));
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
}
|
||||
rv = pipe((int *)ptr);
|
||||
report_survival(rv, errno);
|
||||
if (rv == 0) {
|
||||
memmove(fds, ptr, 2 * sizeof(int));
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_pipe(void)
|
||||
{
|
||||
pipe_badptr(NULL, "pipe with NULL pointer");
|
||||
pipe_badptr(INVAL_PTR, "pipe with invalid pointer");
|
||||
pipe_badptr(KERN_PTR, "pipe with kernel pointer");
|
||||
void test_pipe(void) {
|
||||
pipe_badptr(NULL, "pipe with NULL pointer");
|
||||
pipe_badptr(INVAL_PTR, "pipe with invalid pointer");
|
||||
pipe_badptr(KERN_PTR, "pipe with kernel pointer");
|
||||
|
||||
pipe_unaligned();
|
||||
pipe_unaligned();
|
||||
}
|
||||
|
||||
@@ -33,10 +33,7 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_read(void)
|
||||
{
|
||||
test_read_fd();
|
||||
test_read_buf();
|
||||
void test_read(void) {
|
||||
test_read_fd();
|
||||
test_read_buf();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,57 +36,45 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
readlink_file(void)
|
||||
{
|
||||
char buf[128];
|
||||
int fd, rv;
|
||||
static void readlink_file(void) {
|
||||
char buf[128];
|
||||
int fd, rv;
|
||||
|
||||
report_begin("readlink on file");
|
||||
fd = open_testfile("the question contains an invalid assumption");
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
rv = readlink(TESTFILE, buf, sizeof(buf));
|
||||
report_check(rv, errno, EINVAL);
|
||||
remove(TESTFILE);
|
||||
report_begin("readlink on file");
|
||||
fd = open_testfile("the question contains an invalid assumption");
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
rv = readlink(TESTFILE, buf, sizeof(buf));
|
||||
report_check(rv, errno, EINVAL);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readlink_dir(void)
|
||||
{
|
||||
char buf[128];
|
||||
int rv;
|
||||
static void readlink_dir(void) {
|
||||
char buf[128];
|
||||
int rv;
|
||||
|
||||
report_begin("readlink on .");
|
||||
rv = readlink(".", buf, sizeof(buf));
|
||||
report_check(rv, errno, EISDIR);
|
||||
report_begin("readlink on .");
|
||||
rv = readlink(".", buf, sizeof(buf));
|
||||
report_check(rv, errno, EISDIR);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readlink_empty(void)
|
||||
{
|
||||
char buf[128];
|
||||
int rv;
|
||||
static void readlink_empty(void) {
|
||||
char buf[128];
|
||||
int rv;
|
||||
|
||||
report_begin("readlink on empty string");
|
||||
rv = readlink("", buf, sizeof(buf));
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("readlink on empty string");
|
||||
rv = readlink("", buf, sizeof(buf));
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_readlink(void)
|
||||
{
|
||||
test_readlink_path();
|
||||
test_readlink_buf();
|
||||
void test_readlink(void) {
|
||||
test_readlink_path();
|
||||
test_readlink_buf();
|
||||
|
||||
readlink_file();
|
||||
readlink_dir();
|
||||
readlink_empty();
|
||||
readlink_file();
|
||||
readlink_dir();
|
||||
readlink_empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,20 +43,13 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
reboot_badflags(void)
|
||||
{
|
||||
int rv;
|
||||
static void reboot_badflags(void) {
|
||||
int rv;
|
||||
|
||||
printf("(This should not kill the system...)\n");
|
||||
report_begin("reboot with invalid flags");
|
||||
rv = reboot(15353);
|
||||
report_check(rv, errno, EINVAL);
|
||||
printf("(This should not kill the system...)\n");
|
||||
report_begin("reboot with invalid flags");
|
||||
rv = reboot(15353);
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_reboot(void)
|
||||
{
|
||||
reboot_badflags();
|
||||
}
|
||||
void test_reboot(void) { reboot_badflags(); }
|
||||
|
||||
@@ -43,64 +43,50 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
remove_dir(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_dir(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on a directory");
|
||||
report_begin("remove() on a directory");
|
||||
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
|
||||
rv = remove(TESTDIR);
|
||||
report_check(rv, errno, EISDIR);
|
||||
rmdir(TESTDIR);
|
||||
rv = remove(TESTDIR);
|
||||
report_check(rv, errno, EISDIR);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on .");
|
||||
rv = remove(".");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("remove() on .");
|
||||
rv = remove(".");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on ..");
|
||||
rv = remove("..");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("remove() on ..");
|
||||
rv = remove("..");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
remove_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void remove_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("remove() on empty string");
|
||||
rv = remove("");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
report_begin("remove() on empty string");
|
||||
rv = remove("");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_remove(void)
|
||||
{
|
||||
test_remove_path();
|
||||
void test_remove(void) {
|
||||
test_remove_path();
|
||||
|
||||
remove_dir();
|
||||
remove_dot();
|
||||
remove_dotdot();
|
||||
remove_empty();
|
||||
remove_dir();
|
||||
remove_dot();
|
||||
remove_dotdot();
|
||||
remove_empty();
|
||||
}
|
||||
|
||||
@@ -36,76 +36,61 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
rename_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename .");
|
||||
report_begin("rename .");
|
||||
|
||||
rv = rename(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv==0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, ".");
|
||||
}
|
||||
rv = rename(".", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, ".");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rename_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename ..");
|
||||
rv = rename("..", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv==0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, "..");
|
||||
}
|
||||
report_begin("rename ..");
|
||||
rv = rename("..", TESTDIR);
|
||||
report_check(rv, errno, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* oops... put it back */
|
||||
rename(TESTDIR, "..");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rename_empty1(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_empty1(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename empty string");
|
||||
rv = rename("", TESTDIR);
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
if (rv==0) {
|
||||
/* don't try to remove it */
|
||||
rename(TESTDIR, TESTDIR "-foo");
|
||||
}
|
||||
report_begin("rename empty string");
|
||||
rv = rename("", TESTDIR);
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
if (rv == 0) {
|
||||
/* don't try to remove it */
|
||||
rename(TESTDIR, TESTDIR "-foo");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rename_empty2(void)
|
||||
{
|
||||
int rv;
|
||||
static void rename_empty2(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rename to empty string");
|
||||
if (create_testdir()<0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = rename(TESTDIR, "");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
report_begin("rename to empty string");
|
||||
if (create_testdir() < 0) {
|
||||
/*report_aborted();*/ /* XXX in create_testdir */
|
||||
return;
|
||||
}
|
||||
rv = rename(TESTDIR, "");
|
||||
report_check2(rv, errno, EISDIR, EINVAL);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
void
|
||||
test_rename(void)
|
||||
{
|
||||
test_rename_paths();
|
||||
void test_rename(void) {
|
||||
test_rename_paths();
|
||||
|
||||
rename_dot();
|
||||
rename_dotdot();
|
||||
rename_empty1();
|
||||
rename_empty2();
|
||||
rename_dot();
|
||||
rename_dotdot();
|
||||
rename_empty1();
|
||||
rename_empty2();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,62 +43,48 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_file(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_file(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir a file");
|
||||
if (create_testfile()<0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
rv = rmdir(TESTFILE);
|
||||
report_check(rv, errno, ENOTDIR);
|
||||
remove(TESTFILE);
|
||||
report_begin("rmdir a file");
|
||||
if (create_testfile() < 0) {
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
rv = rmdir(TESTFILE);
|
||||
report_check(rv, errno, ENOTDIR);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_dot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_dot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir .");
|
||||
rv = rmdir(".");
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("rmdir .");
|
||||
rv = rmdir(".");
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_dotdot(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_dotdot(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir ..");
|
||||
rv = rmdir("..");
|
||||
report_check2(rv, errno, EINVAL, ENOTEMPTY);
|
||||
report_begin("rmdir ..");
|
||||
rv = rmdir("..");
|
||||
report_check2(rv, errno, EINVAL, ENOTEMPTY);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
rmdir_empty(void)
|
||||
{
|
||||
int rv;
|
||||
static void rmdir_empty(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("rmdir empty string");
|
||||
rv = rmdir("");
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("rmdir empty string");
|
||||
rv = rmdir("");
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_rmdir(void)
|
||||
{
|
||||
test_rmdir_path();
|
||||
void test_rmdir(void) {
|
||||
test_rmdir_path();
|
||||
|
||||
rmdir_file();
|
||||
rmdir_dot();
|
||||
rmdir_dotdot();
|
||||
rmdir_empty();
|
||||
rmdir_file();
|
||||
rmdir_dot();
|
||||
rmdir_dotdot();
|
||||
rmdir_empty();
|
||||
}
|
||||
|
||||
@@ -46,80 +46,56 @@
|
||||
/*
|
||||
* typing wrapper around sbrk
|
||||
*/
|
||||
static
|
||||
int
|
||||
try_sbrk(long val)
|
||||
{
|
||||
void *rv;
|
||||
rv = sbrk(val);
|
||||
if (rv==(void *)-1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
static int try_sbrk(long val) {
|
||||
void *rv;
|
||||
rv = sbrk(val);
|
||||
if (rv == (void *)-1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
enforce_sbrk(long val, const char *desc, int err)
|
||||
{
|
||||
int result;
|
||||
static void enforce_sbrk(long val, const char *desc, int err) {
|
||||
int result;
|
||||
|
||||
report_begin("sbrk %s", desc);
|
||||
report_begin("sbrk %s", desc);
|
||||
|
||||
result = try_sbrk(val);
|
||||
report_check(result, errno, err);
|
||||
result = try_sbrk(val);
|
||||
report_check(result, errno, err);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_bigpos(void)
|
||||
{
|
||||
enforce_sbrk(4096*1024*256, "huge positive", ENOMEM);
|
||||
static void sbrk_bigpos(void) {
|
||||
enforce_sbrk(4096 * 1024 * 256, "huge positive", ENOMEM);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_bigneg(void)
|
||||
{
|
||||
enforce_sbrk(-4096*1024*256, "huge negative", EINVAL);
|
||||
static void sbrk_bigneg(void) {
|
||||
enforce_sbrk(-4096 * 1024 * 256, "huge negative", EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_neg(void)
|
||||
{
|
||||
enforce_sbrk(-8192, "too-large negative", EINVAL);
|
||||
static void sbrk_neg(void) {
|
||||
enforce_sbrk(-8192, "too-large negative", EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_unalignedpos(void)
|
||||
{
|
||||
int result;
|
||||
static void sbrk_unalignedpos(void) {
|
||||
int result;
|
||||
|
||||
report_begin("sbrk unaligned positive");
|
||||
result = try_sbrk(17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
report_begin("sbrk unaligned positive");
|
||||
result = try_sbrk(17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sbrk_unalignedneg(void)
|
||||
{
|
||||
int result;
|
||||
static void sbrk_unalignedneg(void) {
|
||||
int result;
|
||||
|
||||
report_begin("sbrk unaligned negative");
|
||||
result = try_sbrk(-17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
report_begin("sbrk unaligned negative");
|
||||
result = try_sbrk(-17);
|
||||
report_check2(result, errno, 0, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_sbrk(void)
|
||||
{
|
||||
sbrk_neg();
|
||||
sbrk_bigpos();
|
||||
sbrk_bigneg();
|
||||
sbrk_unalignedpos();
|
||||
sbrk_unalignedneg();
|
||||
void test_sbrk(void) {
|
||||
sbrk_neg();
|
||||
sbrk_bigpos();
|
||||
sbrk_bigneg();
|
||||
sbrk_unalignedpos();
|
||||
sbrk_unalignedneg();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,84 +45,54 @@
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
int
|
||||
badbuf_fstat(struct stat *sb)
|
||||
{
|
||||
return fstat(STDIN_FILENO, sb);
|
||||
static int badbuf_fstat(struct stat *sb) { return fstat(STDIN_FILENO, sb); }
|
||||
|
||||
static int badbuf_lstat(struct stat *sb) { return lstat("null:", sb); }
|
||||
|
||||
static int badbuf_stat(struct stat *sb) { return stat("null:", sb); }
|
||||
|
||||
static void common_badbuf(int (*statfunc)(struct stat *), void *ptr,
|
||||
const char *call, const char *ptrdesc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s with %s buf", call, ptrdesc);
|
||||
rv = statfunc(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
badbuf_lstat(struct stat *sb)
|
||||
{
|
||||
return lstat("null:", sb);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
badbuf_stat(struct stat *sb)
|
||||
{
|
||||
return stat("null:", sb);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
common_badbuf(int (*statfunc)(struct stat *), void *ptr,
|
||||
const char *call, const char *ptrdesc)
|
||||
{
|
||||
int rv;
|
||||
|
||||
report_begin("%s with %s buf", call, ptrdesc);
|
||||
rv = statfunc(ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
any_badbuf(int (*statfunc)(struct stat *), const char *call)
|
||||
{
|
||||
common_badbuf(statfunc, NULL, call, "NULL");
|
||||
common_badbuf(statfunc, INVAL_PTR, call, "invalid pointer");
|
||||
common_badbuf(statfunc, KERN_PTR, call, "kernel pointer");
|
||||
static void any_badbuf(int (*statfunc)(struct stat *), const char *call) {
|
||||
common_badbuf(statfunc, NULL, call, "NULL");
|
||||
common_badbuf(statfunc, INVAL_PTR, call, "invalid pointer");
|
||||
common_badbuf(statfunc, KERN_PTR, call, "kernel pointer");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
any_empty(int (*statfunc)(const char *, struct stat *), const char *call)
|
||||
{
|
||||
struct stat sb;
|
||||
int rv;
|
||||
static void any_empty(int (*statfunc)(const char *, struct stat *),
|
||||
const char *call) {
|
||||
struct stat sb;
|
||||
int rv;
|
||||
|
||||
report_begin("%s on empty string", call);
|
||||
rv = statfunc("", &sb);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
report_begin("%s on empty string", call);
|
||||
rv = statfunc("", &sb);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
test_fstat(void)
|
||||
{
|
||||
test_fstat_fd();
|
||||
any_badbuf(badbuf_fstat, "fstat");
|
||||
void test_fstat(void) {
|
||||
test_fstat_fd();
|
||||
any_badbuf(badbuf_fstat, "fstat");
|
||||
}
|
||||
|
||||
void
|
||||
test_lstat(void)
|
||||
{
|
||||
test_lstat_path();
|
||||
any_empty(lstat, "lstat");
|
||||
any_badbuf(badbuf_lstat, "lstat");
|
||||
void test_lstat(void) {
|
||||
test_lstat_path();
|
||||
any_empty(lstat, "lstat");
|
||||
any_badbuf(badbuf_lstat, "lstat");
|
||||
}
|
||||
|
||||
void
|
||||
test_stat(void)
|
||||
{
|
||||
test_stat_path();
|
||||
any_empty(stat, "stat");
|
||||
any_badbuf(badbuf_stat, "stat");
|
||||
void test_stat(void) {
|
||||
test_stat_path();
|
||||
any_empty(stat, "stat");
|
||||
any_badbuf(badbuf_stat, "stat");
|
||||
}
|
||||
|
||||
|
||||
@@ -36,33 +36,25 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
symlink_empty1(void)
|
||||
{
|
||||
int rv;
|
||||
static void symlink_empty1(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("symlink -> empty string");
|
||||
rv = symlink("", TESTLINK);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
remove(TESTLINK);
|
||||
report_begin("symlink -> empty string");
|
||||
rv = symlink("", TESTLINK);
|
||||
report_check2(rv, errno, 0, EINVAL);
|
||||
remove(TESTLINK);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
symlink_empty2(void)
|
||||
{
|
||||
int rv;
|
||||
static void symlink_empty2(void) {
|
||||
int rv;
|
||||
|
||||
report_begin("symlink named empty string");
|
||||
rv = symlink("foo", "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
report_begin("symlink named empty string");
|
||||
rv = symlink("foo", "");
|
||||
report_check(rv, errno, EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
test_symlink(void)
|
||||
{
|
||||
test_symlink_paths();
|
||||
symlink_empty1();
|
||||
symlink_empty2();
|
||||
void test_symlink(void) {
|
||||
test_symlink_paths();
|
||||
symlink_empty1();
|
||||
symlink_empty2();
|
||||
}
|
||||
|
||||
@@ -43,34 +43,26 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
time_badsecs(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void time_badsecs(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = __time(ptr, NULL);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("%s", desc);
|
||||
rv = __time(ptr, NULL);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
time_badnsecs(void *ptr, const char *desc)
|
||||
{
|
||||
int rv;
|
||||
static void time_badnsecs(void *ptr, const char *desc) {
|
||||
int rv;
|
||||
|
||||
report_begin("%s", desc);
|
||||
rv = __time(NULL, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
report_begin("%s", desc);
|
||||
rv = __time(NULL, ptr);
|
||||
report_check(rv, errno, EFAULT);
|
||||
}
|
||||
|
||||
void
|
||||
test_time(void)
|
||||
{
|
||||
time_badsecs(INVAL_PTR, "__time with invalid seconds pointer");
|
||||
time_badsecs(KERN_PTR, "__time with kernel seconds pointer");
|
||||
void test_time(void) {
|
||||
time_badsecs(INVAL_PTR, "__time with invalid seconds pointer");
|
||||
time_badsecs(KERN_PTR, "__time with kernel seconds pointer");
|
||||
|
||||
time_badnsecs(INVAL_PTR, "__time with invalid nsecs pointer");
|
||||
time_badnsecs(KERN_PTR, "__time with kernel nsecs pointer");
|
||||
time_badnsecs(INVAL_PTR, "__time with invalid nsecs pointer");
|
||||
time_badnsecs(KERN_PTR, "__time with kernel nsecs pointer");
|
||||
}
|
||||
|
||||
@@ -41,383 +41,344 @@
|
||||
#include "config.h"
|
||||
#include "test.h"
|
||||
|
||||
static
|
||||
void
|
||||
wait_badpid(pid_t pid, const char *desc)
|
||||
{
|
||||
pid_t rv;
|
||||
int x;
|
||||
int err;
|
||||
static void wait_badpid(pid_t pid, const char *desc) {
|
||||
pid_t rv;
|
||||
int x;
|
||||
int err;
|
||||
|
||||
report_begin(desc);
|
||||
rv = waitpid(pid, &x, 0);
|
||||
err = errno;
|
||||
/* Allow ENOSYS for 0 or negative values of pid only */
|
||||
if (pid <= 0 && rv == -1 && err == ENOSYS) {
|
||||
err = ESRCH;
|
||||
}
|
||||
else if (err == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_check2(rv, err, ESRCH, ECHILD);
|
||||
report_begin(desc);
|
||||
rv = waitpid(pid, &x, 0);
|
||||
err = errno;
|
||||
/* Allow ENOSYS for 0 or negative values of pid only */
|
||||
if (pid <= 0 && rv == -1 && err == ENOSYS) {
|
||||
err = ESRCH;
|
||||
} else if (err == ENOSYS) {
|
||||
report_saw_enosys();
|
||||
}
|
||||
report_check2(rv, err, ESRCH, ECHILD);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_nullstatus(void)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
static void wait_nullstatus(void) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait with NULL status");
|
||||
report_begin("wait with NULL status");
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* POSIX explicitly says passing NULL for status is allowed */
|
||||
rv = waitpid(pid, NULL, 0);
|
||||
report_check(rv, errno, 0);
|
||||
waitpid(pid, &x, 0);
|
||||
/* POSIX explicitly says passing NULL for status is allowed */
|
||||
rv = waitpid(pid, NULL, 0);
|
||||
report_check(rv, errno, 0);
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_badstatus(void *ptr, const char *desc)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
static void wait_badstatus(void *ptr, const char *desc) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
|
||||
report_begin(desc);
|
||||
report_begin(desc);
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
rv = waitpid(pid, ptr, 0);
|
||||
report_check(rv, errno, EFAULT);
|
||||
waitpid(pid, &x, 0);
|
||||
rv = waitpid(pid, ptr, 0);
|
||||
report_check(rv, errno, EFAULT);
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_unaligned(void)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
int status[2]; /* will have integer alignment */
|
||||
char *ptr;
|
||||
static void wait_unaligned(void) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
int status[2]; /* will have integer alignment */
|
||||
char *ptr;
|
||||
|
||||
report_begin("wait with unaligned status");
|
||||
report_begin("wait with unaligned status");
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* start with proper integer alignment */
|
||||
ptr = (char *)(&status[0]);
|
||||
/* start with proper integer alignment */
|
||||
ptr = (char *)(&status[0]);
|
||||
|
||||
/* generate improper alignment on platforms with restrictions */
|
||||
ptr++;
|
||||
/* generate improper alignment on platforms with restrictions */
|
||||
ptr++;
|
||||
|
||||
rv = waitpid(pid, (int *)ptr, 0);
|
||||
report_survival(rv, errno);
|
||||
if (rv<0) {
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
rv = waitpid(pid, (int *)ptr, 0);
|
||||
report_survival(rv, errno);
|
||||
if (rv < 0) {
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_badflags(void)
|
||||
{
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
static void wait_badflags(void) {
|
||||
pid_t pid, rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait with bad flags");
|
||||
report_begin("wait with bad flags");
|
||||
|
||||
pid = fork();
|
||||
if (pid<0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid==0) {
|
||||
exit(0);
|
||||
}
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
report_warn("fork failed");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
rv = waitpid(pid, &x, 309429);
|
||||
report_check(rv, errno, EINVAL);
|
||||
waitpid(pid, &x, 0);
|
||||
rv = waitpid(pid, &x, 309429);
|
||||
report_check(rv, errno, EINVAL);
|
||||
waitpid(pid, &x, 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_self(void)
|
||||
{
|
||||
pid_t rv;
|
||||
int x;
|
||||
static void wait_self(void) {
|
||||
pid_t rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait for self");
|
||||
report_begin("wait for self");
|
||||
|
||||
rv = waitpid(getpid(), &x, 0);
|
||||
report_survival(rv, errno);
|
||||
rv = waitpid(getpid(), &x, 0);
|
||||
report_survival(rv, errno);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_parent(void)
|
||||
{
|
||||
pid_t mypid, childpid, rv;
|
||||
int x;
|
||||
static void wait_parent(void) {
|
||||
pid_t mypid, childpid, rv;
|
||||
int x;
|
||||
|
||||
report_begin("wait for parent");
|
||||
report_hassubs();
|
||||
report_begin("wait for parent");
|
||||
report_hassubs();
|
||||
|
||||
mypid = getpid();
|
||||
childpid = fork();
|
||||
if (childpid<0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (childpid==0) {
|
||||
/* Child. Wait for parent. */
|
||||
rv = waitpid(mypid, &x, 0);
|
||||
report_beginsub("from child:");
|
||||
report_survival(rv, errno);
|
||||
_exit(0);
|
||||
}
|
||||
rv = waitpid(childpid, &x, 0);
|
||||
report_beginsub("from parent:");
|
||||
report_survival(rv, errno);
|
||||
mypid = getpid();
|
||||
childpid = fork();
|
||||
if (childpid < 0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
if (childpid == 0) {
|
||||
/* Child. Wait for parent. */
|
||||
rv = waitpid(mypid, &x, 0);
|
||||
report_beginsub("from child:");
|
||||
report_survival(rv, errno);
|
||||
_exit(0);
|
||||
}
|
||||
rv = waitpid(childpid, &x, 0);
|
||||
report_beginsub("from parent:");
|
||||
report_survival(rv, errno);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static
|
||||
void
|
||||
wait_siblings_child(const char *semname)
|
||||
{
|
||||
pid_t pids[2], mypid, otherpid;
|
||||
int rv, fd, semfd, x;
|
||||
char c;
|
||||
static void wait_siblings_child(const char *semname) {
|
||||
pid_t pids[2], mypid, otherpid;
|
||||
int rv, fd, semfd, x;
|
||||
char c;
|
||||
|
||||
mypid = getpid();
|
||||
mypid = getpid();
|
||||
|
||||
/*
|
||||
* Get our own handle for the semaphore, in case naive
|
||||
* file-level synchronization causes concurrent use to
|
||||
* deadlock.
|
||||
*/
|
||||
semfd = open(semname, O_RDONLY);
|
||||
if (semfd < 0) {
|
||||
report_warn("child process (pid %d) can't open %s",
|
||||
mypid, semname);
|
||||
}
|
||||
else {
|
||||
if (read(semfd, &c, 1) < 0) {
|
||||
report_warn("in pid %d: %s: read", mypid, semname);
|
||||
}
|
||||
close(semfd);
|
||||
}
|
||||
/*
|
||||
* Get our own handle for the semaphore, in case naive
|
||||
* file-level synchronization causes concurrent use to
|
||||
* deadlock.
|
||||
*/
|
||||
semfd = open(semname, O_RDONLY);
|
||||
if (semfd < 0) {
|
||||
report_warn("child process (pid %d) can't open %s", mypid, semname);
|
||||
} else {
|
||||
if (read(semfd, &c, 1) < 0) {
|
||||
report_warn("in pid %d: %s: read", mypid, semname);
|
||||
}
|
||||
close(semfd);
|
||||
}
|
||||
|
||||
fd = open(TESTFILE, O_RDONLY);
|
||||
if (fd<0) {
|
||||
report_warn("child process (pid %d) can't open %s",
|
||||
mypid, TESTFILE);
|
||||
return;
|
||||
}
|
||||
fd = open(TESTFILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
report_warn("child process (pid %d) can't open %s", mypid, TESTFILE);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case the semaphore above didn't work, as a backup
|
||||
* busy-wait until the parent writes the pids into the
|
||||
* file. If the semaphore did work, this shouldn't loop.
|
||||
*/
|
||||
do {
|
||||
rv = lseek(fd, 0, SEEK_SET);
|
||||
if (rv<0) {
|
||||
report_warn("child process (pid %d) lseek error",
|
||||
mypid);
|
||||
return;
|
||||
}
|
||||
rv = read(fd, pids, sizeof(pids));
|
||||
if (rv<0) {
|
||||
report_warn("child process (pid %d) read error",
|
||||
mypid);
|
||||
return;
|
||||
}
|
||||
} while (rv < (int)sizeof(pids));
|
||||
/*
|
||||
* In case the semaphore above didn't work, as a backup
|
||||
* busy-wait until the parent writes the pids into the
|
||||
* file. If the semaphore did work, this shouldn't loop.
|
||||
*/
|
||||
do {
|
||||
rv = lseek(fd, 0, SEEK_SET);
|
||||
if (rv < 0) {
|
||||
report_warn("child process (pid %d) lseek error", mypid);
|
||||
return;
|
||||
}
|
||||
rv = read(fd, pids, sizeof(pids));
|
||||
if (rv < 0) {
|
||||
report_warn("child process (pid %d) read error", mypid);
|
||||
return;
|
||||
}
|
||||
} while (rv < (int)sizeof(pids));
|
||||
|
||||
if (mypid==pids[0]) {
|
||||
otherpid = pids[1];
|
||||
}
|
||||
else if (mypid==pids[1]) {
|
||||
otherpid = pids[0];
|
||||
}
|
||||
else {
|
||||
report_warn("child process (pid %d) got garbage in comm file",
|
||||
mypid);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
if (mypid == pids[0]) {
|
||||
otherpid = pids[1];
|
||||
} else if (mypid == pids[1]) {
|
||||
otherpid = pids[0];
|
||||
} else {
|
||||
report_warn("child process (pid %d) got garbage in comm file", mypid);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
rv = waitpid(otherpid, &x, 0);
|
||||
report_beginsub("sibling (pid %d)", mypid);
|
||||
report_survival(rv, errno);
|
||||
rv = waitpid(otherpid, &x, 0);
|
||||
report_beginsub("sibling (pid %d)", mypid);
|
||||
report_survival(rv, errno);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wait_siblings(void)
|
||||
{
|
||||
pid_t pids[2];
|
||||
int rv, fd, semfd, x;
|
||||
int bad = 0;
|
||||
char semname[32];
|
||||
static void wait_siblings(void) {
|
||||
pid_t pids[2];
|
||||
int rv, fd, semfd, x;
|
||||
int bad = 0;
|
||||
char semname[32];
|
||||
|
||||
/* This test may also blow up if FS synchronization is substandard */
|
||||
/* This test may also blow up if FS synchronization is substandard */
|
||||
|
||||
report_begin("siblings wait for each other");
|
||||
report_hassubs();
|
||||
report_begin("siblings wait for each other");
|
||||
report_hassubs();
|
||||
|
||||
snprintf(semname, sizeof(semname), "sem:badcall.%d", (int)getpid());
|
||||
semfd = open(semname, O_WRONLY|O_CREAT|O_TRUNC, 0664);
|
||||
if (semfd < 0) {
|
||||
report_warn("can't make semaphore");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
snprintf(semname, sizeof(semname), "sem:badcall.%d", (int)getpid());
|
||||
semfd = open(semname, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (semfd < 0) {
|
||||
report_warn("can't make semaphore");
|
||||
report_aborted();
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open_testfile(NULL);
|
||||
if (fd<0) {
|
||||
report_aborted();
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
fd = open_testfile(NULL);
|
||||
if (fd < 0) {
|
||||
report_aborted();
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
|
||||
pids[0] = fork();
|
||||
if (pids[0]<0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[0]==0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
pids[0] = fork();
|
||||
if (pids[0] < 0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[0] == 0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
pids[1] = fork();
|
||||
if (pids[1]<0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
/* abandon the other child process :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[1]==0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
pids[1] = fork();
|
||||
if (pids[1] < 0) {
|
||||
report_warn("can't fork");
|
||||
report_aborted();
|
||||
/* abandon the other child process :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (pids[1] == 0) {
|
||||
close(fd);
|
||||
close(semfd);
|
||||
wait_siblings_child(semname);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
rv = write(fd, pids, sizeof(pids));
|
||||
if (rv < 0) {
|
||||
report_warn("write error on %s", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (rv != (int)sizeof(pids)) {
|
||||
report_warnx("write error on %s: short count", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
rv = write(fd, pids, sizeof(pids));
|
||||
if (rv < 0) {
|
||||
report_warn("write error on %s", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
if (rv != (int)sizeof(pids)) {
|
||||
report_warnx("write error on %s: short count", TESTFILE);
|
||||
report_aborted();
|
||||
/* abandon child procs :( */
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* gate the child procs */
|
||||
rv = write(semfd, " ", 2);
|
||||
if (rv < 0) {
|
||||
report_warn("%s: write", semname);
|
||||
bad = 1;
|
||||
}
|
||||
/* gate the child procs */
|
||||
rv = write(semfd, " ", 2);
|
||||
if (rv < 0) {
|
||||
report_warn("%s: write", semname);
|
||||
bad = 1;
|
||||
}
|
||||
|
||||
report_beginsub("overall");
|
||||
rv = waitpid(pids[0], &x, 0);
|
||||
if (rv<0) {
|
||||
report_warn("error waiting for child 0 (pid %d)", pids[0]);
|
||||
bad = 1;
|
||||
}
|
||||
rv = waitpid(pids[1], &x, 0);
|
||||
if (rv<0) {
|
||||
report_warn("error waiting for child 1 (pid %d)", pids[1]);
|
||||
bad = 1;
|
||||
}
|
||||
if (bad) {
|
||||
/* XXX: aborted, or failure, or what? */
|
||||
report_aborted();
|
||||
}
|
||||
else {
|
||||
report_passed();
|
||||
}
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
remove(TESTFILE);
|
||||
report_beginsub("overall");
|
||||
rv = waitpid(pids[0], &x, 0);
|
||||
if (rv < 0) {
|
||||
report_warn("error waiting for child 0 (pid %d)", pids[0]);
|
||||
bad = 1;
|
||||
}
|
||||
rv = waitpid(pids[1], &x, 0);
|
||||
if (rv < 0) {
|
||||
report_warn("error waiting for child 1 (pid %d)", pids[1]);
|
||||
bad = 1;
|
||||
}
|
||||
if (bad) {
|
||||
/* XXX: aborted, or failure, or what? */
|
||||
report_aborted();
|
||||
} else {
|
||||
report_passed();
|
||||
}
|
||||
close(fd);
|
||||
close(semfd);
|
||||
remove(semname);
|
||||
remove(TESTFILE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
test_waitpid(void)
|
||||
{
|
||||
wait_badpid(-8, "wait for pid -8");
|
||||
wait_badpid(-1, "wait for pid -1");
|
||||
wait_badpid(0, "pid zero");
|
||||
wait_badpid(NONEXIST_PID, "nonexistent pid");
|
||||
void test_waitpid(void) {
|
||||
wait_badpid(-8, "wait for pid -8");
|
||||
wait_badpid(-1, "wait for pid -1");
|
||||
wait_badpid(0, "pid zero");
|
||||
wait_badpid(NONEXIST_PID, "nonexistent pid");
|
||||
|
||||
wait_nullstatus();
|
||||
wait_badstatus(INVAL_PTR, "wait with invalid pointer status");
|
||||
wait_badstatus(KERN_PTR, "wait with kernel pointer status");
|
||||
wait_nullstatus();
|
||||
wait_badstatus(INVAL_PTR, "wait with invalid pointer status");
|
||||
wait_badstatus(KERN_PTR, "wait with kernel pointer status");
|
||||
|
||||
wait_unaligned();
|
||||
wait_unaligned();
|
||||
|
||||
wait_badflags();
|
||||
wait_badflags();
|
||||
|
||||
wait_self();
|
||||
wait_parent();
|
||||
wait_siblings();
|
||||
wait_self();
|
||||
wait_parent();
|
||||
wait_siblings();
|
||||
}
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
void
|
||||
test_write(void)
|
||||
{
|
||||
test_write_fd();
|
||||
test_write_buf();
|
||||
void test_write(void) {
|
||||
test_write_fd();
|
||||
test_write_buf();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user