aurblup.c 7.53 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* aurblup - AUR blacklist updater
 *
 * Small utility to update the AUR package blacklist. Can be used in a cronjob.
 * Check the "README" file for details.
 */

#include <alpm.h>
#include <mysql.h>
#include <stdio.h>
#include <string.h>

#include "config.h"

#define alpm_die(...) die(__VA_ARGS__, alpm_strerrorlast());
#define mysql_die(...) die(__VA_ARGS__, mysql_error(c));

17
18
19
20
21
22
23
24
25
26
27
static void die(const char *, ...);
static alpm_list_t *pkglist_append(alpm_list_t *, const char *);
static alpm_list_t *blacklist_get_pkglist();
static void blacklist_add(const char *);
static void blacklist_remove(const char *);
static void blacklist_sync(alpm_list_t *, alpm_list_t *);
static alpm_list_t *dblist_get_pkglist(alpm_list_t *);
static alpm_list_t *dblist_create(void);
static void read_config(const char *);
static void init(void);
static void cleanup(void);
28
29
30
31
32
33
34

static char *mysql_host = NULL;
static char *mysql_socket = NULL;
static char *mysql_user = NULL;
static char *mysql_passwd = NULL;
static char *mysql_db = NULL;

35
static MYSQL *c;
36

37
static void
38
39
40
41
42
die(const char *format, ...)
{
  va_list arg;

  va_start(arg, format);
43
  fprintf(stderr, "aurblup: ");
44
45
46
47
48
49
50
  vfprintf(stderr, format, arg);
  va_end(arg);

  cleanup();
  exit(1);
}

51
static alpm_list_t *
52
53
54
pkglist_append(alpm_list_t *pkglist, const char *pkgname)
{
  int len = strcspn(pkgname, "<=>");
Dan McGee's avatar
Dan McGee committed
55
56
  if (!len)
    len = strlen(pkgname);
57
58
59
60

  char *s = malloc(len + 1);

  strncpy(s, pkgname, len);
Dan McGee's avatar
Dan McGee committed
61
  s[len] = '\0';
62
63
64
65
66
67
68
69
70

  if (alpm_list_find_str(pkglist, s))
    free(s);
  else
    pkglist = alpm_list_add(pkglist, s);

  return pkglist;
}

71
static alpm_list_t *
72
73
74
75
76
77
blacklist_get_pkglist()
{
  MYSQL_RES *res;
  MYSQL_ROW row;
  alpm_list_t *pkglist = NULL;

Dan McGee's avatar
Dan McGee committed
78
  if (mysql_query(c, "SELECT Name FROM PackageBlacklist"))
79
80
81
82
83
84
85
86
87
88
89
90
91
    mysql_die("failed to read blacklist from MySQL database: %s\n");

  if (!(res = mysql_store_result(c)))
    mysql_die("failed to store MySQL result: %s\n");

  while ((row = mysql_fetch_row(res)))
    pkglist = pkglist_append(pkglist, row[0]);

  mysql_free_result(res);

  return pkglist;
}

92
static void
93
blacklist_add(const char *name)
94
{
95
  char *esc = malloc(strlen(name) * 2 + 1);
96
97
  char query[1024];

98
  mysql_real_escape_string(c, esc, name, strlen(name));
99
  snprintf(query, 1024, "INSERT INTO PackageBlacklist (Name) "
Dan McGee's avatar
Dan McGee committed
100
                        "VALUES ('%s')", esc);
101
102
103
104
105
106
  free(esc);

  if (mysql_query(c, query))
    mysql_die("failed to query MySQL database (\"%s\"): %s\n", query);
}

107
static void
108
109
110
111
112
113
blacklist_remove(const char *name)
{
  char *esc = malloc(strlen(name) * 2 + 1);
  char query[1024];

  mysql_real_escape_string(c, esc, name, strlen(name));
Dan McGee's avatar
Dan McGee committed
114
  snprintf(query, 1024, "DELETE FROM PackageBlacklist WHERE Name = '%s'", esc);
115
116
117
118
119
120
  free(esc);

  if (mysql_query(c, query))
    mysql_die("failed to query MySQL database (\"%s\"): %s\n", query);
}

121
static void
122
blacklist_sync(alpm_list_t *pkgs_cur, alpm_list_t *pkgs_new)
123
{
124
  alpm_list_t *pkgs_add, *pkgs_rem, *p;
125

126
127
  pkgs_add = alpm_list_diff(pkgs_new, pkgs_cur, (alpm_list_fn_cmp)strcmp);
  pkgs_rem = alpm_list_diff(pkgs_cur, pkgs_new, (alpm_list_fn_cmp)strcmp);
128

Dan McGee's avatar
Dan McGee committed
129
  if (mysql_query(c, "START TRANSACTION"))
130
    mysql_die("failed to start MySQL transaction: %s\n");
131

132
133
  for (p = pkgs_add; p; p = alpm_list_next(p))
    blacklist_add(alpm_list_getdata(p));
134

135
136
  for (p = pkgs_rem; p; p = alpm_list_next(p))
    blacklist_remove(alpm_list_getdata(p));
137

Dan McGee's avatar
Dan McGee committed
138
  if (mysql_query(c, "COMMIT"))
139
    mysql_die("failed to commit MySQL transaction: %s\n");
140
141
142

  alpm_list_free(pkgs_add);
  alpm_list_free(pkgs_rem);
143
144
}

