]> git.saurik.com Git - apple/libutil.git/commitdiff
libutil-20.tar.gz mac-os-x-106 mac-os-x-1061 mac-os-x-1062 mac-os-x-1063 v20
authorApple <opensource@apple.com>
Wed, 13 May 2009 00:39:33 +0000 (00:39 +0000)
committerApple <opensource@apple.com>
Wed, 13 May 2009 00:39:33 +0000 (00:39 +0000)
ExtentManager.cpp [new file with mode: 0644]
ExtentManager.h [new file with mode: 0644]
Makefile
libutil.exports [new file with mode: 0644]
libutil.h
reexec_to_match_kernel.3 [new file with mode: 0644]
reexec_to_match_kernel.c [new file with mode: 0644]
wipefs.3 [new file with mode: 0644]
wipefs.cpp [new file with mode: 0644]
wipefs.h [new file with mode: 0644]

diff --git a/ExtentManager.cpp b/ExtentManager.cpp
new file mode 100644 (file)
index 0000000..74d54c6
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+//     ExtentManager.cpp
+//
+
+#include "ExtentManager.h"
+
+void
+ExtentManager::Init(uint32_t theBlockSize, uint32_t theNativeBlockSize, off_t theTotalBytes)
+{
+       blockSize = theBlockSize;
+       nativeBlockSize = theNativeBlockSize;
+       totalBytes = theTotalBytes;
+       totalBlocks = howmany(totalBytes, blockSize);
+
+       // add sentry empty extents at both sides so empty partition doesn't need to be handled specially
+       AddBlockRangeExtent(0, 0);
+       AddBlockRangeExtent(totalBlocks, 0);
+}
+
+void
+ExtentManager::MergeExtent(const ExtentInfo &a, const ExtentInfo &b, ExtentInfo *c)
+{
+       // merge ext into *curIt
+       c->blockAddr = min(a.blockAddr, b.blockAddr);
+       c->numBlocks = max(a.blockAddr + a.numBlocks, b.blockAddr + b.numBlocks) - c->blockAddr;
+}
+
+void
+ExtentManager::AddBlockRangeExtent(off_t blockAddr, off_t numBlocks)
+{
+       struct ExtentInfo ext, newExt;
+       ListExtIt curIt, newIt;
+       bool merged = false;
+
+       // make the range a valid range
+       if ((blockAddr > totalBlocks) || (blockAddr + numBlocks < 0)) { // totally out of range, do nothing
+               return;
+       }
+       if (blockAddr < 0) {
+               numBlocks = blockAddr + numBlocks;
+               blockAddr = 0;
+       }
+       if (blockAddr + numBlocks > totalBlocks) {
+               numBlocks = totalBlocks - blockAddr;
+       }
+
+       ext.blockAddr = blockAddr;
+       ext.numBlocks = numBlocks;
+
+       for (curIt = extentList.begin(); curIt != extentList.end(); curIt++) {
+               if (BeforeExtent(ext, *curIt))
+                       break;
+               if (!BeforeExtent(*curIt, ext)) { // overlapped extents
+                       MergeExtent(ext, *curIt, &newExt);
+                       *curIt = newExt;
+                       merged = true;
+                       break;
+               }
+       }
+
+       // insert ext before curIt
+       if (!merged) {
+               curIt = extentList.insert(curIt, ext); // throws bad_alloc when out of memory
+       }
+
+       // merge the extents
+       newIt = curIt;
+       curIt = extentList.begin();
+       while (curIt != extentList.end()) {
+               if (curIt == newIt || BeforeExtent(*curIt, *newIt)) { // curIt is before newIt
+                       curIt++;
+                       continue;
+               }
+               if (BeforeExtent(*newIt, *curIt)) { // curIt is after newIt now, we are done
+                       break;
+               }
+               // merge the two extents
+               MergeExtent(*curIt, *newIt, &newExt);
+               *newIt = newExt;
+               curIt = extentList.erase(curIt);
+       }
+       // printf("After %s(%lld, %lld)\n", __func__, blockAddr, numBlocks);     DebugPrint();
+} // ExtentManager::AddBlockRangeExtent
+
+void
+ExtentManager::RemoveBlockRangeExtent(off_t blockAddr, off_t numBlocks)
+{
+       struct ExtentInfo ext, newExt;
+       ListExtIt curIt;
+
+       ext.blockAddr = blockAddr;
+       ext.numBlocks = numBlocks;
+
+       curIt = extentList.begin();
+       while (curIt != extentList.end()) {
+               if (BeforeExtent(*curIt, ext)) {
+                       curIt++;
+                       continue;
+               }
+               if (BeforeExtent(ext, *curIt)) // we are done
+                       break;
+               // overlapped extents
+               if (curIt->blockAddr >= ext.blockAddr &&
+                       curIt->blockAddr + curIt->numBlocks <= ext.blockAddr + ext.numBlocks) {
+                       // *curIt is totally within ext, remove curIt
+                       curIt = extentList.erase(curIt);
+               } else if (curIt->blockAddr < ext.blockAddr &&
+                       curIt->blockAddr + curIt->numBlocks > ext.blockAddr + ext.numBlocks) {
+                       // ext is totally within *curIt, split ext into two
+                       newExt.blockAddr = ext.blockAddr + ext.numBlocks;
+                       newExt.numBlocks = curIt->blockAddr + curIt->numBlocks - newExt.blockAddr;
+                       curIt->numBlocks = ext.blockAddr - curIt->blockAddr;
+                       curIt++;
+                       extentList.insert(curIt, newExt); // throws bad_alloc when out of memory
+                       curIt++;        
+               } else { // remove part of ext
+                       if (curIt->blockAddr >= ext.blockAddr) { // remove the former part of *curIt
+                               assert(curIt->blockAddr + curIt->numBlocks > newExt.blockAddr);
+                               newExt.blockAddr = ext.blockAddr + ext.numBlocks;
+                               newExt.numBlocks = curIt->blockAddr + curIt->numBlocks - newExt.blockAddr;
+                               *curIt = newExt;
+                       } else { // remove the latter part of *curIt
+                               curIt->numBlocks = ext.blockAddr - curIt->blockAddr;
+                       }
+                       curIt++;
+               }
+       }
+       //printf("After %s(%lld, %lld)\n", __func__, blockAddr, numBlocks);      DebugPrint();
+}
+
+void
+ExtentManager::AddByteRangeExtent(off_t byteAddr, off_t numBytes)
+{
+       off_t blockAddr = byteAddr / blockSize;
+       off_t blockAddrOfLastByte = (byteAddr + numBytes - 1) / blockSize;
+       off_t numBlocks = blockAddrOfLastByte - blockAddr + 1;
+       AddBlockRangeExtent(blockAddr, numBlocks);
+}
+
+void
+ExtentManager::DebugPrint()
+{
+       ListExtIt it;
+
+       for (it = extentList.begin(); it != extentList.end(); it++) {
+               printf("[%lld, %lld] ", it->blockAddr, it->numBlocks);
+       }
+       printf("\n");
+}
diff --git a/ExtentManager.h b/ExtentManager.h
new file mode 100644 (file)
index 0000000..2dc25f6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008 Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+//     ExtentManager.h
+//
+#ifndef EXTENTMANAGER_H
+#define EXTENTMANAGER_H
+
+#include <list>
+#include <vector>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <cstdio>
+#include <cassert>
+using namespace std;
+
+struct ExtentInfo {
+       off_t blockAddr;
+       off_t numBlocks;
+};
+
+inline bool BeforeExtent(const ExtentInfo &a, const ExtentInfo &b)
+{
+               return (a.blockAddr + a.numBlocks) < b.blockAddr;
+}
+
+typedef list<ExtentInfo>::iterator ListExtIt;
+
+class ExtentManager {
+public:
+       ExtentManager() : blockSize(0), totalBytes(0), totalBlocks(0) {};
+       ~ExtentManager() {};
+
+       void Init(uint32_t theBlockSize, uint32_t theNativeBlockSize, off_t theTotalBytes);
+
+       void AddBlockRangeExtent(off_t blockAddr, off_t numBlocks);
+       void AddByteRangeExtent(off_t byteAddr, off_t numBytes);
+       void RemoveBlockRangeExtent(off_t blockAddr, off_t numBlocks);
+
+       void DebugPrint();
+
+protected:
+       void MergeExtent(const ExtentInfo &a, const ExtentInfo &b, ExtentInfo *c);
+
+public:
+       size_t blockSize;
+       size_t nativeBlockSize;
+       off_t totalBytes;
+       off_t totalBlocks;
+       list<ExtentInfo> extentList;
+};
+
+#endif // #ifndef EXTENTMANAGER_H
index 19c1c9b3d70c7cc641510863e98f501193232081..67173c8ab9ca461c02a084a3af60bc173c1a6819 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,18 @@
 SHELL          := /bin/sh
