mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-24 17:44:17 +01:00
ln: Improve link(1) variant of ln(1).
* Give link(1) its own usage message. * Use getprogname(3) instead of rolling our own. * Verify that the target file does not already exist. * Add tests specific to link(1). MFC after: 3 days Sponsored by: Klara, Inc. Reviewed by: allanjude Differential Revision: https://reviews.freebsd.org/D44635
This commit is contained in:
parent
8311bc5f17
commit
bee7cf9e97
36
bin/ln/ln.c
36
bin/ln/ln.c
@ -55,13 +55,14 @@ static bool wflag; /* Warn if symlink target does not
|
|||||||
static char linkch;
|
static char linkch;
|
||||||
|
|
||||||
static int linkit(const char *, const char *, bool);
|
static int linkit(const char *, const char *, bool);
|
||||||
|
static void link_usage(void) __dead2;
|
||||||
static void usage(void) __dead2;
|
static void usage(void) __dead2;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char *p, *targetdir;
|
char *targetdir;
|
||||||
int ch, exitval;
|
int ch, exitval;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -69,17 +70,20 @@ main(int argc, char *argv[])
|
|||||||
* "link", for which the functionality provided is greatly
|
* "link", for which the functionality provided is greatly
|
||||||
* simplified.
|
* simplified.
|
||||||
*/
|
*/
|
||||||
if ((p = strrchr(argv[0], '/')) == NULL)
|
if (strcmp(getprogname(), "link") == 0) {
|
||||||
p = argv[0];
|
|
||||||
else
|
|
||||||
++p;
|
|
||||||
if (strcmp(p, "link") == 0) {
|
|
||||||
while (getopt(argc, argv, "") != -1)
|
while (getopt(argc, argv, "") != -1)
|
||||||
usage();
|
link_usage();
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
usage();
|
link_usage();
|
||||||
|
if (lstat(argv[1], &sb) == 0)
|
||||||
|
errc(1, EEXIST, "%s", argv[1]);
|
||||||
|
/*
|
||||||
|
* We could simply call link(2) here, but linkit()
|
||||||
|
* performs additional checks and gives better
|
||||||
|
* diagnostics.
|
||||||
|
*/
|
||||||
exit(linkit(argv[0], argv[1], false));
|
exit(linkit(argv[0], argv[1], false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,11 +342,17 @@ linkit(const char *source, const char *target, bool isdir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
link_usage(void)
|
||||||
{
|
{
|
||||||
(void)fprintf(stderr, "%s\n%s\n%s\n",
|
(void)fprintf(stderr, "usage: link source_file target_file\n");
|
||||||
"usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]",
|
exit(1);
|
||||||
" ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir",
|
}
|
||||||
" link source_file target_file");
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
(void)fprintf(stderr, "%s\n%s\n",
|
||||||
|
"usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]",
|
||||||
|
" ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ target_exists_hard_body()
|
|||||||
{
|
{
|
||||||
atf_check touch A B
|
atf_check touch A B
|
||||||
atf_check -s exit:1 -e inline:'ln: B: File exists\n' \
|
atf_check -s exit:1 -e inline:'ln: B: File exists\n' \
|
||||||
ln A B
|
ln A B
|
||||||
}
|
}
|
||||||
|
|
||||||
atf_test_case target_exists_symbolic
|
atf_test_case target_exists_symbolic
|
||||||
@ -103,7 +103,7 @@ target_exists_symbolic_body()
|
|||||||
{
|
{
|
||||||
atf_check touch A B
|
atf_check touch A B
|
||||||
atf_check -s exit:1 -e inline:'ln: B: File exists\n' \
|
atf_check -s exit:1 -e inline:'ln: B: File exists\n' \
|
||||||
ln -s A B
|
ln -s A B
|
||||||
}
|
}
|
||||||
|
|
||||||
atf_test_case shf_flag_dir
|
atf_test_case shf_flag_dir
|
||||||
@ -210,10 +210,65 @@ sw_flag_head()
|
|||||||
sw_flag_body()
|
sw_flag_body()
|
||||||
{
|
{
|
||||||
atf_check -s exit:0 -e inline:'ln: warning: A: No such file or directory\n' \
|
atf_check -s exit:0 -e inline:'ln: warning: A: No such file or directory\n' \
|
||||||
ln -sw A B
|
ln -sw A B
|
||||||
atf_check_symlink_to A B
|
atf_check_symlink_to A B
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atf_test_case link_argc
|
||||||
|
link_argc_head() {
|
||||||
|
atf_set "descr" "Verify that link(1) requires exactly two arguments"
|
||||||
|
}
|
||||||
|
link_argc_body() {
|
||||||
|
atf_check -s exit:1 -e match:"usage: link" \
|
||||||
|
link foo
|
||||||
|
atf_check -s exit:1 -e match:"No such file" \
|
||||||
|
link foo bar
|
||||||
|
atf_check -s exit:1 -e match:"No such file" \
|
||||||
|
link -- foo bar
|
||||||
|
atf_check -s exit:1 -e match:"usage: link" \
|
||||||
|
link foo bar baz
|
||||||
|
}
|
||||||
|
|
||||||
|
atf_test_case link_basic
|
||||||
|
link_basic_head() {
|
||||||
|
atf_set "descr" "Verify that link(1) creates a link"
|
||||||
|
}
|
||||||
|
link_basic_body() {
|
||||||
|
touch foo
|
||||||
|
atf_check link foo bar
|
||||||
|
atf_check_same_file foo bar
|
||||||
|
rm bar
|
||||||
|
ln -s foo bar
|
||||||
|
atf_check link bar baz
|
||||||
|
atf_check_same_file foo baz
|
||||||
|
}
|
||||||
|
|
||||||
|
atf_test_case link_eexist
|
||||||
|
link_eexist_head() {
|
||||||
|
atf_set "descr" "Verify that link(1) fails if the target exists"
|
||||||
|
}
|
||||||
|
link_eexist_body() {
|
||||||
|
touch foo bar
|
||||||
|
atf_check -s exit:1 -e match:"bar.*exists" \
|
||||||
|
link foo bar
|
||||||
|
ln -s non-existent baz
|
||||||
|
atf_check -s exit:1 -e match:"baz.*exists" \
|
||||||
|
link foo baz
|
||||||
|
}
|
||||||
|
|
||||||
|
atf_test_case link_eisdir
|
||||||
|
link_eisdir_head() {
|
||||||
|
atf_set "descr" "Verify that link(1) fails if the source is a directory"
|
||||||
|
}
|
||||||
|
link_eisdir_body() {
|
||||||
|
mkdir foo
|
||||||
|
atf_check -s exit:1 -e match:"foo.*directory" \
|
||||||
|
link foo bar
|
||||||
|
ln -s foo bar
|
||||||
|
atf_check -s exit:1 -e match:"bar.*directory" \
|
||||||
|
link bar baz
|
||||||
|
}
|
||||||
|
|
||||||
atf_init_test_cases()
|
atf_init_test_cases()
|
||||||
{
|
{
|
||||||
atf_add_test_case L_flag
|
atf_add_test_case L_flag
|
||||||
@ -229,4 +284,8 @@ atf_init_test_cases()
|
|||||||
atf_add_test_case s_flag
|
atf_add_test_case s_flag
|
||||||
atf_add_test_case s_flag_broken
|
atf_add_test_case s_flag_broken
|
||||||
atf_add_test_case sw_flag
|
atf_add_test_case sw_flag
|
||||||
|
atf_add_test_case link_argc
|
||||||
|
atf_add_test_case link_basic
|
||||||
|
atf_add_test_case link_eexist
|
||||||
|
atf_add_test_case link_eisdir
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user