f4560a9527
This removes the ability to override standard shell utilities using environment variables. The standard names are invoked unconditionally and can be overridden using the standard approach of adding replacements to the PATH. Additionally environment variables like PREFIX and HOST are no longer honored as defaults for the --prefix and --host options. These features are removed because they've never been used and cause more trouble than they are worth. The tix collection option now defaults to the root directory to simplify common invocations. The tix-build prefix also now defaults to the empty prefix. Support installing multiple packages at once with tix-install. Tighten file and directory creation modes while here. Add --generation for forward compatibility. Silence tix-collection creation. Fix uninitialized getline invocations. Fix porttix-create buffer overflow.
433 lines
11 KiB
C++
433 lines
11 KiB
C++
/*******************************************************************************
|
|
|
|
Copyright(C) Jonas 'Sortie' Termansen 2013, 2015.
|
|
|
|
This file is part of Tix.
|
|
|
|
Tix 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.
|
|
|
|
Tix 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
|
|
Tix. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
porttix-create.cpp
|
|
Creates a port tix by generating patches using source code and tarballs.
|
|
|
|
*******************************************************************************/
|
|
|
|
#define __STDC_CONSTANT_MACROS
|
|
#define __STDC_LIMIT_MACROS
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <error.h>
|
|
#include <fcntl.h>
|
|
#include <libgen.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "util.h"
|
|
|
|
int redirect(const char* path, int flags, mode_t mode = 0)
|
|
{
|
|
int fd = open(path, flags, mode);
|
|
if ( fd < 0 )
|
|
return -1;
|
|
dup2(fd, 1);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
static void help(FILE* fp, const char* argv0)
|
|
{
|
|
fprintf(fp, "Usage: %s [OPTION]... --tarball=TARBALL --normalized=NORMALIZED SOURCE-TIX\n", argv0);
|
|
fprintf(fp, "Creates a port tix by generating patches using source code and tarballs.\n");
|
|
}
|
|
|
|
static void version(FILE* fp, const char* argv0)
|
|
{
|
|
fprintf(fp, "%s (Sortix) %s\n", argv0, VERSIONSTR);
|
|
fprintf(fp, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n");
|
|
fprintf(fp, "This is free software: you are free to change and redistribute it.\n");
|
|
fprintf(fp, "There is NO WARRANTY, to the extent permitted by law.\n");
|
|
}
|
|
int main(int argc, char* argv[])
|
|
{
|
|
char* input_normalized_path = NULL;
|
|
char* input_tarball_path = NULL;
|
|
char* output_directory = strdup(".");
|
|
char* output = NULL;
|
|
char* tmp = strdup(getenv_def("TMP", "/tmp"));
|
|
|
|
const char* argv0 = argv[0];
|
|
for ( int i = 0; i < argc; i++ )
|
|
{
|
|
const char* arg = argv[i];
|
|
if ( arg[0] != '-' || !arg[1] )
|
|
continue;
|
|
argv[i] = NULL;
|
|
if ( !strcmp(arg, "--") )
|
|
break;
|
|
if ( arg[1] != '-' )
|
|
{
|
|
while ( char c = *++arg ) switch ( c )
|
|
{
|
|
default:
|
|
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
|
help(stderr, argv0);
|
|
exit(1);
|
|
}
|
|
}
|
|
else if ( !strcmp(arg, "--help") )
|
|
help(stdout, argv0), exit(0);
|
|
else if ( !strcmp(arg, "--version") )
|
|
version(stdout, argv0), exit(0);
|
|
else if ( GET_OPTION_VARIABLE("--normalized", &input_normalized_path) ) { }
|
|
else if ( GET_OPTION_VARIABLE("--output-directory", &output_directory) ) { }
|
|
else if ( GET_OPTION_VARIABLE("--output", &output) ) { }
|
|
else if ( GET_OPTION_VARIABLE("--tarball", &input_tarball_path) ) { }
|
|
else if ( GET_OPTION_VARIABLE("--tmp", &tmp) ) { }
|
|
else
|
|
{
|
|
fprintf(stderr, "%s: unknown option: %s\n", argv0, arg);
|
|
help(stderr, argv0);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if ( argc == 1 )
|
|
{
|
|
help(stdout, argv0);
|
|
exit(0);
|
|
}
|
|
|
|
compact_arguments(&argc, &argv);
|
|
|
|
if ( argc <= 1 )
|
|
{
|
|
fprintf(stderr, "%s: no source tix specified\n", argv0);
|
|
help(stderr, argv0);
|
|
exit(1);
|
|
}
|
|
|
|
if ( 3 <= argc )
|
|
{
|
|
fprintf(stderr, "%s: unexpected extra operand `%s'\n", argv0, argv[2]);
|
|
help(stderr, argv0);
|
|
exit(1);
|
|
}
|
|
|
|
const char* input_srctix_path = argv[1];
|
|
|
|
if ( !IsDirectory(input_srctix_path) )
|
|
error(1, errno, "`%s'", input_srctix_path);
|
|
|
|
char* tixbuildinfo_path = print_string("%s/tixbuildinfo", input_srctix_path);
|
|
|
|
string_array_t package_info = string_array_make();
|
|
if ( !dictionary_append_file_path(&package_info, tixbuildinfo_path) )
|
|
{
|
|
if ( errno == ENOENT )
|
|
fprintf(stderr, "%s: `%s' doesn't appear to be a source tix:\n",
|
|
argv0, input_srctix_path);
|
|
error(1, errno, "`%s'", tixbuildinfo_path);
|
|
}
|
|
|
|
const char* package_name = strdup(dictionary_get(&package_info, "pkg.name"));
|
|
|
|
if ( !output )
|
|
output = print_string("%s/%s.porttix.tar.xz", output_directory, package_name);
|
|
|
|
char* tmp_root = print_string("%s/tmppid.%ju", tmp, (uintmax_t) getpid());
|
|
if ( mkdir_p(tmp_root, 0755) != 0 )
|
|
error(1, errno, "mkdir: `%s'", tmp_root);
|
|
|
|
on_exit(cleanup_file_or_directory, tmp_root);
|
|
|
|
const char* tarball_basename = non_modify_basename(input_tarball_path);
|
|
|
|
char* rel_srctix_path = print_string("%s.srctix", package_name);
|
|
char* rel_normalized_path = print_string("%s.normalized", package_name);
|
|
|
|
char* porttix_path = print_string("%s/%s", tmp_root, package_name);
|
|
if ( mkdir_p(porttix_path, 0755) != 0 )
|
|
error(1, errno, "mkdir: `%s'", porttix_path);
|
|
|
|
char* srctix_path = print_string("%s/%s", tmp_root, rel_srctix_path);
|
|
if ( mkdir_p(srctix_path, 0755) != 0 )
|
|
error(1, errno, "mkdir: `%s'", srctix_path);
|
|
|
|
char* normalized_path = print_string("%s/%s", tmp_root, rel_normalized_path);
|
|
if ( mkdir_p(normalized_path, 0755) != 0 )
|
|
error(1, errno, "mkdir: `%s'", normalized_path);
|
|
|
|
// Create the porttixinfo file.
|
|
char* porttixinfo_path = join_paths(porttix_path, "porttixinfo");
|
|
FILE* porttixinfo_fp = fopen(porttixinfo_path, "w");
|
|
if ( !porttixinfo_fp )
|
|
error(1, errno, "`%s'", porttixinfo_path);
|
|
fprintf(porttixinfo_fp, "package_name %s\n", package_name);
|
|
|
|
// Copy the input source tix to the temporary root.
|
|
if ( fork_and_wait_or_death() )
|
|
{
|
|
const char* cmd_argv[] =
|
|
{
|
|
"cp",
|
|
"-HRT",
|
|
"--preserve=timestamps,links",
|
|
"--",
|
|
input_srctix_path,
|
|
srctix_path,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
|
|
// If no tarball exists, then package up the source directory!
|
|
if ( !input_tarball_path )
|
|
{
|
|
input_tarball_path = print_string("%s/%s.tar.xz", tmp_root, package_name);
|
|
if ( fork_and_wait_or_death() )
|
|
{
|
|
char* work_dir = dirname(strdup(srctix_path));
|
|
char* subdir_name = dirname(strdup(srctix_path));
|
|
if ( chdir(work_dir) != 0 )
|
|
error(1, errno, "chdir: `%s'", work_dir);
|
|
const char* cmd_argv[] =
|
|
{
|
|
"tar",
|
|
"--create",
|
|
"--xz",
|
|
"--directory", input_normalized_path,
|
|
"--file", input_tarball_path,
|
|
"--",
|
|
subdir_name,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
}
|
|
|
|
// Copy the normalized directory (if one exists) to the temporary root.
|
|
if ( input_normalized_path )
|
|
{
|
|
if ( fork_and_wait_or_death() )
|
|
{
|
|
const char* cmd_argv[] =
|
|
{
|
|
"cp",
|
|
"-HRT",
|
|
"--preserve=timestamps,links",
|
|
"--",
|
|
input_normalized_path,
|
|
normalized_path,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
}
|
|
|
|
// There is no input normalized directory, so just extract the tarball here.
|
|
else
|
|
{
|
|
if ( fork_and_wait_or_death() )
|
|
{
|
|
const char* cmd_argv[] =
|
|
{
|
|
"tar",
|
|
"--extract",
|
|
"--directory", normalized_path,
|
|
"--file", input_tarball_path,
|
|
"--strip-components=1",
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
}
|
|
|
|
// Copy the tarball into the port tix.
|
|
char* porttix_tarball_path = print_string("%s/%s", porttix_path, tarball_basename);
|
|
if ( fork_and_wait_or_death() )
|
|
{
|
|
const char* cmd_argv[] =
|
|
{
|
|
"cp",
|
|
"--",
|
|
input_tarball_path,
|
|
porttix_tarball_path,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
fprintf(porttixinfo_fp, "tar_extract %s\n", tarball_basename);
|
|
|
|
// Create the normalization patch.
|
|
int normalized_fd = open(normalized_path, O_RDONLY | O_DIRECTORY);
|
|
if ( normalized_fd < 0 )
|
|
error(1, errno, "`%s'", normalized_path);
|
|
|
|
char* patch_normalize_path = join_paths(porttix_path, "patch.normalize");
|
|
FILE* patch_normalize_fp = fopen(patch_normalize_path, "w");
|
|
if ( !patch_normalize_fp )
|
|
error(1, errno, "`%s'", patch_normalize_path);
|
|
|
|
int pipes[2];
|
|
if ( pipe(pipes) )
|
|
error(1, errno, "pipe");
|
|
pid_t tar_pid = fork_or_death();
|
|
if ( !tar_pid )
|
|
{
|
|
dup2(pipes[1], 1);
|
|
close(pipes[1]);
|
|
close(pipes[0]);
|
|
const char* cmd_argv[] =
|
|
{
|
|
"tar",
|
|
"--list",
|
|
"--file", porttix_tarball_path,
|
|
"--strip-components=1",
|
|
NULL
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
close(pipes[1]);
|
|
FILE* tar_fp = fdopen(pipes[0], "r");
|
|
|
|
char* line = NULL;
|
|
size_t line_size = 0;
|
|
ssize_t line_len;
|
|
while ( 0 < (line_len = getline(&line, &line_size, tar_fp)) )
|
|
{
|
|
if ( line_len && line[line_len-1] == '\n' )
|
|
line[--line_len] = '\0';
|
|
const char* path = line;
|
|
while ( *path && *path != '/' )
|
|
path++;
|
|
if ( *path == '/' )
|
|
path++;
|
|
if ( !*path )
|
|
continue;
|
|
struct stat st;
|
|
if ( fstatat(normalized_fd, path, &st, 0) != 0 && errno == ENOENT )
|
|
{
|
|
fprintf(patch_normalize_fp, "rm -rf -- '");
|
|
for ( size_t i = 0; path[i]; i++ )
|
|
if ( path[i] == '\'' )
|
|
fprintf(patch_normalize_fp, "'\\''");
|
|
else
|
|
fputc(path[i], patch_normalize_fp);
|
|
fprintf(patch_normalize_fp, "'\n");
|
|
}
|
|
}
|
|
free(line);
|
|
|
|
fclose(tar_fp);
|
|
int tar_exit_status;
|
|
waitpid(tar_pid, &tar_exit_status, 0);
|
|
if ( !WIFEXITED(tar_exit_status) || WEXITSTATUS(tar_exit_status) != 0 )
|
|
{
|
|
error(1, 0, "Unable to list contents of `%s'.", porttix_tarball_path);
|
|
exit(WEXITSTATUS(tar_exit_status));
|
|
}
|
|
|
|
fclose(patch_normalize_fp);
|
|
free(patch_normalize_path);
|
|
fprintf(porttixinfo_fp, "apply_normalize patch.normalize\n");
|
|
|
|
close(normalized_fd);
|
|
|
|
// Create the patch between the source tix and the normalized tree.
|
|
char* patch_path = join_paths(porttix_path, "patch.patch");
|
|
if ( fork_and_wait_or_death(false) )
|
|
{
|
|
close(1);
|
|
if ( open(patch_path, O_WRONLY | O_CREAT | O_TRUNC, 0644) != 1 )
|
|
error(1, errno, "`%s'", patch_path);
|
|
if ( chdir(tmp_root) != 0 )
|
|
error(1, errno, "chdir(`%s')", tmp_root);
|
|
const char* cmd_argv[] =
|
|
{
|
|
"diff",
|
|
"--no-dereference",
|
|
"-Naur",
|
|
"--",
|
|
rel_normalized_path,
|
|
rel_srctix_path,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
free(patch_path);
|
|
fprintf(porttixinfo_fp, "apply_patch patch.patch\n");
|
|
|
|
// Created the execpatch between the source tix and the normalized tree.
|
|
char* patch_exec_path = join_paths(porttix_path, "patch.execpatch");
|
|
if ( fork_and_wait_or_death(false) )
|
|
{
|
|
if ( redirect(patch_exec_path, O_WRONLY | O_CREAT | O_TRUNC, 0644) != 0 )
|
|
error(1, errno, "`%s'", patch_exec_path);
|
|
if ( chdir(tmp_root) != 0 )
|
|
error(1, errno, "chdir(`%s')", tmp_root);
|
|
const char* cmd_argv[] =
|
|
{
|
|
"tix-execdiff",
|
|
"--",
|
|
rel_normalized_path,
|
|
rel_srctix_path,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
free(patch_exec_path);
|
|
fprintf(porttixinfo_fp, "apply_execpatch patch.execpatch\n");
|
|
|
|
// Close the porttixinfo file.
|
|
fclose(porttixinfo_fp);
|
|
free(porttixinfo_path);
|
|
|
|
// Package up the output archived port tix.
|
|
if ( fork_and_wait_or_death() )
|
|
{
|
|
const char* cmd_argv[] =
|
|
{
|
|
"tar",
|
|
"--create",
|
|
"--xz",
|
|
"--directory", tmp_root,
|
|
"--file", output,
|
|
"--",
|
|
package_name,
|
|
NULL,
|
|
};
|
|
execvp(cmd_argv[0], (char* const*) cmd_argv);
|
|
error(127, errno, "%s", cmd_argv[0]);
|
|
}
|
|
|
|
return 0;
|
|
}
|