diff --git a/CHANGES b/CHANGES index 8b56ae1..b594cbb 100644 --- a/CHANGES +++ b/CHANGES @@ -63,6 +63,10 @@ Porting: Corrected message format when no strftime() is available; improved handling of very long host or program names +Features: + Filan prints target of symlink when appropriate + Test: FILANSYMLINK + Testing: Unset SOCAT_MAIN_WAIT on informational Socat calls diff --git a/filan.c b/filan.c index 6403b45..dbc54f0 100644 --- a/filan.c +++ b/filan.c @@ -79,17 +79,20 @@ int filan_file(const char *filename, FILE *outfile) { default: if ((fd = Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK +#ifdef O_NOFOLLOW + |(filan_followsymlinks?0:O_NOFOLLOW) +#endif #ifdef O_LARGEFILE |O_LARGEFILE #endif , 0700)) < 0) { - Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s", + Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE, 0700): %s", filename, strerror(errno)); } } - result = filan_stat(&buf, fd, -1, outfile); + result = filan_stat(&buf, fd, -1, outfile, filename); fputc('\n', outfile); return result; } @@ -119,7 +122,7 @@ int filan_fd(int fd, FILE *outfile) { } Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode)); - result = filan_stat(&buf, fd, fd, outfile); + result = filan_stat(&buf, fd, fd, outfile, NULL); if (result >= 0) { /* even more dynamic info */ @@ -212,7 +215,12 @@ int filan_stat( #else struct stat *buf #endif /* !HAVE_STAT64 */ - , int statfd, int dynfd, FILE *outfile) { + , int statfd, int dynfd, FILE *outfile, + const char *filename /* Linux does not (yet) provide an + freadlink system call, so we need + the original name for readlink in + case it is a symlink */ + ) { char stdevstr[8]; /* print header */ @@ -380,7 +388,11 @@ int filan_stat( break; case (S_IFREG): /* 8, regular file */ break; +#ifdef S_IFLNK case (S_IFLNK): /* 10, symbolic link */ + /* we wait for freadlink() sytem call */ + break; +#endif /* S_IFLNK */ break; #ifdef S_IFSOCK case (S_IFSOCK): /* 12, socket */ @@ -393,6 +405,19 @@ int filan_stat( break; #endif /* S_IFSOCK */ } + } else { + switch (buf->st_mode&S_IFMT) { +#ifdef S_IFLNK + case (S_IFLNK): /* 10, symbolic link */ + { + char linktarget[PATH_MAX+1]; + memset(linktarget, 0, PATH_MAX+1); + Readlink(filename, linktarget, PATH_MAX); + fprintf(outfile, "LINKTARGET=%s", linktarget); + } + break; +#endif /* S_IFLNK */ + } } /* ioctl() */ return 0; diff --git a/filan.h b/filan.h index d42877b..b86539b 100644 --- a/filan.h +++ b/filan.h @@ -22,7 +22,8 @@ extern int filan_stat( #else struct stat *buf #endif /* !HAVE_STAT64 */ - , int statfd, int dynfd, FILE *outfile); + , int statfd, int dynfd, FILE *outfile, + const char *filename); extern int cdevan(int fd, FILE *outfile); diff --git a/test.sh b/test.sh index df7b8a0..668f64d 100755 --- a/test.sh +++ b/test.sh @@ -6502,10 +6502,13 @@ esac N=$((N+1)) +# Test if Filan can determine UNIX domain socket in file system NAME=FILANSOCKET case "$TESTS" in *%$N%*|*%filan%*|*%$NAME%*) TEST="$NAME: capability to analyze named unix socket" +# Run Filan on a listening UNIX domain socket. +# When its output gives "socket" as type (2nd column), the test succeeded if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" te1="$td/test$N.stderr1" # socat @@ -6517,10 +6520,16 @@ waitfile "$ts" 1 type=$($FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print($2);}') if [ "$type" = "socket" ]; then $PRINTF "$OK\n" - numOK=$((numOK+1)) + if [ "$VERBOSE" ]; then + echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" + echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" + fi + numOK=$((numOK+1)) else $PRINTF "$FAILED\n" + echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" >&2 cat "$te1" + echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" >&2 cat "$te2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" @@ -15602,6 +15611,46 @@ esac N=$((N+1)) +# Test if Filan can print the target of symbolic links +NAME=FILANSYMLINK +case "$TESTS" in +*%$N%*|*%filan%*|*%$NAME%*) +TEST="$NAME: capability to display symlink target" +# Run Filan on a symbolic link +# When its output contains "LINKTARGET=" the test succeeded +if ! eval $NUMCOND; then :; else +tf="$td/test$N.file" +tl="$td/test$N.symlink" +te1="$td/test$N.stderr1" # socat +te2="$td/test$N.stderr2" # filan +printf "test $F_n $TEST... " $N +touch "$tf" +ln -s "$tf" "$tl" +target=$($FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/') +if [ "$target" = "$tf" ]; then + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then + echo "touch \"$tf\"" + echo "ln -s \"$tf\" \"$tl\"" + echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" + fi + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "touch \"$tf\"" >&2 + echo "ln -s \"$tf\" \"$tl\"" >&2 + echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" >&2 + cat "$te" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +fi +kill $spid 2>/dev/null +wait +fi ;; # NUMCOND +esac +N=$((N+1)) + + # end of common tests ##################################################################################