• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/opkg-lede/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 <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