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 <libgen.h> /* dirname */ 20 #include <unistd.h> 21 22 #include "file_util.h" 23 #include "libbb/libbb.h" 24 #include "opkg_message.h" 25 #include "pkg.h" 26 #include "pkg_hash.h" 27 #include "pkg_alternatives.h" 28 #include "sprintf_alloc.h" 29 30 struct alternative_provider { 31 char *name; 32 char *altpath; 33 }; 34 35 static const struct alternative_provider providers[] = { 36 { 37 .name = "busybox", 38 .altpath = "/bin/busybox", 39 }, 40 }; 41 42 static const char *pkg_alternatives_check_providers(const char *path) 43 { 44 pkg_t *pkg; 45 str_list_t *files; 46 str_list_elt_t *iter; 47 int i; 48 49 for (i = 0; i < ARRAY_SIZE(providers); i++) { 50 pkg = pkg_hash_fetch_installed_by_name(providers[i].name); 51 if (!pkg) { 52 continue; 53 } 54 files = pkg_get_installed_files(pkg); 55 for (iter = str_list_first(files); iter; iter = str_list_next(files, iter)) { 56 if (!strcmp(path, (char *)(iter->data))) { 57 pkg_free_installed_files(pkg); 58 return providers[i].altpath; 59 } 60 } 61 pkg_free_installed_files(pkg); 62 } 63 return NULL; 64 } 65 66 static int pkg_alternatives_update_path(pkg_t *pkg, const pkg_vec_t *installed, const char *path) 67 { 68 struct pkg_alternatives *pkg_alts; 69 struct pkg_alternative *the_alt = NULL; 70 pkg_t *the_pkg = pkg; 71 int i, j; 72 int r; 73 char *path_in_dest; 74 const char *target_path = NULL; 75 76 for (i = 0; i < installed->len; i++) { 77 pkg_t *pkg = installed->pkgs[i]; 78 pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES); 79 if (!pkg_alts) 80 continue; 81 82 for (j = 0; j < pkg_alts->nalts; j++) { 83 struct pkg_alternative *alt = pkg_alts->alts[j]; 84 85 if (strcmp(path, alt->path)) 86 continue; 87 if (!the_alt || the_alt->prio < alt->prio) { 88 the_pkg = pkg; 89 the_alt = alt; 90 } 91 } 92 } 93 94 /* path is assumed to be an absolute one */ 95 sprintf_alloc(&path_in_dest, "%s%s", the_pkg->dest->root_dir, &path[1]); 96 if (!path_in_dest) 97 return -1; 98 99 if (the_alt) { 100 target_path = the_alt->altpath; 101 } else { 102 target_path = pkg_alternatives_check_providers(path); 103 } 104 105 if (target_path) { 106 struct stat sb; 107 108 r = lstat(path_in_dest, &sb); 109 if (!r) { 110 char *realpath; 111 112 if (!S_ISLNK(sb.st_mode)) { 113 opkg_msg(ERROR, "%s exists but is not a symlink\n", path_in_dest); 114 r = -1; 115 goto out; 116 } 117 realpath = xreadlink(path_in_dest); 118 if (realpath && strcmp(realpath, target_path)) 119 unlink(path_in_dest); 120 free(realpath); 121 } else if (errno != ENOENT) { 122 goto out; 123 } 124 { 125 char *path_copy = xstrdup(path_in_dest); 126 char *path_parent = dirname(path_copy); 127 128 r = file_mkdir_hier(path_parent, 0755); 129 free(path_copy); 130 if (r) { 131 goto out; 132 } 133 r = symlink(target_path, path_in_dest); 134 if (r && errno == EEXIST) { 135 /* 136 * the strcmp & unlink check above will make sure that if EEXIST 137 * happens, the symlink target also matches 138 */ 139 r = 0; 140 } 141 if (r) { 142 opkg_perror(ERROR, "failed symlinking %s -> %s", path_in_dest, target_path); 143 } 144 } 145 } else { 146 unlink(path_in_dest); 147 r = 0; 148 } 149 150 out: 151 free(path_in_dest); 152 return r; 153 } 154 155 int pkg_alternatives_update(pkg_t * pkg) 156 { 157 int r = 0; 158 int i; 159 struct pkg_alternatives *pkg_alts; 160 struct pkg_alternative *alt = NULL; 161 pkg_vec_t *installed; 162 163 pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES); 164 if (!pkg_alts) 165 return 0; 166 167 installed = pkg_vec_alloc(); 168 pkg_hash_fetch_all_installed(installed); 169 for (i = 0; i < pkg_alts->nalts; i++) { 170 alt = pkg_alts->alts[i]; 171 r |= pkg_alternatives_update_path(pkg, installed, alt->path); 172 } 173 pkg_vec_free(installed); 174 175 return r; 176 } 177
This page was automatically generated by LXR 0.3.1. • OpenWrt