Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/LexicalPath.h>
8#include <LibCore/ArgsParser.h>
9#include <LibCore/System.h>
10
11ErrorOr<int> serenity_main(Main::Arguments arguments)
12{
13 TRY(Core::System::pledge("stdio cpath rpath"));
14
15 bool force = false;
16 bool symbolic = false;
17 StringView target;
18 StringView path;
19
20 Core::ArgsParser args_parser;
21 args_parser.add_option(force, "Force the creation", "force", 'f');
22 args_parser.add_option(symbolic, "Create a symlink", "symbolic", 's');
23 args_parser.add_positional_argument(target, "Link target", "target");
24 args_parser.add_positional_argument(path, "Link path", "path", Core::ArgsParser::Required::No);
25 args_parser.parse(arguments);
26
27 DeprecatedString path_buffer;
28 if (path.is_empty()) {
29 path_buffer = LexicalPath::basename(target);
30 path = path_buffer.view();
31 }
32
33 auto stat = Core::System::lstat(path);
34
35 if (stat.is_error() && stat.error().code() != ENOENT)
36 return stat.release_error();
37
38 if (!stat.is_error() && S_ISDIR(stat.value().st_mode)) {
39 // The target path is a directory, so we presumably want <path>/<filename> as the effective path.
40 path_buffer = LexicalPath::join(path, LexicalPath::basename(target)).string();
41 path = path_buffer.view();
42 stat = Core::System::lstat(path);
43 }
44
45 if (force && !stat.is_error()) {
46 TRY(Core::System::unlink(path));
47 }
48
49 if (symbolic) {
50 TRY(Core::System::symlink(target, path));
51 } else {
52 TRY(Core::System::link(target, path));
53 }
54
55 return 0;
56}