/*
 * Copyright (c) 2003 Apple 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@
 */
#define REDO_PREBINDING_VERSION 2
#include <mach/machine.h>
/*
 * For all APIs in this file the parameters program_name and error_message
 * are used the same.  For unrecoverable resource errors like being unable to
 * allocate memory each API prints a message to stderr precede with program_name
 * then calls exit(2) with the value EXIT_FAILURE.  If an API is unsuccessful
 * and if error_message pass to it is not NULL it is set to a malloc(3)'ed
 * buffer with a NULL terminated string with the error message.  For all APIs 
 * when they return they release all resources (memory, open file descriptors,
 * etc). 
 * 
 * The file_name parameter for these APIs may be of the form "foo(bar)" which is
 * NOT interpreted as an archive name and a member name in that archive.  As
 * these API deal with prebinding and prebound binaries ready for execution
 * can't be in archives.
 * 
 * If the executable_path parameter for these APIs is not NULL it is used for
 * any dependent library has a path that starts with "@executable_path". Then
 * "@executable_path" is replaced with executable_path. 
 * 
 * If the root_dir parameter is not NULL it is prepended to all the rooted
 * dependent library paths. 
 */

/*
 * dependent_libs() takes a file_name of a binary and returns a malloc(3)'ed
 * array of pointers (NULL terminated) to names (also malloc(3)'ed and '\0'
 * terminated names) of all the dependent libraries for that binary (not
 * recursive) for all of the architectures of that binary.  If successful
 * dependent_libs() returns a non NULL value (at minimum a pointer to one NULL
 * pointer). If unsuccessful dependent_libs() returns NULL.
 */ 
extern
char **
dependent_libs(
const char *file_name,
const char *program_name,
char **error_message);

/*
 * install_name() takes a file_name of a binary and returns a malloc(3)'ed
 * pointer to a NULL terminated string containing the install_name value for
 * the binary. If unsuccessful install_name() returns NULL.  In particular,
 * NULL is returned if the binary is not a dylib and there is no error_message
 * set.  If the all of the arch's are dylibs but all the install names don't
 * match NULL is returned and a error_message is set.  If some but not all of
 * the archs are dylibs NULL is returned and a error_message is set.
 */ 
extern
char *
install_name(
const char *file_name,
const char *program_name,
char **error_message);

/* return values for redo_prebinding() */
enum redo_prebinding_retval {
    REDO_PREBINDING_SUCCESS,
    REDO_PREBINDING_FAILURE,
    /* the following can only be returned if the parameter only_if_needed set */
    REDO_PREBINDING_NOT_NEEDED,
    REDO_PREBINDING_NOT_PREBOUND,
    REDO_PREBINDING_NEEDS_REBUILDING
};

/*
 * redo_prebinding() takes a file_name of a binary and redoes the prebinding on
 * it.  If output_file is not NULL the update file is written to output_file,
 * if not it is written to file_name.  If redo_prebinding() is successful it
 * returns REDO_PREBINDING_SUCCESS otherwise it returns REDO_PREBINDING_FAILURE.
 * If the parameter allow_missing_architectures is zero and not all
 * architectures can be updated it is not successful and nothing is done and
 * this returns REDO_PREBINDING_FAILURE.  If the parameter
 * allow_missing_architectures is non-zero then only problems with missing
 * architectures for the architecure of the cputype specified by 
 * allow_missing_architectures will cause this call to fail.  Other
 * architectures that could not be prebound due to missing architectures in
 * depending libraries will not have their prebinding updated but will not
 * cause this call to fail.
 * If the slide_to_address parameter is non-zero and the binary is a
 * dynamic library it is relocated to have that has its prefered address.  If
 * only_if_needed is non-zero the prebinding is checked first and only done if
 * needed.  The checking includes checking the prefered address against the
 * slide_to_address value if it is non-zero.  If only_if_needed is non-zero
 * and the prebinding does not have to be redone REDO_PREBINDING_NOT_NEEDED is
 * returned, if the binary is not prebound REDO_PREBINDING_NOT_PREBOUND is
 * returned and if the new load commands do not fit in the binary and it needs
 * to be rebuilt REDO_PREBINDING_NEEDS_REBUILDING is returned.
 * If zero_out_prebind_checksum is non-zero then the cksum field of the
 * LC_PREBIND_CKSUM load command (if any) is set to zero on output (this should
 * always be set by B&I tools and never set by the update_prebinding(1)
 * command).
 * If throttle is non-NULL it points to a value of the maximum bytes per second
 * to use for writting the output.  If the value is ULONG_MAX then the actual
 * bytes per second is returned indirectly through *throttle.
 */
extern 
enum redo_prebinding_retval
redo_prebinding(
const char *file_name,
const char *executable_path,
const char *root_dir,
const char *output_file,
const char *program_name,
char **error_message,
unsigned long slide_to_address,
int only_if_needed,
int zero_out_prebind_checksum,
cpu_type_t allow_missing_architectures,
unsigned long *throttle);


/* return values for needs_redo_prebinding() */
enum needs_redo_prebinding_retval {
    PREBINDING_UPTODATE,  /* a binary who's prebinding is up todate */
    PREBINDING_OUTOFDATE, /* a binary who's prebinding is out of date */
    NOT_PREBOUND,	  /* a binary, but not built prebound */
    NOT_PREBINDABLE,	  /* not a binary or statically linked,
			     prebinding does not apply */
    PREBINDING_UNKNOWN	  /* a binary who's prebinding can't be determined
			     because it is malformed, a library it depends
			     on is missing, etc. */
};

