diff options
-rw-r--r-- | usr/src/man/man7/zpool-features.7 | 1420 | ||||
-rw-r--r-- | usr/src/pkg/manifests/developer-build-onbld.p5m | 3 | ||||
-rw-r--r-- | usr/src/tools/Makefile | 2 | ||||
-rw-r--r-- | usr/src/tools/find_elf/Makefile | 68 | ||||
-rw-r--r-- | usr/src/tools/find_elf/find_elf.1onbld (renamed from usr/src/tools/scripts/find_elf.1onbld) | 21 | ||||
-rw-r--r-- | usr/src/tools/find_elf/find_elf.c | 863 | ||||
-rw-r--r-- | usr/src/tools/scripts/Makefile | 3 | ||||
-rw-r--r-- | usr/src/tools/scripts/find_elf.pl | 457 |
8 files changed, 1585 insertions, 1252 deletions
diff --git a/usr/src/man/man7/zpool-features.7 b/usr/src/man/man7/zpool-features.7 index 146bfc5262..aabc9bc4ad 100644 --- a/usr/src/man/man7/zpool-features.7 +++ b/usr/src/man/man7/zpool-features.7 @@ -1,4 +1,4 @@ -'\" te +.\" .\" Copyright (c) 2013, 2017 by Delphix. All rights reserved. .\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved. .\" Copyright (c) 2014, Joyent, Inc. All rights reserved. @@ -15,821 +15,661 @@ .\" CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your .\" own identifying information: .\" Portions Copyright [yyyy] [name of copyright owner] -.TH ZPOOL-FEATURES 7 "May 15, 2019" -.SH NAME -zpool\-features \- ZFS pool feature descriptions -.SH DESCRIPTION -.LP -ZFS pool on\-disk format versions are specified via "features" which replace -the old on\-disk format numbers (the last supported on\-disk format number is -28). To enable a feature on a pool use the \fBupgrade\fR subcommand of the -\fBzpool\fR(8) command, or set the \fBfeature@\fR\fIfeature_name\fR property -to \fBenabled\fR. -.sp -.LP +.\" Copyright (c) 2019, Klara Inc. +.\" Copyright (c) 2019, Allan Jude +.Dd June 21, 2022 +.Dt ZPOOL-FEATURES 7 +.Os +. +.Sh NAME +.Nm zpool-features +.Nd description of ZFS pool features +. +.Sh DESCRIPTION +ZFS pool on-disk format versions are specified via +.Dq features +which replace the old on-disk format numbers +.Pq the last supported on-disk format number is 28 . +To enable a feature on a pool use the +.Nm zpool Cm upgrade , +or set the +.Sy feature Ns @ Ns Ar feature-name +property to +.Sy enabled . +.Pp The pool format does not affect file system version compatibility or the ability to send file systems between pools. -.sp -.LP -Since most features can be enabled independently of each other the on\-disk +.Pp +Since most features can be enabled independently of each other, the on-disk format of the pool is specified by the set of all features marked as -\fBactive\fR on the pool. If the pool was created by another software version +.Sy active +on the pool. +If the pool was created by another software version this set may include unsupported features. -.SS "Identifying features" -.LP -Every feature has a guid of the form \fIcom.example:feature_name\fR. The reverse -DNS name ensures that the feature's guid is unique across all ZFS -implementations. When unsupported features are encountered on a pool they will -be identified by their guids. Refer to the documentation for the ZFS +. +.Ss Identifying features +Every feature has a GUID of the form +.Ar com.example : Ns Ar feature-name . +The reversed DNS name ensures that the feature's GUID is unique across all ZFS +implementations. +When unsupported features are encountered on a pool they will +be identified by their GUIDs. +Refer to the documentation for the ZFS implementation that created the pool for information about those features. -.sp -.LP -Each supported feature also has a short name. By convention a feature's short -name is the portion of its guid which follows the ':' (e.g. -\fIcom.example:feature_name\fR would have the short name \fIfeature_name\fR), +.Pp +Each supported feature also has a short name. +By convention a feature's short name is the portion of its GUID which follows the +.Sq \&: +.Po +i.e. +.Ar com.example : Ns Ar feature-name +would have the short name +.Ar feature-name +.Pc , however a feature's short name may differ across ZFS implementations if following the convention would result in name conflicts. -.SS "Feature states" -.LP +. +.Ss Feature states Features can be in one of three states: -.sp -.ne 2 -.na -\fB\fBactive\fR\fR -.ad -.RS 12n -This feature's on\-disk format changes are in effect on the pool. Support for -this feature is required to import the pool in read\-write mode. If this -feature is not read-only compatible, support is also required to import the pool -in read\-only mode (see "Read\-only compatibility"). -.RE - -.sp -.ne 2 -.na -\fB\fBenabled\fR\fR -.ad -.RS 12n +.Bl -tag -width "disabled" +.It Sy active +This feature's on-disk format changes are in effect on the pool. +Support for this feature is required to import the pool in read-write mode. +If this feature is not read-only compatible, +support is also required to import the pool in read-only mode +.Pq see Sx Read-only compatibility . +.It Sy enabled An administrator has marked this feature as enabled on the pool, but the -feature's on\-disk format changes have not been made yet. The pool can still be -imported by software that does not support this feature, but changes may be made -to the on\-disk format at any time which will move the feature to the -\fBactive\fR state. Some features may support returning to the \fBenabled\fR -state after becoming \fBactive\fR. See feature\-specific documentation for -details. -.RE - -.sp -.ne 2 -.na -\fBdisabled\fR -.ad -.RS 12n -This feature's on\-disk format changes have not been made and will not be made -unless an administrator moves the feature to the \fBenabled\fR state. Features -cannot be disabled once they have been enabled. -.RE - -.sp -.LP +feature's on-disk format changes have not been made yet. +The pool can still be imported by software that does not support this feature, +but changes may be made to the on-disk format at any time +which will move the feature to the +.Sy active +state. +Some features may support returning to the +.Sy enabled +state after becoming +.Sy active . +See feature-specific documentation for details. +.It Sy disabled +This feature's on-disk format changes have not been made and will not be made +unless an administrator moves the feature to the +.Sy enabled +state. +Features cannot be disabled once they have been enabled. +.El +.Pp The state of supported features is exposed through pool properties of the form -\fIfeature@short_name\fR. -.SS "Read\-only compatibility" -.LP -Some features may make on\-disk format changes that do not interfere with other -software's ability to read from the pool. These features are referred to as -"read\-only compatible". If all unsupported features on a pool are read\-only -compatible, the pool can be imported in read\-only mode by setting the -\fBreadonly\fR property during import (see \fBzpool\fR(8) for details on -importing pools). -.SS "Unsupported features" -.LP -For each unsupported feature enabled on an imported pool a pool property -named \fIunsupported@feature_guid\fR will indicate why the import was allowed -despite the unsupported feature. Possible values for this property are: - -.sp -.ne 2 -.na -\fB\fBinactive\fR\fR -.ad -.RS 12n -The feature is in the \fBenabled\fR state and therefore the pool's on\-disk +.Sy feature Ns @ Ns Ar short-name . +. +.Ss Read-only compatibility +Some features may make on-disk format changes that do not interfere with other +software's ability to read from the pool. +These features are referred to as +.Dq read-only compatible . +If all unsupported features on a pool are read-only compatible, +the pool can be imported in read-only mode by setting the +.Sy readonly +property during import +.Po see +.Xr zpool 8 +for details on importing pools +.Pc . +. +.Ss Unsupported features +For each unsupported feature enabled on an imported pool, a pool property +named +.Sy unsupported Ns @ Ns Ar feature-name +will indicate why the import was allowed despite the unsupported feature. +Possible values for this property are: +.Bl -tag -width "readonly" +.It Sy inactive +The feature is in the +.Sy enabled +state and therefore the pool's on-disk format is still compatible with software that does not support this feature. -.RE - -.sp -.ne 2 -.na -\fB\fBreadonly\fR\fR -.ad -.RS 12n -The feature is read\-only compatible and the pool has been imported in -read\-only mode. -.RE - -.SS "Feature dependencies" -.LP -Some features depend on other features being enabled in order to function -properly. Enabling a feature will automatically enable any features it -depends on. -.SH FEATURES -.LP +.It Sy readonly +The feature is read-only compatible and the pool has been imported in +read-only mode. +.El +. +.Ss Feature dependencies +Some features depend on other features being enabled in order to function. +Enabling a feature will automatically enable any features it depends on. +. +.de feature +.It Sy \\$2 +.Bl -tag -compact -width "READ-ONLY COMPATIBLE" +.It GUID +.Sy \\$1:\\$2 +.if !"\\$4"" \{\ +.It DEPENDENCIES +\fB\\$4\fP\c +.if !"\\$5"" , \fB\\$5\fP\c +.if !"\\$6"" , \fB\\$6\fP\c +.if !"\\$7"" , \fB\\$7\fP\c +.if !"\\$8"" , \fB\\$8\fP\c +.if !"\\$9"" , \fB\\$9\fP\c +.\} +.It READ-ONLY COMPATIBLE +\\$3 +.El +.Pp +.. +. +.ds instant-never \ +.No This feature becomes Sy active No as soon as it is enabled \ +and will never return to being Sy enabled . +. +.ds remount-upgrade \ +.No Each filesystem will be upgraded automatically when remounted, \ +or when a new file is created under that filesystem. \ +The upgrade can also be triggered on filesystems via \ +Nm zfs Cm set Sy version Ns = Ns Sy current Ar fs . \ +No The upgrade process runs in the background and may take a while to complete \ +for filesystems containing large amounts of files. +. +.de checksum-spiel +When the +.Sy \\$1 +feature is set to +.Sy enabled , +the administrator can turn on the +.Sy \\$1 +checksum on any dataset using +.Nm zfs Cm set Sy checksum Ns = Ns Sy \\$1 Ar dset +.Po see Xr zfs 8 Pc . +This feature becomes +.Sy active +once a +.Sy checksum +property has been set to +.Sy \\$1 , +and will return to being +.Sy enabled +once all filesystems that have ever had their checksum set to +.Sy \\$1 +are destroyed. +.. +. +.Sh FEATURES The following features are supported on this system: -.sp -.ne 2 -.na -\fB\fBasync_destroy\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:async_destroy -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - +.Bl -tag -width Ds +.feature org.zfsonlinux allocation_classes yes +This feature enables support for separate allocation classes. +.Pp +This feature becomes +.Sy active +when a dedicated allocation class vdev +.Pq dedup or special +is created with the +.Nm zpool Cm create No or Nm zpool Cm add No commands . +With device removal, it can be returned to the +.Sy enabled +state if all the dedicated allocation class vdevs are removed. +. +.feature com.delphix async_destroy yes Destroying a file system requires traversing all of its data in order to -return its used space to the pool. Without \fBasync_destroy\fR the file system -is not fully removed until all space has been reclaimed. If the destroy -operation is interrupted by a reboot or power outage the next attempt to open -the pool will need to complete the destroy operation synchronously. - -When \fBasync_destroy\fR is enabled the file system's data will be reclaimed -by a background process, allowing the destroy operation to complete without -traversing the entire file system. The background process is able to resume +return its used space to the pool. +Without +.Sy async_destroy , +the file system is not fully removed until all space has been reclaimed. +If the destroy operation is interrupted by a reboot or power outage, +the next attempt to open the pool will need to complete the destroy +operation synchronously. +.Pp +When +.Sy async_destroy +is enabled, the file system's data will be reclaimed by a background process, +allowing the destroy operation to complete +without traversing the entire file system. +The background process is able to resume interrupted destroys after the pool has been opened, eliminating the need -to finish interrupted destroys as part of the open operation. The amount -of space remaining to be reclaimed by the background process is available -through the \fBfreeing\fR property. - -This feature is only \fBactive\fR while \fBfreeing\fR is non\-zero. -.RE - -.sp -.ne 2 -.na -\fB\fBempty_bpobj\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:empty_bpobj -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - +to finish interrupted destroys as part of the open operation. +The amount of space remaining to be reclaimed by the background process +is available through the +.Sy freeing +property. +.Pp +This feature is only +.Sy active +while +.Sy freeing +is non-zero. +. +.feature com.delphix bookmarks yes extensible_dataset +This feature enables use of the +.Nm zfs Cm bookmark +command. +.Pp +This feature is +.Sy active +while any bookmarks exist in the pool. +All bookmarks in the pool can be listed by running +.Nm zfs Cm list Fl t Sy bookmark Fl r Ar poolname . +. +.feature com.datto bookmark_v2 no bookmark extensible_dataset +This feature enables the creation and management of larger bookmarks which are +needed for other features in ZFS. +.Pp +This feature becomes +.Sy active +when a v2 bookmark is created and will be returned to the +.Sy enabled +state when all v2 bookmarks are destroyed. +. +.feature com.delphix device_removal no +This feature enables the +.Nm zpool Cm remove +command to remove top-level vdevs, +evacuating them to reduce the total size of the pool. +.Pp +This feature becomes +.Sy active +when the +.Nm zpool Cm remove +command is used +on a top-level vdev, and will never return to being +.Sy enabled . +. +.feature org.illumos edonr no extensible_dataset +This feature enables the use of the Edon-R hash algorithm for checksum, +including for nopwrite +.Po if compression is also enabled, an overwrite of +a block whose checksum matches the data being written will be ignored +.Pc . +In an abundance of caution, Edon-R requires verification when used with +dedup: +.Nm zfs Cm set Sy dedup Ns = Ns Sy edonr , Ns Sy verify +.Po see Xr zfs 8 Pc . +.Pp +Edon-R is a very high-performance hash algorithm that was part +of the NIST SHA-3 competition. +It provides extremely high hash performance +.Pq over 350% faster than SHA-256 , +but was not selected because of its unsuitability +as a general purpose secure hash algorithm. +This implementation utilizes the new salted checksumming functionality +in ZFS, which means that the checksum is pre-seeded with a secret +256-bit random key +.Pq stored on the pool +before being fed the data block to be checksummed. +Thus the produced checksums are unique to a given pool, +preventing hash collision attacks on systems with dedup. +.Pp +.checksum-spiel edonr +. +.feature com.delphix embedded_data no +This feature improves the performance and compression ratio of +highly-compressible blocks. +Blocks whose contents can compress to 112 bytes +or smaller can take advantage of this feature. +.Pp +When this feature is enabled, the contents of highly-compressible blocks are +stored in the block +.Dq pointer +itself +.Po a misnomer in this case, as it contains +the compressed data, rather than a pointer to its location on disk +.Pc . +Thus the space of the block +.Pq one sector, typically 512 B or 4 KiB +is saved, and no additional I/O is needed to read and write the data block. +. +\*[instant-never] +. +.feature com.delphix empty_bpobj yes This feature increases the performance of creating and using a large number of snapshots of a single filesystem or volume, and also reduces the disk space required. - +.Pp When there are many snapshots, each snapshot uses many Block Pointer -Objects (bpobj's) to track blocks associated with that snapshot. -However, in common use cases, most of these bpobj's are empty. This -feature allows us to create each bpobj on-demand, thus eliminating the -empty bpobjs. - -This feature is \fBactive\fR while there are any filesystems, volumes, +Objects +.Pq bpobjs +to track blocks associated with that snapshot. +However, in common use cases, most of these bpobjs are empty. +This feature allows us to create each bpobj on-demand, +thus eliminating the empty bpobjs. +.Pp +This feature is +.Sy active +while there are any filesystems, volumes, or snapshots which were created after enabling this feature. -.RE - -.sp -.ne 2 -.na -\fB\fBfilesystem_limits\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.joyent:filesystem_limits -READ\-ONLY COMPATIBLE yes -DEPENDENCIES extensible_dataset -.TE - -This feature enables filesystem and snapshot limits. These limits can be used -to control how many filesystems and/or snapshots can be created at the point in -the tree on which the limits are set. - -This feature is \fBactive\fR once either of the limit properties has been -set on a dataset. Once activated the feature is never deactivated. -.RE - -.sp -.ne 2 -.na -\fB\fBlz4_compress\fR\fR -.ad -.RS 4n -.TS -l l . -GUID org.illumos:lz4_compress -READ\-ONLY COMPATIBLE no -DEPENDENCIES none -.TE - -\fBlz4\fR is a high-performance real-time compression algorithm that -features significantly faster compression and decompression as well as a -higher compression ratio than the older \fBlzjb\fR compression. -Typically, \fBlz4\fR compression is approximately 50% faster on -compressible data and 200% faster on incompressible data than -\fBlzjb\fR. It is also approximately 80% faster on decompression, while -giving approximately 10% better compression ratio. - -When the \fBlz4_compress\fR feature is set to \fBenabled\fR, the -administrator can turn on \fBlz4\fR compression on any dataset on the -pool using the \fBzfs\fR(8) command. Also, all newly written metadata -will be compressed with \fBlz4\fR algorithm. Since this feature is not -read-only compatible, this operation will render the pool unimportable -on systems without support for the \fBlz4_compress\fR feature. Booting -off of \fBlz4\fR-compressed root pools is supported. - -This feature becomes \fBactive\fR as soon as it is enabled and will -never return to being \fBenabled\fR. -.RE - -.sp -.ne 2 -.na -\fB\fBspacemap_histogram\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:spacemap_histogram -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - -This features allows ZFS to maintain more information about how free space -is organized within the pool. If this feature is \fBenabled\fR, ZFS will -set this feature to \fBactive\fR when a new space map object is created or -an existing space map is upgraded to the new format. Once the feature is -\fBactive\fR, it will remain in that state until the pool is destroyed. -.RE - -.sp -.ne 2 -.na -\fB\fBmulti_vdev_crash_dump\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.joyent:multi_vdev_crash_dump -READ\-ONLY COMPATIBLE no -DEPENDENCIES none -.TE - -This feature allows a dump device to be configured with a pool comprised -of multiple vdevs. Those vdevs may be arranged in any mirrored or raidz -configuration. - -When the \fBmulti_vdev_crash_dump\fR feature is set to \fBenabled\fR, -the administrator can use the \fBdumpadm\fR(8) command to configure a -dump device on a pool comprised of multiple vdevs. -.RE - -.sp -.ne 2 -.na -\fB\fBextensible_dataset\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:extensible_dataset -READ\-ONLY COMPATIBLE no -DEPENDENCIES none -.TE - +. +.feature com.delphix enabled_txg yes +Once this feature is enabled, ZFS records the transaction group number +in which new features are enabled. +This has no user-visible impact, but other features may depend on this feature. +.Pp +This feature becomes +.Sy active +as soon as it is enabled and will never return to being +.Sy enabled . +. +.feature com.datto encryption no bookmark_v2 extensible_dataset +This feature enables the creation and management of natively encrypted datasets. +.Pp +This feature becomes +.Sy active +when an encrypted dataset is created and will be returned to the +.Sy enabled +state when all datasets that use this feature are destroyed. +. +.feature com.delphix extensible_dataset no This feature allows more flexible use of internal ZFS data structures, and exists for other features to depend on. - -This feature will be \fBactive\fR when the first dependent feature uses it, -and will be returned to the \fBenabled\fR state when all datasets that use -this feature are destroyed. - -.RE - -.sp -.ne 2 -.na -\fB\fBbookmarks\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:bookmarks -READ\-ONLY COMPATIBLE yes -DEPENDENCIES extensible_dataset -.TE - -This feature enables use of the \fBzfs bookmark\fR subcommand. - -This feature is \fBactive\fR while any bookmarks exist in the pool. -All bookmarks in the pool can be listed by running -\fBzfs list -t bookmark -r \fIpoolname\fR\fR. - -.RE - -.sp -.ne 2 -.na -\fB\fBenabled_txg\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:enabled_txg -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - -Once this feature is enabled ZFS records the transaction group number -in which new features are enabled. This has no user-visible impact, -but other features may depend on this feature. - -This feature becomes \fBactive\fR as soon as it is enabled and will -never return to being \fBenabled\fR. - -.RE - -.sp -.ne 2 -.na -\fB\fBhole_birth\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:hole_birth -READ\-ONLY COMPATIBLE no -DEPENDENCIES enabled_txg -.TE - -This feature improves performance of incremental sends ("zfs send -i") -and receives for objects with many holes. The most common case of -hole-filled objects is zvols. - -An incremental send stream from snapshot \fBA\fR to snapshot \fBB\fR -contains information about every block that changed between \fBA\fR and -\fBB\fR. Blocks which did not change between those snapshots can be +.Pp +This feature will be +.Sy active +when the first dependent feature uses it, and will be returned to the +.Sy enabled +state when all datasets that use this feature are destroyed. +. +.feature com.joyent filesystem_limits yes extensible_dataset +This feature enables filesystem and snapshot limits. +These limits can be used to control how many filesystems and/or snapshots +can be created at the point in the tree on which the limits are set. +.Pp +This feature is +.Sy active +once either of the limit properties has been set on a dataset +and will never return to being +.Sy enabled . +. +.feature com.delphix hole_birth no enabled_txg +This feature has/had bugs, the result of which is that, if you do a +.Nm zfs Cm send Fl i +.Pq or Fl R , No since it uses Fl i +from an affected dataset, the receiving party will not see any checksum +or other errors, but the resulting destination snapshot +will not match the source. +Its use by +.Nm zfs Cm send Fl i +has been disabled by default +.Po +see +.Sy send_holes_without_birth_time +in +.Xr zfs 4 +.Pc . +.Pp +This feature improves performance of incremental sends +.Pq Nm zfs Cm send Fl i +and receives for objects with many holes. +The most common case of hole-filled objects is zvols. +.Pp +An incremental send stream from snapshot +.Sy A No to snapshot Sy B +contains information about every block that changed between +.Sy A No and Sy B . +Blocks which did not change between those snapshots can be identified and omitted from the stream using a piece of metadata called -the 'block birth time', but birth times are not recorded for holes (blocks -filled only with zeroes). Since holes created after \fBA\fR cannot be -distinguished from holes created before \fBA\fR, information about every -hole in the entire filesystem or zvol is included in the send stream. - -For workloads where holes are rare this is not a problem. However, when -incrementally replicating filesystems or zvols with many holes (for -example a zvol formatted with another filesystem) a lot of time will -be spent sending and receiving unnecessary information about holes that +the +.Dq block birth time , +but birth times are not recorded for holes +.Pq blocks filled only with zeroes . +Since holes created after +.Sy A No cannot be distinguished from holes created before Sy A , +information about every hole in the entire filesystem or zvol +is included in the send stream. +.Pp +For workloads where holes are rare this is not a problem. +However, when incrementally replicating filesystems or zvols with many holes +.Pq for example a zvol formatted with another filesystem +a lot of time will be spent sending and receiving unnecessary information +about holes that already exist on the receiving side. +.Pp +Once the +.Sy hole_birth +feature has been enabled the block birth times +of all new holes will be recorded. +Incremental sends between snapshots created after this feature is enabled +will use this new metadata to avoid sending information about holes that already exist on the receiving side. - -Once the \fBhole_birth\fR feature has been enabled the block birth times -of all new holes will be recorded. Incremental sends between snapshots -created after this feature is enabled will use this new metadata to avoid -sending information about holes that already exist on the receiving side. - -This feature becomes \fBactive\fR as soon as it is enabled and will -never return to being \fBenabled\fR. - -.RE - -.sp -.ne 2 -.na -\fB\fBembedded_data\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:embedded_data -READ\-ONLY COMPATIBLE no -DEPENDENCIES none -.TE - -This feature improves the performance and compression ratio of -highly-compressible blocks. Blocks whose contents can compress to 112 bytes -or smaller can take advantage of this feature. - -When this feature is enabled, the contents of highly-compressible blocks are -stored in the block "pointer" itself (a misnomer in this case, as it contains -the compresseed data, rather than a pointer to its location on disk). Thus -the space of the block (one sector, typically 512 bytes or 4KB) is saved, -and no additional i/o is needed to read and write the data block. - -This feature becomes \fBactive\fR as soon as it is enabled and will -never return to being \fBenabled\fR. - -.RE -.sp -.ne 2 -.na -\fB\fBdevice_removal\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:device_removal -READ\-ONLY COMPATIBLE no -DEPENDENCIES none -.TE - -This feature enables the "zpool remove" subcommand to remove top-level -vdevs, evacuating them to reduce the total size of the pool. - -This feature becomes \fBactive\fR when the "zpool remove" command is used -on a top-level vdev, and will never return to being \fBenabled\fR. - -.RE -.sp -.ne 2 -.na -\fB\fBobsolete_counts\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:obsolete_counts -READ\-ONLY COMPATIBLE yes -DEPENDENCIES device_removal -.TE - -This feature is an enhancement of device_removal, which will over time -reduce the memory used to track removed devices. When indirect blocks -are freed or remapped, we note that their part of the indirect mapping -is "obsolete", i.e. no longer needed. See also the \fBzfs remap\fR -subcommand in \fBzfs\fR(8). - -This feature becomes \fBactive\fR when the "zpool remove" command is -used on a top-level vdev, and will never return to being \fBenabled\fR. - -.RE -.sp -.ne 2 -.na -\fB\fBzpool_checkpoint\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:zpool_checkpoint -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - -This feature enables the "zpool checkpoint" subcommand that can -checkpoint the state of the pool at the time it was issued and later -rewind back to it or discard it. - -This feature becomes \fBactive\fR when the "zpool checkpoint" command -is used to checkpoint the pool. -The feature will only return back to being \fBenabled\fR when the pool -is rewound or the checkpoint has been discarded. - -.RE -.sp -.ne 2 -.na -\fB\fBspacemap_v2\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:spacemap_v2 -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - +.Pp +\*[instant-never] +. +.feature org.open-zfs large_blocks no extensible_dataset +This feature allows the record size on a dataset to be set larger than 128 KiB. +.Pp +This feature becomes +.Sy active +once a dataset contains a file with a block size larger than 128 KiB, +and will return to being +.Sy enabled +once all filesystems that have ever had their recordsize larger than 128 KiB +are destroyed. +. +.feature org.zfsonlinux large_dnode no extensible_dataset +This feature allows the size of dnodes in a dataset to be set larger than 512 B. +. +This feature becomes +.Sy active +once a dataset contains an object with a dnode larger than 512 B, +which occurs as a result of setting the +.Sy dnodesize +dataset property to a value other than +.Sy legacy . +The feature will return to being +.Sy enabled +once all filesystems that have ever contained a dnode larger than 512 B +are destroyed. +Large dnodes allow more data to be stored in the bonus buffer, +thus potentially improving performance by avoiding the use of spill blocks. +. +.feature com.delphix log_spacemap yes com.delphix:spacemap_v2 +This feature improves performance for heavily-fragmented pools, +especially when workloads are heavy in random-writes. +It does so by logging all the metaslab changes on a single spacemap every TXG +instead of scattering multiple writes to all the metaslab spacemaps. +.Pp +\*[instant-never] +. +.feature org.illumos lz4_compress no +.Sy lz4 +is a high-performance real-time compression algorithm that +features significantly faster compression and decompression as well as a +higher compression ratio than the older +.Sy lzjb +compression. +Typically, +.Sy lz4 +compression is approximately 50% faster on compressible data and 200% faster +on incompressible data than +.Sy lzjb . +It is also approximately 80% faster on decompression, +while giving approximately a 10% better compression ratio. +.Pp +When the +.Sy lz4_compress +feature is set to +.Sy enabled , +the administrator can turn on +.Sy lz4 +compression on any dataset on the pool using the +.Xr zfs 8 +command. +All newly written metadata will be compressed with the +.Sy lz4 +algorithm. +.Pp +\*[instant-never] +. +.feature com.joyent multi_vdev_crash_dump no +This feature allows a dump device to be configured with a pool comprised +of multiple vdevs. +Those vdevs may be arranged in any mirrored or raidz configuration. +.Pp +When the +.Sy multi_vdev_crash_dump +feature is set to +.Sy enabled , +the administrator can use +.Xr dumpadm 8 +to configure a dump device on a pool comprised of multiple vdevs. +.Pp +Under +.Fx +and Linux this feature is unused, but registered for compatibility. +New pools created on these systems will have the feature +.Sy enabled +but will never transition to +.Sy active , +as this functionality is not required for crash dump support. +Existing pools where this feature is +.Sy active +can be imported. +. +.feature com.delphix obsolete_counts yes device_removal +This feature is an enhancement of +.Sy device_removal , +which will over time reduce the memory used to track removed devices. +When indirect blocks are freed or remapped, +we note that their part of the indirect mapping is +.Dq obsolete +– no longer needed. +.Pp +This feature becomes +.Sy active +when the +.Nm zpool Cm remove +command is used on a top-level vdev, and will never return to being +.Sy enabled . +. +.feature org.zfsonlinux project_quota yes extensible_dataset +This feature allows administrators to account the spaces and objects usage +information against the project identifier +.Pq ID . +.Pp +The project ID is an object-based attribute. +When upgrading an existing filesystem, +objects without a project ID will be assigned a zero project ID. +When this feature is enabled, newly created objects inherit +their parent directories' project ID if the parent's inherit flag is set +.Pq via Nm chattr Sy [+-]P No or Nm zfs Cm project Fl s Ns | Ns Fl C . +Otherwise, the new object's project ID will be zero. +An object's project ID can be changed at any time by the owner +.Pq or privileged user +via +.Nm chattr Fl p Ar prjid +or +.Nm zfs Cm project Fl p Ar prjid . +.Pp +This feature will become +.Sy active +as soon as it is enabled and will never return to being +.Sy disabled . +\*[remount-upgrade] +. +.feature com.datto resilver_defer yes +This feature allows ZFS to postpone new resilvers if an existing one is already +in progress. +Without this feature, any new resilvers will cause the currently +running one to be immediately restarted from the beginning. +.Pp +This feature becomes +.Sy active +once a resilver has been deferred, and returns to being +.Sy enabled +when the deferred resilver begins. +. +.feature org.illumos sha512 no extensible_dataset +This feature enables the use of the SHA-512/256 truncated hash algorithm +.Pq FIPS 180-4 +for checksum and dedup. +The native 64-bit arithmetic of SHA-512 provides an approximate 50% +performance boost over SHA-256 on 64-bit hardware +and is thus a good minimum-change replacement candidate +for systems where hash performance is important, +but these systems cannot for whatever reason utilize the faster +.Sy skein No and Sy edonr +algorithms. +.Pp +.checksum-spiel sha512 +. +.feature org.illumos skein no extensible_dataset +This feature enables the use of the Skein hash algorithm for checksum and dedup. +Skein is a high-performance secure hash algorithm that was a +finalist in the NIST SHA-3 competition. +It provides a very high security margin and high performance on 64-bit hardware +.Pq 80% faster than SHA-256 . +This implementation also utilizes the new salted checksumming +functionality in ZFS, which means that the checksum is pre-seeded with a +secret 256-bit random key +.Pq stored on the pool +before being fed the data block to be checksummed. +Thus the produced checksums are unique to a given pool, +preventing hash collision attacks on systems with dedup. +.Pp +.checksum-spiel skein +. +.feature com.delphix spacemap_histogram yes +This features allows ZFS to maintain more information about how free space +is organized within the pool. +If this feature is +.Sy enabled , +it will be activated when a new space map object is created, or +an existing space map is upgraded to the new format, +and never returns back to being +.Sy enabled . +. +.feature com.delphix spacemap_v2 yes This feature enables the use of the new space map encoding which -consists of two words (instead of one) whenever it is advantageous. +consists of two words +.Pq instead of one +whenever it is advantageous. The new encoding allows space maps to represent large regions of space more efficiently on-disk while also increasing their maximum addressable offset. - -This feature becomes \fBactive\fR once it is \fBenabled\fR, and never -returns back to being \fBenabled\fR. - -.RE -.sp -.ne 2 -.na -\fB\fBlarge_blocks\fR\fR -.ad -.RS 4n -.TS -l l . -GUID org.open-zfs:large_block -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -The \fBlarge_block\fR feature allows the record size on a dataset to be -set larger than 128KB. - -This feature becomes \fBactive\fR once a \fBrecordsize\fR property has been -set larger than 128KB, and will return to being \fBenabled\fR once all -filesystems that have ever had their recordsize larger than 128KB are destroyed. -.RE - -.ne 2 -.na -\fB\fBlarge_dnode\fR\fR -.ad -.RS 4n -.TS -l l . -GUID org.zfsonlinux:large_dnode -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -The \fBlarge_dnode\fR feature allows the size of dnodes in a dataset to be -set larger than 512B. - -This feature becomes \fBactive\fR once a dataset contains an object with a -dnode larger than 512B, which occurs as a result of setting the \fBdnodesize\fR -dataset property to a value other than \fBlegacy\fR. The feature will return to -being \fBenabled\fR once all filesystems that have ever contained a dnode larger -than 512B are destroyed. Large dnodes allow more data to be stored in the -bonus buffer, thus potentially improving performance by avoiding the use of -spill blocks. -.RE - -.sp -.ne 2 -.na -\fB\fBsha512\fR\fR -.ad -.RS 4n -.TS -l l . -GUID org.illumos:sha512 -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -This feature enables the use of the SHA-512/256 truncated hash algorithm -(FIPS 180-4) for checksum and dedup. The native 64-bit arithmetic of -SHA-512 provides an approximate 50% performance boost over SHA-256 on -64-bit hardware and is thus a good minimum-change replacement candidate -for systems where hash performance is important, but these systems -cannot for whatever reason utilize the faster \fBskein\fR and -\fBedonr\fR algorithms. - -When the \fBsha512\fR feature is set to \fBenabled\fR, the administrator -can turn on the \fBsha512\fR checksum on any dataset using the -\fBzfs set checksum=sha512\fR command. This feature becomes -\fBactive\fR once a \fBchecksum\fR property has been set to \fBsha512\fR, -and will return to being \fBenabled\fR once all filesystems that have -ever had their checksum set to \fBsha512\fR are destroyed. - -Booting off of pools utilizing SHA-512/256 is supported. - -.RE - -.sp -.ne 2 -.na -\fB\fBskein\fR\fR -.ad -.RS 4n -.TS -l l . -GUID org.illumos:skein -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -This feature enables the use of the Skein hash algorithm for checksum -and dedup. Skein is a high-performance secure hash algorithm that was a -finalist in the NIST SHA-3 competition. It provides a very high security -margin and high performance on 64-bit hardware (80% faster than -SHA-256). This implementation also utilizes the new salted checksumming -functionality in ZFS, which means that the checksum is pre-seeded with a -secret 256-bit random key (stored on the pool) before being fed the data -block to be checksummed. Thus the produced checksums are unique to a -given pool, preventing hash collision attacks on systems with dedup. - -When the \fBskein\fR feature is set to \fBenabled\fR, the administrator -can turn on the \fBskein\fR checksum on any dataset using the -\fBzfs set checksum=skein\fR command. This feature becomes -\fBactive\fR once a \fBchecksum\fR property has been set to \fBskein\fR, -and will return to being \fBenabled\fR once all filesystems that have -ever had their checksum set to \fBskein\fR are destroyed. - -Booting off of pools using \fBskein\fR is supported. - -.RE - -.sp -.ne 2 -.na -\fB\fBbookmark_v2\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.datto:bookmark_v2 -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -This feature enables the creation and management of larger bookmarks which are -needed for other features in ZFS. - -This feature becomes \fBactive\fR when a v2 bookmark is created and will be -returned to the \fBenabled\fR state when all v2 bookmarks are destroyed. - -.RE - -.sp -.ne 2 -.na -\fB\fBedonr\fR\fR -.ad -.RS 4n -.TS -l l . -GUID org.illumos:edonr -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -This feature enables the use of the Edon-R hash algorithm for checksum, -including for nopwrite (if compression is also enabled, an overwrite of -a block whose checksum matches the data being written will be ignored). -In an abundance of caution, Edon-R can not be used with dedup -(without verification). - -Edon-R is a very high-performance hash algorithm that was part -of the NIST SHA-3 competition. It provides extremely high hash -performance (over 350% faster than SHA-256), but was not selected -because of its unsuitability as a general purpose secure hash algorithm. -This implementation utilizes the new salted checksumming functionality -in ZFS, which means that the checksum is pre-seeded with a secret -256-bit random key (stored on the pool) before being fed the data block -to be checksummed. Thus the produced checksums are unique to a given -pool. - -When the \fBedonr\fR feature is set to \fBenabled\fR, the administrator -can turn on the \fBedonr\fR checksum on any dataset using the -\fBzfs set checksum=edonr\fR command. This feature becomes -\fBactive\fR once a \fBchecksum\fR property has been set to \fBedonr\fR, -and will return to being \fBenabled\fR once all filesystems that have -ever had their checksum set to \fBedonr\fR are destroyed. - -Booting off of pools using \fBedonr\fR is supported. - -.RE - -.sp -.ne 2 -.na -\fB\fBallocation_classes\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.intel:allocation_classes -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - -This feature enables support for separate allocation classes. - -This feature becomes \fBactive\fR when a dedicated allocation class vdev -(dedup or special) is created with zpool create or zpool add. With device -removal, it can be returned to the \fBenabled\fR state if all the top-level -vdevs from an allocation class are removed. -.RE - -.sp -.ne 2 -.na -\fB\fBencryption\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.datto:encryption -READ\-ONLY COMPATIBLE no -DEPENDENCIES extensible_dataset -.TE - -This feature enables the creation and management of natively encrypted datasets. - -This feature becomes \fBactive\fR when an encrypted dataset is created -and will be returned to the \fBenabled\fR state when all datasets that -use this feature are destroyed. - -.RE -.sp -.ne 2 -.na -\fB\fBresilver_defer\fR\fR -.ad -.RS 4n -.TS -l l . -GUID com.datto:resilver_defer -READ\-ONLY COMPATIBLE yes -DEPENDENCIES none -.TE - -This feature allows zfs to postpone new resilvers if an existing one is already -in progress. Without this feature, any new resilvers will cause the currently -running one to be immediately restarted from the beginning. - -This feature becomes \fBactive\fR once a resilver has been deferred, and -returns to being \fBenabled\fR when the deferred resilver begins. -.RE - -.sp -.ne 2 -.na -\fBuserobj_accounting\fR -.ad -.RS 4n -.TS -l l . -GUID org.zfsonlinux:userobj_accounting -READ\-ONLY COMPATIBLE yes -DEPENDENCIES extensible_dataset -.TE - +.Pp +This feature becomes +.Sy active +once it is +.Sy enabled , +and never returns back to being +.Sy enabled . +. +.feature org.zfsonlinux userobj_accounting yes extensible_dataset This feature allows administrators to account the object usage information by user and group. - -This feature becomes \fBactive\fR as soon as it is enabled and will never -return to being \fBenabled\fR. -Each filesystem will be upgraded automatically when remounted, or when new -files are created under that filesystem. -The upgrade can also be started manually on filesystems by running -`zfs set version=current <pool/fs>`. -The upgrade process runs in the background and may take a while to complete -for filesystems containing a large number of files. -.RE - -.sp -.ne 2 -.na -\fBproject_quota\fR -.ad -.RS 4n -.TS -l l . -GUID org.zfsonlinux:project_quota -READ\-ONLY COMPATIBLE yes -DEPENDENCIES extensible_dataset -.TE - -This feature allows administrators to account the space and object usage -information against the project identifier (ID). - -The project ID is a new object-based attribute. -When upgrading an existing filesystem, an object without a project ID -attribute will be assigned a zero project ID. -After this feature is enabled, a newly created object will inherit -its parent directory's project ID if the parent's inherit flag is set (via -\fBzfs project [-s|-C]\fR). -Otherwise, the new object's project ID will be set as zero. -An object's project ID can be changed at any time by the owner (or privileged -user) via \fBzfs project -p $prjid\fR. - -This feature will become \fBactive\fR as soon as it is enabled and will never -return to being \fBdisabled\fR. -Each filesystem will be upgraded automatically when remounted or when a new file -is created under that filesystem. -The upgrade can also be triggered on filesystems via `zfs set version=current -<pool/fs>`. -The upgrade process runs in the background and may take a while to complete -for the filesystems containing a large number of files. -.RE - -.sp -.ne 2 -.na -\fBlog_spacemap\fR -.ad -.RS 4n -.TS -l l . -GUID com.delphix:log_spacemap -READ\-ONLY COMPATIBLE yes -DEPENDENCIES com.delphix:spacemap_v2 -.TE - -This feature improves performance for heavily-fragmented pools, -especially when workloads are heavy in random-writes. -It does so by logging all the metaslab changes on a single spacemap every TXG -instead of scattering multiple writes to all the metaslab spacemaps. - -This feature becomes \fBactive\fR as soon as it is enabled and will never -return to being \fBenabled\fR. -.RE - -.SH "SEE ALSO" -.BR zfs (8), -.BR zpool (8) +.Pp +\*[instant-never] +\*[remount-upgrade] +. +.feature org.openzfs zilsaxattr yes extensible_dataset +This feature enables +.Sy xattr Ns = Ns Sy sa +extended attribute logging in the ZIL. +If enabled, extended attribute changes +.Pq both Sy xattrdir Ns = Ns Sy dir No and Sy xattr Ns = Ns Sy sa +are guaranteed to be durable if either the dataset had +.Sy sync Ns = Ns Sy always +set at the time the changes were made, or +.Xr sync 2 +is called on the dataset after the changes were made. +.Pp +This feature becomes +.Sy active +when a ZIL is created for at least one dataset and will be returned to the +.Sy enabled +state when it is destroyed for all datasets that use this feature. +. +.feature com.delphix zpool_checkpoint yes +This feature enables the +.Nm zpool Cm checkpoint +command that can checkpoint the state of the pool +at the time it was issued and later rewind back to it or discard it. +.Pp +This feature becomes +.Sy active +when the +.Nm zpool Cm checkpoint +command is used to checkpoint the pool. +The feature will only return back to being +.Sy enabled +when the pool is rewound or the checkpoint has been discarded. +.El +. +.Sh SEE ALSO +.Xr zfs 8 , +.Xr zpool 8 diff --git a/usr/src/pkg/manifests/developer-build-onbld.p5m b/usr/src/pkg/manifests/developer-build-onbld.p5m index efa509a89b..ca55e019f7 100644 --- a/usr/src/pkg/manifests/developer-build-onbld.p5m +++ b/usr/src/pkg/manifests/developer-build-onbld.p5m @@ -27,6 +27,7 @@ # Copyright 2019 Joyent, Inc. # Copyright 2016 Toomas Soome <tsoome@me.com> # Copyright 2021 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2022 Jason King # set name=pkg.fmri value=pkg:/developer/build/onbld@$(PKGVERS) @@ -59,6 +60,7 @@ file path=opt/onbld/bin/$(ARCH)/ctfstrip mode=0555 file path=opt/onbld/bin/$(ARCH)/cw mode=0555 link path=opt/onbld/bin/$(ARCH)/dmake target=make $(i386_ONLY)file path=opt/onbld/bin/$(ARCH)/elfextract mode=0555 +file path=opt/onbld/bin/$(ARCH)/find_elf mode=0555 file path=opt/onbld/bin/$(ARCH)/findunref mode=0555 $(sparc_ONLY)file path=opt/onbld/bin/$(ARCH)/forth mode=0555 $(sparc_ONLY)file path=opt/onbld/bin/$(ARCH)/forth_preload.so.1 mode=0555 @@ -89,7 +91,6 @@ file path=opt/onbld/bin/copyrightchk mode=0555 \ pkg.depend.bypass-generate=.*(?:Checks|onbld|Copyright).* file path=opt/onbld/bin/cstyle mode=0555 file path=opt/onbld/bin/elfcmp mode=0555 -file path=opt/onbld/bin/find_elf mode=0555 file path=opt/onbld/bin/findcrypto mode=0555 file path=opt/onbld/bin/flg.flp mode=0555 file path=opt/onbld/bin/genoffsets mode=0555 diff --git a/usr/src/tools/Makefile b/usr/src/tools/Makefile index 5524ad71bd..2193a1bda9 100644 --- a/usr/src/tools/Makefile +++ b/usr/src/tools/Makefile @@ -26,6 +26,7 @@ # Copyright (c) 2016, Chris Fraire <cfraire@me.com>. # Copyright 2019 Joyent, Inc. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2021 Jason King # include ../Makefile.master @@ -53,6 +54,7 @@ COMMON_SUBDIRS= \ codesign \ cscope-fast \ env \ + find_elf \ findunref \ lintdump \ make \ diff --git a/usr/src/tools/find_elf/Makefile b/usr/src/tools/find_elf/Makefile new file mode 100644 index 0000000000..db723147bf --- /dev/null +++ b/usr/src/tools/find_elf/Makefile @@ -0,0 +1,68 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2022 Jason King +# + +PROG = find_elf +MAN1ONBLDFILES = find_elf.1onbld + +# +# Since libcustr is private, we just build and link in the code directly +# into the binary. If more build utilities require it in the future, we +# can transition to building a tools version of the library and link +# against it. +CUSTRDIR = $(SRC)/lib/libcustr/common + +OBJS = find_elf.o custr.o + +include $(SRC)/tools/Makefile.tools +include $(SRC)/cmd/Makefile.ctf + +$(ROOTONBLDMAN1ONBLDFILES) := FILEMODE= 644 + +LDLIBS = -lelf -lavl +NATIVE_LIBS += libelf.so libc.so libavl.so + +CPPFLAGS += -I$(CUSTRDIR) +LDFLAGS = \ + -L$(ROOTONBLDLIBMACH) \ + '-R$$ORIGIN/../../lib/$(MACH)' \ + $(BDIRECT) $(ZLAZYLOAD) + +CSTD = $(CSTD_GNU99) + +.KEEP_STATE: + +.PARALLEL: $(OBJS) + +all: $(PROG) + +install: all .WAIT $(ROOTONBLDMACHPROG) $(ROOTONBLDDATAFILES) \ + $(ROOTONBLDMAN1ONBLDFILES) + +clean: + $(RM) -f $(OBJS) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +%.o: %.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.o: $(CUSTRDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include $(SRC)/tools/Makefile.targ diff --git a/usr/src/tools/scripts/find_elf.1onbld b/usr/src/tools/find_elf/find_elf.1onbld index ac578ea9df..8fe9b7713b 100644 --- a/usr/src/tools/scripts/find_elf.1onbld +++ b/usr/src/tools/find_elf/find_elf.1onbld @@ -19,11 +19,13 @@ .\" .\" CDDL HEADER END .\" -.TH FIND_ELF 1ONBLD "December 3, 2021" +.\" Copyright 2022 Jason King +.\" +.TH FIND_ELF 1ONBLD "May 29, 2022" .SH NAME find_elf \- Locate ELF objects .SH SYNOPSIS -\fBfind_elf [-afrs] path\fP +\fBfind_elf [-afhnrs] path\fP .SH DESCRIPTION The .I find_elf @@ -46,6 +48,21 @@ shared objects must end with a .so extension. Files that do not meet these requirements are silently eliminated from consideration without further analysis. .TP 4 +.B \-h +Show usage message. +.TP 4 +.B \-n +Do not treat well known hard-linked binaries as special. Certain well known +binaries (currently \fBalias\fP and \fBisaexec\fP) are hard linked to many +other names in a proto directory tree. +.P +By default, +.I find_elf +will use these well known names as the initial name and all other hard links +to those binaries are treated as aliases. Disabling this behavior with the +\fB-n\fR option will choose the first name encountered during directory +traversal as the name, and all other hard links to the binary as aliases. +.TP 4 .B \-r Report file names as relative paths, relative to the given file or directory, instead of fully qualified. diff --git a/usr/src/tools/find_elf/find_elf.c b/usr/src/tools/find_elf/find_elf.c new file mode 100644 index 0000000000..7c31ccc685 --- /dev/null +++ b/usr/src/tools/find_elf/find_elf.c @@ -0,0 +1,863 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Joyent, Inc. + * Copyright 2022 Jason King + */ + +#include <sys/debug.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/avl.h> +#include <sys/fcntl.h> +#include <sys/sysmacros.h> +#include <dirent.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <gelf.h> +#include <libcustr.h> +#include <libelf.h> +#include <libgen.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static inline bool +is_same(const struct stat *s1, const struct stat *s2) +{ + if ((s1->st_ino == s2->st_ino) && (s1->st_dev == s2->st_dev)) + return (true); + return (false); +} + +typedef enum dir_flags { + DF_NONE = 0, + DF_IS_SELF = 1 << 0, + DF_IS_SYMLINK = 1 << 2, +} dir_flags_t; + +typedef struct path { + custr_t *p_name; + size_t p_pfxidx; +} path_t; + +typedef struct name { + char *n_name; + bool n_is_symlink; +} name_t; + +typedef struct names { + name_t *ns_names; + uint_t ns_num; + uint_t ns_alloc; +} names_t; + +typedef struct elfinfo { + int ei_class; + uint16_t ei_type; + bool ei_hasverdef; +} elfinfo_t; + +typedef struct obj { + avl_node_t obj_avlid; + avl_node_t obj_avlname; + dev_t obj_dev; + ino_t obj_inode; + names_t obj_names; + elfinfo_t obj_elfinfo; +} obj_t; + +static void path_init(path_t *, const char *, bool); +static size_t path_append(path_t *, const char *); +static const char *path_name(const path_t *); +static const char *path_fullpath(const path_t *); +static void path_pop(path_t *, size_t); + +static bool maybe_obj(const char *, mode_t); +static bool get_elfinfo(const path_t *, int, elfinfo_t *); +static void add_name(obj_t *, const path_t *, bool); +static int cmp_id(const void *, const void *); +static int cmp_objname(const void *, const void *); +static int cmp_names(const void *, const void *); + +static void process_dir(path_t *, int, const struct stat *, dir_flags_t); +static void process_file(path_t *, int, const struct stat *, bool); +static void process_arg(char *); + +static void sort_names(void *, void *); +static void print_entry(void *, void *); + +static void foreach_avl(avl_tree_t *, void (*)(void *, void *), void *); + +static void nomem(void); +static char *xstrdup(const char *); +static void *xcalloc(size_t, size_t); + +static avl_tree_t avl_byid; +static avl_tree_t avl_byname; + +static const char *special_paths[] = { + "usr/bin/alias", + "usr/lib/isaexec", +}; + +static int rootfd = -1; + +/* By default, we process aliases */ +static bool do_alias = true; + +/* By default, we treat certain well known names (e.g. isaexec) as special */ +static bool do_special = true; + +/* fast_mode, relpath, and so_only are all false by default */ +static bool fast_mode; +static bool relpath; +static bool so_only; + +static void __NORETURN +usage(const char *name) +{ + (void) fprintf(stderr, + "Usage: %s [-afnrs] file | dir\n" + "\t[-a]\texpand symlink aliases\n" + "\t[-f]\tuse file name at mode to speed search\n" + "\t[-h]\tshow this help\n" + "\t[-n]\tdon\'t treat well known paths as special in sorting\n" + "\t[-r]\treport relative paths\n" + "\t[-s]\tonly remote shareable (ET_DYN) objects\n", name); + exit(EXIT_FAILURE); +} + +int +main(int argc, char **argv) +{ + int c; + + if (elf_version(EV_CURRENT) == EV_NONE) + errx(EXIT_FAILURE, "elf library is out of date"); + + while ((c = getopt(argc, argv, "ahfnrs")) != -1) { + switch (c) { + case 'a': + do_alias = false; + break; + case 'f': + fast_mode = true; + break; + case 'n': + do_special = false; + break; + case 'r': + relpath = true; + break; + case 's': + so_only = true; + break; + case 'h': + usage(argv[0]); + case '?': + (void) fprintf(stderr, "Unknown option -%c\n", optopt); + usage(argv[0]); + } + } + + if (optind == argc) { + (void) fprintf(stderr, "Missing file or dir parameter\n"); + usage(argv[0]); + } + + if (argv[optind][0] == '\0') + errx(EXIT_FAILURE, "Invalid file or dir value"); + + avl_create(&avl_byid, cmp_id, sizeof (obj_t), + offsetof(obj_t, obj_avlid)); + avl_create(&avl_byname, cmp_objname, sizeof (obj_t), + offsetof(obj_t, obj_avlname)); + + process_arg(argv[optind]); + foreach_avl(&avl_byid, sort_names, &avl_byname); + foreach_avl(&avl_byname, print_entry, NULL); + + return (EXIT_SUCCESS); +} + +static void +process_arg(char *arg) +{ + path_t path; + struct stat sb; + int fd; + + if ((fd = open(arg, O_RDONLY)) == -1) { + err(EXIT_FAILURE, "could not open %s", arg); + } + + if (fstat(fd, &sb) < 0) { + err(EXIT_FAILURE, "failed to stat %s", arg); + } + + if (S_ISDIR(sb.st_mode)) { + path_init(&path, arg, relpath); + if (relpath) { + (void) printf("PREFIX %s\n", arg); + } + + rootfd = fd; + /* process_dir() will close fd */ + process_dir(&path, fd, &sb, DF_NONE); + return; + } + + char *argcopy = xstrdup(arg); + char *dir = dirname(argcopy); + + if (!S_ISREG(sb.st_mode)) { + err(EXIT_FAILURE, "not a file or directory: %s", arg); + } + + rootfd = open(dir, O_RDONLY|O_DIRECTORY); + if (rootfd < 0) { + err(EXIT_FAILURE, "%s", dir); + } + + path_init(&path, dir, relpath); + if (relpath) { + (void) printf("PREFIX %s\n", dir); + } + free(argcopy); + + process_file(&path, fd, &sb, DF_NONE); +} + +/* + * Processing a directory has some subtleties. When we encounter a + * subdirectory that's a symlink, we want any files we encounter when + * we traverse it to be treated as aliases. We may also have a symlink that's + * a link back to ourself (e.g. 32 -> .). In this special case, we still want + * to reprocess the directory to generate alias names, but we use the + * DFLAG_SELF flag to avoid recursing forever. + * + * A limitation of this approach is that we cannot handle a loop over multiple + * levels (e.g. foo -> ../..). Nothing currently in illumos-gate creates any + * such symlinks in the proto area, so we've opted to avoid complicating + * processing further to handle scenarios that aren't realistically expected + * to occur. + * + * Note that dirfd is always closed upon return from process_dir(). + */ +static void +process_dir(path_t *p, int dirfd, const struct stat *dirsb, dir_flags_t dflags) +{ + DIR *d; + struct dirent *de; + + d = fdopendir(dirfd); + if (d == NULL) { + warn("opendir(%s)", path_fullpath(p)); + VERIFY0(close(dirfd)); + return; + } + + while ((de = readdir(d)) != NULL) { + struct stat sb; + int fd; + bool is_link = false; + size_t plen; + + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) { + continue; + } + + plen = path_append(p, de->d_name); + + if (fstatat(rootfd, path_name(p), &sb, + AT_SYMLINK_NOFOLLOW) < 0) { + warn("%s", path_fullpath(p)); + path_pop(p, plen); + continue; + } + + fd = openat(dirfd, de->d_name, O_RDONLY); + if (fd < 0) { + /* + * Symlinks in the proto area may point to a path + * that's not present (e.g. /dev/stdin -> fd/0). + * Silently skip such entries. + */ + if (errno != ENOENT || !S_ISLNK(sb.st_mode)) { + warn("%s", path_fullpath(p)); + } + path_pop(p, plen); + continue; + } + + if (S_ISLNK(sb.st_mode)) { + is_link = true; + + if (fstat(fd, &sb) < 0) { + warn("stat %s", path_fullpath(p)); + path_pop(p, plen); + continue; + } + } + + if (S_ISDIR(sb.st_mode)) { + if ((dflags & DF_IS_SELF) != 0) { + VERIFY0(close(fd)); + path_pop(p, plen); + continue; + } + + dir_flags_t newflags = dflags; + + /* The recursive process_dir() call closes fd */ + if (is_link) + newflags |= DF_IS_SYMLINK; + if (is_same(&sb, dirsb)) + newflags |= DF_IS_SELF; + process_dir(p, fd, &sb, newflags); + } else if (S_ISREG(sb.st_mode)) { + if (!maybe_obj(de->d_name, sb.st_mode)) { + VERIFY0(close(fd)); + path_pop(p, plen); + continue; + } + + if ((dflags & (DF_IS_SELF | DF_IS_SYMLINK)) != 0) + is_link = true; + + /* process_file() closes fd */ + process_file(p, fd, &sb, is_link); + } + + path_pop(p, plen); + } + + /* Closes dirfd */ + VERIFY0(closedir(d)); +} + +/* Note that fd is always closed upon return */ +static void +process_file(path_t *p, int fd, const struct stat *sb, bool is_link) +{ + avl_index_t where = { 0 }; + obj_t templ = { + .obj_dev = sb->st_dev, + .obj_inode = sb->st_ino, + }; + obj_t *obj = avl_find(&avl_byid, &templ, &where); + elfinfo_t elfinfo = { 0 }; + + if (obj != NULL) + goto done; + + if (!get_elfinfo(p, fd, &elfinfo)) { + VERIFY0(close(fd)); + return; + } + + obj = xcalloc(1, sizeof (*obj)); + obj->obj_dev = sb->st_dev; + obj->obj_inode = sb->st_ino; + obj->obj_elfinfo = elfinfo; + avl_add(&avl_byid, obj); + +done: + add_name(obj, p, is_link); + VERIFY0(close(fd)); +} + +static void +print_entry(void *a, void *arg __unused) +{ + obj_t *obj = a; + const char *objname = obj->obj_names.ns_names[0].n_name; + const char *bits = ""; + const char *type = ""; + const char *verdef = obj->obj_elfinfo.ei_hasverdef ? + "VERDEF" : "NOVERDEF"; + + switch (obj->obj_elfinfo.ei_class) { + case ELFCLASS32: + bits = "32"; + break; + case ELFCLASS64: + bits = "64"; + break; + default: + errx(EXIT_FAILURE, "unknown elfclass value %x for %s", + obj->obj_elfinfo.ei_class, objname); + } + + switch (obj->obj_elfinfo.ei_type) { + case ET_REL: + type = "REL"; + break; + case ET_DYN: + type = "DYN"; + break; + case ET_EXEC: + type = "EXEC"; + break; + default: + errx(EXIT_FAILURE, "unexpected elf type %x for %s", + obj->obj_elfinfo.ei_type, objname); + } + + names_t *names = &obj->obj_names; + + VERIFY3U(names->ns_num, >, 0); + VERIFY(!names->ns_names[0].n_is_symlink); + + (void) printf("OBJECT %2s %-4s %-8s %s\n", bits, type, verdef, + objname); + + for (uint_t i = 1; i < names->ns_num; i++) { + if (do_alias) { + (void) printf("%-23s %s\t%s\n", + "ALIAS", objname, names->ns_names[i].n_name); + } else { + (void) printf("OBJECT %2s %-4s %-8s %s\n", bits, type, + verdef, names->ns_names[i].n_name); + } + } +} + +/* + * Returns true and eip populated if name was an elf object, otherwise + * returns false. + */ +static bool +get_elfinfo(const path_t *p, int fd, elfinfo_t *eip) +{ + Elf *elf = NULL; + Elf_Scn *scn = NULL; + GElf_Ehdr ehdr = { 0 }; + int eval; + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) + goto fail_noend; + + if ((eip->ei_class = gelf_getclass(elf)) == ELFCLASSNONE) { + VERIFY0(elf_end(elf)); + return (false); + } + + if (gelf_getehdr(elf, &ehdr) == NULL) + goto fail; + + eip->ei_type = ehdr.e_type; + eip->ei_hasverdef = false; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + Elf_Data *data = NULL; + GElf_Shdr shdr = { 0 }; + + if (gelf_getshdr(scn, &shdr) == NULL) + goto fail; + + if (shdr.sh_type != SHT_DYNAMIC) + continue; + + if ((data = elf_getdata(scn, NULL)) == NULL) + continue; + + size_t nent = shdr.sh_size / shdr.sh_entsize; + + for (size_t i = 0; i < nent; i++) { + GElf_Dyn dyn = { 0 }; + + if (gelf_getdyn(data, i, &dyn) == NULL) { + goto fail; + } + + if (dyn.d_tag == DT_VERDEF) { + eip->ei_hasverdef = true; + break; + } + } + } + + VERIFY0(elf_end(elf)); + return (true); + +fail: + VERIFY0(elf_end(elf)); + +fail_noend: + eval = elf_errno(); + + warnx("%s: %s", path_fullpath(p), elf_errmsg(eval)); + return (false); +} + +static bool +is_special(const char *name) +{ + for (uint_t i = 0; i < ARRAY_SIZE(special_paths); i++) { + if (strcmp(special_paths[i], name) == 0) + return (true); + } + return (false); +} + +static void +sort_names(void *a, void *b) +{ + obj_t *obj = a; + avl_tree_t *name_avl = b; + names_t *names = &obj->obj_names; + + /* We should always have at least one name */ + VERIFY3U(names->ns_num, >, 0); + + /* If there is only one, they get the prize and we're done */ + if (names->ns_num == 1) + return; + + name_t *first = NULL; + + /* + * Find the first (in sorted order) pathname for this object + * that isn't a symlink. + */ + for (uint_t i = 0; i < names->ns_num; i++) { + name_t *n = &names->ns_names[i]; + + if (n->n_is_symlink) + continue; + + if (first == NULL) { + first = n; + continue; + } + + /* + * If we're treating isaexec as special, we always + * want it to be the first entry. Otherwise, pick + * the 'lowest' sorted pathname. + */ + if (do_special) { + if (is_special(n->n_name)) { + first = n; + break; + } + + if (strcmp(n->n_name, first->n_name) < 0) + first = n; + } + } + + /* + * If the first pathname (in sorted order) isn't the first + * name entry, we swap it into first place (while also updating + * the names AVL tree). + */ + if (first != NULL && first != &names->ns_names[0]) { + name_t tmp = names->ns_names[0]; + + avl_remove(name_avl, obj); + (void) memcpy(&names->ns_names[0], first, sizeof (name_t)); + (void) memcpy(first, &tmp, sizeof (name_t)); + avl_add(name_avl, obj); + } + + /* + * The remaining names (symlinks or not) are sorted by + * their pathname. + */ + qsort(&names->ns_names[1], names->ns_num - 1, sizeof (name_t), + cmp_names); +} + +/* + * We grow the names array by NAME_CHUNK entries every time we need to + * extend it. + */ +#define NAME_CHUNK 4 + +static name_t * +name_new(names_t *names) +{ + if (names->ns_num < names->ns_alloc) + return (&names->ns_names[names->ns_num++]); + + name_t *newn = NULL; + uint_t newamt = names->ns_alloc + NAME_CHUNK; + + /* + * Since we may be building on a machine that doesn't + * have reallocarray or the like, we avoid their use here. + * If we ever officially designate an illumos-gate build + * as the minimum required to build master that contains + * reallocarray and such, we can replace most of this logic + * with it. + * + * Also use xcalloc so we get the unused entries zeroed already. + * Not strictly necessary, but useful for debugging. + */ + newn = xcalloc(newamt, sizeof (name_t)); + + /* Move over existing entries */ + (void) memcpy(newn, names->ns_names, names->ns_num * sizeof (name_t)); + + free(names->ns_names); + + names->ns_names = newn; + names->ns_alloc = newamt; + return (&names->ns_names[names->ns_num++]); +} + +static void +add_name(obj_t *obj, const path_t *p, bool is_symlink) +{ + names_t *ns = &obj->obj_names; + const char *srcname = path_name(p); + + /* We should never have duplicates */ + for (size_t i = 0; i < ns->ns_num; i++) + VERIFY3S(strcmp(ns->ns_names[i].n_name, srcname), !=, 0); + + name_t *n = name_new(ns); + + n->n_name = xstrdup(srcname); + n->n_is_symlink = is_symlink; + + if (is_symlink) + return; + + /* + * If the name was not a symlink, first determine if there are + * existing (hard) links to this name already, and if so, which entry + * is the first one. Typically this will be the name we just added + * unless the file does have multiple hard links (e.g. isaexec). + */ + uint_t nhlink = 0; + uint_t firsthlink = UINT_MAX; + + for (uint_t i = 0; i < ns->ns_num; i++) { + if (ns->ns_names[i].n_is_symlink) + continue; + if (nhlink == 0) + firsthlink = i; + nhlink++; + } + + if (nhlink > 1) + return; + + /* + * Put the first non-symlink name as the very first + * entry. + */ + VERIFY3U(firsthlink, !=, UINT_MAX); + + if (firsthlink != 0) { + name_t tmp = { + .n_name = ns->ns_names[0].n_name, + .n_is_symlink = ns->ns_names[0].n_is_symlink, + }; + + (void) memcpy(&ns->ns_names[0], &ns->ns_names[firsthlink], + sizeof (name_t)); + (void) memcpy(&ns->ns_names[firsthlink], &tmp, sizeof (name_t)); + } + + avl_add(&avl_byname, obj); +} + +/* + * This is an arbitrary initial value -- basically we can nest 16 directories + * deep before having to grow p->p_idx (which seems like a nice power of 2). + */ +#define PATH_INIT 16 + +static void +path_init(path_t *p, const char *name, bool relpath) +{ + (void) memset(p, '\0', sizeof (*p)); + + if (custr_alloc(&p->p_name) < 0) { + nomem(); + } + + if (name != NULL && custr_append(p->p_name, name) < 0) + nomem(); + + size_t len = custr_len(p->p_name); + + /* Trim off any trailing /'s, but don't trim '/' to an empty path */ + while (len > 1 && custr_cstr(p->p_name)[len - 1] == '/') { + VERIFY0(custr_rtrunc(p->p_name, 0)); + len--; + } + + p->p_pfxidx = relpath ? len + 1 : 0; +} + +static size_t +path_append(path_t *p, const char *name) +{ + size_t clen = custr_len(p->p_name); + + if (clen > 0) + VERIFY0(custr_appendc(p->p_name, '/')); + VERIFY0(custr_append(p->p_name, name)); + + return (clen); +} + +static const char * +path_name(const path_t *p) +{ + return (custr_cstr(p->p_name) + p->p_pfxidx); +} + +static const char * +path_fullpath(const path_t *p) +{ + return (custr_cstr(p->p_name)); +} + +static void +path_pop(path_t *p, size_t idx) +{ + VERIFY0(custr_trunc(p->p_name, idx)); +} + +static int +cmp_id(const void *a, const void *b) +{ + const obj_t *l = a; + const obj_t *r = b; + + if (l->obj_dev < r->obj_dev) + return (-1); + if (l->obj_dev > r->obj_dev) + return (1); + if (l->obj_inode < r->obj_inode) + return (-1); + if (l->obj_inode > r->obj_inode) + return (1); + return (0); +} + +static int +cmp_objname(const void *a, const void *b) +{ + const obj_t *l = a; + const obj_t *r = b; + const name_t *ln = &l->obj_names.ns_names[0]; + const name_t *rn = &r->obj_names.ns_names[0]; + + return (cmp_names(ln, rn)); +} + +static int +cmp_names(const void *a, const void *b) +{ + const name_t *l = a; + const name_t *r = b; + int cmp = strcmp(l->n_name, r->n_name); + + if (cmp < 0) + return (-1); + if (cmp > 0) + return (1); + return (0); +} + +/* + * Use the filename and permission bits to determine if this file could + * possibly be an executable. + */ +static bool +maybe_obj(const char *name, mode_t mode) +{ + /* If not in fast mode, check everything, so always return true */ + if (!fast_mode) + return (true); + + size_t len = strlen(name); + + /* If the file name ends in .so, we check */ + if (len >= 3 && strcmp(&name[len - 4], ".so") == 0) { + return (true); + } + + /* If the file name contains '.so', we check */ + if (len >= 4 && strstr(name, ".so.") != NULL) { + return (true); + } + + /* If the above checks fail, we assume it's not a shared library */ + if (so_only) + return (false); + + /* + * The original perl script used a -x test which only looked at + * file permissions. This may return slightly different results + * than using access(2) or faccessat(2). + */ + if ((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) + return (false); + + return (true); +} + +static void +foreach_avl(avl_tree_t *avl, void (*cb)(void *, void *), void *arg) +{ + void *obj; + + for (obj = avl_first(avl); obj != NULL; obj = AVL_NEXT(avl, obj)) + cb(obj, arg); +} + +static char * +xstrdup(const char *s) +{ + char *news = strdup(s); + + if (news == NULL) { + nomem(); + } + return (news); +} + +static void * +xcalloc(size_t nelem, size_t elsize) +{ + void *p = calloc(nelem, elsize); + + if (p == NULL) { + nomem(); + } + + return (p); +} + +#define NOMEM_MSG "out of memory\n" +static void __NORETURN +nomem(void) +{ + /* Try to get the error out before aborting */ + (void) write(STDERR_FILENO, NOMEM_MSG, sizeof (NOMEM_MSG)); + abort(); +} diff --git a/usr/src/tools/scripts/Makefile b/usr/src/tools/scripts/Makefile index d6cd4cbfda..f28b285b14 100644 --- a/usr/src/tools/scripts/Makefile +++ b/usr/src/tools/scripts/Makefile @@ -25,6 +25,7 @@ # # Copyright 2020 Joyent, Inc. # Copyright 2020 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2022 Jason King SHELL=/usr/bin/ksh93 @@ -51,7 +52,6 @@ SHFILES= \ PERLFILES= \ check_rtime \ - find_elf \ interface_check \ interface_cmp \ jstyle \ @@ -86,7 +86,6 @@ MAN1ONBLDFILES= \ check_rtime.1onbld \ ctfconvert.1onbld \ cstyle.1onbld \ - find_elf.1onbld \ flg.flp.1onbld \ git-pbchk.1onbld \ hdrchk.1onbld \ diff --git a/usr/src/tools/scripts/find_elf.pl b/usr/src/tools/scripts/find_elf.pl deleted file mode 100644 index a1e0afa1f0..0000000000 --- a/usr/src/tools/scripts/find_elf.pl +++ /dev/null @@ -1,457 +0,0 @@ -#!/usr/bin/perl -w -# -# 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 -# or http://www.opensolaris.org/os/licensing. -# 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. -# - -# -# Find ELF executables and sharable objects -# -# This script descends a directory hierarchy and reports the ELF -# objects found, one object per line of output. -# -# find_elf [-frs] path -# -# Where path is a file or directory. -# -# Each line of output is of the form: -# -# ELFCLASS ELFTYPE VERDEF|NOVERDEF relpath -# -# where relpath is the path relative to the directory from which the -# search started. - -use strict; - -use vars qw($Prog %Output @SaveArgv); -use vars qw(%opt $HaveElfedit); - -# Hashes used to detect aliases --- symlinks that reference a common file -# -# id_hash - Maps the unique st_dev/st_ino pair to the real file -# alias_hash - Maps symlinks to the real file they reference -# -use vars qw(%id_hash %alias_hash); - -use POSIX qw(getenv); -use Getopt::Std; -use File::Basename; -use IO::Dir; -use Config; - -BEGIN { - if ($Config{useithreads}) { - require threads; - require threads::shared; - threads::shared->import(qw(share)); - require Thread::Queue; - } -} - -# -# We need to clamp the maximum number of threads that we use. Because -# this program is mostly an exercise in fork1, more threads doesn't -# actually help us after a certain point as we just spend more and more -# time trying to stop all of our LWPs than making forward progress. -# We've seen experimentally on both 2P systems with 128 cores and 1P -# systems with 16 cores that around 8 threads is a relative sweet spot. -# -chomp (my $NPROCESSORS_ONLN = `getconf NPROCESSORS_ONLN 2>/dev/null` || 1); -my $max_threads = $ENV{DMAKE_MAX_JOBS} || $NPROCESSORS_ONLN; -if ($max_threads > 8) { - $max_threads = 8; -} - -my $tq; - -if ($Config{useithreads}) { - share(%Output); - share(%id_hash); - share(%alias_hash); - - $tq = Thread::Queue->new; -} - -## GetObjectInfo(path) -# -# Return a 3 element output array describing the object -# given by path. The elements of the array contain: -# -# Index Meaning -# ----------------------------------------------- -# 0 ELFCLASS of object (0 if not an ELF object) -# 1 Type of object (NONE if not an ELF object) -# 2 VERDEF if object defines versions, NOVERDEF otherwise -# -sub GetObjectInfo { - my $path = $_[0]; - - # If elfedit is available, we use it to obtain the desired information - # by executing three commands in order, to produce a 0, 2, or 3 - # element output array. - # - # Command Meaning - # ----------------------------------------------- - # ehdr:ei_class ELFCLASS of object - # ehdr:ei_e_type Type of object - # dyn:tag verdef Address of verdef items - # - # We discard stderr, and simply examine the resulting array to - # determine the situation: - # - # # Array Elements Meaning - # ----------------------------------------------- - # 0 File is not ELF object - # 2 Object with no versions (no VERDEF) - # 3 Object that has versions - if ($HaveElfedit) { - my $ecmd = "elfedit -r -o simple -e ehdr:ei_class " . - "-e ehdr:e_type -e 'dyn:tag verdef'"; - my @Elf = split(/\n/, `$ecmd $path 2>/dev/null`); - - my $ElfCnt = scalar @Elf; - - # Return ET_NONE array if not an ELF object - return (0, 'NONE', 'NOVERDEF') if ($ElfCnt == 0); - - # Otherwise, convert the result to standard form - $Elf[0] =~ s/^ELFCLASS//; - $Elf[1] =~ s/^ET_//; - $Elf[2] = ($ElfCnt == 3) ? 'VERDEF' : 'NOVERDEF'; - return @Elf; - } - - # For older platforms, we use elfdump to get the desired information. - my @Elf = split(/\n/, `elfdump -ed $path 2>&1`); - my $Header = 'None'; - my $Verdef = 'NOVERDEF'; - my ($Class, $Type); - - foreach my $Line (@Elf) { - # If we have an invalid file type (which we can tell from the - # first line), or we're processing an archive, bail. - if ($Header eq 'None') { - if (($Line =~ /invalid file/) || - ($Line =~ /$path(.*):/)) { - return (0, 'NONE', 'NOVERDEF'); - } - } - - if ($Line =~ /^ELF Header/) { - $Header = 'Ehdr'; - next; - } - - if ($Line =~ /^Dynamic Section/) { - $Header = 'Dyn'; - next; - } - - if ($Header eq 'Ehdr') { - if ($Line =~ /e_type:\s*ET_([^\s]+)/) { - $Type = $1; - next; - } - if ($Line =~ /ei_class:\s+ELFCLASS(\d+)/) { - $Class = $1; - next; - } - next; - } - - if (($Header eq 'Dyn') && - ($Line =~ /^\s*\[\d+\]\s+VERDEF\s+/)) { - $Verdef = 'VERDEF'; - next; - } - } - return ($Class, $Type, $Verdef); -} - - -## ProcFile(FullPath, RelPath, AliasedPath, IsSymLink, dev, ino) -# -# Determine whether this a ELF dynamic object and if so, add a line -# of output for it to @Output describing it. -# -# entry: -# FullPath - Fully qualified path -# RelPath - Path relative to starting root directory -# AliasedPath - True if RelPath contains a symlink directory component. -# Such a path represents an alias to the same file found -# completely via actual directories. -# IsSymLink - True if basename (final component) of path is a symlink. -# -sub ProcFile { - my($FullPath, $RelPath, $AliasedPath, $IsSymLink, $dev, $ino) = @_; - my(@Elf, @Pvs, @Pvs_don, @Vers, %TopVer); - my($Aud, $Max, $Priv, $Pub, $ElfCnt, $Val, $Ttl, $NotPlugin); - - my $uniqid = sprintf("%llx-%llx", $dev, $ino); - - # Remove ./ from front of relative path - $RelPath =~ s/^\.\///; - - my $name = $opt{r} ? $RelPath : $FullPath; - - # If this is a symlink, or the path contains a symlink, put it in - # the alias hash for later analysis. We do this before testing to - # see if it is an ELF file, because that's a relatively expensive - # test. The tradeoff is that the alias hash will contain some files - # we don't care about. That is a small cost. - if (($IsSymLink || $AliasedPath) && !$opt{a}) { - $alias_hash{$name} = $uniqid; - return; - } - - # Obtain the ELF information for this object. - @Elf = GetObjectInfo($FullPath); - - if ($Elf[1] eq 'NONE') { - return; - } - - # Return quietly if object is executable or relocatable but the -s - # option was used. - if ((($Elf[1] eq 'EXEC') || ($Elf[1] eq 'REL')) && $opt{s}) { - return; - } - - $Output{$name} = sprintf("OBJECT %2s %-4s %-8s %s\n", - $Elf[0], $Elf[1], $Elf[2], $name); - - # Remember it for later alias analysis - $id_hash{$uniqid} = $name; -} - - -## ProcDir(FullPath, RelPath, AliasedPath, SelfSymlink) -# -# Recursively search directory for dynamic ELF objects, calling -# ProcFile() on each one. -# -# entry: -# FullPath - Fully qualified path -# RelPath - Path relative to starting root directory -# AliasedPath - True if RelPath contains a symlink directory component. -# Such a path represents an alias to the same file found -# completely via actual directories. -# SelfSymlink - True (1) if the last segment in the path is a symlink -# that points at the same directory (i.e. 32->.). If SelfSymlink -# is True, ProcDir() examines the given directory for objects, -# but does not recurse past it. This captures the aliases for -# those objects, while avoiding entering a recursive loop, -# or generating nonsensical paths (i.e., 32/amd64/...). -# -sub ProcDir { - if ($Config{useithreads}) { - threads->create(sub { - while (my $q = $tq->dequeue) { - ProcFile(@$q) - } - }) for (1 .. $max_threads); - } - - _ProcDir(@_); - - if ($Config{useithreads}) { - $tq->end; - $_->join for threads->list; - } -} - -sub _ProcDir { - my($FullDir, $RelDir, $AliasedPath, $SelfSymlink) = @_; - my($NewFull, $NewRel, $Entry); - - # Open the directory and read each entry, omit files starting with "." - my $Dir = IO::Dir->new($FullDir); - if (defined($Dir)) { - foreach $Entry ($Dir->read()) { - - # In fast mode, we skip any file name that starts - # with a dot, which by side effect also skips the - # '.' and '..' entries. In regular mode, we must - # explicitly filter out those entries. - if ($opt{f}) { - next if ($Entry =~ /^\./); - } else { - next if ($Entry =~ /^\.\.?$/); - } - - $NewFull = join('/', $FullDir, $Entry); - - # We need to follow symlinks in order to capture - # all possible aliases for each object. However, - # symlinks that point back at the same directory - # (e.g. 32->.) must be flagged via the SelfSymlink - # argument to our recursive self in order to avoid - # taking it more than one level down. - my $RecurseAliasedPath = $AliasedPath; - my $RecurseSelfSymlink = 0; - my $IsSymLink = -l $NewFull; - if ($IsSymLink) { - my $trans = readlink($NewFull); - - $trans =~ s/\/*$//; - $RecurseSelfSymlink = 1 if $trans eq '.'; - $RecurseAliasedPath = 1; - } - - if (!stat($NewFull)) { - next; - } - $NewRel = join('/', $RelDir, $Entry); - - # Descend into and process any directories. - if (-d _) { - # If we have recursed here via a $SelfSymlink, - # then do not persue directories. We only - # want to find objects in the same directory - # via that link. - next if $SelfSymlink; - - _ProcDir($NewFull, $NewRel, $RecurseAliasedPath, - $RecurseSelfSymlink); - next; - } - - # In fast mode, we skip objects unless they end with - # a .so extension, or are executable. We touch - # considerably fewer files this way. - if ($opt{f} && !($Entry =~ /\.so$/) && - !($Entry =~ /\.so\./) && - ($opt{s} || (! -x _))) { - next; - } - - # Process any standard files. - if (-f _) { - my ($dev, $ino) = stat(_); - if ($Config{useithreads}) { - $tq->enqueue([ $NewFull, $NewRel, - $AliasedPath, $IsSymLink, $dev, - $ino ]); - } - else { - ProcFile($NewFull, $NewRel, - $AliasedPath, $IsSymLink, $dev, - $ino); - } - next; - } - - } - $Dir->close(); - } -} - - -# ----------------------------------------------------------------------------- - -# Establish a program name for any error diagnostics. -chomp($Prog = `basename $0`); - -# The onbld_elfmod package is maintained in the same directory as this -# script, and is installed in ../lib/perl. Use the local one if present, -# and the installed one otherwise. -my $moddir = dirname($0); -$moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm"; -require "$moddir/onbld_elfmod.pm"; - -# Check that we have arguments. -@SaveArgv = @ARGV; -if ((getopts('afrs', \%opt) == 0) || (scalar(@ARGV) != 1)) { - print "usage: $Prog [-frs] file | dir\n"; - print "\t[-a]\texpand symlink aliases\n"; - print "\t[-f]\tuse file name at mode to speed search\n"; - print "\t[-r]\treport relative paths\n"; - print "\t[-s]\tonly remote sharable (ET_DYN) objects\n"; - exit 1; -} - -%Output = (); -%id_hash = (); -%alias_hash = (); -$HaveElfedit = -x '/usr/bin/elfedit'; - -my $Arg = $ARGV[0]; -my $Error = 0; - -ARG: { - # Process simple files. - if (-f $Arg) { - my($RelPath) = $Arg; - - if ($opt{r}) { - my $Prefix = $Arg; - - $Prefix =~ s/(^.*)\/.*$/$1/; - $Prefix = '.' if ($Prefix eq $Arg); - print "PREFIX $Prefix\n"; - } - $RelPath =~ s/^.*\//.\//; - my ($dev, $ino) = stat(_); - my $IsSymLink = -l $Arg; - ProcFile($Arg, $RelPath, 0, $IsSymLink, $dev, $ino); - next; - } - - # Process directories. - if (-d $Arg) { - $Arg =~ s/\/$//; - print "PREFIX $Arg\n" if $opt{r}; - ProcDir($Arg, ".", 0, 0); - next; - } - - print STDERR "$Prog: not a file or directory: $Arg\n"; - $Error = 1; -} - -# Build a hash, using the primary file name as the key, that has the -# strings for any aliases to that file. -my %alias_text = (); -foreach my $Alias (sort keys %alias_hash) { - my $id = $alias_hash{$Alias}; - if (defined($id_hash{$id})) { - my $obj = $id_hash{$id}; - my $str = "ALIAS $id_hash{$id}\t$Alias\n"; - - if (defined($alias_text{$obj})) { - $alias_text{$obj} .= $str; - } else { - $alias_text{$obj} = $str; - } - } -} - -# Output the main files sorted by name. Place the alias lines immediately -# following each main file. -foreach my $Path (sort keys %Output) { - print $Output{$Path}; - print $alias_text{$Path} if defined($alias_text{$Path}); -} - -exit $Error; |