--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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
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
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
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)
# 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
$(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
--- /dev/null
+__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
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
int pidfile_remove(struct pidfh *pfh);
#endif
+int reexec_to_match_kernel(void);
+
__END_DECLS
#define UU_LOCK_INUSE (1)
--- /dev/null
+.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.
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+.\"\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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
+