+SDKROOT                ?= /
 
 VERSION                = 1.0
-CC             = cc
+CC             = xcrun cc
+CPP            = xcrun c++
 CPPFLAGS       = -I$(SRCROOT)
-CFLAGS         = -Os -g3 -no-cpp-precomp -Wall $(RC_CFLAGS)
+CFLAGS         = -Os -g3 -no-cpp-precomp -Wall $(RC_CFLAGS) -isysroot $(SDKROOT)
 LDFLAGS                = $(RC_CFLAGS) -install_name /usr/lib/libutil.dylib -compatibility_version $(VERSION) \
-                 -current_version $(VERSION)
+                 -current_version $(VERSION) -lstdc++ -exported_symbols_list libutil.exports -isysroot $(SDKROOT)
 INSTALL                = install -c
 LN             = ln
-MKDIR          = mkdir
+MKDIR          = mkdir -p
 STRIP          = strip
+DSYMUTIL       = dsymutil
 AR             = ar
 RANLIB         = ranlib
 
@@ -20,13 +23,15 @@ DSTROOT             =
 
 LIB            := libutil1.0.dylib
 SRCS           := _secure_path.c getmntopts.c humanize_number.c \
-                  pidfile.c property.c realhostname.c trimdomain.c uucplock.c
-HDRS           := libutil.h mntopts.h
+                  pidfile.c property.c realhostname.c trimdomain.c uucplock.c \
+                  ExtentManager.cpp wipefs.cpp reexec_to_match_kernel.c
+HDRS           := libutil.h mntopts.h wipefs.h
 MAN3           := _secure_path.3 getmntopts.3 humanize_number.3 pidfile.3 \
