/* * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 * The President and Fellows of Harvard College. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Concurrent directory operations test. * * Your system should survive this (without leaving a corrupted file * system behind) once the file system assignment is complete. */ #include #include #include #include #include #include #include #include #include #define NTRIES 100 /* loop count */ #define NPROCS 5 /* actually totals 4x this +1 processes */ #define TESTDIR "dirconc" #define NNAMES 4 #define NAMESIZE 32 //////////////////////////////////////////////////////////// static const char *const names[NNAMES] = { "aaaa", "bbbb", "cccc", "dddd", }; static void choose_name(char *buf, size_t len) { const char *a, *b, *c; a = names[random()%NNAMES]; if (random()%2==0) { snprintf(buf, len, "%s", a); return; } b = names[random()%NNAMES]; if (random()%2==0) { snprintf(buf, len, "%s/%s", a, b); return; } c = names[random()%NNAMES]; snprintf(buf, len, "%s/%s/%s", a, b, c); } //////////////////////////////////////////////////////////// /* * The purpose of this is to be atomic. In our world, straight * printf tends not to be. */ static void #ifdef __GNUC__ __attribute__((__format__(__printf__, 1, 2))) #endif say(const char *fmt, ...) { char buf[512]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); write(STDOUT_FILENO, buf, strlen(buf)); } //////////////////////////////////////////////////////////// static void dorename(const char *name1, const char *name2) { if (rename(name1, name2) < 0) { switch (errno) { case ENOENT: case ENOTEMPTY: case EINVAL: break; default: say("pid %d: rename %s -> %s: %s\n", getpid(), name1, name2, strerror(errno)); break; } } } static void domkdir(const char *name) { if (mkdir(name, 0775)<0) { switch (errno) { case ENOENT: case EEXIST: break; default: say("pid %d: mkdir %s: %s\n", getpid(), name, strerror(errno)); break; } } } static void dormdir(const char *name) { if (rmdir(name)<0) { switch (errno) { case ENOENT: case ENOTEMPTY: break; default: say("pid %d: rmdir %s: %s\n", getpid(), name, strerror(errno)); break; } } } static void cleanup_rmdir(const char *name) { if (rmdir(name)<0) { switch (errno) { case ENOENT: break; default: say("cleanup (pid %d): rmdir %s: %s\n", getpid(), name, strerror(errno)); break; } } } //////////////////////////////////////////////////////////// static void rename_proc(void) { char name1[NAMESIZE], name2[NAMESIZE]; int ct; for (ct=0; ct %s\n", (int)getpid(), name1, name2); dorename(name1, name2); } } static void mkdir_proc(void) { char name[NAMESIZE]; int ct; for (ct=0; ct=0) { wp = waitpid(pids[i], &status, 0); if (wp<0) { say("waitpid %d: %s\n", (int) pids[i], strerror(errno)); } else if (WIFSIGNALED(status)) { say("pid %d: signal %d\n", (int) pids[i], WTERMSIG(status)); } else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) { say("pid %d: exit %d\n", (int) pids[i], WEXITSTATUS(status)); } } } } //////////////////////////////////////////////////////////// static void setup(const char *fs) { if (chdir(fs)<0) { say("chdir: %s: %s\n", fs, strerror(errno)); exit(1); } if (mkdir(TESTDIR, 0775)<0) { say("mkdir: %s: %s\n", TESTDIR, strerror(errno)); exit(1); } if (chdir(TESTDIR)<0) { say("chdir: %s: %s\n", TESTDIR, strerror(errno)); exit(1); } } static void recursive_cleanup(const char *sofar, int depth) { char buf[NAMESIZE*32]; int i; for (i=0; i