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 int linkit(const char *, const char *, bool);
|
||||
static void link_usage(void) __dead2;
|
||||
static void usage(void) __dead2;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct stat sb;
|
||||
char *p, *targetdir;
|
||||
char *targetdir;
|
||||
int ch, exitval;
|
||||
|
||||
/*
|
||||
@ -69,17 +70,20 @@ main(int argc, char *argv[])
|
||||
* "link", for which the functionality provided is greatly
|
||||
* simplified.
|
||||
*/
|
||||
if ((p = strrchr(argv[0], '/')) == NULL)
|
||||
p = argv[0];
|
||||
else
|
||||
++p;
|
||||
if (strcmp(p, "link") == 0) {
|
||||
if (strcmp(getprogname(), "link") == 0) {
|
||||
while (getopt(argc, argv, "") != -1)
|
||||
usage();
|
||||
link_usage();
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
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));
|
||||
}
|
||||
|
||||
@ -338,11 +342,17 @@ linkit(const char *source, const char *target, bool isdir)
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
link_usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "%s\n%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",
|
||||
" link source_file target_file");
|
||||
(void)fprintf(stderr, "usage: link source_file target_file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ target_exists_hard_body()
|
||||
{
|
||||
atf_check touch A B
|
||||
atf_check -s exit:1 -e inline:'ln: B: File exists\n' \
|
||||
ln A B
|
||||
ln A B
|
||||
}
|
||||
|
||||
atf_test_case target_exists_symbolic
|
||||
@ -103,7 +103,7 @@ target_exists_symbolic_body()
|
||||
{
|
||||
atf_check touch A B
|
||||
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
|
||||
@ -210,10 +210,65 @@ sw_flag_head()
|
||||
sw_flag_body()
|
||||
{
|
||||
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_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_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_broken
|
||||
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