-                  property.3 realhostname.3 realhostname_sa.3 trimdomain.3 uucplock.3
+                  property.3 realhostname.3 realhostname_sa.3 trimdomain.3 \
+                  uucplock.3 wipefs.3 reexec_to_match_kernel.3
 
 .SUFFIXES :
-.SUFFIXES : .c .h .o
+.SUFFIXES : .c .cpp .h .o
 
 .PHONY :
 .PHONY : all installsrc installhdrs install clean installlib installman
@@ -57,7 +62,7 @@ installhdrs :
 install : installhdrs installlib strip installman install-plist
 
 clean :
-       rm -f $(patsubst %.c,$(OBJROOT)/%.o,$(SRCS))
+       rm -f $(patsubst %.cpp,$(OBJROOT)/%.o,$(patsubst %.c,$(OBJROOT)/%.o,$(SRCS)))
        rm -f $(SYMROOT)/*~
        rm -f $(SRCROOT)/.\#*
        rm -f $(SYMROOT)/$(LIB)
@@ -69,6 +74,7 @@ strip:
 # Internal targets and rules.
 #
 installlib : $(SYMROOT)/$(LIB)
+       $(DSYMUTIL) $(SYMROOT)/$(LIB) -o $(SYMROOT)/$(LIB).dSYM
        $(INSTALL) -d $(DSTROOT)/usr/lib
        $(INSTALL) -m 0755 $< $(DSTROOT)/usr/lib
        $(LN) -fs libutil1.0.dylib $(DSTROOT)/usr/lib/libutil.dylib
@@ -84,8 +90,12 @@ $(OBJROOT)/%.o : $(SRCROOT)/%.c \
             $(patsubst %.h,$(SRCROOT)/%.h,$(HDRS))
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
 
-$(SYMROOT)/$(LIB) : $(patsubst %.c,$(OBJROOT)/%.o,$(SRCS))
-       $(CC) -dynamiclib $(LDFLAGS) -o $@ $?
+$(OBJROOT)/%.o : $(SRCROOT)/%.cpp \
+            $(patsubst %.h,$(SRCROOT)/%.h,$(HDRS))
+       $(CPP) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+$(SYMROOT)/$(LIB) : $(patsubst %.cpp,$(OBJROOT)/%.o,$(patsubst %.c,$(OBJROOT)/%.o,$(SRCS)))
+       $(CC) -dynamiclib $(LDFLAGS) -o $@ $(patsubst %.cpp,$(OBJROOT)/%.o,$(patsubst %.c,$(OBJROOT)/%.o,$(SRCS)))
 
 OSV    = $(DSTROOT)/usr/local/OpenSourceVersions
 OSL    = $(DSTROOT)/usr/local/OpenSourceLicenses
diff --git a/libutil.exports b/libutil.exports
new file mode 100644 (file)
index 0000000..5da5c6f
--- /dev/null
@@ -0,0 +1,26 @@
+__secure_path
+_freemntopts
+_getmnt_silent
+_getmntoptnum
+_getmntopts
+_getmntoptstr
+_humanize_number
+_pidfile_close
+_pidfile_open
+_pidfile_remove
+_pidfile_write
+_properties_free
+_properties_read
+_property_find
+_realhostname
+_realhostname_sa
+_reexec_to_match_kernel
+_trimdomain
+_uu_lock
+_uu_lock_txfr
+_uu_lockerr
+_uu_unlock
+_wipefs_alloc
+_wipefs_except_blocks
+_wipefs_free
+_wipefs_wipe
index 7135673bfd9c640334ddbfc0e96e6b0cc7d4e216..c1a1bcd2058dcb6695978c8b42c393e56d7590c5 100644 (file)
--- a/libutil.h
+++ b/libutil.h
@@ -96,9 +96,6 @@ struct sockaddr;
 int    realhostname_sa(char *host, size_t hsize, struct sockaddr *addr,
                             int addrlen);
 
-int    kld_isloaded(const char *name);
-int    kld_load(const char *name);
-
 #ifdef _STDIO_H_       /* avoid adding new includes */
 char   *fparseln(FILE *, size_t *, size_t *, const char[3], int);
 #endif
@@ -125,6 +122,8 @@ int pidfile_close(struct pidfh *pfh);
 int pidfile_remove(struct pidfh *pfh);
 #endif
 
+int reexec_to_match_kernel(void);
+
 __END_DECLS
 
 #define UU_LOCK_INUSE (1)
diff --git a/reexec_to_match_kernel.3 b/reexec_to_match_kernel.3
new file mode 100644 (file)
index 0000000..df1c77d
--- /dev/null
@@ -0,0 +1,30 @@
+.Dd Apr 14, 2008
+.Dt REEXEC_TO_MATCH_KERNEL 3
+.Os "Mac OS X"
+.Sh NAME
+.Nm reexec_to_match_kernel
+.Nd Re-exec the current binary to match the ABI of the running kernel
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In libutil.h
+.Ft int
+.Fo reexec_to_match_kernel
+.Fa "void"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn reexec_to_match_kernel
+function re-executes the current binary to match the ABI of the running kernel.
+That is, if the current kernel is a 64-bit Intel kernel, it will attempt to
+execute the 64-bit x86_64 userspace slice of the universal binary. The API
+intentionally does not take arguments because its use should be transparent
+to the program and to the user.
+.Sh RETURN VALUES
+The
+.Fn reexec_to_match_kernel
+function returns 0 if re-execution was not required. It returns -1 and
+sets errno if there was an error performing the re-execution, for example
+if the binary is not universal, or does not contain a slice to match the running
+kernel's ABI. If the function succeeds, control never returns to the caller
+and the program starts from main() again.
diff --git a/reexec_to_match_kernel.c b/reexec_to_match_kernel.c
new file mode 100644 (file)
index 0000000..a617c64
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/cdefs.h>
+
+#include <spawn.h>
+#include <errno.h>
+#include <crt_externs.h>
+#include <mach/mach.h>
+#include <mach-o/loader.h>
+#include <mach-o/dyld.h>
+#include <sys/sysctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libutil.h"
+
+static cpu_type_t current_program_arch(void);
+static cpu_type_t current_kernel_arch(void);
+static int reexec(cpu_type_t cputype);
+
+#define kReExec "REEXEC_TO_MATCH_KERNEL"
+
+int reexec_to_match_kernel(void)
+{
+       cpu_type_t kernarch, progarch;
+       char *alreadyenv;
+       
+       alreadyenv = getenv(kReExec);
+       if (alreadyenv) {
+               /* we've done this at least once, assume
+                  another try won't help */
+               return 0;
+       }
+
+       kernarch = current_kernel_arch();
+       progarch = current_program_arch();
+
+       if (kernarch == 0) {
+               /* could not determine kernel arch */
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (kernarch == progarch) {
+               /* nothing to do here */
+               return 0;
+       }
+
+       /* Now we need to re-exec */
+       return reexec(kernarch);
+}
+
+static cpu_type_t current_program_arch(void)
+{
+       cpu_type_t current_arch = (_NSGetMachExecuteHeader())->cputype;
+
+       return current_arch;
+}
+
+static cpu_type_t current_kernel_arch(void)
+{
+       struct host_basic_info  hi;
+       unsigned int            size;
+       kern_return_t           kret;
+       cpu_type_t                              current_arch;
+       int                                             ret, mib[4];
+       size_t                                  len;
+       struct kinfo_proc               kp;
+       
+       size = sizeof(hi)/sizeof(int);
+       kret = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hi, &size);
+       if (kret != KERN_SUCCESS) {
+               return 0;
+       }
+
+       current_arch = hi.cpu_type;
+
+       /* Now determine if the kernel is running in 64-bit mode */
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_PROC;
+       mib[2] = KERN_PROC_PID;
+       mib[3] = 0; /* kernproc, pid 0 */
+       len = sizeof(kp);
+       ret = sysctl(mib, sizeof(mib)/sizeof(mib[0]), &kp, &len, NULL, 0);
+       if (ret == -1) {
+               return 0;
+       }
+
+       if (kp.kp_proc.p_flag & P_LP64) {
+               current_arch |= CPU_ARCH_ABI64;
+       }
+
+       return current_arch;
+}
+
+static int reexec(cpu_type_t cputype)
+{
+       posix_spawnattr_t  attr;
+       int                ret, envcount;
+       size_t             copied = 0;
+       char                       **argv, **oldenvp, **newenvp;
+       char                       execpath[MAXPATHLEN+1];
+       uint32_t                   execsize;
+
+       argv = *_NSGetArgv();
+       oldenvp = *_NSGetEnviron();
+       for (envcount = 0; oldenvp[envcount]; envcount++);
+       // if there are 4 elements and a NULL, envcount will be 4
+
+       newenvp = calloc(envcount+2, sizeof(newenvp[0]));
+       for (envcount = 0; oldenvp[envcount]; envcount++) {
+               newenvp[envcount] = oldenvp[envcount];
+       }
+       newenvp[envcount++] = kReExec"=1";
+       newenvp[envcount] = NULL;
+
+       execsize = (uint32_t)sizeof(execpath);
+       ret = _NSGetExecutablePath(execpath, &execsize);
+       if (ret != 0) {
+               return -1;
+       }
+
+       ret = posix_spawnattr_init(&attr);
+       if (ret != 0) {
+               return -1;
+       }
+       ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);
+       if (ret != 0) {
+               return -1;
+       }
+       ret = posix_spawnattr_setbinpref_np(&attr, 1, &cputype, &copied);
+       if (ret != 0 || copied != 1) {
+               return -1;
+       }
+
+       /*
+       fprintf(stderr, "reexec: %s\n", execpath);
+       for (envcount=0; newenvp[envcount]; envcount++) {
+               fprintf(stderr, "env[%d] = %s\n", envcount, newenvp[envcount]);
+       }
+       for (envcount=0; argv[envcount]; envcount++) {
+               fprintf(stderr, "argv[%d] = %s\n", envcount, argv[envcount]);
+       }
+       */
+       ret = posix_spawn(NULL, execpath, NULL, &attr, argv, newenvp);
+       if (ret != 0) {
+               errno = ret;
+               return -1;
+       }
+
+       /* should not be reached */
+       return 0;
+}
diff --git a/wipefs.3 b/wipefs.3
new file mode 100644 (file)
index 0000000..0f14dfc
--- /dev/null
+++ b/wipefs.3
@@ -0,0 +1,134 @@
+.\"\r
+.\" Copyright (c) 2008 Apple Inc. All rights reserved.\r
+.\"\r
+.\" @APPLE_LICENSE_HEADER_START@\r
+.\" \r
+.\" This file contains Original Code and/or Modifications of Original Code\r
+.\" as defined in and that are subject to the Apple Public Source License\r
+.\" Version 2.0 (the 'License'). You may not use this file except in\r
+.\" compliance with the License. Please obtain a copy of the License at\r
+.\" http://www.opensource.apple.com/apsl/ and read it before using this\r
+.\" file.\r
+.\" \r
+.\" The Original Code and all software distributed under the License are\r
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
+.\" Please see the License for the specific language governing rights and\r
+.\" limitations under the License.\r
+.\" \r
+.\" @APPLE_LICENSE_HEADER_END@\r
+.\"\r
+.Dd 2/25/08               \" DATE \r
+.Dt libutil 3      \" Program name and manual section number \r
+.Os Mac OS X\r
+.Sh NAME                 \" Section Header - required - don't modify \r
+.\" The following lines are read in generating the apropos(man -k) database. Use only key\r
+.\" words here as the database is built based on the words here and in the .ND line. \r
+.Nm wipefs_alloc ,\r
+.Nm wipefs_except_blocks ,\r
+.Nm wipefs_wipe ,\r
+.Nm wipefs_free\r
+.\" Use .Nm macro to designate other names for the documented program.\r
+.Nd wipes existing file systems on a volume\r
+.Sh LIBRARY             \" Section Header - required - don't modify\r
+.Lb libutil\r
+.Sh SYNOPSIS\r
+.In wipefs.h\r
+.Ft int\r
+.Fo wipefs_alloc\r
+.Fa "int file_desc"\r
+.Fa "size_t block_size"\r
+.Fa "wipefs_ctx *handlep"\r
+.Fc\r
+.Ft int\r
+.Fo wipefs_except_blocks\r
+.Fa "wipefs_ctx handle"\r
+.Fa "off_t blockoff"\r
+.Fa "off_t nblocks"\r
+.Fc\r
+.Ft int\r
+.Fo wipefs_wipe\r
+.Fa "wipefs_ctx handle"\r
+.Fc\r
+.Ft void\r
+.Fo wipefs_free\r
+.Fa "wipefs_ctx *handlep"\r
+.Fc\r
+.Sh DESCRIPTION          \" Section Header - required - don't modify\r
+The wipefs family of functions wipe existing file systems on a volume.  This is usually used by the newfs_* utilities before they create new file systems on the volume, so that the existing file system will not be mounted accidentally after the new file system is created.\r
+.Pp\r
+The\r
+.Fn wipefs_alloc\r
+function initializes a\r
+.Fa wipefs_ctx\r
+object (which is an opaque data type).\r
+.Fa file_desc\r
+is the file handle of the volume to be wiped, which can be a block device node, a character device node, or a file.\r
+.Fa file_desc\r
+must be opened with write access.  If\r
+.Fa block_size\r
+is 0, this function calls\r
+.Xr ioctl 2\r
+to get the block size.  A valid\r
+.Fa block_size \r
+must be supplied if \r
+.Fa file_desc\r
+is a regular file.  This function does not write any data to the volume.\r
+.Pp\r
+The\r
+.Fn wipefs_except_blocks\r
+function tells wipefs not to write anything in the block range provided.  This function is used for performance\r
+optimizations if the caller will write to these blocks.  It is the caller's responsibility to write to these blocks.\r
+Otherwise, some file systems may still be recognized on the volume.  This function does not write any data to the\r
+volume.  If this function is called multiple times, the union of all the ranges provided will be excluded from being\r
+written by\r
+.Fn wipefs_wipe .\r
+.Pp\r
+The\r
+.Fn wipefs_wipe\r
+function writes data to the volume to wipe out existing file systems on it.\r
+.Cm Caution:\r
+this function destroys any file system or partition scheme on the volume represented by\r
+.Fa file_desc .\r
+If\r
+.Fa file_desc\r
+represents the entire disk (e.g. /dev/diskX), the partition map of the disk will be destroyed.  If\r
+.Fa file_desc\r
+represents a partition (e.g., /dev/diskXsY), only the file system in that partition is destroyed.  Although the partition scheme or file system on\r
+.Fa file_desc\r
+may be beyond repair after \r
+.Fn wipefs_wipe ,\r
+this function is not designed as a means to safely delete all data.  It is possible that some user data (or intact file systems in some partitions) may still be recovered.\r
+.Pp\r
+The\r
+.Fn wipefs_free\r
+function frees the allocated \r
+.Fa wipefs_ctx\r
+handle and set\r
+.Fa *handlep\r
+to NULL.\r
+.Sh RETURN VALUES\r
+The\r
+.Fn wipefs_alloc ,\r
+.Fn wipefs_except_blocks\r
+and\r
+.Fn wipefs_wipe\r
+functions return 0 on success, or will fail and return an error code.\r
+Each function may return\r
+.Fa ENOMEM\r
+if insufficient memory is available.  In addition, if\r
+.Fa block_size\r
+is not provided,\r
+.Fn wipefs_alloc\r
+may return any error\r
+.Xr ioctl 2\r
+returns;\r
+.Fn wipefs_wipe\r
+may return any error\r
+.Xr pwrite 2\r
+returns.\r
+.\" .Sh BUGS              \" Document known, unremedied bugs \r
+.\".Sh HISTORY           \" Document history if command behaves in a unique manner \r
+.\"The wipefs family of functions first appeared in Mac OS X Leopard (10.5.3).\r
diff --git a/wipefs.cpp b/wipefs.cpp
new file mode 100644 (file)
index 0000000..d5efc05
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+//     wipefs.cpp
+//
+
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <sys/disk.h>
+#include <sys/stat.h>
+
+#include "ExtentManager.h"
+#include "wipefs.h"
+
+#define        roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
+
+struct __wipefs_ctx {
+       int fd;
+       class ExtentManager extMan;
+};
+
+void
+AddExtentsForFutureFS(class ExtentManager *extMan)
+{
+       // we don't know what blocks future FS will use to recognize itself.  But we'd better be safe than sorry and write
+       // the first and last 2MB of the volume
+       off_t size = 2 * 1024 * 1024;
+       extMan->AddByteRangeExtent(0, size);
+       extMan->AddByteRangeExtent(extMan->totalBytes - size, size);
+}
+
+void
+AddExtentsForHFS(class ExtentManager *extMan)
+{
+       // first 1KB is boot block, last 512B is reserved
+       // the Volume Header (512B) is after 1KB and before the last 512B
+       extMan->AddByteRangeExtent(0, 1024 + 512);
+       extMan->AddByteRangeExtent(extMan->totalBytes - 1024, 1024);
+}
+
+void
+AddExtentsForMSDOS(class ExtentManager *extMan)
+{
+       // MSDOS needs the first block (in theory, up to 32KB)
+       extMan->AddByteRangeExtent(0, 32 * 1024);
+}
+
+void
+AddExtentsForNTFS(class ExtentManager *extMan)
+{
+       // NTFS supports block size from 256B to 32768B.  The first, middle and last block are needed
+       extMan->AddByteRangeExtent(0, 32 * 1024);
+       extMan->AddByteRangeExtent(extMan->totalBytes - 32 * 1024, 32 * 1024);
+       // to be safe, add the rage from (mid_point - 32KB) to (mid_point + 32KB)
+       extMan->AddByteRangeExtent(extMan->totalBytes / 2 - 32 * 1024, 64 * 1024);
+}
+
+void
+AddExtentsForUDF(class ExtentManager *extMan)
+{
+       off_t lastBlockAddr = extMan->totalBlocks - 1;
+
+       // Volume Recognization Sequence (VRS) starts at 32KB, usually less than 7 Volume Structure Descriptors (2KB each)
+       extMan->AddByteRangeExtent(32 * 1024, 14 * 1024);
+
+       // AVDP is on 256, 512, last block, last block - 256
+       extMan->AddBlockRangeExtent(256, 1);
+       extMan->AddBlockRangeExtent(512, 1);
+       extMan->AddBlockRangeExtent(lastBlockAddr, 1);
+       extMan->AddBlockRangeExtent(lastBlockAddr - 256, 1);
+
+       // to be safe, assume the device has 2KB block size and do it again
+       if (extMan->blockSize != 2048) {
+               off_t blockSize = 2048;
+               // AVDP is on 256, 512, last block, last block - 256
+               extMan->AddByteRangeExtent(256 * blockSize, blockSize);
+               extMan->AddByteRangeExtent(512 * blockSize, blockSize);
+               extMan->AddByteRangeExtent(extMan->totalBytes - blockSize, blockSize);
+               extMan->AddByteRangeExtent(extMan->totalBytes - 256 * blockSize, blockSize);
+       }
+}
+
+void
+AddExtentsForUFS(class ExtentManager *extMan)
+{
+       // UFS super block is 8KB at offset 8KB
+       extMan->AddByteRangeExtent(8192, 8192);
+}
+
+void
+AddExtentsForZFS(class ExtentManager *extMan)
+{
+       // ZFS needs the first 512KB and last 512KB for all the 4 disk labels
+       extMan->AddByteRangeExtent(0, 512 * 1024);
+       extMan->AddByteRangeExtent(extMan->totalBytes - 512 * 1024, 512 * 1024);
+}
+
+void
+AddExtentsForPartitions(class ExtentManager *extMan)
+{
+       // MBR (Master Boot Record) needs the first sector
+       // APM (Apple Partition Map) needs the second sector
+       // GPT (GUID Partition Table) needs the first 34 and last 33 sectors
+       extMan->AddByteRangeExtent(0, 512 * 34);
+       extMan->AddByteRangeExtent(extMan->totalBytes - 512 * 33, 512 * 33);
+}
+
+extern "C" int
+wipefs_alloc(int fd, size_t block_size, wipefs_ctx *handle)
+{
+       int err = 0;
+       uint64_t numBlocks = 0;
+       uint32_t nativeBlockSize = 0;
+       off_t totalSizeInBytes = 0;
+       class ExtentManager *extMan = NULL;
+       struct stat sbuf = { 0 };
+
+       *handle = NULL;
+       (void)fstat(fd, &sbuf);
+       switch (sbuf.st_mode & S_IFMT) {
+       case S_IFCHR:
+       case S_IFBLK:
+               if (ioctl(fd, DKIOCGETBLOCKSIZE, (char *)&nativeBlockSize) < 0) {
+                       err = errno;
+                       goto labelExit;
+               }
+               if (ioctl(fd, DKIOCGETBLOCKCOUNT, (char *)&numBlocks) < 0) {
+                       err = errno;
+                       goto labelExit;
+               }
+               totalSizeInBytes = numBlocks * nativeBlockSize;
+               break;
+       case S_IFREG:
+               nativeBlockSize = sbuf.st_blksize;
+               numBlocks = sbuf.st_size / sbuf.st_blksize;
+               totalSizeInBytes = sbuf.st_size;
+               break;
+       default:
+               errno = EINVAL;
+               goto labelExit;
+       }
+       if (block_size == 0) {
+               block_size = nativeBlockSize;
+       }
+       if (block_size == 0 || totalSizeInBytes == 0) {
+               err = EINVAL;
+               goto labelExit;
+       }
+
+       try {
+               *handle = new __wipefs_ctx;
+               if (*handle == NULL) {
+                       bad_alloc e;
+                       throw e;
+               }
+
+               (*handle)->fd = fd;
+               extMan = &(*handle)->extMan;
+
+               extMan->Init(block_size, nativeBlockSize, totalSizeInBytes);
+               AddExtentsForFutureFS(extMan);
+               AddExtentsForHFS(extMan);
+               AddExtentsForMSDOS(extMan);
+               AddExtentsForNTFS(extMan);
+               AddExtentsForUDF(extMan);
+               AddExtentsForUFS(extMan);
+               AddExtentsForZFS(extMan);
+               AddExtentsForPartitions(extMan);
+       }
+       catch (bad_alloc &e) {
+               err = ENOMEM;
+       }
+       catch (...) { // currently only ENOMEM is possible
+               err = ENOMEM;
+       }
+
+  labelExit:
+       if (err != 0) {
+               wipefs_free(handle);
+       }
+       return err;
+} // wipefs_alloc
+
+extern "C" int
+wipefs_except_blocks(wipefs_ctx handle, off_t block_offset, off_t nblocks)
+{
+       int err = 0;
+       try {
+               handle->extMan.RemoveBlockRangeExtent(block_offset, nblocks);
+       }
+       catch (bad_alloc &e) {
+               err = ENOMEM;
+       }
+       catch (...) { // currently only ENOMEM is possible
+               err = ENOMEM;
+       }
+       return err;
+}
+
+extern "C" int
+wipefs_wipe(wipefs_ctx handle)
+{
+       int err = 0;
+       uint8_t *bufZero = NULL;
+       ListExtIt curExt;
+       size_t bufSize;
+       dk_discard_t discard;
+
+       memset(&discard, 0, sizeof(dk_discard_t));
+       discard.length = handle->extMan.totalBytes;
+
+       //
+       // Don't bother to check the return value since this is mostly
+       // informational for the lower-level drivers.
+       //
+       ioctl(handle->fd, DKIOCDISCARD, (caddr_t)&discard);
+       
+
+       bufSize = 256 * 1024; // issue large I/O to get better performance
+       bufZero = new uint8_t[bufSize];
+       bzero(bufZero, bufSize);
+
+       off_t byteOffset, totalBytes;
+       size_t numBytes, numBytesToWrite, blockSize;
+
+       blockSize = handle->extMan.blockSize;
+       totalBytes = handle->extMan.totalBytes;
+       // write zero to all extents
+       for (curExt = handle->extMan.extentList.begin(); curExt != handle->extMan.extentList.end(); curExt++) {
+               byteOffset = curExt->blockAddr * blockSize;
+               numBytes = curExt->numBlocks * blockSize;
+               // make both offset and numBytes on native block boundary
+               if (byteOffset % handle->extMan.nativeBlockSize != 0 ||
+                       numBytes % handle->extMan.nativeBlockSize != 0) {
+                       size_t nativeBlockSize = handle->extMan.nativeBlockSize;
+                       off_t newOffset, newEndOffset;
+                       newOffset = byteOffset / nativeBlockSize * nativeBlockSize;
+                       newEndOffset = roundup(byteOffset + numBytes, nativeBlockSize);
+                       byteOffset = newOffset;
+                       numBytes = newEndOffset - newOffset;
+               }
+               if (byteOffset + (off_t)numBytes > totalBytes) {
+                       numBytes = totalBytes - byteOffset;
+               }
+               while (numBytes > 0) {
+                       numBytesToWrite = min(numBytes, bufSize);
+                       if (pwrite(handle->fd, bufZero, numBytesToWrite, byteOffset) != (ssize_t)numBytesToWrite) {
+                               err = errno;
+                               goto labelExit;
+                       }
+                       numBytes -= numBytesToWrite;
+                       byteOffset += numBytesToWrite;
+               }
+       }       
+
+  labelExit:
+       if (bufZero != NULL)
+               delete[] bufZero;
+       return err;
+} // wipefs_wipe
+
+extern "C" void
+wipefs_free(wipefs_ctx *handle)
+{
+       if (*handle != NULL) {
+               delete *handle;
+               *handle = NULL;
+       }
+}
diff --git a/wipefs.h b/wipefs.h
new file mode 100644 (file)
index 0000000..e615d5e
--- /dev/null
+++ b/wipefs.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+//     wipefs.h
+//
+#ifndef WIPEFS_H
+#define WIPEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct __wipefs_ctx *wipefs_ctx;
+
+__BEGIN_DECLS
+extern int wipefs_alloc(int fd, size_t block_size, wipefs_ctx *handle);
+extern int wipefs_except_blocks(wipefs_ctx handle, off_t block_offset, off_t nblocks);
+extern int wipefs_wipe(wipefs_ctx handle);
+extern void wipefs_free(wipefs_ctx *handle);
+__END_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef WIPEFS_H
+