[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
system/2208: Incorrect 'join' behaviour?
>Number: 2208
>Category: system
>Synopsis: Inconsistent field ordering between pairable and unpairable lines
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bugs
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Nov 27 17:20:02 MST 2001
>Last-Modified:
>Originator: Jonathan Martin
>Organization:
Department of Computing Science at University of Alberta.
>Release: OPENBSD_2_9
>Environment:
System : OpenBSD 2.9
Architecture: OpenBSD.i386
Machine : i386
>Description:
When joining with the -a<num> flag, lines which are joined are output with
the join field first, with the rest of the fields following in the order they
appeared in the input. However, lines which are not joined are output without
any reordering. The man page is vague about how unpairable lines will appear
on output. IRIX, Solaris, and GNU join all reorder unpairable lines so that
the join field is first.
>How-To-Repeat:
Input file foo:
a 1
Input file bar:
b 1
x 2 apple
y 2 orange
Command line: join -12 -22 -a2 foo bar
OpenBSD output:
1 a b
x 2 apple
y 2 orange
Other systems output:
1 a b
2 x apple
2 y orange
Side effects of a fix:
Unfortunately changing the behavior of join affects the /etc/security script
(the setuid and device change checks). If join reorders the unpairable
fields, then additions and deletions placed in TMP2 will not match with
anything in CUR and TMP1 (which will still be the order that find output).
So every addition and deletion will also be flagged as a change, and will be
output twice.
>Fix:
The fix for join is simple.
Index: usr.bin/join/join.c
===================================================================
RCS file: /cvs/src/usr.bin/join/join.c,v
retrieving revision 1.13
diff -u -r1.13 join.c
--- usr.bin/join/join.c 2001/01/29 01:57:59 1.13
+++ usr.bin/join/join.c 2001/11/27 23:33:52
@@ -454,9 +454,15 @@
else
outfield(lp, 0, 1);
}
- else
+ else {
+ /*
+ * Output the join field, then the remaining fields from F
+ */
+ outfield(lp, F->joinf, 0);
for (cnt = 0; cnt < lp->fieldcnt; ++cnt)
- outfield(lp, cnt, 0);
+ if (F->joinf != cnt)
+ outfield(lp, cnt, 0);
+ }
putchar('\n');
if (ferror(stdout))
err(1, "stdout");
The side-effect fix for /etc/security is less pleasant. Basically it means
always re-ordering the output of the find so it is consistent with what join
will output later.
Index: etc/security
===================================================================
RCS file: /cvs/src/etc/security,v
retrieving revision 1.48
diff -u -r1.48 security
--- etc/security 2001/04/06 17:13:37 1.48
+++ etc/security 2001/11/27 23:32:58
@@ -473,7 +473,7 @@
fi
# Display any changes in the setuid/setgid file list.
-egrep -v '^[bc]' $LIST > $TMP1
+egrep -v '^[bc]' $LIST | join -110 -210 -v2 /dev/null - | sort +0 > $TMP1
if [ -s $TMP1 ] ; then
# Check to make sure uudecode isn't setuid.
if grep -w uudecode $TMP1 > /dev/null ; then
@@ -489,7 +489,7 @@
:
else
> $TMP2
- join -110 -210 -v2 $CUR $TMP1 > $OUTPUT
+ join -11 -21 -v2 $CUR $TMP1 > $OUTPUT
if [ -s $OUTPUT ] ; then
echo "${pending}Setuid additions:"
pending=
@@ -497,7 +497,7 @@
echo ""
fi
- join -110 -210 -v1 $CUR $TMP1 > $OUTPUT
+ join -11 -21 -v1 $CUR $TMP1 > $OUTPUT
if [ -s $OUTPUT ] ; then
echo "${pending}Setuid deletions:"
pending=
@@ -505,8 +505,7 @@
echo ""
fi
- sort +9 $TMP2 $CUR $TMP1 | \
- sed -e 's/[ ][ ]*/ /g' | uniq -u > $OUTPUT
+ sort +0 $TMP2 $CUR $TMP1 | uniq -u > $OUTPUT
if [ -s $OUTPUT ] ; then
echo "${pending}Setuid changes:"
pending=
@@ -545,7 +544,7 @@
fi
# Display any changes in the device file list.
-egrep '^[bc]' $LIST | sort +10 > $TMP1
+egrep '^[bc]' $LIST | join -111 -211 -v2 /dev/null - | sort +0 > $TMP1
if [ -s $TMP1 ] ; then
CUR=/var/backups/device.current
BACK=/var/backups/device.backup
@@ -555,14 +554,14 @@
:
else
> $TMP2
- join -111 -211 -v2 $CUR $TMP1 > $OUTPUT
+ join -11 -21 -v2 $CUR $TMP1 > $OUTPUT
if [ -s $OUTPUT ] ; then
echo "Device additions:"
tee -a $TMP2 < $OUTPUT
echo ""
fi
- join -111 -211 -v1 $CUR $TMP1 > $OUTPUT
+ join -11 -21 -v1 $CUR $TMP1 > $OUTPUT
if [ -s $OUTPUT ] ; then
echo "Device deletions:"
tee -a $TMP2 < $OUTPUT
@@ -571,10 +570,8 @@
# Report any block device change. Ignore character
# devices, only the name is significant.
- cat $TMP2 $CUR $TMP1 | \
- sed -e '/^c/d' | \
- sort +10 | \
- sed -e 's/[ ][ ]*/ /g' | \
+ sort +0 $TMP2 $CUR $TMP1 | \
+ awk '$2 !~ /c........./' | \
uniq -u > $OUTPUT
if [ -s $OUTPUT ] ; then
echo "Block device changes:"
>Audit-Trail:
>Unformatted: