1#!/usr/bin/ksh 2# 3# This file and its contents are supplied under the terms of the 4# Common Development and Distribution License ("CDDL"), version 1.0. 5# You may only use this file in accordance with the terms of version 6# 1.0 of the CDDL. 7# 8# A full copy of the text of the CDDL should have accompanied this 9# source. A copy of the CDDL is also available via the Internet at 10# http://www.illumos.org/license/CDDL. 11# 12 13# 14# Copyright 2022 Oxide Computer Company 15# 16 17# 18# This contains a number of basic tests for ar(1). When adding something 19# to ar or fixing a bug, please expand this! 20# 21 22unalias -a 23set -o pipefail 24 25ar_arg0="$(basename $0)" 26ar_data="$(dirname $0)" 27ar_data0="$ar_data/ar_test0.o" 28ar_data1="$ar_data/ar_test1.o" 29ar_prog=/usr/bin/ar 30ar_tmpdir=/tmp/ar.$$ 31 32ar_f01="$ar_tmpdir/test01.a" 33ar_f10="$ar_tmpdir/test10.a" 34 35ar_t01="ar_test0.o 36ar_test1.o" 37ar_t10="ar_test1.o 38ar_test0.o" 39 40strip_prog=/usr/bin/strip 41dump_prog=/usr/bin/dump 42nm_prog=/usr/bin/nm 43 44ar_exit=0 45 46function warn 47{ 48 typeset msg="$*" 49 [[ -z "$msg" ]] && msg="failed" 50 print -u2 "TEST FAILED: $ar_arg0: $msg" 51 ar_exit=1 52} 53 54function compare_files 55{ 56 typeset base="$1" 57 typeset comp="$2" 58 typeset err=0 59 60 if ! $dump_prog -g $comp | sed 1d > $comp.dump; then 61 warn "failed to dump -g $comp" 62 err=1 63 fi 64 65 if ! $nm_prog -P -tx $comp > $comp.nm; then 66 warn "failed to nm $comp" 67 err=1 68 fi 69 70 if ! diff $base.dump $comp.dump; then 71 warn "$base.dump and $comp.dump don't match" 72 err=1 73 fi 74 75 if ! diff $base.nm $comp.nm; then 76 warn "$base.dump and $comp.dump don't match" 77 err=1 78 fi 79 80 return $err 81} 82 83# 84# To set things up, we first go and create two basic archives that we 85# will then use as the basis for comaring various operations later. 86# 87function setup_baseline 88{ 89 if ! $ar_prog cr $ar_f01 $ar_data0 $ar_data1; then 90 warn "failed to create basic archive $ar_f01" 91 fi 92 93 if ! $ar_prog cr $ar_f10 $ar_data1 $ar_data0; then 94 warn "failed to create basic archive $ar_f10" 95 fi 96 97 if ! $dump_prog -g $ar_f01 | sed 1d > $ar_f01.dump; then 98 warn "failed to dump archive $ar_f01" 99 fi 100 101 if ! $dump_prog -g $ar_f10 | sed 1d > $ar_f10.dump; then 102 warn "failed to dump archive $ar_f10" 103 fi 104 105 if ! $nm_prog -P -tx $ar_f01 > $ar_f01.nm; then 106 warn "failed to nm archive $ar_f01" 107 fi 108 109 if ! $nm_prog -P -tx $ar_f10 > $ar_f10.nm; then 110 warn "failed to nm archive $ar_f01" 111 fi 112 113 print "TEST PASSED: basic archive creation" 114} 115 116function strip_archive 117{ 118 typeset file="$1" 119 typeset output= 120 121 if ! $strip_prog $file 2>/dev/null; then 122 warn "failed to strip $alt" 123 return 1 124 fi 125 126 output=$($dump_prog -g $file) 127 if [[ -n "$output" ]]; then 128 warn "stripped file $file somehow has an ar header" 129 return 1 130 fi 131 132 return 0 133} 134 135# 136# Validate that stripping and regenerating a symbol table actually 137# works. 138# 139function test_s 140{ 141 typeset alt="$ar_tmpdir/s.a" 142 typeset output= 143 144 if ! cp $ar_f01 $alt; then 145 warn "failed to copy file" 146 return 147 fi 148 149 if ! strip_archive $alt; then 150 return 151 fi 152 153 if ! $ar_prog s $alt; then 154 warn "restore symbol table with ar s" 155 fi 156 157 if compare_files "$ar_f01" "$alt"; then 158 print "TEST PASSED: restoring stripped archive with -s" 159 fi 160 161 if ! strip_archive $alt; then 162 return 163 fi 164 165 if ! $ar_prog st $alt >/dev/null; then 166 warn "restore symbol table with ar st" 167 fi 168 169 if compare_files "$ar_f01" "$alt"; then 170 print "TEST PASSED: restoring stripped archive with -st" 171 fi 172 173 if ! strip_archive $alt; then 174 return 175 fi 176 177 output=$($ar_prog sv $alt 2>&1) 178 if [[ "$output" == "ar: writing $alt" ]]; then 179 print "TEST PASSED: ar -sv has proper output" 180 else 181 warn "ar -sv has unexpected output: $output" 182 fi 183 184 if compare_files "$ar_f01" "$alt"; then 185 print "TEST PASSED: restoring stripped archive with -sv" 186 fi 187} 188 189# 190# Ensure that use of -s and -r still works. This is a regression test 191# for the original integration of standalone -s support. 192# 193function test_rs 194{ 195 typeset alt="$ar_tmpdir/rs.a" 196 197 if ! $ar_prog rs $alt $ar_data1 $ar_data0; then 198 warn "ar -rs: did not create an archive" 199 fi 200 201 if ! compare_files $ar_f10 $alt; then 202 warn "ar -rs: did not create expected file" 203 else 204 print "TEST PASSED: ar -rs creates archives" 205 fi 206 207 rm -f $alt 208 209 if ! $ar_prog crs $alt $ar_data1 $ar_data0; then 210 warn "ar -crs: did not create an archive" 211 fi 212 213 if ! compare_files $ar_f10 $alt; then 214 warn "ar -crs: did not create expected file" 215 else 216 print "TEST PASSED: ar -crs creates archives" 217 fi 218} 219 220# 221# Verify that basic ar -r invocations ultimately end up creating what 222# we'd expect. 223# 224function test_incremental 225{ 226 typeset alt="$ar_tmpdir/incr.a" 227 228 if ! $ar_prog cr $alt $ar_data0; then 229 warn "incremental archive: failed to create archive" 230 return 231 fi 232 233 if ! $ar_prog cr $alt $ar_data1; then 234 warn "incremental archive: failed to add to archive" 235 return 236 fi 237 238 if ! compare_files $ar_f01 $alt; then 239 warn "incremental archive: did not create expected file" 240 else 241 print "TEST PASSED: incremental archive creation" 242 fi 243 244} 245 246# 247# Validate that ar's various -a and -b variants work. 248# 249function test_pos 250{ 251 typeset alt="$ar_tmpdir/pos.a" 252 253 if ! $ar_prog cr $alt $ar_data1; then 254 warn "positional tests: failed to create archive" 255 return; 256 fi 257 258 if ! $ar_prog -cra ar_test1.o $alt $ar_data0; then 259 warn "positional tests: -a append failed" 260 return 261 fi 262 263 if ! compare_files $ar_f10 $alt; then 264 warn "positional tests: -cra archive is incorrect" 265 else 266 print "TEST PASSED: positional tests: ar -cra" 267 fi 268 269 rm -f $alt 270 271 if ! $ar_prog cr $alt $ar_data1; then 272 warn "positional tests: failed to create archive" 273 return; 274 fi 275 276 if ! $ar_prog -crb ar_test1.o $alt $ar_data0; then 277 warn "positional tests: -b prepend failed" 278 return 279 fi 280 281 if ! compare_files $ar_f01 $alt; then 282 warn "positional tests: -crb archive is incorrect" 283 else 284 print "TEST PASSED: positional tests: ar -crb" 285 fi 286 287 rm -f $alt 288 289 if ! $ar_prog cr $alt $ar_data1; then 290 warn "positional tests: failed to create archive" 291 return; 292 fi 293 294 if ! $ar_prog -cri ar_test1.o $alt $ar_data0; then 295 warn "positional tests: -i prepend failed" 296 return 297 fi 298 299 if ! compare_files $ar_f01 $alt; then 300 warn "positional tests: -cri archive is incorrect" 301 else 302 print "TEST PASSED: positional tests: ar -cri" 303 fi 304 305} 306 307# 308# Go through and validate the various versions of ar x. 309# 310function test_x 311{ 312 typeset out0="$ar_tmpdir/ar_test0.o" 313 typeset out1="$ar_tmpdir/ar_test1.o" 314 typeset output= 315 316 rm -f $out0 $out1 317 318 if ! $ar_prog x $ar_f01; then 319 warn "ar -x: failed to extract files" 320 fi 321 322 if cmp -s $out0 $ar_data0 && cmp -s $out1 $ar_data1; then 323 print "TEST PASSED: ar -x" 324 else 325 warn "ar -x: extracted files differs" 326 fi 327 328 rm -f $out0 $out1 329 echo elberth > $out0 330 331 # 332 # For some reason, ar -Cx will actually fail if you have an 333 # existing file. It seems a bit weird as it means you can't 334 # extract existing files (depdendent on order), but that's how 335 # it goes. 336 # 337 if $ar_prog Cx $ar_f01 ar_test0.o; then 338 warn "ar -Cx: failed to extract file that wasn't in fs\n" 339 fi 340 341 output=$(cat $out0) 342 if [[ "$output" != "elberth" ]]; then 343 warn "ar -Cx: overwrote pre-existing file" 344 else 345 print "TEST PASSED: ar -Cx did not overwrite existing file" 346 fi 347 348 if ! $ar_prog Cx $ar_f01 ar_test1.o; then 349 warn "ar -Cx: failed to extract file that wasn't in fs\n" 350 fi 351 352 if cmp -s $out1 $ar_data1; then 353 print "TEST PASSED: ar -Cx extracted file that didn't exist" 354 else 355 warn "ar -Cx: failed to extract file that exists" 356 fi 357} 358 359# 360# Variant of -x that ensures we restore stripped archives. 361# 362function test_xs 363{ 364 typeset alt="$ar_tmpdir/xs.a" 365 typeset out0="$ar_tmpdir/ar_test0.o" 366 typeset out1="$ar_tmpdir/ar_test1.o" 367 368 rm -f $out0 $out1 369 370 if ! cp $ar_f01 $alt; then 371 warn "failed to copy file" 372 return 373 fi 374 375 if ! strip_archive $alt; then 376 return 377 fi 378 379 if ! $ar_prog xs $alt; then 380 warn "ar -xs: failed to extract files" 381 fi 382 383 if cmp -s $out0 $ar_data0 && cmp -s $out1 $ar_data1 && \ 384 compare_files "$ar_f01" "$alt"; then 385 print "TEST PASSED: ar -xs" 386 else 387 warn "ar -xs: extracted and restore archive differ" 388 fi 389} 390 391function test_m 392{ 393 typeset alt="$ar_tmpdir/pos.a" 394 395 if ! cp $ar_f01 $alt; then 396 warn "failed to copy file" 397 return 398 fi 399 400 if ! $ar_prog ma ar_test1.o $alt ar_test0.o; then 401 warn "ar -ma: failed didn't work" 402 fi 403 404 if compare_files "$ar_f10" "$alt"; then 405 print "TEST PASSED: ar -ma" 406 else 407 warn "ar -ma: did not create expected archive" 408 fi 409 410 if ! $ar_prog mb ar_test1.o $alt ar_test0.o; then 411 warn "ar -ma: failed didn't work" 412 fi 413 414 if compare_files "$ar_f01" "$alt"; then 415 print "TEST PASSED: ar -mb" 416 else 417 warn "ar -mb: did not create expected archive" 418 fi 419} 420 421function test_t 422{ 423 typeset output= 424 425 output=$($ar_prog t $ar_f01) 426 if [[ "$ar_t01" != "$output" ]]; then 427 warn "ar t: mismatched output on $ar_t01, found $output" 428 else 429 print "TEST PASSED: ar -t (output 01)" 430 fi 431 432 output=$($ar_prog t $ar_f10) 433 if [[ "$ar_t10" != "$output" ]]; then 434 warn "ar t: mismatched output on $ar_f10, found $output" 435 else 436 print "TEST PASSED: ar -t (output 10)" 437 fi 438} 439 440function test_q 441{ 442 typeset alt="$ar_tmpdir/q.a" 443 444 if ! $ar_prog q $alt $ar_data1 $ar_data0; then 445 warn "ar -q: did not create an archive" 446 fi 447 448 if ! compare_files $ar_f10 $alt; then 449 warn "ar -q: did not create expected file" 450 else 451 print "TEST PASSED: ar -q creates archives" 452 fi 453 454 rm -f $alt 455 456 if ! $ar_prog cq $alt $ar_data1 $ar_data0; then 457 warn "ar -rs: did not create an archive" 458 fi 459 460 if ! compare_files $ar_f10 $alt; then 461 warn "ar -cq: did not create expected file" 462 else 463 print "TEST PASSED: ar -cq creates archives" 464 fi 465 466 rm -f $alt 467 468 if ! $ar_prog cqs $alt $ar_data1 $ar_data0; then 469 warn "ar -cqs: did not create an archive" 470 fi 471 472 if ! compare_files $ar_f10 $alt; then 473 warn "ar -cqs: did not create expected file" 474 else 475 print "TEST PASSED: ar -cqs creates archives" 476 fi 477 478} 479 480function test_err 481{ 482 if $ar_prog $@ 2>/dev/null 1>/dev/null; then 483 warn "should have failed with args "$@", but passed" 484 else 485 printf "TEST PASSED: invalid arguments %s\n" "$*" 486 fi 487} 488 489# 490# Before we begin execution, set up the environment such that we have a 491# standard locale and that umem will help us catch mistakes. 492# 493export LC_ALL=C.UTF-8 494export LD_PRELOAD=libumem.so 495export UMEM_DEBUG=default 496 497if ! mkdir "$ar_tmpdir"; then 498 printf "failed to make output directory %s\n" "$ar_tmpdir" >&2 499 exit 1 500fi 501 502if ! cd "$ar_tmpdir"; then 503 printf "failed to cd into output directory %s\n" "$ar_tmpdir" >&2 504 exit 1 505fi 506 507if [[ ! -d "$ar_data" ]]; then 508 printf "failed to find data directory %s\n" "$ar_data" >&2 509 exit 1 510fi 511 512if [[ -n $AR ]]; then 513 echo overwrote AR as $AR 514 ar_prog=$AR 515fi 516 517setup_baseline 518test_s 519test_rs 520test_incremental 521test_pos 522test_x 523test_xs 524test_m 525test_t 526test_q 527 528# 529# Note, there are many cases here which probably should be failures and 530# aren't (e.g. ar -mabi) because that's how the tool works today. With 531# proper regression testing of building 3rd party packages this could be 532# changed. 533# 534test_err "" 535test_err "-z" 536test_err "-d" 537test_err "-d" "$ar_tmpdir/enoent" 538test_err "-d" "$ar_f01" "foobar.exe" 539test_err "-m" "$ar_tmpdir/enoent" 540test_err "-ma" "foobar.exe" "$ar_tmpdir/enoent" 541test_err "-mb" "foobar.exe" "$ar_tmpdir/enoent" 542test_err "-mi" "foobar.exe" "$ar_tmpdir/enoent" 543test_err "-p" "$ar_tmpdir/enoent" 544test_err "-P" "$ar_tmpdir/enoent" 545test_err "-q" 546test_err "-qa" "foobar.exe" "$ar_f0.a" 547test_err "-qb" "foobar.exe" "$ar_f0.a" 548test_err "-qi" "foobar.exe" "$ar_f0.a" 549test_err "-qa" "ar_test0.o" "$ar_f0.a" 550test_err "-qb" "ar_test0.o" "$ar_f0.a" 551test_err "-qi" "ar_test0.o" "$ar_f0.a" 552test_err "-r" 553test_err "-ra" "foobar.exe" 554test_err "-ra" "foobar.exe" "$ar_tmpdir/enoent" 555test_err "-rb" "foobar.exe" 556test_err "-rb" "foobar.exe" "$ar_tmpdir/enoent" 557test_err "-ri" "foobar.exe" 558test_err "-ri" "foobar.exe" "$ar_tmpdir/enoent" 559test_err "-t" 560test_err "-t" "$ar_tmpdir/enoent" 561test_err "-x" 562test_err "-x" "$ar_tmpdir/enoent" 563test_err "-s" 564test_err "-s" "$ar_tmpdir/enoent" 565test_err "-s" "$ar_f01" "$ar_f10" 566test_err "-sz" "$ar_f01" 567test_err "-rd" 568test_err "-xd" 569test_err "-qp" 570 571if (( ar_exit == 0 )); then 572 printf "All tests passed successfully!\n" 573fi 574 575cd - >/dev/null 576rm -rf "$ar_tmpdir" 577exit $ar_exit 578