aboutsummaryrefslogtreecommitdiff
path: root/src/install.c
blob: cf22d23da983574cddcd9e6ffd58f5103ce83065 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/**
 * @file install.c
 */
#include "spm.h"

extern const char *METADATA_FILES[];

/**
 * SPM packages contain metadata files that are not useful post-install and would amount to a lot of clutter.
 * This function removes these data files from a directory tree
 * @param _path
 * @return success=0, error=-1
 */
int metadata_remove(const char *_path) {
    if (exists(_path) != 0) {
        perror(_path);
        fprintf(SYSERROR);
        return -1;
    }

    for (int i = 0; METADATA_FILES[i] != NULL; i++) {
        char path[PATH_MAX];
        sprintf(path, "%s%c%s", _path, DIRSEP, METADATA_FILES[i]);
        if (exists(path) != 0) {
            continue;
        }
        if (unlink(path) < 0) {
            perror(path);
            fprintf(SYSERROR);
            return -1;
        }
    }
    return 0;
}

void install_show_package(ManifestPackage *package) {
    if (package == NULL) {
        fprintf(stderr, "ERROR: package was NULL\n");
        return;
    }
    printf("  -> %-10s %-10s (origin: %s)\n", package->name, package->version, package->origin);
}

/**
 * Install a package and its dependencies into a destination root.
 * The destination is created if it does not exist.
 * @param _destroot directory to install package
 * @param _package name of archive to install (not a path)
 * @return success=0, error=-1 (general), -2 (unable to create `destroot`)
 */
int install(const char *destroot, const char *_package) {
    char *package = strdup(_package);
    if (!package) {
        fprintf(SYSERROR);
        return -1;
    }

    if (exists(destroot) != 0) {
        if (SPM_GLOBAL.verbose) {
            printf("Creating destination root: %s\n", destroot);
        }
        if (mkdirs(destroot, 0755) != 0) {
            fprintf(SYSERROR);
            return -2;
        }
    }

    char source[PATH_MAX];
    char template[PATH_MAX];

    // circumvent -Wformat-truncation
    char *suffix = (char *) calloc(PATH_MAX, sizeof(char));
    if (!suffix) {
        perror("suffix");
        fprintf(SYSERROR);
        return -1;
    }
    strcpy(suffix, "spm_destroot_XXXXXX");
    snprintf(template, PATH_MAX, "%s%c%s", TMP_DIR, DIRSEP, suffix);
    free(suffix);

    // Create a new temporary directory and extract the requested package into it
    char *tmpdir = mkdtemp(template);
    if (exists(tmpdir) != 0) {
        fprintf(stderr, "Failed to create temporary storage directory\n");
        fprintf(SYSERROR);
        exit(errno);
    }

    if (SPM_GLOBAL.verbose) {
        printf("Extracting archive: %s\n", package);
    }
    if (tar_extract_archive(package, tmpdir) != 0) {
        fprintf(stderr, "%s: %s\n", package, strerror(errno));
        return -1;
    }

    // Relocate temporary directory
    relocate_root(destroot, tmpdir);

    // Append a trailing slash to tmpdir to direct rsync to copy files, not the directory, into destroot
    sprintf(source, "%s%c", tmpdir, DIRSEP);

    // Remove metadata files before copying
    if (SPM_GLOBAL.verbose) {
        printf("Removing metadata\n");
    }
    metadata_remove(source);

    // Copy temporary directory to destination
    if (SPM_GLOBAL.verbose) {
        printf("Installing tree: '%s' => '%s'\n", source, destroot);
    }

    if (rsync(NULL, source, destroot) != 0) {
        exit(1);
    }

    if (SPM_GLOBAL.verbose) {
        printf("Removing temporary storage: '%s'\n", tmpdir);
    }
    rmdirs(tmpdir);

    free(package);
    return 0;
}