update-alternatives.c 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454
  1. /*
  2. * update-alternatives
  3. *
  4. * Copyright © 1995 Ian Jackson <ian@davenant.greenend.org.uk>
  5. * Copyright © 2000-2002 Wichert Akkerman <wakkerma@debian.org>
  6. * Copyright © 2006-2010 Guillem Jover <guillem@debian.org>
  7. * Copyright © 2008 Pierre Habouzit <madcoder@debian.org>
  8. * Copyright © 2009-2010 Raphaël Hertzog <hertzog@debian.org>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #include <config.h>
  24. #include <compat.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/wait.h>
  28. #include <errno.h>
  29. #include <stdarg.h>
  30. #include <stdbool.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <unistd.h>
  34. #include <string.h>
  35. #include <dirent.h>
  36. #include <time.h>
  37. #include <setjmp.h>
  38. #include <assert.h>
  39. #include <locale.h>
  40. #include <ctype.h>
  41. #include <limits.h>
  42. #include <dpkg/macros.h>
  43. #include <dpkg/i18n.h>
  44. /* Global variables: */
  45. #define PROGNAME "update-alternatives"
  46. static const char *altdir = SYSCONFDIR "/alternatives";
  47. static const char *admdir = ADMINDIR "/alternatives";
  48. static const char *prog_path = "update-alternatives";
  49. /* Action to perform */
  50. static const char *action = NULL;
  51. static const char *log_file = LOGDIR "/alternatives.log";
  52. /* Skip alternatives properly configured in auto mode (for --config) */
  53. static int opt_skip_auto = 0;
  54. static int opt_verbose = 0;
  55. static int opt_force = 0;
  56. #define MAX_OPTS 128
  57. #define PUSH_OPT(a) if (nb_opts < MAX_OPTS) pass_opts[nb_opts++] = a;
  58. static char *pass_opts[MAX_OPTS];
  59. static int nb_opts = 0;
  60. #define DPKG_TMP_EXT ".dpkg-tmp"
  61. /*
  62. * Functions.
  63. */
  64. static void
  65. version(void)
  66. {
  67. printf(_("Debian %s version %s.\n"), PROGNAME, VERSION);
  68. printf("\n");
  69. printf(_(
  70. "Copyright (C) 1995 Ian Jackson.\n"
  71. "Copyright (C) 2000-2002 Wichert Akkerman.\n"
  72. "Copyright (C) 2009-2010 Raphael Hertzog.\n"));
  73. printf(_(
  74. "This is free software; see the GNU General Public License version 2 or\n"
  75. "later for copying conditions. There is NO warranty.\n"));
  76. }
  77. static void
  78. usage(void)
  79. {
  80. printf(_(
  81. "Usage: %s [<option> ...] <command>\n"
  82. "\n"
  83. "Commands:\n"
  84. " --install <link> <name> <path> <priority>\n"
  85. " [--slave <link> <name> <path>] ...\n"
  86. " add a group of alternatives to the system.\n"
  87. " --remove <name> <path> remove <path> from the <name> group alternative.\n"
  88. " --remove-all <name> remove <name> group from the alternatives system.\n"
  89. " --auto <name> switch the master link <name> to automatic mode.\n"
  90. " --display <name> display information about the <name> group.\n"
  91. " --query <name> machine parseable version of --display <name>.\n"
  92. " --list <name> display all targets of the <name> group.\n"
  93. " --config <name> show alternatives for the <name> group and ask the\n"
  94. " user to select which one to use.\n"
  95. " --set <name> <path> set <path> as alternative for <name>.\n"
  96. " --all call --config on all alternatives.\n"
  97. "\n"
  98. "<link> is the symlink pointing to %s/<name>.\n"
  99. " (e.g. /usr/bin/pager)\n"
  100. "<name> is the master name for this link group.\n"
  101. " (e.g. pager)\n"
  102. "<path> is the location of one of the alternative target files.\n"
  103. " (e.g. /usr/bin/less)\n"
  104. "<priority> is an integer; options with higher numbers have higher priority in\n"
  105. " automatic mode.\n"
  106. "\n"
  107. "Options:\n"
  108. " --altdir <directory> change the alternatives directory.\n"
  109. " --admindir <directory> change the administrative directory.\n"
  110. " --skip-auto skip prompt for alternatives correctly configured\n"
  111. " in automatic mode (relevant for --config only)\n"
  112. " --verbose verbose operation, more output.\n"
  113. " --quiet quiet operation, minimal output.\n"
  114. " --help show this help message.\n"
  115. " --version show the version.\n"
  116. ), PROGNAME, altdir);
  117. }
  118. static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(1)
  119. error(char const *fmt, ...)
  120. {
  121. va_list args;
  122. fprintf(stderr, PROGNAME ": %s: ", _("error"));
  123. va_start(args, fmt);
  124. vfprintf(stderr, fmt, args);
  125. va_end(args);
  126. fprintf(stderr, "\n");
  127. exit(2);
  128. }
  129. static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(1)
  130. badusage(char const *fmt, ...)
  131. {
  132. va_list args;
  133. fprintf(stderr, PROGNAME ": ");
  134. va_start(args, fmt);
  135. vfprintf(stderr, fmt, args);
  136. va_end(args);
  137. fprintf(stderr, "\n\n");
  138. usage();
  139. exit(2);
  140. }
  141. static void DPKG_ATTR_PRINTF(1)
  142. warning(char const *fmt, ...)
  143. {
  144. va_list args;
  145. if (opt_verbose < 0)
  146. return;
  147. fprintf(stderr, PROGNAME ": %s: ", _("warning"));
  148. va_start(args, fmt);
  149. vfprintf(stderr, fmt, args);
  150. va_end(args);
  151. fprintf(stderr, "\n");
  152. }
  153. static void DPKG_ATTR_PRINTF(1)
  154. debug(char const *fmt, ...)
  155. {
  156. #if 0
  157. va_list args;
  158. fprintf(stderr, "DEBUG: ");
  159. va_start(args, fmt);
  160. vfprintf(stderr, fmt, args);
  161. va_end(args);
  162. fprintf(stderr, "\n");
  163. #endif
  164. }
  165. static void DPKG_ATTR_PRINTF(1)
  166. verbose(char const *fmt, ...)
  167. {
  168. va_list args;
  169. if (opt_verbose < 1)
  170. return;
  171. printf(PROGNAME ": ");
  172. va_start(args, fmt);
  173. vprintf(fmt, args);
  174. va_end(args);
  175. printf("\n");
  176. }
  177. static void DPKG_ATTR_PRINTF(1)
  178. info(char const *fmt, ...)
  179. {
  180. va_list args;
  181. if (opt_verbose < 0)
  182. return;
  183. printf(PROGNAME ": ");
  184. va_start(args, fmt);
  185. vprintf(fmt, args);
  186. va_end(args);
  187. printf("\n");
  188. }
  189. static void DPKG_ATTR_PRINTF(1)
  190. pr(char const *fmt, ...)
  191. {
  192. va_list args;
  193. va_start(args, fmt);
  194. vprintf(fmt, args);
  195. va_end(args);
  196. printf("\n");
  197. }
  198. static void *
  199. xmalloc(size_t size)
  200. {
  201. void *r;
  202. r = malloc(size);
  203. if (!r)
  204. error(_("malloc failed (%ld bytes)"), (long)size);
  205. return r;
  206. }
  207. static char *
  208. xstrdup(const char *str)
  209. {
  210. char *new_str;
  211. if (!str)
  212. return NULL;
  213. new_str = strdup(str);
  214. if (!new_str)
  215. error(_("failed to allocate memory"));
  216. return new_str;
  217. }
  218. static char *
  219. xreadlink(const char *linkname, bool error_out)
  220. {
  221. struct stat st;
  222. char *buf;
  223. ssize_t size;
  224. /* Allocate required memory to store the value of the symlink */
  225. if (lstat(linkname, &st)) {
  226. if (!error_out)
  227. return NULL;
  228. error(_("cannot stat %s: %s"), linkname, strerror(errno));
  229. }
  230. buf = xmalloc(st.st_size + 1);
  231. /* Read it and terminate the string properly */
  232. size = readlink(linkname, buf, st.st_size);
  233. if (size == -1) {
  234. if (!error_out) {
  235. free(buf);
  236. return NULL;
  237. }
  238. error(_("readlink(%s) failed: %s"), linkname, strerror(errno));
  239. }
  240. buf[size] = '\0';
  241. return buf;
  242. }
  243. static int DPKG_ATTR_PRINTF(2)
  244. xasprintf(char **strp, const char *fmt, ...)
  245. {
  246. va_list args;
  247. int ret;
  248. va_start(args, fmt);
  249. ret = vasprintf(strp, fmt, args);
  250. va_end(args);
  251. if (ret < 0)
  252. error(_("failed to allocate memory"));
  253. return ret;
  254. }
  255. static void
  256. set_action(const char *new_action)
  257. {
  258. if (action)
  259. badusage(_("two commands specified: --%s and --%s"), action, new_action);
  260. action = new_action;
  261. }
  262. static FILE *fh_log = NULL;
  263. static void DPKG_ATTR_PRINTF(1)
  264. log_msg(const char *fmt, ...)
  265. {
  266. va_list args;
  267. if (fh_log == NULL) {
  268. fh_log = fopen(log_file, "a");
  269. if (fh_log == NULL && errno != EACCES)
  270. error(_("cannot append to %s: %s"), log_file, strerror(errno));
  271. }
  272. if (fh_log) {
  273. char timestamp[64];
  274. time_t now;
  275. time(&now);
  276. strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S",
  277. localtime(&now));
  278. fprintf(fh_log, "%s " PROGNAME ": ", timestamp);
  279. va_start(args, fmt);
  280. vfprintf(fh_log, fmt, args);
  281. va_end(args);
  282. fprintf(fh_log, "\n");
  283. }
  284. }
  285. static int
  286. filter_altdir(const struct dirent *entry)
  287. {
  288. if (strcmp(entry->d_name, ".") == 0 ||
  289. strcmp(entry->d_name, "..") == 0 ||
  290. (strlen(entry->d_name) > strlen(DPKG_TMP_EXT) &&
  291. strcmp(entry->d_name + strlen(entry->d_name) -
  292. strlen(DPKG_TMP_EXT), DPKG_TMP_EXT) == 0))
  293. return 0;
  294. return 1;
  295. }
  296. static int
  297. get_all_alternatives(struct dirent ***table)
  298. {
  299. int count;
  300. count = scandir(admdir, table, filter_altdir, alphasort);
  301. if (count < 0)
  302. error(_("scan of %s failed: %s"), admdir, strerror(errno));
  303. return count;
  304. }
  305. static int
  306. spawn(const char *prog, const char *args[])
  307. {
  308. const char **cmd;
  309. int i = 0;
  310. pid_t pid, r;
  311. int status;
  312. while (args[i++]);
  313. cmd = xmalloc(sizeof(char *) * (i + 2));
  314. cmd[0] = prog;
  315. for (i = 0; args[i]; i++)
  316. cmd[i + 1] = args[i];
  317. cmd[i + 1] = NULL;
  318. pid = fork();
  319. if (pid == -1)
  320. error(_("fork failed"));
  321. if (pid == 0) {
  322. execvp(prog, (char *const *)cmd);
  323. error(_("failed to execute %s: %s"), prog, strerror(errno));
  324. }
  325. while ((r = waitpid(pid, &status, 0)) == -1 && errno == EINTR) ;
  326. if (r != pid)
  327. error(_("wait for subprocess %s failed"), prog);
  328. free(cmd);
  329. return status;
  330. }
  331. static void DPKG_ATTR_SENTINEL
  332. subcall(const char *prog, ...)
  333. {
  334. va_list args;
  335. const char **cmd;
  336. int res, i, j, count;
  337. /* Count the arguments */
  338. va_start(args, prog);
  339. count = 0;
  340. while (va_arg(args, char *))
  341. count++;
  342. va_end(args);
  343. /* Prepare table for all parameters */
  344. cmd = xmalloc(sizeof(*cmd) * (nb_opts + count + 1));
  345. i = 0;
  346. for (j = 0; j < nb_opts; j++)
  347. cmd[i++] = pass_opts[j];
  348. va_start(args, prog);
  349. for (j = 0; j < count; j++)
  350. cmd[i++] = va_arg(args, char *);
  351. va_end(args);
  352. cmd[i++] = NULL;
  353. /* Run the command */
  354. res = spawn(prog, cmd);
  355. if (WIFEXITED(res) && WEXITSTATUS(res) == 0)
  356. return;
  357. if (WIFEXITED(res))
  358. exit(WEXITSTATUS(res));
  359. exit(128);
  360. }
  361. static void
  362. config_all(void)
  363. {
  364. struct dirent **table;
  365. int i, count;
  366. count = get_all_alternatives(&table);
  367. for (i = 0; i < count; i++) {
  368. subcall(prog_path, "--config", table[i]->d_name, NULL);
  369. printf("\n");
  370. }
  371. }
  372. static bool
  373. rename_mv(const char *src, const char *dst)
  374. {
  375. struct stat st;
  376. if (lstat(src, &st) != 0)
  377. return false;
  378. if (rename(src, dst) != 0) {
  379. const char *args[3] = { src, dst, NULL };
  380. int r;
  381. r = spawn("mv", args);
  382. if (WIFEXITED(r) && WEXITSTATUS(r) == 0)
  383. return true;
  384. return false;
  385. }
  386. return true;
  387. }
  388. static void
  389. checked_symlink(const char *filename, const char *linkname)
  390. {
  391. if (symlink(filename, linkname))
  392. error(_("unable to make %s a symlink to %s: %s"), linkname,
  393. filename, strerror(errno));
  394. }
  395. static void
  396. checked_mv(const char *src, const char *dst)
  397. {
  398. if (!rename_mv(src, dst))
  399. error(_("unable to install %s as %s: %s"), src, dst, strerror(errno));
  400. }
  401. static void
  402. checked_rm(const char *f)
  403. {
  404. if (!unlink(f))
  405. return;
  406. if (errno != ENOENT)
  407. error(_("unable to remove %s: %s"), f, strerror(errno));
  408. }
  409. /*
  410. * OBJECTS
  411. */
  412. struct fileset {
  413. struct fileset *next;
  414. char *master_file;
  415. int priority;
  416. struct slave_file {
  417. struct slave_file *next;
  418. char *name;
  419. char *file;
  420. } *slaves;
  421. };
  422. static struct fileset *
  423. fileset_new(const char *master_file, int prio)
  424. {
  425. struct fileset *fs;
  426. fs = xmalloc(sizeof(*fs));
  427. fs->next = NULL;
  428. fs->master_file = xstrdup(master_file);
  429. fs->priority = prio;
  430. fs->slaves = NULL;
  431. return fs;
  432. }
  433. static void
  434. fileset_free(struct fileset *fs)
  435. {
  436. struct slave_file *slave, *next;
  437. free(fs->master_file);
  438. for (slave = fs->slaves; slave; slave = next) {
  439. next = slave->next;
  440. free(slave->name);
  441. free(slave->file);
  442. free(slave);
  443. }
  444. free(fs);
  445. }
  446. /* name and file must be allocated with malloc */
  447. static void
  448. fileset_add_slave(struct fileset *fs, char *name, char *file)
  449. {
  450. struct slave_file *sl, *cur, *prev = NULL;
  451. /* Replace existing first */
  452. for (cur = fs->slaves; cur; cur = cur->next) {
  453. if (strcmp(cur->name, name) == 0) {
  454. free(cur->file);
  455. cur->file = xstrdup(file);
  456. return;
  457. }
  458. prev = cur;
  459. }
  460. /* Otherwise add new at the end */
  461. sl = xmalloc(sizeof(*sl));
  462. sl->next = NULL;
  463. sl->name = name;
  464. sl->file = file;
  465. if (prev)
  466. prev->next = sl;
  467. else
  468. fs->slaves = sl;
  469. }
  470. static const char *
  471. fileset_get_slave(struct fileset *fs, const char *name)
  472. {
  473. struct slave_file *slave;
  474. for (slave = fs->slaves; slave; slave = slave->next) {
  475. if (strcmp(slave->name, name) == 0)
  476. return slave->file;
  477. }
  478. return NULL;
  479. }
  480. static bool
  481. fileset_has_slave(struct fileset *fs, const char *name)
  482. {
  483. const char *file = fileset_get_slave(fs, name);
  484. if (file == NULL)
  485. return false;
  486. return strlen(file) ? true : false;
  487. }
  488. static bool
  489. fileset_can_install_slave(struct fileset *fs, const char *slave_name)
  490. {
  491. struct stat st;
  492. bool install_slave = false;
  493. /* Decide whether the slave alternative must be setup */
  494. if (fileset_has_slave(fs, slave_name)) {
  495. const char *slave = fileset_get_slave(fs, slave_name);
  496. errno = 0;
  497. if (stat(slave, &st) == -1 && errno != ENOENT)
  498. error(_("cannot stat %s: %s"), slave,
  499. strerror(errno));
  500. install_slave = (errno == 0) ? true : false;
  501. }
  502. return install_slave;
  503. }
  504. struct slave_link {
  505. struct slave_link *next;
  506. char *name;
  507. char *link;
  508. };
  509. struct commit_operation {
  510. struct commit_operation *next;
  511. enum opcode {
  512. opcode_nop,
  513. opcode_rm,
  514. opcode_mv,
  515. } opcode;
  516. char *arg_a;
  517. char *arg_b;
  518. };
  519. struct alternative {
  520. char *master_name;
  521. char *master_link;
  522. enum alternative_status {
  523. ALT_ST_UNKNOWN,
  524. ALT_ST_AUTO,
  525. ALT_ST_MANUAL,
  526. } status;
  527. struct slave_link *slaves;
  528. struct fileset *choices;
  529. struct commit_operation *commit_ops;
  530. bool modified;
  531. };
  532. static void
  533. slave_link_free(struct slave_link *slave)
  534. {
  535. free(slave->name);
  536. free(slave->link);
  537. free(slave);
  538. }
  539. static void
  540. commit_operation_free(struct commit_operation *commit_op)
  541. {
  542. free(commit_op->arg_a);
  543. free(commit_op->arg_b);
  544. free(commit_op);
  545. }
  546. static struct alternative *
  547. alternative_new(const char *name)
  548. {
  549. struct alternative *alt;
  550. alt = xmalloc(sizeof(*alt));
  551. alt->master_name = xstrdup(name);
  552. alt->master_link = NULL;
  553. alt->status = ALT_ST_UNKNOWN;
  554. alt->slaves = NULL;
  555. alt->choices = NULL;
  556. alt->commit_ops = NULL;
  557. alt->modified = false;
  558. return alt;
  559. }
  560. static void
  561. alternative_choices_free(struct alternative *a)
  562. {
  563. struct fileset *fs;
  564. if (a->choices)
  565. a->modified = true;
  566. while (a->choices) {
  567. fs = a->choices;
  568. a->choices = fs->next;
  569. fileset_free(fs);
  570. }
  571. }
  572. static void
  573. alternative_reset(struct alternative *alt)
  574. {
  575. struct slave_link *slave;
  576. struct commit_operation *commit_op;
  577. free(alt->master_link);
  578. alt->master_link = NULL;
  579. while (alt->slaves) {
  580. slave = alt->slaves;
  581. alt->slaves = slave->next;
  582. slave_link_free(slave);
  583. }
  584. alternative_choices_free(alt);
  585. while (alt->commit_ops) {
  586. commit_op = alt->commit_ops;
  587. alt->commit_ops = commit_op->next;
  588. commit_operation_free(commit_op);
  589. }
  590. alt->modified = false;
  591. }
  592. static void
  593. alternative_free(struct alternative *alt)
  594. {
  595. alternative_reset(alt);
  596. free(alt->master_name);
  597. free(alt);
  598. }
  599. static int
  600. alternative_choices_count(struct alternative *alt)
  601. {
  602. struct fileset *fs;
  603. int count = 0;
  604. for (fs = alt->choices; fs; fs = fs->next)
  605. count++;
  606. return count;
  607. }
  608. static int
  609. alternative_slaves_count(struct alternative *alt)
  610. {
  611. struct slave_link *sl;
  612. int count = 0;
  613. for (sl = alt->slaves; sl; sl = sl->next)
  614. count++;
  615. return count;
  616. }
  617. static int
  618. compare_fileset(const void *va, const void *vb)
  619. {
  620. const struct fileset *a = *(const struct fileset **)va;
  621. const struct fileset *b = *(const struct fileset **)vb;
  622. assert(a && a->master_file);
  623. assert(b && b->master_file);
  624. return strcmp(a->master_file, b->master_file);
  625. }
  626. static int
  627. compare_slave_link(const void *va, const void *vb)
  628. {
  629. const struct slave_link *a = *(const struct slave_link **)va;
  630. const struct slave_link *b = *(const struct slave_link **)vb;
  631. assert(a && a->name);
  632. assert(b && b->name);
  633. return strcmp(a->name, b->name);
  634. }
  635. static void
  636. alternative_sort_choices(struct alternative *a)
  637. {
  638. int count, i;
  639. struct fileset **table, *fs;
  640. count = alternative_choices_count(a);
  641. if (count < 2) /* Nothing to sort */
  642. return;
  643. /* Store objects in a table instead of a linked list */
  644. table = xmalloc(sizeof(fs) * count);
  645. for (fs = a->choices, i = 0; fs; fs = fs->next) {
  646. assert(fs->master_file);
  647. table[i++] = fs;
  648. }
  649. qsort(table, count, sizeof(fs), compare_fileset);
  650. /* Rewrite the linked list from the sorted table */
  651. a->choices = fs = table[0];
  652. table[count - 1]->next = NULL;
  653. for (i = 1; i < count; fs = fs->next, i++)
  654. fs->next = table[i];
  655. free(table);
  656. }
  657. static void
  658. alternative_sort_slaves(struct alternative *a)
  659. {
  660. int count, i;
  661. struct slave_link **table, *sl;
  662. count = alternative_slaves_count(a);
  663. if (count < 2) /* Nothing to sort */
  664. return;
  665. /* Store objects in a table instead of a linked list */
  666. table = xmalloc(sizeof(sl) * count);
  667. for (sl = a->slaves, i = 0; sl; sl = sl->next, i++) {
  668. table[i] = sl;
  669. }
  670. qsort(table, count, sizeof(sl), compare_slave_link);
  671. /* Rewrite the linked list from the sorted table */
  672. a->slaves = sl = table[0];
  673. table[count - 1]->next = NULL;
  674. for (i = 1; i < count; sl = sl->next, i++)
  675. sl->next = table[i];
  676. free(table);
  677. }
  678. static struct fileset *
  679. alternative_get_fileset(struct alternative *a, const char *file)
  680. {
  681. struct fileset *fs;
  682. for (fs = a->choices; fs; fs = fs->next)
  683. if (strcmp(fs->master_file, file) == 0)
  684. return fs;
  685. return NULL;
  686. }
  687. static struct slave_link *
  688. alternative_get_slave(struct alternative *a, const char *name)
  689. {
  690. struct slave_link *sl;
  691. for (sl = a->slaves; sl; sl = sl->next)
  692. if (strcmp(sl->name, name) == 0)
  693. return sl;
  694. return NULL;
  695. }
  696. static bool
  697. alternative_has_slave(struct alternative *a, const char *name)
  698. {
  699. return alternative_get_slave(a, name) ? true : false;
  700. }
  701. static bool
  702. alternative_has_choice(struct alternative *a, const char *file)
  703. {
  704. return alternative_get_fileset(a, file) ? true : false;
  705. }
  706. static void
  707. alternative_add_choice(struct alternative *a, struct fileset *fs)
  708. {
  709. struct fileset *cur, *prev = NULL;
  710. /* Replace if already existing */
  711. for (cur = a->choices; cur; cur = cur->next) {
  712. if (strcmp(cur->master_file, fs->master_file) == 0) {
  713. fs->next = cur->next;
  714. fileset_free(cur);
  715. if (prev)
  716. prev->next = fs;
  717. else
  718. a->choices = fs;
  719. a->modified = true; /* XXX: be smarter in detecting change? */
  720. return;
  721. }
  722. prev = cur;
  723. }
  724. /* Otherwise add at the end */
  725. if (prev == NULL)
  726. a->choices = fs;
  727. else
  728. prev->next = fs;
  729. fs->next = NULL;
  730. a->modified = true;
  731. }
  732. /* slave_name and slave_link must be allocated with malloc */
  733. static void
  734. alternative_add_slave(struct alternative *a, char *slave_name,
  735. char *slave_link)
  736. {
  737. struct slave_link *sl, *new;
  738. /* Replace if already existing */
  739. for (sl = a->slaves; sl; sl = sl->next) {
  740. if (strcmp(sl->name, slave_name) == 0) {
  741. free(sl->link);
  742. sl->link = xstrdup(slave_link);
  743. return;
  744. }
  745. if (sl->next == NULL)
  746. break;
  747. }
  748. /* Otherwise create new and add at the end */
  749. new = xmalloc(sizeof(*new));
  750. new->name = slave_name;
  751. new->link = slave_link;
  752. new->next = NULL;
  753. if (sl)
  754. sl->next = new;
  755. else
  756. a->slaves = new;
  757. }
  758. static const char *
  759. alternative_status_string(enum alternative_status status)
  760. {
  761. return (status == ALT_ST_AUTO) ? "auto" : "manual";
  762. }
  763. static void
  764. alternative_set_status(struct alternative *a, enum alternative_status status)
  765. {
  766. if (a->status == ALT_ST_UNKNOWN || status != a->status)
  767. a->modified = true;
  768. if (a->status != ALT_ST_UNKNOWN && status != a->status)
  769. log_msg("status of link group %s set to %s", a->master_link,
  770. alternative_status_string(status));
  771. a->status = status;
  772. }
  773. /* link must be allocated with malloc */
  774. static void
  775. alternative_set_link(struct alternative *a, char *linkname)
  776. {
  777. if (a->master_link == NULL || strcmp(linkname, a->master_link) != 0)
  778. a->modified = true;
  779. free(a->master_link);
  780. a->master_link = linkname;
  781. }
  782. static bool
  783. alternative_remove_choice(struct alternative *a, const char *file)
  784. {
  785. struct fileset *fs, *fs_prev;
  786. fs_prev = NULL;
  787. for (fs = a->choices; fs; fs = fs->next) {
  788. if (strcmp(fs->master_file, file) != 0) {
  789. fs_prev = fs;
  790. continue;
  791. }
  792. if (fs_prev)
  793. fs_prev->next = fs->next;
  794. else
  795. a->choices = fs->next;
  796. fileset_free(fs);
  797. a->modified = true;
  798. return true;
  799. }
  800. return false;
  801. }
  802. /*
  803. * Alternatives Database Load/Store functions.
  804. */
  805. struct altdb_context {
  806. FILE *fh;
  807. char *filename;
  808. void DPKG_ATTR_PRINTF(2) (*bad_format)(struct altdb_context *, const char *format, ...);
  809. jmp_buf on_error;
  810. };
  811. static char *
  812. altdb_get_line(struct altdb_context *ctx, const char *name)
  813. {
  814. char *buf, *line;
  815. size_t len, bufsz, i;
  816. bufsz = 1024;
  817. buf = xmalloc(bufsz);
  818. for (i = 0; true; i += strlen(line)) {
  819. errno = 0;
  820. line = fgets(buf + i, bufsz - i, ctx->fh);
  821. if (line) {
  822. if (strlen(buf) < bufsz - 1 || buf[bufsz - 2] == '\n')
  823. break;
  824. /* Need more space */
  825. bufsz *= 2;
  826. buf = realloc(buf, bufsz);
  827. if (!buf)
  828. error(_("failed to allocate memory"));
  829. continue;
  830. }
  831. if (feof(ctx->fh))
  832. ctx->bad_format(ctx, _("unexpected end of file while trying "
  833. "to read %s"), name);
  834. ctx->bad_format(ctx, _("while reading %s: %s"),
  835. name, strerror(errno));
  836. }
  837. len = strlen(buf);
  838. if (len == 0 || buf[len - 1] != '\n') {
  839. ctx->bad_format(ctx, _("line not terminated while trying "
  840. "to read %s"), name);
  841. }
  842. line[len - 1] = '\0';
  843. return buf;
  844. }
  845. static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(2)
  846. altdb_parse_error(struct altdb_context *ctx, const char *format, ...)
  847. {
  848. char *msg;
  849. va_list args;
  850. int ret;
  851. va_start(args, format);
  852. ret = vasprintf(&msg, format, args);
  853. va_end(args);
  854. if (ret < 0)
  855. error(_("failed to allocate memory"));
  856. error(_("%s corrupt: %s"), ctx->filename, msg);
  857. }
  858. static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(2)
  859. altdb_interrupt_parsing(struct altdb_context *ctx, const char *format, ...)
  860. {
  861. longjmp(ctx->on_error, 1);
  862. }
  863. static void
  864. altdb_print_line(struct altdb_context *ctx, const char *line)
  865. {
  866. if (strchr(line, '\n') != NULL)
  867. error(_("newlines prohibited in update-alternatives files (%s)"),
  868. line);
  869. if (fprintf(ctx->fh, "%s\n", line) < (int) strlen(line) + 1)
  870. error(_("while writing %s: %s"), ctx->filename, strerror(errno));
  871. }
  872. static bool
  873. alternative_parse_slave(struct alternative *a, struct altdb_context *ctx)
  874. {
  875. char *name, *linkname;
  876. struct slave_link *sl;
  877. name = altdb_get_line(ctx, _("slave name"));
  878. if (!strlen(name)) { /* End of list */
  879. free(name);
  880. return false;
  881. }
  882. if (alternative_has_slave(a, name)) {
  883. sl = alternative_get_slave(a, name);
  884. free(name);
  885. ctx->bad_format(ctx, _("duplicate slave %s"), sl->name);
  886. }
  887. linkname = altdb_get_line(ctx, _("slave link"));
  888. if (strcmp(linkname, a->master_link) == 0) {
  889. free(linkname);
  890. free(name);
  891. ctx->bad_format(ctx, _("slave link same as main link %s"),
  892. a->master_link);
  893. }
  894. for(sl = a->slaves; sl; sl = sl->next) {
  895. if (strcmp(linkname, sl->link) == 0) {
  896. free(linkname);
  897. free(name);
  898. ctx->bad_format(ctx, _("duplicate slave link %s"),
  899. sl->link);
  900. }
  901. }
  902. alternative_add_slave(a, name, linkname);
  903. return true;
  904. }
  905. static bool
  906. alternative_parse_fileset(struct alternative *a, struct altdb_context *ctx,
  907. bool *modified, bool must_not_die)
  908. {
  909. struct fileset *fs;
  910. struct slave_link *sl;
  911. struct stat st;
  912. char *master_file;
  913. master_file = altdb_get_line(ctx, _("master file"));
  914. if (!strlen(master_file)) { /* End of list */
  915. free(master_file);
  916. return false;
  917. }
  918. for (fs = a->choices; fs; fs = fs->next) {
  919. if (strcmp(fs->master_file, master_file) == 0) {
  920. free(master_file);
  921. ctx->bad_format(ctx, _("duplicate path %s"),
  922. fs->master_file);
  923. }
  924. }
  925. if (stat(master_file, &st)) {
  926. char *junk;
  927. if (errno != ENOENT)
  928. error(_("cannot stat %s: %s"), master_file,
  929. strerror(errno));
  930. /* File not found - remove. */
  931. if (!must_not_die)
  932. warning(_("alternative %s (part of link group %s) "
  933. "doesn't exist. Removing from list of "
  934. "alternatives."), master_file, a->master_name);
  935. junk = altdb_get_line(ctx, _("priority"));
  936. free(junk);
  937. for (sl = a->slaves; sl; sl = sl->next) {
  938. junk = altdb_get_line(ctx, _("slave file"));
  939. free(junk);
  940. }
  941. *modified = true;
  942. } else {
  943. char *endptr, *prio;
  944. long int iprio;
  945. prio = altdb_get_line(ctx, _("priority"));
  946. iprio = strtol(prio, &endptr, 10);
  947. /* XXX: Leak master_file/prio on non-fatal error */
  948. if (*endptr != '\0')
  949. ctx->bad_format(ctx, _("priority of %s: %s"),
  950. master_file, prio);
  951. fs = fileset_new(master_file, (int) iprio);
  952. for (sl = a->slaves; sl; sl = sl->next) {
  953. fileset_add_slave(fs, xstrdup(sl->name),
  954. altdb_get_line(ctx, _("slave file")));
  955. }
  956. alternative_add_choice(a, fs);
  957. }
  958. return true;
  959. }
  960. static bool
  961. alternative_load(struct alternative *a, bool must_not_die)
  962. {
  963. struct altdb_context ctx;
  964. struct stat st;
  965. char *fn, *status;
  966. bool modified = false;
  967. /* Initialize parse context */
  968. if (setjmp(ctx.on_error)) {
  969. if (ctx.fh)
  970. fclose(ctx.fh);
  971. free(ctx.filename);
  972. alternative_reset(a);
  973. return false;
  974. }
  975. if (must_not_die)
  976. ctx.bad_format = altdb_interrupt_parsing;
  977. else
  978. ctx.bad_format = altdb_parse_error;
  979. xasprintf(&fn, "%s/%s", admdir, a->master_name);
  980. ctx.filename = fn;
  981. /* Verify the alternative exists */
  982. if (stat(ctx.filename, &st) == -1) {
  983. if (errno == ENOENT)
  984. return false;
  985. else
  986. error(_("unable to stat %s: %s"), ctx.filename,
  987. strerror(errno));
  988. }
  989. if (st.st_size == 0) {
  990. return false;
  991. }
  992. /* Open the database file */
  993. ctx.fh = fopen(ctx.filename, "r");
  994. if (ctx.fh == NULL)
  995. error(_("unable to read %s: %s"), ctx.filename, strerror(errno));
  996. /* Start parsing mandatory attributes (link+status) of the alternative */
  997. alternative_reset(a);
  998. status = altdb_get_line(&ctx, _("status"));
  999. if (strcmp(status, "auto") != 0 && strcmp(status, "manual") != 0)
  1000. ctx.bad_format(&ctx, _("invalid status"));
  1001. alternative_set_status(a, (strcmp(status, "auto") == 0) ?
  1002. ALT_ST_AUTO : ALT_ST_MANUAL);
  1003. free(status);
  1004. alternative_set_link(a, altdb_get_line(&ctx, _("master link")));
  1005. /* Parse the description of the slaves links of the alternative */
  1006. while (alternative_parse_slave(a, &ctx));
  1007. /* Parse the available choices in the alternative */
  1008. while (alternative_parse_fileset(a, &ctx, &modified, must_not_die));
  1009. /* Close database file */
  1010. if (fclose(ctx.fh))
  1011. error(_("unable to close %s: %s"), ctx.filename, strerror(errno));
  1012. free(ctx.filename);
  1013. /* Initialize the modified field which has been erroneously changed
  1014. * by the various alternative_(add|set)_* calls:
  1015. * false unless a choice has been auto-cleaned */
  1016. a->modified = modified;
  1017. return true;
  1018. }
  1019. static void
  1020. alternative_save(struct alternative *a, const char *file)
  1021. {
  1022. struct altdb_context ctx;
  1023. struct slave_link *sl, *sl_prev;
  1024. struct fileset *fs;
  1025. /* Cleanup unused slaves before writing admin file. */
  1026. sl_prev = NULL;
  1027. for (sl = a->slaves; sl; sl_prev = sl, sl = sl->next) {
  1028. bool has_slave = false;
  1029. for (fs = a->choices; fs; fs = fs->next) {
  1030. if (fileset_has_slave(fs, sl->name)) {
  1031. has_slave = true;
  1032. break;
  1033. }
  1034. }
  1035. if (!has_slave) {
  1036. struct slave_link *sl_rm;
  1037. verbose(_("discarding obsolete slave link %s (%s)."),
  1038. sl->name, sl->link);
  1039. if (sl_prev)
  1040. sl_prev->next = sl->next;
  1041. else
  1042. a->slaves = sl->next;
  1043. sl_rm = sl;
  1044. sl = sl_prev ? sl_prev : a->slaves;
  1045. slave_link_free(sl_rm);
  1046. if (!sl)
  1047. break; /* no other slave left */
  1048. }
  1049. }
  1050. /* Sort entries */
  1051. alternative_sort_slaves(a);
  1052. alternative_sort_choices(a);
  1053. /* Write admin file. */
  1054. ctx.filename = xstrdup(file);
  1055. ctx.fh = fopen(file, "w");
  1056. if (ctx.fh == NULL)
  1057. error(_("cannot write %s: %s"), file, strerror(errno));
  1058. altdb_print_line(&ctx, alternative_status_string(a->status));
  1059. altdb_print_line(&ctx, a->master_link);
  1060. for (sl = a->slaves; sl; sl = sl->next) {
  1061. altdb_print_line(&ctx, sl->name);
  1062. altdb_print_line(&ctx, sl->link);
  1063. }
  1064. altdb_print_line(&ctx, "");
  1065. for (fs = a->choices; fs; fs = fs->next) {
  1066. char *prio;
  1067. altdb_print_line(&ctx, fs->master_file);
  1068. xasprintf(&prio, "%d", fs->priority);
  1069. altdb_print_line(&ctx, prio);
  1070. free(prio);
  1071. for (sl = a->slaves; sl; sl = sl->next) {
  1072. if (fileset_has_slave(fs, sl->name))
  1073. altdb_print_line(&ctx,
  1074. fileset_get_slave(fs, sl->name));
  1075. else
  1076. altdb_print_line(&ctx, "");
  1077. }
  1078. }
  1079. altdb_print_line(&ctx, "");
  1080. /* Close database file */
  1081. if (fclose(ctx.fh))
  1082. error(_("unable to close %s: %s"), ctx.filename, strerror(errno));
  1083. }
  1084. static struct fileset *
  1085. alternative_get_best(struct alternative *a)
  1086. {
  1087. struct fileset *fs, *best;
  1088. for (best = fs = a->choices; fs; fs = fs->next)
  1089. if (fs->priority > best->priority)
  1090. best = fs;
  1091. return best;
  1092. }
  1093. static bool
  1094. alternative_has_current_link(struct alternative *a)
  1095. {
  1096. struct stat st;
  1097. char *curlink;
  1098. xasprintf(&curlink, "%s/%s", altdir, a->master_name);
  1099. if (lstat(curlink, &st)) {
  1100. if (errno == ENOENT) {
  1101. free(curlink);
  1102. return false;
  1103. }
  1104. error(_("cannot stat %s: %s"), curlink, strerror(errno));
  1105. } else {
  1106. free(curlink);
  1107. return true;
  1108. }
  1109. }
  1110. static char *
  1111. alternative_get_current(struct alternative *a)
  1112. {
  1113. char *curlink, *file;
  1114. if (!alternative_has_current_link(a))
  1115. return NULL;
  1116. xasprintf(&curlink, "%s/%s", altdir, a->master_name);
  1117. file = xreadlink(curlink, true);
  1118. free(curlink);
  1119. return file;
  1120. }
  1121. static void
  1122. alternative_display_query(struct alternative *a)
  1123. {
  1124. struct fileset *best, *fs;
  1125. struct slave_link *sl;
  1126. char *current;
  1127. pr("Link: %s", a->master_name);
  1128. pr("Status: %s", alternative_status_string(a->status));
  1129. best = alternative_get_best(a);
  1130. if (best)
  1131. pr("Best: %s", best->master_file);
  1132. current = alternative_get_current(a);
  1133. if (current) {
  1134. pr("Value: %s", current);
  1135. free(current);
  1136. } else {
  1137. pr("Value: none");
  1138. }
  1139. for (fs = a->choices; fs; fs = fs->next) {
  1140. printf("\n");
  1141. pr("Alternative: %s", fs->master_file);
  1142. pr("Priority: %d", fs->priority);
  1143. if (alternative_slaves_count(a) == 0)
  1144. continue;
  1145. pr("Slaves:");
  1146. for (sl = a->slaves; sl; sl = sl->next) {
  1147. if (fileset_has_slave(fs, sl->name))
  1148. pr(" %s %s", sl->name,
  1149. fileset_get_slave(fs, sl->name));
  1150. }
  1151. }
  1152. }
  1153. static void
  1154. alternative_display_user(struct alternative *a)
  1155. {
  1156. char *current;
  1157. struct fileset *fs;
  1158. struct slave_link *sl;
  1159. pr("%s - %s", a->master_name,
  1160. (a->status == ALT_ST_AUTO) ? _("auto mode") : _("manual mode"));
  1161. current = alternative_get_current(a);
  1162. if (current) {
  1163. pr(_(" link currently points to %s"), current);
  1164. free(current);
  1165. } else {
  1166. pr(_(" link currently absent"));
  1167. }
  1168. for (fs = a->choices; fs; fs = fs->next) {
  1169. pr(_("%s - priority %d"), fs->master_file, fs->priority);
  1170. for (sl = a->slaves; sl; sl = sl->next) {
  1171. if (fileset_has_slave(fs, sl->name))
  1172. pr(_(" slave %s: %s"), sl->name,
  1173. fileset_get_slave(fs, sl->name));
  1174. }
  1175. }
  1176. fs = alternative_get_best(a);
  1177. if (fs)
  1178. pr(_("Current 'best' version is '%s'."), fs->master_file);
  1179. else
  1180. pr(_("No versions available."));
  1181. }
  1182. static void
  1183. alternative_display_list(struct alternative *a)
  1184. {
  1185. struct fileset *fs;
  1186. for (fs = a->choices; fs; fs = fs->next)
  1187. pr("%s", fs->master_file);
  1188. }
  1189. static const char *
  1190. alternative_select_choice(struct alternative *a)
  1191. {
  1192. char *current, *ret, selection[_POSIX_PATH_MAX];
  1193. struct fileset *best, *fs;
  1194. int len, idx;
  1195. current = alternative_get_current(a);
  1196. best = alternative_get_best(a);
  1197. assert(best);
  1198. for (;;) {
  1199. const char *mark;
  1200. int n_choices;
  1201. n_choices = alternative_choices_count(a);
  1202. pr(P_("There is %d choice for the alternative %s (providing %s).",
  1203. "There are %d choices for the alternative %s (providing %s).",
  1204. n_choices), n_choices, a->master_name, a->master_link);
  1205. printf("\n");
  1206. len = 15;
  1207. for (fs = a->choices; fs; fs = fs->next)
  1208. len = max(len, (int)strlen(fs->master_file) + 1);
  1209. pr(" %-12.12s %-*.*s %-10.10s %s", _("Selection"), len, len,
  1210. _("Path"), _("Priority"), _("Status"));
  1211. pr("------------------------------------------------------------");
  1212. if (a->status == ALT_ST_AUTO && current &&
  1213. strcmp(current, best->master_file) == 0)
  1214. mark = "*";
  1215. else
  1216. mark = " ";
  1217. pr("%s %-12d %-*s % -10d %s", mark, 0, len, best->master_file,
  1218. best->priority, _("auto mode"));
  1219. idx = 1;
  1220. for (fs = a->choices; fs; fs = fs->next) {
  1221. if (a->status == ALT_ST_MANUAL && current &&
  1222. strcmp(current, fs->master_file) == 0)
  1223. mark = "*";
  1224. else
  1225. mark = " ";
  1226. pr("%s %-12d %-*s % -10d %s", mark, idx, len,
  1227. fs->master_file, fs->priority, _("manual mode"));
  1228. idx++;
  1229. }
  1230. printf("\n");
  1231. printf(_("Press enter to keep the current choice[*], "
  1232. "or type selection number: "));
  1233. ret = fgets(selection, sizeof(selection), stdin);
  1234. if (ret == NULL || strlen(selection) == 0) {
  1235. free(current);
  1236. return NULL;
  1237. }
  1238. selection[strlen(selection) - 1] = '\0';
  1239. if (strlen(selection) == 0)
  1240. return current;
  1241. idx = strtol(selection, &ret, 10);
  1242. if (*ret == '\0') {
  1243. /* Look up by index */
  1244. if (idx == 0) {
  1245. alternative_set_status(a, ALT_ST_AUTO);
  1246. free(current);
  1247. return xstrdup(best->master_file);
  1248. }
  1249. idx--;
  1250. for (fs = a->choices; idx && fs; idx--)
  1251. fs = fs->next;
  1252. if (fs) {
  1253. alternative_set_status(a, ALT_ST_MANUAL);
  1254. free(current);
  1255. return xstrdup(fs->master_file);
  1256. }
  1257. } else {
  1258. /* Look up by name */
  1259. for (fs = a->choices; fs; fs = fs->next) {
  1260. if (strcmp(fs->master_file, selection) == 0) {
  1261. alternative_set_status(a, ALT_ST_MANUAL);
  1262. free(current);
  1263. return xstrdup(selection);
  1264. }
  1265. }
  1266. }
  1267. }
  1268. free(current);
  1269. return NULL;
  1270. }
  1271. static void
  1272. alternative_add_commit_op(struct alternative *a, enum opcode opcode,
  1273. const char *arg_a, const char *arg_b)
  1274. {
  1275. struct commit_operation *op, *cur;
  1276. op = xmalloc(sizeof(*op));
  1277. op->opcode = opcode;
  1278. op->arg_a = xstrdup(arg_a);
  1279. op->arg_b = xstrdup(arg_b);
  1280. op->next = NULL;
  1281. /* Add at the end */
  1282. cur = a->commit_ops;
  1283. while (cur && cur->next)
  1284. cur = cur->next;
  1285. if (cur)
  1286. cur->next = op;
  1287. else
  1288. a->commit_ops = op;
  1289. }
  1290. static void
  1291. alternative_commit(struct alternative *a)
  1292. {
  1293. struct commit_operation *op;
  1294. for (op = a->commit_ops; op; op = op->next) {
  1295. switch (op->opcode) {
  1296. case opcode_nop:
  1297. break;
  1298. case opcode_rm:
  1299. checked_rm(op->arg_a);
  1300. break;
  1301. case opcode_mv:
  1302. checked_mv(op->arg_a, op->arg_b);
  1303. break;
  1304. }
  1305. }
  1306. while (a->commit_ops) {
  1307. op = a->commit_ops;
  1308. a->commit_ops = op->next;
  1309. commit_operation_free(op);
  1310. }
  1311. }
  1312. static void
  1313. alternative_prepare_install_single(struct alternative *a, const char *name,
  1314. const char *linkname, const char *file)
  1315. {
  1316. char *fntmp, *fn;
  1317. struct stat st;
  1318. bool create_link;
  1319. /* Create link in /etc/alternatives. */
  1320. xasprintf(&fntmp, "%s/%s" DPKG_TMP_EXT, altdir, name);
  1321. xasprintf(&fn, "%s/%s", altdir, name);
  1322. checked_rm(fntmp);
  1323. checked_symlink(file, fntmp);
  1324. alternative_add_commit_op(a, opcode_mv, fntmp, fn);
  1325. free(fntmp);
  1326. errno = 0;
  1327. if (lstat(linkname, &st) == -1) {
  1328. if (errno != ENOENT)
  1329. error(_("cannot stat %s: %s"), linkname,
  1330. strerror(errno));
  1331. create_link = true;
  1332. } else {
  1333. create_link = S_ISLNK(st.st_mode);
  1334. }
  1335. if (create_link || opt_force) {
  1336. /* Create alternative link. */
  1337. xasprintf(&fntmp, "%s" DPKG_TMP_EXT, linkname);
  1338. checked_rm(fntmp);
  1339. checked_symlink(fn, fntmp);
  1340. alternative_add_commit_op(a, opcode_mv, fntmp, linkname);
  1341. free(fntmp);
  1342. } else {
  1343. warning(_("not replacing %s with a link."), linkname);
  1344. }
  1345. free(fn);
  1346. }
  1347. static void
  1348. alternative_prepare_install(struct alternative *a, const char *choice)
  1349. {
  1350. struct slave_link *sl;
  1351. struct fileset *fs;
  1352. fs = alternative_get_fileset(a, choice);
  1353. if (fs == NULL)
  1354. error(_("can't install unknown choice %s"), choice);
  1355. /* Take care of master alternative */
  1356. alternative_prepare_install_single(a, a->master_name, a->master_link,
  1357. choice);
  1358. /* Take care of slaves alternatives */
  1359. for (sl = a->slaves; sl; sl = sl->next) {
  1360. char *fn;
  1361. if (fileset_can_install_slave(fs, sl->name)) {
  1362. alternative_prepare_install_single(a, sl->name,
  1363. sl->link, fileset_get_slave(fs, sl->name));
  1364. continue;
  1365. }
  1366. /* Slave can't be installed */
  1367. if (fileset_has_slave(fs, sl->name))
  1368. warning(_("skip creation of %s because associated "
  1369. "file %s (of link group %s) doesn't exist."),
  1370. sl->link, fileset_get_slave(fs, sl->name),
  1371. a->master_name);
  1372. /* Drop unused slave. */
  1373. xasprintf(&fn, "%s/%s", altdir, sl->name);
  1374. alternative_add_commit_op(a, opcode_rm, sl->link, NULL);
  1375. alternative_add_commit_op(a, opcode_rm, fn, NULL);
  1376. free(fn);
  1377. }
  1378. }
  1379. static void
  1380. alternative_remove(struct alternative *a)
  1381. {
  1382. char *fn;
  1383. struct stat st;
  1384. struct slave_link *sl;
  1385. xasprintf(&fn, "%s" DPKG_TMP_EXT, a->master_link);
  1386. checked_rm(fn);
  1387. free(fn);
  1388. if (lstat(a->master_link, &st) == 0 && S_ISLNK(st.st_mode))
  1389. checked_rm(a->master_link);
  1390. xasprintf(&fn, "%s/%s" DPKG_TMP_EXT, altdir, a->master_name);
  1391. checked_rm(fn);
  1392. free(fn);
  1393. xasprintf(&fn, "%s/%s", altdir, a->master_name);
  1394. checked_rm(fn);
  1395. free(fn);
  1396. for (sl = a->slaves; sl; sl = sl->next) {
  1397. xasprintf(&fn, "%s" DPKG_TMP_EXT, sl->link);
  1398. checked_rm(fn);
  1399. free(fn);
  1400. if (lstat(sl->link, &st) == 0 && S_ISLNK(st.st_mode))
  1401. checked_rm(sl->link);
  1402. xasprintf(&fn, "%s/%s" DPKG_TMP_EXT, altdir, sl->name);
  1403. checked_rm(fn);
  1404. free(fn);
  1405. xasprintf(&fn, "%s/%s", altdir, sl->name);
  1406. checked_rm(fn);
  1407. free(fn);
  1408. }
  1409. /* Drop admin file */
  1410. xasprintf(&fn, "%s/%s", admdir, a->master_name);
  1411. checked_rm(fn);
  1412. free(fn);
  1413. }
  1414. static bool
  1415. alternative_is_broken(struct alternative *a)
  1416. {
  1417. char *altlnk, *wanted, *current;
  1418. struct fileset *fs;
  1419. struct slave_link *sl;
  1420. struct stat st;
  1421. if (!alternative_has_current_link(a))
  1422. return true;
  1423. /* Check master link */
  1424. altlnk = xreadlink(a->master_link, false);
  1425. if (!altlnk)
  1426. return true;
  1427. xasprintf(&wanted, "%s/%s", altdir, a->master_name);
  1428. if (strcmp(altlnk, wanted) != 0) {
  1429. free(wanted);
  1430. free(altlnk);
  1431. return true;
  1432. }
  1433. free(wanted);
  1434. free(altlnk);
  1435. /* Stop if we have an unmanaged alternative */
  1436. current = alternative_get_current(a);
  1437. if (!alternative_has_choice(a, current)) {
  1438. free(current);
  1439. return false;
  1440. }
  1441. fs = alternative_get_fileset(a, current);
  1442. free(current);
  1443. /* Check slaves */
  1444. for (sl = a->slaves; sl; sl = sl->next) {
  1445. if (fileset_can_install_slave(fs, sl->name)) {
  1446. char *sl_altlnk, *sl_current;
  1447. /* Verify link -> /etc/alternatives/foo */
  1448. sl_altlnk = xreadlink(sl->link, false);
  1449. if (!sl_altlnk)
  1450. return true;
  1451. xasprintf(&wanted, "%s/%s", altdir, sl->name);
  1452. if (strcmp(sl_altlnk, wanted) != 0) {
  1453. free(wanted);
  1454. free(sl_altlnk);
  1455. return true;
  1456. }
  1457. free(sl_altlnk);
  1458. /* Verify /etc/alternatives/foo -> file */
  1459. sl_current = xreadlink(wanted, false);
  1460. free(wanted);
  1461. if (!sl_current)
  1462. return true;
  1463. if (strcmp(sl_current, fileset_get_slave(fs, sl->name)) != 0) {
  1464. free(sl_current);
  1465. return true;
  1466. }
  1467. free(sl_current);
  1468. } else {
  1469. char *sl_altlnk;
  1470. /* Slave link must not exist. */
  1471. if (lstat(sl->link, &st) == 0)
  1472. return true;
  1473. xasprintf(&sl_altlnk, "%s/%s", altdir, sl->name);
  1474. if (lstat(sl_altlnk, &st) == 0) {
  1475. free(sl_altlnk);
  1476. return true;
  1477. }
  1478. free(sl_altlnk);
  1479. }
  1480. }
  1481. return false;
  1482. }
  1483. struct alternative_map {
  1484. struct alternative_map *next;
  1485. const char *key;
  1486. struct alternative *item;
  1487. };
  1488. static struct alternative_map *
  1489. alternative_map_new(const char *key, struct alternative *a)
  1490. {
  1491. struct alternative_map *am;
  1492. am = xmalloc(sizeof(*am));
  1493. am->next = NULL;
  1494. am->key = key;
  1495. am->item = a;
  1496. return am;
  1497. }
  1498. static struct alternative *
  1499. alternative_map_find(struct alternative_map *am, const char *key)
  1500. {
  1501. for (; am; am = am->next)
  1502. if (am->key && strcmp(am->key, key) == 0)
  1503. return am->item;
  1504. return NULL;
  1505. }
  1506. static void
  1507. alternative_map_add(struct alternative_map *am, const char *key, struct alternative *a)
  1508. {
  1509. if (am->key == NULL) {
  1510. am->key = key;
  1511. am->item = a;
  1512. } else {
  1513. struct alternative_map *new = alternative_map_new(key, a);
  1514. while(am->next)
  1515. am = am->next;
  1516. am->next = new;
  1517. }
  1518. }
  1519. static const char *
  1520. get_argv_string(int argc, char **argv)
  1521. {
  1522. static char string[2048];
  1523. size_t cur_len;
  1524. int i;
  1525. string[0] = '\0';
  1526. cur_len = 0;
  1527. for (i = 1; i < argc; i++) {
  1528. size_t arg_len = strlen(argv[i]);
  1529. if (cur_len + arg_len + 2 > sizeof(string))
  1530. break;
  1531. if (cur_len) {
  1532. strcpy(string + cur_len, " ");
  1533. cur_len++;
  1534. }
  1535. strcpy(string + cur_len, argv[i]);
  1536. cur_len += arg_len;
  1537. }
  1538. return string;
  1539. }
  1540. static void
  1541. alternative_set_selection(struct alternative_map *all, const char *name,
  1542. const char *status, const char *choice)
  1543. {
  1544. struct alternative *a;
  1545. debug("set_selection(%s, %s, %s)", name, status, choice);
  1546. if ((a = alternative_map_find(all, name))) {
  1547. char *cmd;
  1548. if (strcmp(status, "auto") == 0) {
  1549. xasprintf(&cmd, PROGNAME " --auto %s", name);
  1550. pr(_("Call %s."), cmd);
  1551. free(cmd);
  1552. subcall(prog_path, "--auto", name, NULL);
  1553. } else if (alternative_has_choice(a, choice)) {
  1554. xasprintf(&cmd, PROGNAME " --set %s %s",
  1555. name, choice);
  1556. pr(_("Call %s."), cmd);
  1557. free(cmd);
  1558. subcall(prog_path, "--set", name, choice, NULL);
  1559. } else {
  1560. pr(_("Alternative %s unchanged because choice "
  1561. "%s is not available."), name, choice);
  1562. }
  1563. } else {
  1564. pr(_("Skip unknown alternative %s."), name);
  1565. }
  1566. }
  1567. static void
  1568. alternative_set_selections(struct alternative_map *all, FILE* input, const char *desc)
  1569. {
  1570. const char *prefix = "[" PROGNAME "--set-selections] ";
  1571. for (;;) {
  1572. char line[1024], *res, *name, *status, *choice;
  1573. size_t len, i;
  1574. errno = 0;
  1575. /* Can't use scanf("%s %s %s") because choice can
  1576. * contain a space */
  1577. name = status = choice = NULL;
  1578. res = fgets(line, sizeof(line), input);
  1579. if (res == NULL && errno) {
  1580. error(_("while reading %s: %s"), desc, strerror(errno));
  1581. } else if (res == NULL) {
  1582. break;
  1583. }
  1584. len = strlen(line);
  1585. if (len == 0 || line[len - 1] != '\n') {
  1586. error(_("line too long or not terminated while "
  1587. "trying to read %s"), desc);
  1588. }
  1589. line[len - 1] = '\0';
  1590. len--;
  1591. /* Delimit name string in line */
  1592. i = 0;
  1593. name = line;
  1594. while (i < len && !isblank(line[i]))
  1595. i++;
  1596. if (i >= len) {
  1597. printf("%s", prefix);
  1598. pr(_("Skip invalid line: %s"), line);
  1599. continue;
  1600. }
  1601. line[i++] = '\0';
  1602. while (i < len && isblank(line[i]))
  1603. i++;
  1604. /* Delimit status string in line */
  1605. status = line + i;
  1606. while (i < len && !isblank(line[i]))
  1607. i++;
  1608. if (i >= len) {
  1609. printf("%s", prefix);
  1610. pr(_("Skip invalid line: %s"), line);
  1611. continue;
  1612. }
  1613. line[i++] = '\0';
  1614. while (i < len && isblank(line[i]))
  1615. i++;
  1616. /* Delimit choice string in the line */
  1617. if (i >= len) {
  1618. printf("%s", prefix);
  1619. pr(_("Skip invalid line: %s"), line);
  1620. continue;
  1621. }
  1622. choice = line + i;
  1623. printf("%s", prefix);
  1624. alternative_set_selection(all, name, status, choice);
  1625. }
  1626. }
  1627. static void
  1628. alternative_evolve(struct alternative *a, struct alternative *b,
  1629. const char *cur_choice, struct fileset *fs)
  1630. {
  1631. struct slave_link *sl;
  1632. struct stat st;
  1633. bool is_link = (lstat(a->master_link, &st) == 0 && S_ISLNK(st.st_mode));
  1634. if (is_link && strcmp(a->master_link, b->master_link) != 0) {
  1635. info(_("renaming %s link from %s to %s."), b->master_name,
  1636. a->master_link, b->master_link);
  1637. checked_mv(a->master_link, b->master_link);
  1638. }
  1639. alternative_set_link(a, xstrdup(b->master_link));
  1640. /* Check if new slaves have been added, or existing
  1641. * ones renamed. */
  1642. for (sl = b->slaves; sl; sl = sl->next) {
  1643. char *new_file = NULL;
  1644. const char *old, *new;
  1645. if (!alternative_has_slave(a, sl->name)) {
  1646. alternative_add_slave(a, xstrdup(sl->name),
  1647. xstrdup(sl->link));
  1648. continue;
  1649. }
  1650. old = alternative_get_slave(a, sl->name)->link;
  1651. new = sl->link;
  1652. if (cur_choice && strcmp(cur_choice, fs->master_file) == 0) {
  1653. new_file = xstrdup(fileset_get_slave(fs, sl->name));
  1654. } else {
  1655. char *lnk;
  1656. xasprintf(&lnk, "%s/%s", altdir, sl->name);
  1657. new_file = xreadlink(lnk, false);
  1658. free(lnk);
  1659. }
  1660. if (strcmp(old, new) != 0 && lstat(old, &st) == 0 &&
  1661. S_ISLNK(st.st_mode)) {
  1662. if (stat(new_file, &st) == 0) {
  1663. info(_("renaming %s slave link from %s to %s."),
  1664. sl->name, old, new);
  1665. checked_mv(old, new);
  1666. } else {
  1667. checked_rm(old);
  1668. }
  1669. }
  1670. free(new_file);
  1671. alternative_add_slave(a, xstrdup(sl->name), xstrdup(sl->link));
  1672. }
  1673. }
  1674. /*
  1675. * Main program
  1676. */
  1677. #define MISSING_ARGS(nb) (argc < i + nb + 1)
  1678. int
  1679. main(int argc, char **argv)
  1680. {
  1681. /* Alternative worked on. */
  1682. struct alternative *a = NULL;
  1683. /* Alternative to install. */
  1684. struct alternative *inst_alt = NULL;
  1685. /* Set of files to install in the alternative. */
  1686. struct fileset *fileset = NULL;
  1687. /* Path of alternative we are offering. */
  1688. char *path = NULL, *current_choice = NULL;
  1689. /* Alternatives maps for checks */
  1690. struct alternative_map *alt_map_obj, *alt_map_links, *alt_map_parent;
  1691. struct dirent **table;
  1692. const char *new_choice = NULL;
  1693. int i = 0, count;
  1694. setlocale(LC_ALL, "");
  1695. bindtextdomain("dpkg", LOCALEDIR);
  1696. textdomain("dpkg");
  1697. if (setvbuf(stdout, NULL, _IONBF, 0))
  1698. error("setvbuf failed: %s", strerror(errno));
  1699. prog_path = argv[0];
  1700. for (i = 1; i < argc; i++) {
  1701. if (strstr(argv[i], "--") != argv[i]) {
  1702. error(_("unknown argument `%s'"), argv[i]);
  1703. } else if (strcmp("--help", argv[i]) == 0) {
  1704. usage();
  1705. exit(0);
  1706. } else if (strcmp("--version", argv[i]) == 0) {
  1707. version();
  1708. exit(0);
  1709. } else if (strcmp("--verbose", argv[i]) == 0) {
  1710. opt_verbose++;
  1711. PUSH_OPT(argv[i]);
  1712. } else if (strcmp("--quiet", argv[i]) == 0) {
  1713. opt_verbose--;
  1714. PUSH_OPT(argv[i]);
  1715. } else if (strcmp("--install", argv[i]) == 0) {
  1716. long priority;
  1717. char *endptr;
  1718. set_action("install");
  1719. if (MISSING_ARGS(4))
  1720. badusage(_("--install needs <link> <name> "
  1721. "<path> <priority>"));
  1722. if (strcmp(argv[i+1], argv[i+3]) == 0)
  1723. badusage(_("<link> and <path> can't be the same"));
  1724. priority = strtol(argv[i+4], &endptr, 10);
  1725. if (*endptr != '\0')
  1726. badusage(_("priority must be an integer"));
  1727. a = alternative_new(argv[i + 2]);
  1728. inst_alt = alternative_new(argv[i + 2]);
  1729. alternative_set_status(inst_alt, ALT_ST_AUTO);
  1730. alternative_set_link(inst_alt, xstrdup(argv[i + 1]));
  1731. fileset = fileset_new(argv[i + 3], priority);
  1732. i += 4;
  1733. } else if (strcmp("--remove", argv[i]) == 0 ||
  1734. strcmp("--set", argv[i]) == 0) {
  1735. set_action(argv[i] + 2);
  1736. if (MISSING_ARGS(2))
  1737. badusage(_("--%s needs <name> <path>"), argv[i] + 2);
  1738. a = alternative_new(argv[i + 1]);
  1739. path = xstrdup(argv[i + 2]);
  1740. i += 2;
  1741. } else if (strcmp("--display", argv[i]) == 0 ||
  1742. strcmp("--query", argv[i]) == 0 ||
  1743. strcmp("--auto", argv[i]) == 0 ||
  1744. strcmp("--config", argv[i]) == 0 ||
  1745. strcmp("--list", argv[i]) == 0 ||
  1746. strcmp("--remove-all", argv[i]) == 0) {
  1747. set_action(argv[i] + 2);
  1748. if (MISSING_ARGS(1))
  1749. badusage(_("--%s needs <name>"), argv[i] + 2);
  1750. a = alternative_new(argv[i + 1]);
  1751. i++;
  1752. } else if (strcmp("--all", argv[i]) == 0 ||
  1753. strcmp("--get-selections", argv[i]) == 0 ||
  1754. strcmp("--set-selections", argv[i]) == 0) {
  1755. set_action(argv[i] + 2);
  1756. } else if (strcmp("--slave", argv[i]) == 0) {
  1757. char *slink, *sname, *spath;
  1758. struct slave_link *sl;
  1759. if (action && strcmp(action, "install") != 0)
  1760. badusage(_("--slave only allowed with --install"));
  1761. if (MISSING_ARGS(3))
  1762. badusage(_("--slave needs <link> <name> <path>"));
  1763. slink = xstrdup(argv[i + 1]);
  1764. sname = xstrdup(argv[i + 2]);
  1765. spath = xstrdup(argv[i + 3]);
  1766. if (strcmp(slink, spath) == 0)
  1767. badusage(_("<link> and <path> can't be the same"));
  1768. if (strcmp(inst_alt->master_name, sname) == 0)
  1769. badusage(_("name %s is both primary and slave"),
  1770. sname);
  1771. if (strcmp(slink, inst_alt->master_link) == 0)
  1772. badusage(_("link %s is both primary and slave"),
  1773. slink);
  1774. if (alternative_has_slave(inst_alt, sname))
  1775. badusage(_("slave name %s duplicated"), sname);
  1776. for (sl = inst_alt->slaves; sl; sl = sl->next) {
  1777. const char *linkname = sl->link;
  1778. if (linkname == NULL)
  1779. linkname = "";
  1780. if (strcmp(linkname, slink) == 0)
  1781. badusage(_("slave link %s duplicated"),
  1782. slink);
  1783. }
  1784. alternative_add_slave(inst_alt, sname, slink);
  1785. fileset_add_slave(fileset, xstrdup(sname), spath);
  1786. i+= 3;
  1787. } else if (strcmp("--log", argv[i]) == 0) {
  1788. if (MISSING_ARGS(1))
  1789. badusage(_("--%s needs a <file> argument"), "log");
  1790. PUSH_OPT(argv[i]);
  1791. PUSH_OPT(argv[i + 1]);
  1792. log_file = argv[i + 1];
  1793. i++;
  1794. } else if (strcmp("--altdir", argv[i]) == 0) {
  1795. if (MISSING_ARGS(1))
  1796. badusage(_("--%s needs a <directory> argument"), "log");
  1797. PUSH_OPT(argv[i]);
  1798. PUSH_OPT(argv[i + 1]);
  1799. altdir = argv[i + 1];
  1800. i++;
  1801. } else if (strcmp("--admindir", argv[i]) == 0) {
  1802. if (MISSING_ARGS(1))
  1803. badusage(_("--%s needs a <directory> argument"), "log");
  1804. PUSH_OPT(argv[i]);
  1805. PUSH_OPT(argv[i + 1]);
  1806. admdir = argv[i + 1];
  1807. i++;
  1808. } else if (strcmp("--skip-auto", argv[i]) == 0) {
  1809. opt_skip_auto = 1;
  1810. PUSH_OPT(argv[i]);
  1811. } else if (strcmp("--force", argv[i]) == 0) {
  1812. opt_force = 1;
  1813. PUSH_OPT(argv[i]);
  1814. } else {
  1815. badusage(_("unknown option `%s'"), argv[i]);
  1816. }
  1817. }
  1818. if (!action)
  1819. badusage(_("need --display, --query, --list, --get-selections, "
  1820. "--config, --set, --set-selections, --install, "
  1821. "--remove, --all, --remove-all or --auto"));
  1822. /* Load infos about all alternatives to be able to check for mistakes. */
  1823. alt_map_obj = alternative_map_new(NULL, NULL);
  1824. alt_map_links = alternative_map_new(NULL, NULL);
  1825. alt_map_parent = alternative_map_new(NULL, NULL);
  1826. count = get_all_alternatives(&table);
  1827. for (i = 0; i < count; i++) {
  1828. struct slave_link *sl;
  1829. struct alternative *a_new = alternative_new(table[i]->d_name);
  1830. if (!alternative_load(a_new, true)) {
  1831. alternative_free(a_new);
  1832. free(table[i]);
  1833. continue;
  1834. }
  1835. alternative_map_add(alt_map_obj, a_new->master_name, a_new);
  1836. alternative_map_add(alt_map_links, a_new->master_link, a_new);
  1837. alternative_map_add(alt_map_parent, a_new->master_name, a_new);
  1838. for (sl = a_new->slaves; sl; sl = sl->next) {
  1839. alternative_map_add(alt_map_links, sl->link, a_new);
  1840. alternative_map_add(alt_map_parent, sl->name, a_new);
  1841. }
  1842. free(table[i]);
  1843. }
  1844. /* Check that caller don't mix links between alternatives and don't mix
  1845. * alternatives between slave/master, and that the various parameters
  1846. * are fine. */
  1847. if (strcmp(action, "install") == 0) {
  1848. struct alternative *found;
  1849. struct stat st;
  1850. struct slave_link *sl;
  1851. found = alternative_map_find(alt_map_parent,
  1852. inst_alt->master_name);
  1853. if (found && strcmp(found->master_name,
  1854. inst_alt->master_name) != 0) {
  1855. char *msg;
  1856. xasprintf(&msg, _("it is a slave of %s"),
  1857. found->master_name);
  1858. error(_("alternative %s can't be master: %s"),
  1859. inst_alt->master_name, msg);
  1860. }
  1861. found = alternative_map_find(alt_map_links,
  1862. inst_alt->master_link);
  1863. if (found && strcmp(found->master_name,
  1864. inst_alt->master_name) != 0) {
  1865. found = alternative_map_find(alt_map_parent,
  1866. found->master_name);
  1867. error(_("alternative link %s is already managed by %s."),
  1868. inst_alt->master_link, found->master_name);
  1869. }
  1870. if (inst_alt->master_link[0] != '/')
  1871. error(_("alternative link is not absolute as it "
  1872. "should be: %s"), inst_alt->master_link);
  1873. if (fileset->master_file[0] != '/')
  1874. error(_("alternative path is not absolute as it "
  1875. "should be: %s"), fileset->master_file);
  1876. if (stat(fileset->master_file, &st) == -1 && errno == ENOENT)
  1877. error(_("alternative path %s doesn't exist."),
  1878. fileset->master_file);
  1879. if (strpbrk(inst_alt->master_name, "/ \t"))
  1880. error(_("alternative name (%s) must not contain '/' "
  1881. "and spaces."), inst_alt->master_name);
  1882. for (sl = inst_alt->slaves; sl; sl = sl->next) {
  1883. const char *file = fileset_get_slave(fileset, sl->name);
  1884. found = alternative_map_find(alt_map_parent, sl->name);
  1885. if (found && strcmp(found->master_name,
  1886. inst_alt->master_name) != 0) {
  1887. char *msg;
  1888. if (strcmp(found->master_name, sl->name) == 0)
  1889. xasprintf(&msg, "%s",
  1890. _("it is a master alternative."));
  1891. else
  1892. xasprintf(&msg, _("it is a slave of %s"),
  1893. found->master_name);
  1894. error(_("alternative %s can't be slave of "
  1895. "%s: %s"), sl->name,
  1896. inst_alt->master_name, msg);
  1897. }
  1898. found = alternative_map_find(alt_map_links, sl->link);
  1899. if (found && strcmp(found->master_name,
  1900. inst_alt->master_name) != 0) {
  1901. error(_("alternative link %s is already "
  1902. "managed by %s."), sl->link,
  1903. found->master_name);
  1904. }
  1905. if (sl->link[0] != '/')
  1906. error(_("alternative link is not absolute as "
  1907. "it should be: %s"), sl->link);
  1908. if (!file || file[0] != '/')
  1909. error(_("alternative path is not absolute as "
  1910. "it should be: %s"), file);
  1911. if (strpbrk(sl->name, "/ \t"))
  1912. error(_("alternative name (%s) must not contain '/' "
  1913. "and spaces."), sl->name);
  1914. }
  1915. }
  1916. /* Handle actions. */
  1917. if (strcmp(action, "all") == 0) {
  1918. config_all();
  1919. exit(0);
  1920. } else if (strcmp(action, "get-selections") == 0) {
  1921. struct alternative_map *am;
  1922. char *current;
  1923. for (am = alt_map_obj; am && am->item; am = am->next) {
  1924. current = alternative_get_current(am->item);
  1925. printf("%-30s %-8s %s\n", am->key,
  1926. alternative_status_string(am->item->status),
  1927. current ? current : "");
  1928. free(current);
  1929. }
  1930. exit(0);
  1931. } else if (strcmp(action, "set-selections") == 0) {
  1932. log_msg("run with %s", get_argv_string(argc, argv));
  1933. alternative_set_selections(alt_map_obj, stdin, _("<standard input>"));
  1934. exit(0);
  1935. }
  1936. /* Load the alternative info, stop on failure except for --install. */
  1937. if (!alternative_load(a, false) && strcmp(action, "install") != 0) {
  1938. /* FIXME: Be consistent for now with the case when we try to remove a
  1939. * non-existing path from an existing link group file. */
  1940. if (strcmp(action, "remove") == 0) {
  1941. verbose(_("no alternatives for %s."), a->master_name);
  1942. exit(0);
  1943. }
  1944. error(_("no alternatives for %s."), a->master_name);
  1945. }
  1946. if (strcmp(action, "display") == 0) {
  1947. alternative_display_user(a);
  1948. exit(0);
  1949. } else if (strcmp(action, "query") == 0) {
  1950. alternative_display_query(a);
  1951. exit(0);
  1952. } else if (strcmp(action, "list") == 0) {
  1953. alternative_display_list(a);
  1954. exit(0);
  1955. }
  1956. /* Actions below might modify the system. */
  1957. log_msg("run with %s", get_argv_string(argc, argv));
  1958. if (alternative_has_current_link(a)) {
  1959. current_choice = alternative_get_current(a);
  1960. /* Detect manually modified alternative, switch to manual. */
  1961. if (!alternative_has_choice(a, current_choice)) {
  1962. struct stat st;
  1963. char *altlink;
  1964. xasprintf(&altlink, "%s/%s", altdir, a->master_name);
  1965. if (stat(current_choice, &st) == -1 &&
  1966. errno == ENOENT) {
  1967. warning(_("%s is dangling, it will be updated "
  1968. "with best choice."), altlink);
  1969. alternative_set_status(a, ALT_ST_AUTO);
  1970. } else if (a->status != ALT_ST_MANUAL) {
  1971. warning(_("%s has been changed (manually or by "
  1972. "a script). Switching to manual "
  1973. "updates only."), altlink);
  1974. alternative_set_status(a, ALT_ST_MANUAL);
  1975. }
  1976. free(altlink);
  1977. }
  1978. } else {
  1979. /* Lack of alternative link => automatic mode. */
  1980. verbose(_("setting up automatic selection of %s."),
  1981. a->master_name);
  1982. alternative_set_status(a, ALT_ST_AUTO);
  1983. }
  1984. if (strcmp(action, "set") == 0) {
  1985. if (alternative_has_choice(a, path))
  1986. new_choice = path;
  1987. else
  1988. error(_("alternative %s for %s not registered, "
  1989. "not setting."), path, a->master_name);
  1990. alternative_set_status(a, ALT_ST_MANUAL);
  1991. } else if (strcmp(action, "auto") == 0) {
  1992. alternative_set_status(a, ALT_ST_AUTO);
  1993. new_choice = alternative_get_best(a)->master_file;
  1994. } else if (strcmp(action, "config") == 0) {
  1995. if (alternative_choices_count(a) == 0) {
  1996. pr(_("There is no program which provides %s."),
  1997. a->master_name);
  1998. pr(_("Nothing to configure."));
  1999. } else if (opt_skip_auto && a->status == ALT_ST_AUTO) {
  2000. alternative_display_user(a);
  2001. } else if (alternative_choices_count(a) == 1 &&
  2002. a->status == ALT_ST_AUTO &&
  2003. alternative_has_current_link(a)) {
  2004. char *cur = alternative_get_current(a);
  2005. pr(_("There is only one alternative in link group %s: %s"),
  2006. a->master_name, cur);
  2007. pr(_("Nothing to configure."));
  2008. free(cur);
  2009. } else {
  2010. new_choice = alternative_select_choice(a);
  2011. }
  2012. } else if (strcmp(action, "remove") == 0) {
  2013. if (alternative_has_choice(a, path))
  2014. alternative_remove_choice(a, path);
  2015. else
  2016. verbose(_("alternative %s for %s not registered, not "
  2017. "removing."), path, a->master_name);
  2018. if (current_choice && strcmp(current_choice, path) == 0) {
  2019. struct fileset *best;
  2020. /* Current choice is removed. */
  2021. if (a->status == ALT_ST_MANUAL) {
  2022. /* And it was manual, switch to auto. */
  2023. info(_("removing manually selected alternative "
  2024. "- switching %s to auto mode"),
  2025. a->master_name);
  2026. alternative_set_status(a, ALT_ST_AUTO);
  2027. }
  2028. best = alternative_get_best(a);
  2029. if (best)
  2030. new_choice = best->master_file;
  2031. }
  2032. } else if (strcmp(action, "remove-all") == 0) {
  2033. alternative_choices_free(a);
  2034. } else if (strcmp(action, "install") == 0) {
  2035. if (a->master_link) {
  2036. /* Alternative already exists, check if anything got
  2037. * updated. */
  2038. alternative_evolve(a, inst_alt, current_choice, fileset);
  2039. } else {
  2040. /* Alternative doesn't exist, create from parameters. */
  2041. alternative_free(a);
  2042. a = inst_alt;
  2043. }
  2044. alternative_add_choice(a, fileset);
  2045. if (a->status == ALT_ST_AUTO) {
  2046. new_choice = alternative_get_best(a)->master_file;
  2047. } else {
  2048. char *fn;
  2049. xasprintf(&fn, "%s/%s", altdir, a->master_name);
  2050. verbose(_("automatic updates of %s are disabled, "
  2051. "leaving it alone."), fn);
  2052. verbose(_("to return to automatic updates use "
  2053. "`update-alternatives --auto %s'."),
  2054. a->master_name);
  2055. free(fn);
  2056. }
  2057. }
  2058. /* No choice left, remove everything. */
  2059. if (!alternative_choices_count(a)) {
  2060. log_msg("link group %s fully removed", a->master_name);
  2061. alternative_remove(a);
  2062. exit(0);
  2063. }
  2064. /* New choice wanted. */
  2065. if (new_choice && (!current_choice ||
  2066. strcmp(new_choice, current_choice) != 0)) {
  2067. log_msg("link group %s updated to point to %s", a->master_name,
  2068. new_choice);
  2069. info(_("using %s to provide %s (%s) in %s."), new_choice,
  2070. a->master_link, a->master_name,
  2071. (a->status == ALT_ST_AUTO) ? _("auto mode") :
  2072. _("manual mode"));
  2073. debug("prepare_install(%s)", new_choice);
  2074. alternative_prepare_install(a, new_choice);
  2075. } else if (alternative_is_broken(a)) {
  2076. log_msg("auto-repair link group %s", a->master_name);
  2077. warning(_("forcing reinstallation of alternative %s because "
  2078. "link group %s is broken."), current_choice,
  2079. a->master_name);
  2080. if (current_choice && !alternative_has_choice(a, current_choice)) {
  2081. struct fileset *best = alternative_get_best(a);
  2082. new_choice = best->master_file;
  2083. warning(_("current alternative %s is unknown, "
  2084. "switching to %s for link group %s."),
  2085. current_choice, best->master_file,
  2086. a->master_name);
  2087. current_choice = best->master_file;
  2088. alternative_set_status(a, ALT_ST_AUTO);
  2089. }
  2090. if (current_choice)
  2091. alternative_prepare_install(a, current_choice);
  2092. }
  2093. /* Save administrative file if needed. */
  2094. if (a->modified) {
  2095. char *fntmp, *fn;
  2096. xasprintf(&fntmp, "%s/%s" DPKG_TMP_EXT, admdir, a->master_name);
  2097. xasprintf(&fn, "%s/%s", admdir, a->master_name);
  2098. debug("%s is modified and will be saved", a->master_name);
  2099. alternative_save(a, fntmp);
  2100. checked_mv(fntmp, fn);
  2101. free(fntmp);
  2102. free(fn);
  2103. }
  2104. /* Replace all symlinks in one pass. */
  2105. alternative_commit(a);
  2106. return 0;
  2107. }