/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Routines to add file and directory entries into the internal configuration
* information. This information is maintained in a number of hash tables which
* after completion of input file processing will be processed and written to
* the output configuration file.
*
* Each hash table is defined via a Hash_tbl structure. These are organized:
*
* c_strtbl contains a hash entry for every file, directory, pathname and
* alternative path (dldump(3dl) image) processed.
* c_strsize and c_objnum maintain the size and count of the
* strings added to this table and are used to size the output
* configuration file.
*
* c_inotbls contains a list of inode hash tables. Each element of the list
* identifies a unique device. Thus, for each file processed its
* st_dev and st_ino are used to assign its entry to the correct
* hash table.
*
* Each directory processed is assigned a unique id (c_dirnum)
* which insures each file also becomes uniquely identified.
*
* All file and directory additions come through the inspect() entry point.
*/
#include <fcntl.h>
#include <dirent.h>
#include <_libelf.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "machdep.h"
#include "sgs.h"
#include "rtc.h"
#include "_crle.h"
#include "msg.h"
/*
* Add an alternative pathname for an object. Although a configuration file
* may contain several pathnames that resolve to the same real file, there can
* only be one real file. Consequently, there can only be one alternative.
* For multiple pathnames that resolve to the same real file, multiple alter-
* natives may be specified. Always take the alternative for the real file
* over any others.
*/
static int
{
const char *fmt;
/*
* If an alternative has already been captured, only override
* it if the specified file is the real file.
*/
return (1);
}
/*
* Create an alternative pathname from the file and object destination
* directory. If we're dumping an alternative don't allow it to
* override the original.
*/
if (flags & RTC_OBJ_DUMP) {
return (0);
}
} else
/*
* If we're overriding an existing alternative with the real path, free
* up any previous alternative.
*/
} else
/*
* Allocate the new alternative and update the string table size.
*/
return (0);
return (1);
}
/*
* Establish an inode hash entry, this is unique for each dev hash table, and
* establishes the unique object descriptor.
*/
static Hash_ent *
{
int found = 0;
/*
* For configuration file verification we retain information about the
* file or directory.
*/
if (flags & RTC_OBJ_DIRENT)
else
/*
* Determine the objects device number and establish a hash table for
* for this devices inodes.
*/
found = 1;
break;
}
}
if (found == 0) {
return (NULL);
return (NULL);
}
/*
* Reuse or add this new object to the inode hash table.
*/
return (NULL);
/*
* If an object descriptor doesn't yet exist create one.
*/
return (NULL);
/*
* Reallocate the objects name, as it might have been composed
* and passed to us on the stack.
*/
return (NULL);
/*
* Assign this object to the original ino hash entry.
*/
}
return (ent);
}
/*
* Basic directory entry, establishes entry information, updated global counts
* and provides any diagnostics.
*/
static int
{
char *ndir;
/*
* Establish this hash entries key (which is the directory name itself),
* assign the next available directory number, and its object.
*/
return (0);
/*
* Update string table information. We add a dummy filename for each
* real directory so as to have a null terminated file table array for
* this directory.
*/
crle->c_hashstrnum++;
/*
* Provide any diagnostics.
*/
const char *fmt;
else
}
return (1);
}
/*
* Establish a string hash entry for a directory.
*/
static Hash_ent *
{
/*
* Establish the directories real name, this is the name that will be
* recorded in the object identifier.
*/
return (NULL);
else
/*
* If we're not dealing with an all-entries directory (i.e., we're
* recording this directory because of its explicitly specified
* filename) leave off any filename specific attributes.
*/
if ((flags & RTC_OBJ_ALLENTS) == 0)
flags |= RTC_OBJ_DIRENT;
/*
* Establish a inode table entry, and the objects unique descriptor.
*/
return (NULL);
/*
* Create a string table entry for the real directory.
*/
return (NULL);
/*
* If this is a new entry reassign the directory name and assign a
* unique directory id.
*/
return (NULL);
}
/*
* If the directory name supplied is different than the real name we've
* just entered, continue to create an entry for it.
*/
return (ent);
/*
* Create a string table entry for this real directory.
*/
return (NULL);
/*
* If this is a new entry reassign the directory name and assign a
* unique directory id.
*/
return (NULL);
}
return (ent);
}
/*
* Establish a non-existent directory entry. There is no inode entry created
* for this, just a directory and its associated object.
*/
static Hash_ent *
{
/*
* Reuse or add this new non-existent directory to the string table.
*/
return (NULL);
/*
* If this is a new entry, assign both the object and the directory
* entry information.
*/
return (NULL);
return (NULL);
}
return (ent);
}
/*
* Basic file entry, establishes entry information, updated global counts
* and provides any diagnostics.
*/
static int
{
char *nfile;
/*
* If this is a full file name reallocate it, as it might have been
* composed and passed to us on the stack. Otherwise reuse the original
* directory name to satisfy the filename, here we record the offset of
* the file in the directory name so that we can reduce the string table
* in the final configuration file.
*/
if (off == 0) {
return (0);
} else
/*
* Assign directory and directory id, and any real (full) path
* association.
*/
/*
* Increment the file count for this directory.
*/
/*
* Assign this object to the new string hash entry.
*/
/*
* Update string table information.
*/
crle->c_hashstrnum++;
/*
* Provide any diagnostics.
*/
return (1);
}
/*
* Establish a non-existent file entry. There is no inode entry created for
* this, just the files full and simple name, and its associated object.
*/
static Hash_ent *
{
int off;
/*
* Create a string table entry for the full filename.
*/
return (NULL);
/*
* If this is a new entry, assign both the object and the full filename
* entry information.
*/
return (NULL);
return (NULL);
}
return (NULL);
/*
* Express the filename in terms of the full pathname. By reusing the
* name within the full filename we can reduce the overall string table
* size in the output configuration file.
*/
/*
* Create a entry for the individual file within this directory.
*/
return (NULL);
return (NULL);
}
return (ent);
}
/*
* Establish a string hash entry for a file.
*/
static Hash_ent *
{
int off;
/*
* Establish the files real name, this is the name that will be
* recorded in the object identifier.
*/
return (NULL);
nfile++;
else
/*
* Determine if the real pathname has a different directory to
* the original passed to us.
*/
return (NULL);
}
} else {
}
/*
* Establish an inode table entry, and the objects unique descriptor.
*/
return (NULL);
/*
* Create a string table entry for the full filename.
*/
return (NULL);
return (NULL);
}
/*
* Identify this entry and its directory as real paths. If dldump(3dl)
* processing is required this flag is checked, as we only need to dump
* the real pathname. Many other objects may point to the same
* alternative, but only one needs to be dumped. In addition, during
* ld.so.1 validation, only this directory and file need be checked.
*/
/*
* Express the filename in terms of the full pathname. By reusing the
* name within the full filename we can reduce the overall string table
* size in the output configuration file.
*/
/*
* Create a entry for the individual file within this directory.
*/
return (NULL);
return (NULL);
}
/*
* If the original path name is not equivalent to the real path name,
* then we had an alias (typically it's a symlink). Add the path name
* to the string hash table and reference the object data structure.
*/
return (ent);
/*
* Establish an inode table entry, and the objects unique descriptor.
*/
return (NULL);
/*
* Create a string table entry for the full filename.
*/
return (NULL);
return (NULL);
}
/*
* Express the filename in terms of the full pathname. By reusing the
* name within the full filename we can reduce the overall string table
* size in the output configuration file.
*/
/*
* Create a entry for the individual file within this directory.
*/
return (NULL);
return (NULL);
}
return (ent);
}
/*
* Add a file to configuration information.
*/
static int
{
int fd;
/*
* Determine whether this file (inode) has already been processed.
*/
continue;
break;
/*
* This files inode object does exist, make sure it has a file
* entry for this directory.
*/
return (error);
/*
* If an alternative has been asked for, and one has not yet
* been established, create one.
*/
if ((flags & RTC_OBJ_ALTER) &&
return (error);
}
return (0);
}
/*
* This is a new file, determine if it's a valid ELF file.
*/
if (error) {
}
return (error);
}
/*
* Obtain an ELF descriptor and determine if we have a shared object.
*/
if (error)
return (error);
}
if (error)
return (error);
}
/*
* If we're generating alternative objects find this objects DT_FLAGS
* to insure it isn't marked as non-dumpable (libdl.so.1 falls into
* this category).
*/
if (flags & RTC_OBJ_DUMP)
/*
* Dynamic executables can be examined to determine their dependencies,
* dldump(3dl) their dependencies, and may even be dldump(3dl)'ed
* themselves.
*
* If we come across an executable while searching a directory
* (error == 0) it is ignored.
*/
if (error == 0) {
return (0);
}
/*
* If we're not dumping the application itself, or we've not
* asked to gather its dependencies then its rather useless.
*/
return (error);
}
/*
* If we're dumping the application under RTLD_REL_EXEC then the
* configuration file becomes specific to this application, so
* make sure we haven't been here before.
*/
return (error);
}
}
/*
* Enter the file in the string hash table.
*/
return (error);
}
if (flags & RTC_OBJ_ALTER) {
/*
* If this object is marked as non-dumpable make sure we don't
* create a dldump(3dl) alternative. A user requested
* alternative is acceptable.
*/
} else {
return (error);
}
}
}
/*
* Executables are recorded in the configuration file either to allow
* for the configuration files update, or may indicate that the
* configuration file is specific to their use.
*/
if ((flags & RTC_OBJ_DUMP) &&
/*
* Get the reallocated pathname rather than using the
* original (the original might be from an existing
* configuration file being updated, in which case the
* pointer will be unmapped before we get to use it).
*/
}
}
/*
* If we've been asked to process this object as a group determine its
* dependencies.
*/
if (flags & RTC_OBJ_GROUP) {
return (error);
}
}
return (0);
}
/*
* Add a directory to configuration information.
*/
static int
{
int error = 0;
const char *src;
/*
* Determine whether we've already visited this directory to process
* all its entries.
*/
return (0);
} else {
/*
* Create a directory hash entry.
*/
return (1);
}
/*
* Establish the pathname buffer.
*/
if (*dst++ != '/')
*dst++ = '/';
/*
* Access the directory in preparation for reading its entries.
*/
return (1);
/*
* Read each entry from the directory looking for ELF files.
*/
char *_dst;
/*
* Ignore "." and ".." entries.
*/
continue;
/*
* Complete full pathname, and reassign file to the new path.
*/
*_dst = '\0';
continue;
continue;
error = 1;
break;
}
}
return (error);
}
/*
*
* The name doesn't exist:
* The name is assummed to be a non-existent directory and a directory
* cache entry is created to indicate this.
*
* The name is a directory:
* The directory is searched for appropriate files.
*
* The name is a file:
* The file is processed and added to the cache if appropriate.
*/
int
{
int noexist;
/*
* If this is the first time through here establish a string table
* cache.
*/
return (1);
}
/*
* Determine whether the name exists.
*/
return (1);
} else {
/*
* If we've been asked to create an alternative object
* assume the object is a file and create a valid
* alternative entry. This allows the creation of
* alternatives for files that might not yet be
* installed.
*
* Otherwise we have no idea whether the name specified
* is a file or directory, so we assume a directory and
* establish an object descriptor to mark this as
* non-existent. This allows us to mark things like
* platform specific directories as non-existent.
*/
return (1);
return (0);
}
}
}
/*
* Determine whether we're dealing with a directory or a file.
*/
/*
* Process the directory name to collect its shared objects into
* the configuration file.
*/
return (1);
return (0);
}
/*
* If this isn't a regular file we might as well bail now. Note that
* even if it is, we might still reject the file if it's not ELF later
* in inspect_file().
*/
name);
return (1);
}
/*
* Break the pathname into directory and filename components.
*/
} else {
else {
}
file++;
}
/*
* Determine whether we've already visited this directory and if not
* create it.
*/
return (1);
} else {
/*
* Note that this directory will be tagged as
* having an alternative - not that the
* directory does, but supposedly it contains
* a file that does.
*/
return (1);
}
} else {
return (1);
}
}
/*
* Regardless of whether we've already processed this file (say from
* an RTC_OBJ_ALLENTS which we could determine from the above), continue
* to inspect the file. It may require alternatives or something that
* hadn't be specified from the directory entry.
*/
if (noexist) {
return (1);
return (1);
} else {
return (1);
}
/*
* Make sure to propagate any RTC_OBJ_CMDLINE flag.
*/
return (0);
}