/*
This file is part of Darling.
Copyright (C) 2017-2020 Lubos Dolezel
Darling is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Darling is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Darling. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include "xcselect.h"
void printUsage(void);
void doReset(void);
void doSwitch(const char* path);
void doPrintManPaths(void);
int main(int argc, const char** argv)
{
if (argc == 1)
{
fprintf(stderr, "xcode-select: error: no command option given\n");
printUsage();
}
else if (argc == 2 || argc == 3)
{
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)
{
printUsage();
}
else if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-version") == 0)
{
printf("xcode-select for Darling, version 1.0\n");
}
else if (strcmp(argv[1], "-p") == 0 || strcmp(argv[1], "--print-path") == 0 || strcmp(argv[1], "-print-path") == 0)
{
char path[1024];
bool is_cmd_line;
if (xcselect_get_developer_dir_path(path, sizeof(path), &is_cmd_line))
{
printf("%s\n", path);
}
else
{
fprintf(stderr, "xcode-select: error: unable to get active developer directory\n");
return 1;
}
}
else if (strcmp(argv[1], "--show-manpaths") == 0)
{
doPrintManPaths();
}
else if (strcmp(argv[1], "--install") == 0)
{
if (access("/Library/Developer/CommandLineTools/usr/lib/libxcrun.dylib", F_OK) == 0)
{
fprintf(stderr, "xcode-select: error: command line tools are already installed\n");
return 1;
}
else
{
int status = system("/usr/libexec/darling/clt_install.py");
return WEXITSTATUS(status);
}
}
else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--reset") == 0)
{
doReset();
}
else if (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--switch") == 0 || strcmp(argv[1], "-switch") == 0)
{
if (argc != 3)
{
fprintf(stderr, "xcode-select: error: missing argument to '%s'\n", argv[1]);
return 1;
}
doSwitch(argv[2]);
}
else
{
fprintf(stderr, "xcode-select: error: unknown option: %s\n", argv[1]);
printUsage();
return 1;
}
return 0;
}
else
{
fprintf(stderr, "xcode-select: error: bad argument count\n");
printUsage();
}
return 1;
}
void printUsage(void)
{
fprintf(stderr, "Usage: xcode-select [options]\n\n");
fprintf(stderr, "xcode-select is used to set up path to the active developer directory.\n"
"This affects both toolchain commands (such as clang or make) and Xcode-specific\n"
"tools (such as xcodebuild).\n\n");
fprintf(stderr, "Options:\n"
" -h, --help print this help message\n"
" -p, --print-path print the path of the active developer directory\n"
" -s , --switch change the path of the active developer directory\n"
" --install trigger the installation of command line developer tools\n"
" -v, --version print the version of this tool\n"
" -r, --reset reset to the default developer directory\n");
}
static void killLink(const char* path)
{
if (unlink(path) != 0)
{
if (errno != ENOENT)
{
fprintf(stderr, "xcode-select: error: cannot remove existing link at '%s': %s\n",
path, strerror(errno));
exit(1);
}
}
}
void doReset(void)
{
killLink("/var/db/xcode_select_link");
killLink("/usr/share/xcode-select/xcode_dir_link");
killLink("/usr/share/xcode-select/xcode_dir_path");
}
void doSwitch(const char* path)
{
char buffer[1024];
bool unused;
if (!xcselect_find_developer_contents_from_path(path, buffer, &unused, sizeof(buffer)))
{
fprintf(stderr, "xcode-select: error: invalid developer directory '%s'\n", path);
exit(1);
}
doReset();
umask(022);
mkdir("/var/db", 0755);
if (symlink(buffer, "/var/db/xcode_select_link") != 0)
{
fprintf(stderr, "xcode-select: error: unable to create symlink: %s\n",
strerror(errno));
exit(1);
}
}
void doPrintManPaths(void)
{
xcselect_manpaths *xcp;
const char *path;
unsigned i, count;
xcp = xcselect_get_manpaths(NULL);
if (xcp != NULL) {
count = xcselect_manpaths_get_num_paths(xcp);
for (i = 0; i < count; i++) {
path = xcselect_manpaths_get_path(xcp, i);
if (path != NULL) {
puts(path);
}
}
xcselect_manpaths_free(xcp);
}
}