66b64de453c15d5d522619bb6974522ecae064d8
[project/opkg-lede.git] / libopkg / pkg_alternatives.c
1 /* pkg_alternatives.c - the opkg package management system
2
3 Copyright (C) 2017 Yousong Zhou
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2, or (at
8 your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14 */
15
16 #include <stdio.h>
17 #include <sys/types.h> /* stat */
18 #include <sys/stat.h>
19 #include <unistd.h>
20
21 #include "libbb/libbb.h"
22 #include "opkg_message.h"
23 #include "pkg.h"
24 #include "pkg_hash.h"
25 #include "pkg_alternatives.h"
26 #include "sprintf_alloc.h"
27
28 static int pkg_alternatives_update_path(pkg_t *pkg, const pkg_vec_t *installed, const char *path)
29 {
30 struct pkg_alternatives *pkg_alts;
31 struct pkg_alternative *the_alt = NULL;
32 pkg_t *the_pkg = pkg;
33 int i, j;
34 int r;
35 char *path_in_dest;
36
37 for (i = 0; i < installed->len; i++) {
38 pkg_t *pkg = installed->pkgs[i];
39 pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
40 if (!pkg_alts)
41 continue;
42
43 for (j = 0; j < pkg_alts->nalts; j++) {
44 struct pkg_alternative *alt = pkg_alts->alts[j];
45
46 if (strcmp(path, alt->path))
47 continue;
48 if (!the_alt || the_alt->prio < alt->prio) {
49 the_pkg = pkg;
50 the_alt = alt;
51 }
52 }
53 }
54
55 /* path is assumed to be an absolute one */
56 sprintf_alloc(&path_in_dest, "%s%s", the_pkg->dest->root_dir, &path[1]);
57 if (!path_in_dest)
58 return -1;
59
60 if (the_alt) {
61 struct stat sb;
62
63 r = lstat(path_in_dest, &sb);
64 if (!r) {
65 char *realpath;
66
67 if (!S_ISLNK(sb.st_mode)) {
68 opkg_msg(ERROR, "%s exists but is not a symlink\n", path_in_dest);
69 r = -1;
70 goto out;
71 }
72 realpath = xreadlink(path_in_dest);
73 if (realpath && strcmp(realpath, the_alt->altpath))
74 unlink(path_in_dest);
75 free(realpath);
76 } else if (errno != ENOENT) {
77 goto out;
78 }
79 r = symlink(the_alt->altpath, path_in_dest);
80 if (r)
81 opkg_msg(INFO, "failed symlinking %s -> %s\n", path_in_dest, the_alt->altpath);
82 } else {
83 unlink(path_in_dest);
84 r = 0;
85 }
86
87 out:
88 free(path_in_dest);
89 return r;
90 }
91
92 int pkg_alternatives_update(pkg_t * pkg)
93 {
94 int r = 0;
95 int i;
96 struct pkg_alternatives *pkg_alts;
97 struct pkg_alternative *alt = NULL;
98 pkg_vec_t *installed;
99
100 pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
101 if (!pkg_alts)
102 return 0;
103
104 installed = pkg_vec_alloc();
105 pkg_hash_fetch_all_installed(installed);
106 for (i = 0; i < pkg_alts->nalts; i++) {
107 alt = pkg_alts->alts[i];
108 r |= pkg_alternatives_update_path(pkg, installed, alt->path);
109 }
110 pkg_vec_free(installed);
111
112 return r;
113 }