sys.mk:
- Follow-up r325351: Ensure .OBJDIR is set to a safe value if auto.obj.mk did nothing (either because mkdir and the assert failed or it skipped mkdir due to 'make *clean*'). While r325351 was enough to resolve the 'rm -rf /etc', it was not enough to resolve an incorrect .OBJDIR being set. This had no practical impact as long as 'make obj' was properly ran. If files were built directly in etc/ (or sys/boot/) without an objdir then it is possible objects still landed in the root filesystem paths.
src.sys.obj.mk:
- Follow-up r325330: Always attempt to set .OBJDIR to what is wanted even if AUTO_OBJ is enabled, and add a fallback to .CURDIR if needed. This is redundant with the change to sys.mk but the change in sys.mk is only triggered if MK_AUTO_OBJ==yes. It is possible that new code is added at some point between src.sys.obj.mk and the auto.obj.mk inclusion that ends up setting MK_AUTO_OBJ to no. In that case .OBJDIR would retain an unsafe value.
bsd.obj.mk:
- Add an assertion to avoid the rm -rf /etc case.
- Add an assertion to ensure that if AUTO_OBJ enabled, and not NO_OBJ, that .OBJDIR is not .CURDIR. This shouldn't normally happen but if one of the other changes fails then this assertion will trigger. If AUTO_OBJ is enabled we really don't want to build in .CURDIR.
There was at least 1 case where make starts with .OBJDIR=/etc with the new
src.sys.obj.mk (and WITH_DIRDEPS_BUILD=yes before). This happens with 'make
cleandir', and other clean targets, at the top-level. When traversing into
SUBDIR=etc in a sub-make, OBJROOT, MAKEOBJDIR, and SRCTOP are all exported.
MAKEOBJDIR is set to the dynamic '${.CURDIR:S,^${SRCTOP},${OBJTOP},}'. make
expands this MAKEOBJDIR immediately and finds that OBJTOP is empty which
results in just having MAKEOBJDIR=/etc.
/usr/src % OBJROOT=/nonexistent/ SRCTOP=${PWD} MAKEOBJDIR='${.CURDIR:S,^${SRCTOP},${OBJTOP},}' make -C etc -V .OBJDIR MK_AUTO_OBJ=no
/etc
When AUTO_OBJ is disabled, 'make obj' would properly create the directory via
bsd.obj.mk as MAKEOBJDIR would be expanded after OBJTOP was defined in
src.sys.obj.mk. bsd.obj.mk uses MAKEOBJDIR/MAKEOBJDIRPREFIX to determine its
internal CANONICALOBJDIR that in this mode assumes to match what make uses
internally. The next make invocation would set the expected .OBJDIR in
src.sys.obj.mk and everything would be fine.
When AUTO_OBJ is enabled, auto.obj.mk would create the expected object
directory by expanding MAKEOBJDIR after OBJTOP was set and then update
.OBJDIR to point to it. Normally if the mkdir fails in auto.obj.mk
then an .error is triggered. However if running any of the 'clean' targets
then a mkdir is not attempted since there's no sense creating a directory just
to remove it. Since it did not create the expected directory then it never
updates .OBJDIR with a valid directory. This results in the startup
.OBJDIR=/etc being retained. Later in bsd.obj.mk it sets its
CANONICALOBJDIR to be .OBJDIR when AUTO_OBJ is enabled, assuming that
auto.obj.mk did the right thing: created or failed. Then when 'make clean' is
actually ran it operates on /etc.
This problem could manifest in etc/ and sys/boot/*/ since all of these include
bsd.obj.mk in some way. If bsd.subdir.mk had included bsd.obj.mk then other
directories would have been affected as well, such as /lib, /bin, /sbin,
/share, /rescue, and /libexec.
Pointyhat to: bdrewery
Sponsored by: Dell EMC Isilon