145
static alpm_list_t *
146
dblist_get_pkglist(alpm_list_t *dblist)
147
{
148
149
  alpm_list_t *d, *p, *q;
  alpm_list_t *pkglist = NULL;
150

151
152
  for (d = dblist; d; d = alpm_list_next(d)) {
    pmdb_t *db = alpm_list_getdata(d);
153
154
155
156
157
158
159
160

    if (alpm_trans_init(0, NULL, NULL, NULL))
      alpm_die("failed to initialize ALPM transaction: %s\n");
    if (alpm_db_update(0, db) < 0)
      alpm_die("failed to update ALPM database: %s\n");
    if (alpm_trans_release())
      alpm_die("failed to release ALPM transaction: %s\n");

161
162
163
164
165
166
167
168
169
170
171
    for (p = alpm_db_get_pkgcache(db); p; p = alpm_list_next(p)) {
      pmpkg_t *pkg = alpm_list_getdata(p);

      pkglist = pkglist_append(pkglist, alpm_pkg_get_name(pkg));

      for (q = alpm_pkg_get_provides(pkg); q; q = alpm_list_next(q))
        pkglist = pkglist_append(pkglist, alpm_list_getdata(q));

      for (q = alpm_pkg_get_replaces(pkg); q; q = alpm_list_next(q))
        pkglist = pkglist_append(pkglist, alpm_list_getdata(q));
    }
172
173
  }

174
  return pkglist;
175
176
}

177
static alpm_list_t *
178
dblist_create(void)
179
{
180
181
  alpm_list_t *d;
  alpm_list_t *dblist = NULL;
182
183
184
185
186
187
188
189
190
191
  int i;

  for (i = 0; i < sizeof(alpm_repos) / sizeof(char *); i++) {
    if (!alpm_db_register_sync(alpm_repos[i]))
      alpm_die("failed to register sync db \"%s\": %s\n", alpm_repos[i]);
  }

  if (!(dblist = alpm_option_get_syncdbs()))
    alpm_die("failed to get sync DBs: %s\n");

192
193
  for (d = dblist; d; d = alpm_list_next(d)) {
    pmdb_t *db = alpm_list_getdata(d);
194
195
196
197
198
199
200
201
202
203
204

    char server[1024];
    snprintf(server, 1024, ALPM_MIRROR, alpm_db_get_name(db));

    if (alpm_db_setserver(db, server))
      alpm_die("failed to set server \"%s\": %s\n", server);
  }

  return dblist;
}

205
static void
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
read_config(const char *fn)
{
  FILE *fp;
  char line[128];
  char **t, **u, *p, *q;

  if (!(fp = fopen(fn, "r")))
    die("failed to open AUR config file (\"%s\")\n", fn);

  while (fgets(line, sizeof(line), fp)) {
    u = NULL;
    if (strstr(line, CONFIG_KEY_HOST)) {
      t = &mysql_host;
      u = &mysql_socket;
    }
Dan McGee's avatar
Dan McGee committed
221
222
223
224
225
226
227
228
    else if (strstr(line, CONFIG_KEY_USER))
      t = &mysql_user;
    else if (strstr(line, CONFIG_KEY_PASSWD))
      t = &mysql_passwd;
    else if (strstr(line, CONFIG_KEY_DB))
      t = &mysql_db;
    else
      t = NULL;
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

    if (t) {
      strtok(line, "\"");
      strtok(NULL, "\"");
      strtok(NULL, "\"");
      p = strtok(NULL, "\"");

      if (u) {
        p = strtok(p, ":");
        q = strtok(NULL, ":");
      }
      else q = NULL;

      if (p && !*t) {
        *t = malloc(strlen(p) + 1);
        strncpy(*t, p, strlen(p) + 1);
      }

      if (q && !*u) {
        *u = malloc(strlen(q) + 1);
        strncpy(*u, q, strlen(q) + 1);
      }
    }
  }

  fclose(fp);

  if (!mysql_host)
    die("MySQL host setting not found in AUR config file\n");
  if (!mysql_user)
    die("MySQL user setting not found in AUR config file\n");
  if (!mysql_passwd)
    die("MySQL password setting not found in AUR config file\n");
  if (!mysql_db)
    die("MySQL database setting not found in AUR config file\n");
}

266
static void
267
268
init(void)
{
Lukas Fleischer's avatar
Lukas Fleischer committed
269
270
  if (mysql_library_init(0, NULL, NULL))
    mysql_die("could not initialize MySQL library: %s\n");
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  if (!(c = mysql_init(NULL)))
    mysql_die("failed to setup MySQL client: %s\n");
  if (!mysql_real_connect(c, mysql_host, mysql_user, mysql_passwd,
                          mysql_db, 0, mysql_socket, 0))
    mysql_die("failed to initiate MySQL connection to %s: %s\n", mysql_host);

  if (alpm_initialize())
    alpm_die("failed to initialize ALPM: %s\n");
  if (alpm_option_set_root("/"))
    alpm_die("failed to set ALPM root: %s\n");
  if (alpm_option_set_dbpath(ALPM_DBPATH))
    alpm_die("failed to set ALPM database path: %s\n");
}

285
static void
286
287
cleanup(void)
{
Dan McGee's avatar
Dan McGee committed
288
289
290
291
292
  free(mysql_host);
  free(mysql_socket);
  free(mysql_user);
  free(mysql_passwd);
  free(mysql_db);
293
294
295

  alpm_release();
  mysql_close(c);
Lukas Fleischer's avatar
Lukas Fleischer committed
296
  mysql_library_end();
297
298
299
300
}

int main(int argc, char *argv[])
{
301
  alpm_list_t *pkgs_cur, *pkgs_new;
302
303
304

  read_config(AUR_CONFIG);
  init();
305
306
307
308
309
310
311

  pkgs_cur = blacklist_get_pkglist();
  pkgs_new = dblist_get_pkglist(dblist_create());
  blacklist_sync(pkgs_cur, pkgs_new);
  FREELIST(pkgs_new);
  FREELIST(pkgs_cur);

312
313
314
315
  cleanup();

  return 0;
}