aurblup: Do not blacklist provides
[aur.git] / scripts / aurblup / aurblup.c
blob971dc0617905e957d240246cfd068e0e597a42d5
1 /* aurblup - AUR blacklist updater
3 * Small utility to update the AUR package blacklist. Can be used in a cronjob.
4 * Check the "README" file for details.
5 */
7 #include <alpm.h>
8 #include <getopt.h>
9 #include <mysql.h>
10 #include <stdio.h>
11 #include <string.h>
13 #include "config.h"
15 #define alpm_die(...) die(__VA_ARGS__, alpm_strerror(alpm_errno(handle)));
16 #define mysql_die(...) die(__VA_ARGS__, mysql_error(c));
18 static void die(const char *, ...);
19 static alpm_list_t *pkglist_append(alpm_list_t *, const char *);
20 static alpm_list_t *blacklist_get_pkglist();
21 static void blacklist_add(const char *);
22 static void blacklist_remove(const char *);
23 static void blacklist_sync(alpm_list_t *, alpm_list_t *);
24 static alpm_list_t *dblist_get_pkglist(alpm_list_t *);
25 static alpm_list_t *dblist_create(void);
26 static int parse_options(int, char **);
27 static void init(void);
28 static void cleanup(void);
30 static char *mysql_host = "localhost";
31 static char *mysql_socket = NULL;
32 static char *mysql_user = "aur";
33 static char *mysql_passwd = "aur";
34 static char *mysql_db = "AUR";
36 static MYSQL *c;
38 static alpm_handle_t *handle;
40 static void
41 die(const char *format, ...)
43 va_list arg;
45 va_start(arg, format);
46 fprintf(stderr, "aurblup: ");
47 vfprintf(stderr, format, arg);
48 va_end(arg);
50 cleanup();
51 exit(1);
54 static alpm_list_t *
55 pkglist_append(alpm_list_t *pkglist, const char *pkgname)
57 int len = strcspn(pkgname, "<=>");
58 if (!len)
59 len = strlen(pkgname);
61 char *s = malloc(len + 1);
63 strncpy(s, pkgname, len);
64 s[len] = '\0';
66 if (alpm_list_find_str(pkglist, s))
67 free(s);
68 else
69 pkglist = alpm_list_add(pkglist, s);
71 return pkglist;
74 static alpm_list_t *
75 blacklist_get_pkglist()
77 MYSQL_RES *res;
78 MYSQL_ROW row;
79 alpm_list_t *pkglist = NULL;
81 if (mysql_query(c, "SELECT Name FROM PackageBlacklist"))
82 mysql_die("failed to read blacklist from MySQL database: %s\n");
84 if (!(res = mysql_store_result(c)))
85 mysql_die("failed to store MySQL result: %s\n");
87 while ((row = mysql_fetch_row(res)))
88 pkglist = pkglist_append(pkglist, row[0]);
90 mysql_free_result(res);
92 return pkglist;
95 static void
96 blacklist_add(const char *name)
98 char *esc = malloc(strlen(name) * 2 + 1);
99 char query[1024];
101 mysql_real_escape_string(c, esc, name, strlen(name));
102 snprintf(query, 1024, "INSERT INTO PackageBlacklist (Name) "
103 "VALUES ('%s')", esc);
104 free(esc);
106 if (mysql_query(c, query))
107 mysql_die("failed to query MySQL database (\"%s\"): %s\n", query);
110 static void
111 blacklist_remove(const char *name)
113 char *esc = malloc(strlen(name) * 2 + 1);
114 char query[1024];
116 mysql_real_escape_string(c, esc, name, strlen(name));
117 snprintf(query, 1024, "DELETE FROM PackageBlacklist WHERE Name = '%s'", esc);
118 free(esc);
120 if (mysql_query(c, query))
121 mysql_die("failed to query MySQL database (\"%s\"): %s\n", query);
124 static void
125 blacklist_sync(alpm_list_t *pkgs_cur, alpm_list_t *pkgs_new)
127 alpm_list_t *pkgs_add, *pkgs_rem, *p;
129 pkgs_add = alpm_list_diff(pkgs_new, pkgs_cur, (alpm_list_fn_cmp)strcmp);
130 pkgs_rem = alpm_list_diff(pkgs_cur, pkgs_new, (alpm_list_fn_cmp)strcmp);
132 if (mysql_query(c, "START TRANSACTION"))
133 mysql_die("failed to start MySQL transaction: %s\n");
135 for (p = pkgs_add; p; p = alpm_list_next(p))
136 blacklist_add(p->data);
138 for (p = pkgs_rem; p; p = alpm_list_next(p))
139 blacklist_remove(p->data);
141 if (mysql_query(c, "COMMIT"))
142 mysql_die("failed to commit MySQL transaction: %s\n");
144 alpm_list_free(pkgs_add);
145 alpm_list_free(pkgs_rem);
148 static alpm_list_t *
149 dblist_get_pkglist(alpm_list_t *dblist)
151 alpm_list_t *d, *p, *q;
152 alpm_list_t *pkglist = NULL;
154 for (d = dblist; d; d = alpm_list_next(d)) {
155 alpm_db_t *db = d->data;
157 if (alpm_trans_init(handle, 0))
158 alpm_die("failed to initialize ALPM transaction: %s\n");
159 if (alpm_db_update(0, db) < 0)
160 alpm_die("failed to update ALPM database: %s\n");
161 if (alpm_trans_release(handle))
162 alpm_die("failed to release ALPM transaction: %s\n");
164 for (p = alpm_db_get_pkgcache(db); p; p = alpm_list_next(p)) {
165 alpm_pkg_t *pkg = p->data;
167 pkglist = pkglist_append(pkglist, alpm_pkg_get_name(pkg));
169 for (q = alpm_pkg_get_replaces(pkg); q; q = alpm_list_next(q)) {
170 alpm_depend_t *replace = q->data;
171 pkglist = pkglist_append(pkglist, replace->name);
176 return pkglist;
179 static alpm_list_t *
180 dblist_create(void)
182 alpm_list_t *d;
183 alpm_list_t *dblist = NULL;
184 int i;
186 for (i = 0; i < sizeof(alpm_repos) / sizeof(char *); i++) {
187 if (!alpm_register_syncdb(handle, alpm_repos[i], 0))
188 alpm_die("failed to register sync db \"%s\": %s\n", alpm_repos[i]);
191 if (!(dblist = alpm_get_syncdbs(handle)))
192 alpm_die("failed to get sync DBs: %s\n");
194 for (d = dblist; d; d = alpm_list_next(d)) {
195 alpm_db_t *db = d->data;
197 char server[1024];
198 snprintf(server, 1024, ALPM_MIRROR, alpm_db_get_name(db));
200 if (alpm_db_add_server(db, server))
201 alpm_die("failed to set server \"%s\": %s\n", server);
204 return dblist;
207 static int parse_options(int argc, char **argv)
209 int opt;
211 static const struct option opts[] = {
212 { "mysql-host", required_argument, 0, 'h' },
213 { "mysql-socket", required_argument, 0, 'S' },
214 { "mysql-user", required_argument, 0, 'u' },
215 { "mysql-passwd", required_argument, 0, 'p' },
216 { "mysql-db", required_argument, 0, 'D' },
217 { 0, 0, 0, 0 }
220 while((opt = getopt_long(argc, argv, "h:S:u:p:D:", opts, NULL)) != -1) {
221 switch(opt) {
222 case 'h':
223 mysql_host = optarg;
224 break;;
225 case 'S':
226 mysql_socket = optarg;
227 break;;
228 case 'u':
229 mysql_user = optarg;
230 break;;
231 case 'p':
232 mysql_passwd = optarg;
233 break;;
234 case 'D':
235 mysql_db = optarg;
236 break;;
237 default:
238 return 0;
242 return 1;
245 static void
246 init(void)
248 enum _alpm_errno_t alpm_err;
249 if (mysql_library_init(0, NULL, NULL))
250 mysql_die("could not initialize MySQL library: %s\n");
251 if (!(c = mysql_init(NULL)))
252 mysql_die("failed to setup MySQL client: %s\n");
253 if (!mysql_real_connect(c, mysql_host, mysql_user, mysql_passwd,
254 mysql_db, 0, mysql_socket, 0))
255 mysql_die("failed to initiate MySQL connection to %s: %s\n", mysql_host);
257 if ((handle = alpm_initialize("/", ALPM_DBPATH, &alpm_err)) == NULL)
258 die("failed to initialize ALPM: %s\n", alpm_strerror(alpm_err));
261 static void
262 cleanup(void)
264 alpm_release(handle);
265 mysql_close(c);
266 mysql_library_end();
269 int main(int argc, char *argv[])
271 alpm_list_t *pkgs_cur, *pkgs_new;
273 if (!parse_options(argc, argv))
274 return 1;
276 init();
278 pkgs_cur = blacklist_get_pkglist();
279 pkgs_new = dblist_get_pkglist(dblist_create());
280 blacklist_sync(pkgs_cur, pkgs_new);
281 FREELIST(pkgs_new);
282 FREELIST(pkgs_cur);
284 cleanup();
286 return 0;