/*
 * needs_redo_prebinding() takes a file_name and determines if it is a binary
 * and if its prebinding is uptodate.  It returns one of the return values
 * above depending on the state of the binary and libraries. If the parameter
 * allow_missing_architectures is zero then the value returned is based on the
 * first architecture for fat files.  If the parameter
 * allow_missing_architectures is non-zero then the value returned is based on
 * the cputype specified by allow_missing_architectures.  If that architecture
 * is not present then PREBINDING_UPTODATE is returned.  If the parameter
 * expected_address is not zero and the binary is a dynamic library then the
 * library is checked to see if it is at the expected_address if not the
 * prebinding is assumed to be out of date and PREBINDING_OUTOFDATE is returned.
 */
extern
enum needs_redo_prebinding_retval
needs_redo_prebinding(
const char *file_name,
const char *executable_path,
const char *root_dir,
const char *program_name,
char **error_message,
unsigned long expected_address,
cpu_type_t allow_missing_architectures);


/*
 * unprebind() takes a file_name of a binary and resets or removes prebinding
 * information from it.  If inbuf is non-NULL, the memory pointed to by inbuf is
 * used as the input file contents.  Otherwise, the contents are loaded from 
 * the file at path file_name.  Even if inbuf is non-NULL, a file_name 
 * parameter should be specified for error reporting.  Similarly, if outbuf is 
 * non-NULL, upon return, outbuf will point to a buffer containing the 
 * unprebound binary and outlen will point to the length of the output buffer.  
 * This buffer is vm_allocate'd and therefore should be vm_deallocate'd when it 
 * is no longer needed.  If outbuf is NULL, and output_file is not NULL the 
 * update file is written to output_file, if outbuf is NULL and output_file is 
 * NULL, it is written to file_name.  
 * If unprebind() is successful it returns REDO_PREBINDING_SUCCESS otherwise it
 * returns REDO_PREBINDING_FAILURE If the binary is already unprebound (i.e. it
 * has the MH_PREBINDABLE flag set) then REDO_PREBINDING_NOT_NEEDED is returned.
 * If the binary is not prebound and not prebindable, 
 * REDO_PREBINDING_NOT_PREBOUND is returned.  If zero_checksum is non-zero then
 * the cksum field the LC_PREBIND_CKSUM load command (if any) is set to zero on
 * output, otherwise it is left alone.
 * Unprebinding slides dynamic libraries to address zero, resets prebound 
 * symbols to address zero and type undefined, resets symbol pointers, removes 
 * LC_PREBOUND_DYLIB commands, resets library timestamps, resets two-level hints
 * and updates relocation entries if necessary.  Unprebound binaries have
 * the MH_PREBINDABLE flag set, but not MH_PREBOUND.  It will also set the the
 * MH_ALLMODSBOUND flag if all two-level libraries were used and all modules
 * were found to be bound in the LC_PREBOUND_DYLIB commands.
 * As unprebinding is intended to produce a canonical Mach-O
 * binary, bundles and non-prebound executables and dylibs are acceptable
 * as input.  For these files, the  unprebind operation will zero library 
 * time stamps and version numbers and zero entries in the two-level hints
 * table.  These files will not gain the MH_PREBINDABLE flag.
 * All resulting binaries successfully processed by unprebind() will have
 * the MH_CANONICAL flag.
 */
extern
enum redo_prebinding_retval
unprebind(
const char *file_name,
const char *output_file,
const char *program_name,
char **error_message,
int zero_checksum,
void *inbuf,
unsigned long inlen,
void **outbuf,
unsigned long *outlen);

enum object_file_type_retval {
    OFT_OTHER,
    OFT_EXECUTABLE,
    OFT_DYLIB,
    OFT_BUNDLE,
    OFT_ARCHIVE,
    OFT_INCONSISTENT,
    OFT_FILE_ERROR
};

/*
 * object_file_type() takes a file_name and determines what type of object
 * file it is.  If it is a fat file and the architectures are not of the same
 * type then OFT_INCONSISTENT is returned.  If the file_name can't be opened,
 * read or malformed then OFT_FILE_ERROR is returned.
 */
extern
enum object_file_type_retval
object_file_type(
const char *file_name,
const char *program_name,
char **error_message);

struct prebind_cksum_arch {
    cpu_type_t cputype;		/* cpu specifier */
    cpu_subtype_t cpusubtype;	/* machine specifier */
    unsigned long has_cksum;	/* 1 if the arch as an LC_PREBIND_CKSUM */
    unsigned long cksum;	/* value of the cksum in LC_PREBIND_CKSUM */
};

/*
 * get_prebind_cksums() takes a file_name that is a Mach-O file or fat file
 * containing Mach-O files and returns a malloc(3)'ed array of
 * prebind_cksum_arch structs indirectly through the cksums parameter.  The
 * number of prebind_cksum_arch structs is returned indirectly through the
 * ncksums parameter.  If successful it returns zero else it returns non-zero.
 */
extern
int
get_prebind_cksums(
const char *file_name,
struct prebind_cksum_arch **cksums,
unsigned long *ncksums,
const char *program_name,
char **error_message);
