summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-07-06 10:10:02 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-07-06 10:10:02 +0000
commite3ecf7ac9cb7f9881937aa9d01ad2575b53f2713 (patch)
tree993ffe6b4fb4603fe81f949f27159c69062dcc89 /utils
parentd1aa1653467440da1d8a011877732dac1d557058 (diff)
parentec0b42c0d5e4fc95a9a6bfb15606c34e3ad0e403 (diff)
downloaddpkg-e3ecf7ac9cb7f9881937aa9d01ad2575b53f2713.tar.gz
Merge git://git.debian.org/git/dpkg/dpkg
Conflicts: debian/changelog
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile.am14
-rw-r--r--utils/start-stop-daemon.c241
-rw-r--r--utils/update-alternatives.c602
3 files changed, 491 insertions, 366 deletions
diff --git a/utils/Makefile.am b/utils/Makefile.am
index b82362723..8a743d985 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -16,7 +16,7 @@ EXTRA_DIST = \
bin_PROGRAMS =
-if WITH_UPDATE_ALTERNATIVES
+if BUILD_UPDATE_ALTERNATIVES
bin_PROGRAMS += update-alternatives
endif
@@ -30,7 +30,7 @@ update_alternatives_LDADD = \
sbin_PROGRAMS =
-if WITH_START_STOP_DAEMON
+if BUILD_START_STOP_DAEMON
sbin_PROGRAMS += start-stop-daemon
start_stop_daemon_SOURCES = \
@@ -41,7 +41,7 @@ start_stop_daemon_LDADD = \
$(SSD_LIBS)
endif
-if WITH_INSTALL_INFO
+if BUILD_INSTALL_INFO
sbin_PROGRAMS += dpkg-install-info
# Automake has its own install-info rule, gah
@@ -54,15 +54,15 @@ endif
transform = s/dpkg-install-info/install-info/; $(program_transform_name)
install-data-local:
-if WITH_UPDATE_ALTERNATIVES
- $(mkdir_p) $(DESTDIR)$(sysconfdir)/alternatives
- $(mkdir_p) $(DESTDIR)$(admindir)/alternatives
+if BUILD_UPDATE_ALTERNATIVES
+ $(MKDIR_P) $(DESTDIR)$(sysconfdir)/alternatives
+ $(MKDIR_P) $(DESTDIR)$(admindir)/alternatives
$(INSTALL_DATA) $(srcdir)/README.alternatives $(DESTDIR)$(sysconfdir)/alternatives/README
endif
uninstall-local:
rm -f $(DESTDIR)$(sysconfdir)/alternatives/README
-if WITH_INSTALL_INFO
+if BUILD_INSTALL_INFO
rm -f $(DESTDIR)$(sbindir)/install-info
endif
diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index 120d5f976..2bb731fe0 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -159,6 +159,7 @@ static int testmode = 0;
static int quietmode = 0;
static int exitnodo = 1;
static int background = 0;
+static int close_io = 1;
static int mpidfile = 0;
static int signal_nr = SIGTERM;
static int user_id = -1;
@@ -301,6 +302,19 @@ tmul(struct timeval *a, int b)
a->tv_usec %= 1000000;
}
+static char *
+newpath(const char *dirname, const char *filename)
+{
+ char *path;
+ size_t path_len;
+
+ path_len = strlen(dirname) + 1 + strlen(filename) + 1;
+ path = xmalloc(path_len);
+ snprintf(path, path_len, "%s/%s", dirname, filename);
+
+ return path;
+}
+
static long
get_open_fd_max(void)
{
@@ -365,6 +379,27 @@ daemonize(void)
}
static void
+write_pidfile(const char *filename, pid_t pid)
+{
+ FILE *fp;
+ int fd;
+
+ fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666);
+ if (fd < 0)
+ fp = NULL;
+ else
+ fp = fdopen(fd, "w");
+
+ if (fp == NULL)
+ fatal("unable to open pidfile '%s' for writing", filename);
+
+ fprintf(fp, "%d\n", pid);
+
+ if (fclose(fp))
+ fatal("unable to close pidfile '%s'", filename);
+}
+
+static void
pid_list_push(struct pid_list **list, pid_t pid)
{
struct pid_list *p;
@@ -424,6 +459,7 @@ usage(void)
" scheduler (default prio is 4)\n"
" -k|--umask <mask> change the umask to <mask> before starting\n"
" -b|--background force the process to detach\n"
+" -C|--no-close do not close any file descriptor\n"
" -m|--make-pidfile create the pidfile before starting\n"
" -R|--retry <schedule> check whether processes die, and retry\n"
" -t|--test test mode, don't do anything\n"
@@ -504,19 +540,22 @@ static const struct sigpair siglist[] = {
};
static int
-parse_integer(const char *string, int *value_r)
+parse_unsigned(const char *string, int base, int *value_r)
{
- unsigned long ul;
- char *ep;
+ long value;
+ char *endptr;
if (!string[0])
return -1;
- ul = strtoul(string, &ep, 10);
- if (string == ep || ul > INT_MAX || *ep != '\0')
+ errno = 0;
+ value = strtol(string, &endptr, base);
+ if (string == endptr || *endptr != '\0' || errno != 0)
+ return -1;
+ if (value < 0 || value > INT_MAX)
return -1;
- *value_r = ul;
+ *value_r = value;
return 0;
}
@@ -525,7 +564,7 @@ parse_signal(const char *sig_str, int *sig_num)
{
unsigned int i;
- if (parse_integer(sig_str, sig_num) == 0)
+ if (parse_unsigned(sig_str, 10, sig_num) == 0)
return 0;
for (i = 0; i < array_count(siglist); i++) {
@@ -540,15 +579,7 @@ parse_signal(const char *sig_str, int *sig_num)
static int
parse_umask(const char *string, int *value_r)
{
- if (!string[0])
- return -1;
-
- errno = 0;
- *value_r = strtoul(string, NULL, 0);
- if (errno)
- return -1;
- else
- return 0;
+ return parse_unsigned(string, 0, value_r);
}
static void
@@ -577,7 +608,7 @@ parse_proc_schedule(const char *string)
policy_str = strtok(policy_str, ":");
prio_str = strtok(NULL, ":");
- if (prio_str && parse_integer(prio_str, &prio) != 0)
+ if (prio_str && parse_unsigned(prio_str, 10, &prio) != 0)
fatal("invalid process scheduler priority");
proc_sched = xmalloc(sizeof(*proc_sched));
@@ -608,7 +639,7 @@ parse_io_schedule(const char *string)
class_str = strtok(class_str, ":");
prio_str = strtok(NULL, ":");
- if (prio_str && parse_integer(prio_str, &prio) != 0)
+ if (prio_str && parse_unsigned(prio_str, 10, &prio) != 0)
fatal("invalid IO scheduler priority");
io_sched = xmalloc(sizeof(*io_sched));
@@ -671,11 +702,11 @@ parse_schedule_item(const char *string, struct schedule_item *item)
{
const char *after_hyph;
- if (!strcmp(string, "forever")) {
+ if (strcmp(string, "forever") == 0) {
item->type = sched_forever;
} else if (isdigit(string[0])) {
item->type = sched_timeout;
- if (parse_integer(string, &item->value) != 0)
+ if (parse_unsigned(string, 10, &item->value) != 0)
badusage("invalid timeout value in schedule");
} else if ((after_hyph = string + (string[0] == '-')) &&
parse_signal(after_hyph, &item->value) == 0) {
@@ -787,6 +818,7 @@ parse_options(int argc, char * const *argv)
{ "iosched", 1, NULL, 'I'},
{ "umask", 1, NULL, 'k'},
{ "background", 0, NULL, 'b'},
+ { "no-close", 0, NULL, 'C'},
{ "make-pidfile", 0, NULL, 'm'},
{ "retry", 1, NULL, 'R'},
{ "chdir", 1, NULL, 'd'},
@@ -879,6 +911,9 @@ parse_options(int argc, char * const *argv)
case 'b': /* --background */
background = 1;
break;
+ case 'C': /* --no-close */
+ close_io = 0;
+ break;
case 'm': /* --make-pidfile */
mpidfile = 1;
break;
@@ -939,6 +974,9 @@ parse_options(int argc, char * const *argv)
if (background && action != action_start)
badusage("--background is only relevant with --start");
+
+ if (!close_io && !background)
+ badusage("--no-close is only relevant with --background");
}
#if defined(OSHurd)
@@ -962,7 +1000,7 @@ init_procset(void)
}
static struct proc_stat *
-get_proc_stat (pid_t pid, ps_flags_t flags)
+get_proc_stat(pid_t pid, ps_flags_t flags)
{
struct proc_stat *ps;
ps_flags_t wanted_flags = PSTAT_PID | flags;
@@ -1006,6 +1044,25 @@ pid_is_exec(pid_t pid, const struct stat *esb)
return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
}
+#elif defined(OSHurd)
+static bool
+pid_is_exec(pid_t pid, const struct stat *esb)
+{
+ struct proc_stat *ps;
+ struct stat sb;
+ const char *filename;
+
+ ps = get_proc_stat(pid, PSTAT_ARGS);
+ if (ps == NULL)
+ return false;
+
+ filename = proc_stat_args(ps);
+
+ if (stat(filename, &sb) != 0)
+ return false;
+
+ return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
+}
#elif defined(OShpux)
static bool
pid_is_exec(pid_t pid, const struct stat *esb)
@@ -1019,12 +1076,15 @@ pid_is_exec(pid_t pid, const struct stat *esb)
}
#elif defined(HAVE_KVM_H)
static bool
-pid_is_exec(pid_t pid, const char *name)
+pid_is_exec(pid_t pid, const struct stat *esb)
{
kvm_t *kd;
- int nentries;
+ int nentries, argv_len = 0;
struct kinfo_proc *kp;
- char errbuf[_POSIX2_LINE_MAX], *pidexec;
+ struct stat sb;
+ char errbuf[_POSIX2_LINE_MAX], buf[_POSIX2_LINE_MAX];
+ char **pid_argv_p;
+ char *start_argv_0_p, *end_argv_0_p;
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
if (kd == NULL)
@@ -1032,10 +1092,32 @@ pid_is_exec(pid_t pid, const char *name)
kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries);
if (kp == NULL)
errx(1, "%s", kvm_geterr(kd));
- pidexec = (&kp->kp_proc)->p_comm;
- if (strlen(name) != strlen(pidexec))
+ pid_argv_p = kvm_getargv(kd, kp, argv_len);
+ if (pid_argv_p == NULL)
+ errx(1, "%s", kvm_geterr(kd));
+
+ /* Find and compare string. */
+ start_argv_0_p = *pid_argv_p;
+
+ /* Find end of argv[0] then copy and cut of str there. */
+ end_argv_0_p = strchr(*pid_argv_p, ' ');
+ if (end_argv_0_p == NULL)
+ /* There seems to be no space, so we have the command
+ * already in its desired form. */
+ start_argv_0_p = *pid_argv_p;
+ else {
+ /* Tests indicate that this never happens, since
+ * kvm_getargv itself cuts of tailing stuff. This is
+ * not what the manpage says, however. */
+ strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p));
+ buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0';
+ start_argv_0_p = buf;
+ }
+
+ if (stat(start_argv_0_p, &sb) != 0)
return false;
- return (strcmp(name, pidexec) == 0) ? 1 : 0;
+
+ return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
}
#endif
@@ -1143,9 +1225,31 @@ static bool
pid_is_cmd(pid_t pid, const char *name)
{
struct proc_stat *ps;
+ size_t argv0_len;
+ const char *argv0;
+ const char *binary_name;
ps = get_proc_stat(pid, PSTAT_ARGS);
- return ps && !strcmp(proc_stat_args(ps), name);
+ if (ps == NULL)
+ return false;
+
+ argv0 = proc_stat_args(ps);
+ argv0_len = strlen(argv0) + 1;
+
+ binary_name = basename(argv0);
+ if (strcmp(binary_name, name) == 0)
+ return true;
+
+ /* XXX: This is all kinds of ugly, but on the Hurd there's no way to
+ * know the command name of a process, so we have to try to match
+ * also on argv[1] for the case of an interpreted script. */
+ if (proc_stat_args_len(ps) > argv0_len) {
+ const char *script_name = basename(argv0 + argv0_len);
+
+ return strcmp(script_name, name) == 0;
+ }
+
+ return false;
}
#elif defined(OShpux)
static bool
@@ -1162,11 +1266,9 @@ static bool
pid_is_cmd(pid_t pid, const char *name)
{
kvm_t *kd;
- int nentries, argv_len = 0;
+ int nentries;
struct kinfo_proc *kp;
- char errbuf[_POSIX2_LINE_MAX], buf[_POSIX2_LINE_MAX];
- char **pid_argv_p;
- char *start_argv_0_p, *end_argv_0_p;
+ char errbuf[_POSIX2_LINE_MAX], *process_name;
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
if (kd == NULL)
@@ -1174,31 +1276,10 @@ pid_is_cmd(pid_t pid, const char *name)
kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries);
if (kp == NULL)
errx(1, "%s", kvm_geterr(kd));
- pid_argv_p = kvm_getargv(kd, kp, argv_len);
- if (pid_argv_p == NULL)
- errx(1, "%s", kvm_geterr(kd));
-
- /* Find and compare string. */
- start_argv_0_p = *pid_argv_p;
-
- /* Find end of argv[0] then copy and cut of str there. */
- end_argv_0_p = strchr(*pid_argv_p, ' ');
- if (end_argv_0_p == NULL)
- /* There seems to be no space, so we have the command
- * already in its desired form. */
- start_argv_0_p = *pid_argv_p;
- else {
- /* Tests indicate that this never happens, since
- * kvm_getargv itself cuts of tailing stuff. This is
- * not what the manpage says, however. */
- strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p));
- buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0';
- start_argv_0_p = buf;
- }
-
- if (strlen(name) != strlen(start_argv_0_p))
+ process_name = (&kp->kp_proc)->p_comm;
+ if (strlen(name) != strlen(process_name))
return false;
- return (strcmp(name, start_argv_0_p) == 0) ? 1 : 0;
+ return (strcmp(name, process_name) == 0);
}
#endif
@@ -1224,17 +1305,8 @@ pid_is_running(pid_t pid)
static enum status_code
pid_check(pid_t pid)
{
-#if defined(OSLinux) || defined(OShpux)
if (execname && !pid_is_exec(pid, &exec_stat))
return status_dead;
-#elif defined(HAVE_KVM_H)
- if (execname && !pid_is_exec(pid, execname))
- return status_dead;
-#elif defined(OSHurd) || defined(OSFreeBSD) || defined(OSNetBSD)
- /* Let's try this to see if it works. */
- if (execname && !pid_is_cmd(pid, execname))
- return status_dead;
-#endif
if (userspec && !pid_is_user(pid, user_id))
return status_dead;
if (cmdname && !pid_is_cmd(pid, cmdname))
@@ -1594,14 +1666,13 @@ main(int argc, char **argv)
if (execname) {
char *fullexecname;
- if (changeroot) {
- int fullexecname_len = strlen(changeroot) + 1 +
- strlen(execname) + 1;
+ /* If it's a relative path, normalize it. */
+ if (execname[0] != '/')
+ execname = newpath(changedir, execname);
- fullexecname = xmalloc(fullexecname_len);
- snprintf(fullexecname, fullexecname_len, "%s/%s",
- changeroot, execname);
- } else
+ if (changeroot)
+ fullexecname = newpath(changeroot, execname);
+ else
fullexecname = execname;
if (stat(fullexecname, &exec_stat))
@@ -1692,10 +1763,10 @@ main(int argc, char **argv)
if (quietmode < 0)
printf("Starting %s...\n", startas);
*--argv = startas;
- if (background) {
+ if (background)
/* Ok, we need to detach this process. */
daemonize();
-
+ if (background && close_io) {
devnull_fd = open("/dev/null", O_RDWR);
if (devnull_fd < 0)
fatal("unable to open '%s'", "/dev/null");
@@ -1711,17 +1782,9 @@ main(int argc, char **argv)
set_io_schedule(io_sched);
if (umask_value >= 0)
umask(umask_value);
- if (mpidfile && pidfile != NULL) {
+ if (mpidfile && pidfile != NULL)
/* User wants _us_ to make the pidfile. */
- FILE *pidf = fopen(pidfile, "w");
- pid_t pidt = getpid();
- if (pidf == NULL)
- fatal("unable to open pidfile '%s' for writing",
- pidfile);
- fprintf(pidf, "%d\n", pidt);
- if (fclose(pidf))
- fatal("unable to close pidfile '%s'", pidfile);
- }
+ write_pidfile(pidfile, getpid());
if (changeroot != NULL) {
if (chdir(changeroot) < 0)
fatal("unable to chdir() to %s", changeroot);
@@ -1752,12 +1815,12 @@ main(int argc, char **argv)
fatal("unable to set uid to %s", changeuser);
}
- if (background) {
- int i;
+ /* Set a default umask for dumb programs. */
+ if (background && umask_value < 0)
+ umask(022);
- /* Set a default umask for dumb programs. */
- if (umask_value < 0)
- umask(022);
+ if (background && close_io) {
+ int i;
dup2(devnull_fd, 0); /* stdin */
dup2(devnull_fd, 1); /* stdout */
diff --git a/utils/update-alternatives.c b/utils/update-alternatives.c
index 16fd8c66c..a4f38a332 100644
--- a/utils/update-alternatives.c
+++ b/utils/update-alternatives.c
@@ -3,7 +3,7 @@
*
* Copyright © 1995 Ian Jackson <ian@davenant.greenend.org.uk>
* Copyright © 2000-2002 Wichert Akkerman <wakkerma@debian.org>
- * Copyright © 2006-2010 Guillem Jover <guillem@debian.org>
+ * Copyright © 2006-2012 Guillem Jover <guillem@debian.org>
* Copyright © 2008 Pierre Habouzit <madcoder@debian.org>
* Copyright © 2009-2010 Raphaël Hertzog <hertzog@debian.org>
*
@@ -81,11 +81,6 @@ version(void)
printf("\n");
printf(_(
-"Copyright (C) 1995 Ian Jackson.\n"
-"Copyright (C) 2000-2002 Wichert Akkerman.\n"
-"Copyright (C) 2009-2010 Raphael Hertzog.\n"));
-
- printf(_(
"This is free software; see the GNU General Public License version 2 or\n"
"later for copying conditions. There is NO warranty.\n"));
}
@@ -352,9 +347,10 @@ xasprintf(char **strp, const char *fmt, ...)
static void
set_action(const char *new_action)
{
- if (action)
- badusage(_("two commands specified: --%s and --%s"), action, new_action);
- action = new_action;
+ if (action)
+ badusage(_("two commands specified: --%s and --%s"),
+ action, new_action);
+ action = new_action;
}
static const char *
@@ -393,7 +389,7 @@ log_msg(const char *fmt, ...)
time(&now);
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S",
- localtime(&now));
+ localtime(&now));
fprintf(fh_log, "%s %s: ", PROGNAME, timestamp);
va_start(args, fmt);
vfprintf(fh_log, fmt, args);
@@ -403,38 +399,6 @@ log_msg(const char *fmt, ...)
}
static int
-filter_altdir(const struct dirent *entry)
-{
- if (strcmp(entry->d_name, ".") == 0 ||
- strcmp(entry->d_name, "..") == 0 ||
- (strlen(entry->d_name) > strlen(DPKG_TMP_EXT) &&
- strcmp(entry->d_name + strlen(entry->d_name) -
- strlen(DPKG_TMP_EXT), DPKG_TMP_EXT) == 0))
- return 0;
- return 1;
-}
-
-static int
-altdb_get_namelist(struct dirent ***table)
-{
- int count;
-
- count = scandir(admdir, table, filter_altdir, alphasort);
- if (count < 0)
- syserr(_("cannot scan directory `%.255s'"), admdir);
-
- return count;
-}
-
-static void
-altdb_free_namelist(struct dirent **table, int n)
-{
- while (n--)
- free(table[n]);
- free(table);
-}
-
-static int
spawn(const char *prog, const char *args[])
{
const char **cmd;
@@ -498,20 +462,6 @@ subcall(const char *prog, ...)
exit(128);
}
-static void
-config_all(void)
-{
- struct dirent **table;
- int i, count;
-
- count = altdb_get_namelist(&table);
- for (i = 0; i < count; i++) {
- subcall(prog_path, "--config", table[i]->d_name, NULL);
- printf("\n");
- }
- altdb_free_namelist(table, count);
-}
-
static bool
rename_mv(const char *src, const char *dst)
{
@@ -664,14 +614,13 @@ fileset_has_slave(struct fileset *fs, const char *name)
if (file == NULL)
return false;
- return strlen(file) ? true : false;
+ return file[0] != '\0';
}
static bool
fileset_can_install_slave(struct fileset *fs, const char *slave_name)
{
struct stat st;
- bool install_slave = false;
/* Decide whether the slave alternative must be setup */
if (fileset_has_slave(fs, slave_name)) {
@@ -680,10 +629,11 @@ fileset_can_install_slave(struct fileset *fs, const char *slave_name)
errno = 0;
if (stat(slave, &st) == -1 && errno != ENOENT)
syserr(_("cannot stat file '%s'"), slave);
- install_slave = (errno == 0) ? true : false;
+ if (errno == 0)
+ return true;
}
- return install_slave;
+ return false;
}
struct slave_link {
@@ -952,13 +902,13 @@ alternative_get_slave(struct alternative *a, const char *name)
static bool
alternative_has_slave(struct alternative *a, const char *name)
{
- return alternative_get_slave(a, name) ? true : false;
+ return alternative_get_slave(a, name) != NULL;
}
static bool
alternative_has_choice(struct alternative *a, const char *file)
{
- return alternative_get_fileset(a, file) ? true : false;
+ return alternative_get_fileset(a, file) != NULL;
}
static void
@@ -1078,13 +1028,53 @@ alternative_remove_choice(struct alternative *a, const char *file)
* Alternatives Database Load/Store functions.
*/
+enum altdb_flags {
+ altdb_lax_parser = 1 << 0,
+ altdb_warn_parser = 1 << 1,
+};
+
struct altdb_context {
FILE *fh;
char *filename;
- void DPKG_ATTR_PRINTF(2) (*bad_format)(struct altdb_context *, const char *format, ...);
+ enum altdb_flags flags;
+ bool modified;
+ void DPKG_ATTR_PRINTF(2) (*bad_format)(struct altdb_context *,
+ const char *format, ...);
jmp_buf on_error;
};
+static int
+altdb_filter_namelist(const struct dirent *entry)
+{
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0 ||
+ (strlen(entry->d_name) > strlen(DPKG_TMP_EXT) &&
+ strcmp(entry->d_name + strlen(entry->d_name) -
+ strlen(DPKG_TMP_EXT), DPKG_TMP_EXT) == 0))
+ return 0;
+ return 1;
+}
+
+static int
+altdb_get_namelist(struct dirent ***table)
+{
+ int count;
+
+ count = scandir(admdir, table, altdb_filter_namelist, alphasort);
+ if (count < 0)
+ syserr(_("cannot scan directory `%.255s'"), admdir);
+
+ return count;
+}
+
+static void
+altdb_free_namelist(struct dirent **table, int n)
+{
+ while (n--)
+ free(table[n]);
+ free(table);
+}
+
static char *
altdb_get_line(struct altdb_context *ctx, const char *name)
{
@@ -1138,7 +1128,7 @@ altdb_parse_error(struct altdb_context *ctx, const char *format, ...)
}
static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(2)
-altdb_interrupt_parsing(struct altdb_context *ctx, const char *format, ...)
+altdb_parse_stop(struct altdb_context *ctx, const char *format, ...)
{
longjmp(ctx->on_error, 1);
}
@@ -1178,7 +1168,7 @@ alternative_parse_slave(struct alternative *a, struct altdb_context *ctx)
ctx->bad_format(ctx, _("slave link same as main link %s"),
a->master_link);
}
- for(sl = a->slaves; sl; sl = sl->next) {
+ for (sl = a->slaves; sl; sl = sl->next) {
if (strcmp(linkname, sl->link) == 0) {
free(linkname);
free(name);
@@ -1193,8 +1183,7 @@ alternative_parse_slave(struct alternative *a, struct altdb_context *ctx)
}
static bool
-alternative_parse_fileset(struct alternative *a, struct altdb_context *ctx,
- bool *modified, bool must_not_die)
+alternative_parse_fileset(struct alternative *a, struct altdb_context *ctx)
{
struct fileset *fs;
struct slave_link *sl;
@@ -1222,28 +1211,33 @@ alternative_parse_fileset(struct alternative *a, struct altdb_context *ctx,
syserr(_("cannot stat file '%s'"), master_file);
/* File not found - remove. */
- if (!must_not_die)
+ if (ctx->flags & altdb_warn_parser)
warning(_("alternative %s (part of link group %s) "
- "doesn't exist. Removing from list of "
- "alternatives."), master_file, a->master_name);
+ "doesn't exist; removing from list of "
+ "alternatives"), master_file, a->master_name);
junk = altdb_get_line(ctx, _("priority"));
free(junk);
for (sl = a->slaves; sl; sl = sl->next) {
junk = altdb_get_line(ctx, _("slave file"));
free(junk);
}
- *modified = true;
+ ctx->modified = true;
} else {
- char *endptr, *prio;
- long int iprio;
+ char *prio_str, *prio_end;
+ long prio;
- prio = altdb_get_line(ctx, _("priority"));
- iprio = strtol(prio, &endptr, 10);
- /* XXX: Leak master_file/prio on non-fatal error */
- if (*endptr != '\0')
+ prio_str = altdb_get_line(ctx, _("priority"));
+ errno = 0;
+ prio = strtol(prio_str, &prio_end, 10);
+ /* XXX: Leak master_file/prio_str on non-fatal error */
+ if (prio_str == prio_end || *prio_end != '\0')
ctx->bad_format(ctx, _("priority of %s: %s"),
- master_file, prio);
- fs = fileset_new(master_file, (int) iprio);
+ master_file, prio_str);
+ if (prio < INT_MIN || prio > INT_MAX || errno == ERANGE)
+ ctx->bad_format(ctx,
+ _("priority of %s is out of range: %s"),
+ master_file, prio_str);
+ fs = fileset_new(master_file, prio);
for (sl = a->slaves; sl; sl = sl->next) {
fileset_add_slave(fs, xstrdup(sl->name),
altdb_get_line(ctx, _("slave file")));
@@ -1254,12 +1248,11 @@ alternative_parse_fileset(struct alternative *a, struct altdb_context *ctx,
}
static bool
-alternative_load(struct alternative *a, bool must_not_die)
+alternative_load(struct alternative *a, enum altdb_flags flags)
{
struct altdb_context ctx;
struct stat st;
char *fn, *status;
- bool modified = false;
/* Initialize parse context */
if (setjmp(ctx.on_error)) {
@@ -1269,8 +1262,10 @@ alternative_load(struct alternative *a, bool must_not_die)
alternative_reset(a);
return false;
}
- if (must_not_die)
- ctx.bad_format = altdb_interrupt_parsing;
+ ctx.modified = false;
+ ctx.flags = flags;
+ if (flags & altdb_lax_parser)
+ ctx.bad_format = altdb_parse_stop;
else
ctx.bad_format = altdb_parse_error;
xasprintf(&fn, "%s/%s", admdir, a->master_name);
@@ -1307,7 +1302,7 @@ alternative_load(struct alternative *a, bool must_not_die)
while (alternative_parse_slave(a, &ctx));
/* Parse the available choices in the alternative */
- while (alternative_parse_fileset(a, &ctx, &modified, must_not_die));
+ while (alternative_parse_fileset(a, &ctx)) ;
/* Close database file */
if (fclose(ctx.fh))
@@ -1317,7 +1312,7 @@ alternative_load(struct alternative *a, bool must_not_die)
/* Initialize the modified field which has been erroneously changed
* by the various alternative_(add|set)_* calls:
* false unless a choice has been auto-cleaned */
- a->modified = modified;
+ a->modified = ctx.modified;
return true;
}
@@ -1345,7 +1340,7 @@ alternative_save(struct alternative *a)
if (!has_slave) {
struct slave_link *sl_rm;
- verbose(_("discarding obsolete slave link %s (%s)."),
+ verbose(_("discarding obsolete slave link %s (%s)"),
sl->name, sl->link);
if (sl_prev)
sl_prev->next = sl->next;
@@ -1426,34 +1421,22 @@ alternative_get_best(struct alternative *a)
return best;
}
-static bool
-alternative_has_current_link(struct alternative *a)
+static char *
+alternative_get_current(struct alternative *a)
{
struct stat st;
char *curlink;
+ char *file;
xasprintf(&curlink, "%s/%s", altdir, a->master_name);
if (lstat(curlink, &st)) {
if (errno == ENOENT) {
free(curlink);
- return false;
+ return NULL;
}
syserr(_("cannot stat file '%s'"), curlink);
- } else {
- free(curlink);
- return true;
}
-}
-
-static char *
-alternative_get_current(struct alternative *a)
-{
- char *curlink, *file;
-
- if (!alternative_has_current_link(a))
- return NULL;
- xasprintf(&curlink, "%s/%s", altdir, a->master_name);
file = xreadlink(curlink);
free(curlink);
@@ -1467,7 +1450,13 @@ alternative_display_query(struct alternative *a)
struct slave_link *sl;
char *current;
- pr("Link: %s", a->master_name);
+ pr("Name: %s", a->master_name);
+ pr("Link: %s", a->master_link);
+ if (alternative_slaves_count(a) > 0) {
+ pr("Slaves:");
+ for (sl = a->slaves; sl; sl = sl->next)
+ pr(" %s %s", sl->name, sl->link);
+ }
pr("Status: %s", alternative_status_string(a->status));
best = alternative_get_best(a);
if (best)
@@ -1589,7 +1578,10 @@ alternative_select_choice(struct alternative *a)
selection[strlen(selection) - 1] = '\0';
if (strlen(selection) == 0)
return current;
+ errno = 0;
idx = strtol(selection, &ret, 10);
+ if (idx < 0 || errno != 0)
+ continue;
if (*ret == '\0') {
/* Look up by index */
if (idx == 0) {
@@ -1616,13 +1608,25 @@ alternative_select_choice(struct alternative *a)
}
}
}
- free(current);
- return NULL;
+}
+
+static void
+alternative_config_all(void)
+{
+ struct dirent **table;
+ int i, count;
+
+ count = altdb_get_namelist(&table);
+ for (i = 0; i < count; i++) {
+ subcall(prog_path, "--config", table[i]->d_name, NULL);
+ printf("\n");
+ }
+ altdb_free_namelist(table, count);
}
static void
alternative_add_commit_op(struct alternative *a, enum opcode opcode,
- const char *arg_a, const char *arg_b)
+ const char *arg_a, const char *arg_b)
{
struct commit_operation *op, *cur;
@@ -1687,7 +1691,7 @@ alternative_path_classify(const char *linkname)
}
static bool
-alternative_can_replace_path(const char *linkname)
+alternative_path_can_remove(const char *linkname)
{
if (opt_force)
return true;
@@ -1718,7 +1722,7 @@ alternative_path_needs_update(const char *linkname, const char *filename)
return update;
case ALT_PATH_OTHER:
- warning(_("not replacing %s with a link."), linkname);
+ warning(_("not replacing %s with a link"), linkname);
return false;
case ALT_PATH_MISSING:
default:
@@ -1728,7 +1732,7 @@ alternative_path_needs_update(const char *linkname, const char *filename)
static void
alternative_prepare_install_single(struct alternative *a, const char *name,
- const char *linkname, const char *file)
+ const char *linkname, const char *file)
{
char *fntmp, *fn;
@@ -1778,16 +1782,16 @@ alternative_prepare_install(struct alternative *a, const char *choice)
/* Slave can't be installed */
if (fileset_has_slave(fs, sl->name))
warning(_("skip creation of %s because associated "
- "file %s (of link group %s) doesn't exist."),
+ "file %s (of link group %s) doesn't exist"),
sl->link, fileset_get_slave(fs, sl->name),
a->master_name);
/* Drop unused slave. */
xasprintf(&fn, "%s/%s", altdir, sl->name);
- if (alternative_can_replace_path(sl->link))
+ if (alternative_path_can_remove(sl->link))
alternative_add_commit_op(a, opcode_rm, sl->link, NULL);
else
- warning(_("not removing %s since it's not a symlink."),
+ warning(_("not removing %s since it's not a symlink"),
sl->link);
alternative_add_commit_op(a, opcode_rm, fn, NULL);
free(fn);
@@ -1800,7 +1804,7 @@ alternative_remove(struct alternative *a)
struct slave_link *sl;
checked_rm_args("%s" DPKG_TMP_EXT, a->master_link);
- if (alternative_can_replace_path(a->master_link))
+ if (alternative_path_can_remove(a->master_link))
checked_rm(a->master_link);
checked_rm_args("%s/%s" DPKG_TMP_EXT, altdir, a->master_name);
@@ -1808,7 +1812,7 @@ alternative_remove(struct alternative *a)
for (sl = a->slaves; sl; sl = sl->next) {
checked_rm_args("%s" DPKG_TMP_EXT, sl->link);
- if (alternative_can_replace_path(sl->link))
+ if (alternative_path_can_remove(sl->link))
checked_rm(sl->link);
checked_rm_args("%s/%s" DPKG_TMP_EXT, altdir, sl->name);
@@ -1825,9 +1829,6 @@ alternative_is_broken(struct alternative *a)
struct fileset *fs;
struct slave_link *sl;
- if (!alternative_has_current_link(a))
- return true;
-
/* Check master link */
altlnk = areadlink(a->master_link);
if (!altlnk)
@@ -1843,6 +1844,9 @@ alternative_is_broken(struct alternative *a)
/* Stop if we have an unmanaged alternative */
current = alternative_get_current(a);
+ if (current == NULL)
+ return true;
+
if (!alternative_has_choice(a, current)) {
free(current);
return false;
@@ -1925,7 +1929,8 @@ alternative_map_find(struct alternative_map *am, const char *key)
}
static void
-alternative_map_add(struct alternative_map *am, const char *key, struct alternative *a)
+alternative_map_add(struct alternative_map *am, const char *key,
+ struct alternative *a)
{
if (am->key == NULL) {
am->key = key;
@@ -1933,7 +1938,7 @@ alternative_map_add(struct alternative_map *am, const char *key, struct alternat
} else {
struct alternative_map *new = alternative_map_new(key, a);
- while(am->next)
+ while (am->next)
am = am->next;
am->next = new;
}
@@ -1949,7 +1954,7 @@ alternative_map_load_names(struct alternative_map *alt_map_obj)
for (i = 0; i < count; i++) {
struct alternative *a_new = alternative_new(table[i]->d_name);
- if (!alternative_load(a_new, true)) {
+ if (!alternative_load(a_new, altdb_lax_parser)) {
alternative_free(a_new);
continue;
}
@@ -1970,7 +1975,7 @@ alternative_map_load_tree(struct alternative_map *alt_map_links,
struct slave_link *sl;
struct alternative *a_new = alternative_new(table[i]->d_name);
- if (!alternative_load(a_new, true)) {
+ if (!alternative_load(a_new, altdb_lax_parser)) {
alternative_free(a_new);
continue;
}
@@ -2027,13 +2032,36 @@ get_argv_string(int argc, char **argv)
}
static void
+alternative_get_selections(void)
+{
+ struct alternative_map *alt_map_obj;
+ struct alternative_map *am;
+
+ alt_map_obj = alternative_map_new(NULL, NULL);
+ alternative_map_load_names(alt_map_obj);
+
+ for (am = alt_map_obj; am && am->item; am = am->next) {
+ char *current;
+
+ current = alternative_get_current(am->item);
+ printf("%-30s %-8s %s\n", am->key,
+ alternative_status_string(am->item->status),
+ current ? current : "");
+ free(current);
+ }
+
+ alternative_map_free(alt_map_obj);
+}
+
+static void
alternative_set_selection(struct alternative_map *all, const char *name,
const char *status, const char *choice)
{
struct alternative *a;
debug("set_selection(%s, %s, %s)", name, status, choice);
- if ((a = alternative_map_find(all, name))) {
+ a = alternative_map_find(all, name);
+ if (a) {
char *cmd;
if (strcmp(status, "auto") == 0) {
@@ -2057,8 +2085,13 @@ alternative_set_selection(struct alternative_map *all, const char *name,
}
static void
-alternative_set_selections(struct alternative_map *all, FILE* input, const char *desc)
+alternative_set_selections(FILE *input, const char *desc)
{
+ struct alternative_map *alt_map_obj;
+
+ alt_map_obj = alternative_map_new(NULL, NULL);
+ alternative_map_load_names(alt_map_obj);
+
for (;;) {
char line[1024], *res, *name, *status, *choice;
size_t len, i;
@@ -2116,7 +2149,40 @@ alternative_set_selections(struct alternative_map *all, FILE* input, const char
choice = line + i;
printf("[%s %s] ", PROGNAME, "--set-selections");
- alternative_set_selection(all, name, status, choice);
+ alternative_set_selection(alt_map_obj, name, status, choice);
+ }
+
+ alternative_map_free(alt_map_obj);
+}
+
+static void
+alternative_select_mode(struct alternative *a, const char *current_choice)
+{
+ if (current_choice) {
+ /* Detect manually modified alternative, switch to manual. */
+ if (!alternative_has_choice(a, current_choice)) {
+ struct stat st;
+
+ errno = 0;
+ if (stat(current_choice, &st) == -1 && errno != ENOENT)
+ syserr(_("cannot stat file '%s'"), current_choice);
+
+ if (errno == ENOENT) {
+ warning(_("%s/%s is dangling; it will be updated "
+ "with best choice"), altdir, a->master_name);
+ alternative_set_status(a, ALT_ST_AUTO);
+ } else if (a->status != ALT_ST_MANUAL) {
+ warning(_("%s/%s has been changed (manually or by "
+ "a script); switching to manual "
+ "updates only"), altdir, a->master_name);
+ alternative_set_status(a, ALT_ST_MANUAL);
+ }
+ }
+ } else {
+ /* Lack of alternative link => automatic mode. */
+ verbose(_("setting up automatic selection of %s"),
+ a->master_name);
+ alternative_set_status(a, ALT_ST_AUTO);
}
}
@@ -2126,10 +2192,11 @@ alternative_evolve(struct alternative *a, struct alternative *b,
{
struct slave_link *sl;
struct stat st;
+ bool is_link;
- bool is_link = (alternative_path_classify(a->master_link) == ALT_PATH_SYMLINK);
+ is_link = alternative_path_classify(a->master_link) == ALT_PATH_SYMLINK;
if (is_link && strcmp(a->master_link, b->master_link) != 0) {
- info(_("renaming %s link from %s to %s."), b->master_name,
+ info(_("renaming %s link from %s to %s"), b->master_name,
a->master_link, b->master_link);
checked_mv(a->master_link, b->master_link);
}
@@ -2170,7 +2237,7 @@ alternative_evolve(struct alternative *a, struct alternative *b,
}
if (rename_link) {
- info(_("renaming %s slave link from %s to %s."),
+ info(_("renaming %s slave link from %s to %s"),
sl->name, old, new);
checked_mv(old, new);
} else {
@@ -2183,16 +2250,77 @@ alternative_evolve(struct alternative *a, struct alternative *b,
}
static void
-alternative_check_args(const char *name, const char *linkname, const char *file)
+alternative_update(struct alternative *a,
+ char *current_choice, const char *new_choice)
+{
+ /* No choice left, remove everything. */
+ if (!alternative_choices_count(a)) {
+ log_msg("link group %s fully removed", a->master_name);
+ alternative_remove(a);
+ return;
+ }
+
+ /* New choice wanted. */
+ if (new_choice &&
+ (!current_choice || strcmp(new_choice, current_choice) != 0)) {
+ log_msg("link group %s updated to point to %s", a->master_name,
+ new_choice);
+ info(_("using %s to provide %s (%s) in %s"), new_choice,
+ a->master_link, a->master_name,
+ (a->status == ALT_ST_AUTO) ? _("auto mode") :
+ _("manual mode"));
+ debug("prepare_install(%s)", new_choice);
+ alternative_prepare_install(a, new_choice);
+ } else if (alternative_is_broken(a)) {
+ log_msg("auto-repair link group %s", a->master_name);
+ warning(_("forcing reinstallation of alternative %s because "
+ "link group %s is broken"), current_choice,
+ a->master_name);
+
+ if (current_choice && !alternative_has_choice(a, current_choice)) {
+ struct fileset *best = alternative_get_best(a);
+
+ warning(_("current alternative %s is unknown, "
+ "switching to %s for link group %s"),
+ current_choice, best->master_file,
+ a->master_name);
+ current_choice = best->master_file;
+ alternative_set_status(a, ALT_ST_AUTO);
+ }
+
+ if (current_choice)
+ alternative_prepare_install(a, current_choice);
+ }
+
+ /* Save administrative file if needed. */
+ if (a->modified) {
+ debug("%s is modified and will be saved", a->master_name);
+ alternative_save(a);
+ }
+
+ /* Replace all symlinks in one pass. */
+ alternative_commit(a);
+}
+
+static void
+alternative_check_name(const char *name)
{
if (strpbrk(name, "/ \t"))
error(_("alternative name (%s) must not contain '/' "
- "and spaces."), name);
+ "and spaces"), name);
+}
+static void
+alternative_check_link(const char *linkname)
+{
if (linkname[0] != '/')
error(_("alternative link is not absolute as it should be: %s"),
linkname);
+}
+static void
+alternative_check_path(const char *file)
+{
if (!file || file[0] != '/')
error(_("alternative path is not absolute as it should be: %s"),
file);
@@ -2214,6 +2342,10 @@ alternative_check_install_args(struct alternative *inst_alt,
struct slave_link *sl;
struct stat st;
+ alternative_check_name(inst_alt->master_name);
+ alternative_check_link(inst_alt->master_link);
+ alternative_check_path(fileset->master_file);
+
/* Load information about all alternatives to check for mistakes. */
alt_map_links = alternative_map_new(NULL, NULL);
alt_map_parent = alternative_map_new(NULL, NULL);
@@ -2229,16 +2361,13 @@ alternative_check_install_args(struct alternative *inst_alt,
if (found && strcmp(found->master_name, inst_alt->master_name) != 0) {
found = alternative_map_find(alt_map_parent,
found->master_name);
- error(_("alternative link %s is already managed by %s."),
+ error(_("alternative link %s is already managed by %s"),
inst_alt->master_link, found->master_name);
}
- alternative_check_args(inst_alt->master_name, inst_alt->master_link,
- fileset->master_file);
-
if (stat(fileset->master_file, &st) == -1) {
if (errno == ENOENT)
- error(_("alternative path %s doesn't exist."),
+ error(_("alternative path %s doesn't exist"),
fileset->master_file);
else
syserr(_("cannot stat file '%s'"), fileset->master_file);
@@ -2247,12 +2376,16 @@ alternative_check_install_args(struct alternative *inst_alt,
for (sl = inst_alt->slaves; sl; sl = sl->next) {
const char *file = fileset_get_slave(fileset, sl->name);
+ alternative_check_name(sl->name);
+ alternative_check_link(sl->link);
+ alternative_check_path(file);
+
found = alternative_map_find(alt_map_parent, sl->name);
if (found &&
strcmp(found->master_name, inst_alt->master_name) != 0) {
if (strcmp(found->master_name, sl->name) == 0)
error(_("alternative %s can't be slave of %s: "
- "it is a master alternative."),
+ "it is a master alternative"),
sl->name, inst_alt->master_name);
else
error(_("alternative %s can't be slave of %s: "
@@ -2265,7 +2398,7 @@ alternative_check_install_args(struct alternative *inst_alt,
if (found &&
strcmp(found->master_name, inst_alt->master_name) != 0) {
error(_("alternative link %s is already "
- "managed by %s."), sl->link,
+ "managed by %s"), sl->link,
found->master_name);
}
if (found) {
@@ -2276,12 +2409,10 @@ alternative_check_install_args(struct alternative *inst_alt,
break;
if (sl2 && strcmp(sl2->name, sl->name) != 0)
error(_("alternative link %s is already "
- "managed by %s (slave of %s)."),
+ "managed by %s (slave of %s)"),
sl->link, sl2->name,
found->master_name);
}
-
- alternative_check_args(sl->name, sl->link, file);
}
alternative_map_free(alt_map_links);
@@ -2335,24 +2466,35 @@ main(int argc, char **argv)
opt_verbose--;
PUSH_OPT(argv[i]);
} else if (strcmp("--install", argv[i]) == 0) {
- long priority;
- char *endptr;
+ char *prio_str, *prio_end;
+ long prio;
set_action("install");
if (MISSING_ARGS(4))
badusage(_("--install needs <link> <name> "
"<path> <priority>"));
+
+ prio_str = argv[i + 4];
+
if (strcmp(argv[i+1], argv[i+3]) == 0)
badusage(_("<link> and <path> can't be the same"));
- priority = strtol(argv[i+4], &endptr, 10);
- if (*endptr != '\0')
+ errno = 0;
+ prio = strtol(prio_str, &prio_end, 10);
+ if (prio_str == prio_end || *prio_end != '\0')
badusage(_("priority must be an integer"));
+ if (prio < INT_MIN || prio > INT_MAX || errno == ERANGE) {
+ /* XXX: Switch back to error on 1.17.x. */
+ prio = clamp(prio, INT_MIN, INT_MAX);
+ warning(_("priority is out of range: "
+ "%s clamped to %ld"),
+ prio_str, prio);
+ }
a = alternative_new(argv[i + 2]);
inst_alt = alternative_new(argv[i + 2]);
alternative_set_status(inst_alt, ALT_ST_AUTO);
alternative_set_link(inst_alt, xstrdup(argv[i + 1]));
- fileset = fileset_new(argv[i + 3], priority);
+ fileset = fileset_new(argv[i + 3], prio);
i += 4;
} else if (strcmp("--remove", argv[i]) == 0 ||
@@ -2364,6 +2506,9 @@ main(int argc, char **argv)
a = alternative_new(argv[i + 1]);
path = xstrdup(argv[i + 2]);
+ alternative_check_name(a->master_name);
+ alternative_check_path(path);
+
i += 2;
} else if (strcmp("--display", argv[i]) == 0 ||
strcmp("--query", argv[i]) == 0 ||
@@ -2375,6 +2520,9 @@ main(int argc, char **argv)
if (MISSING_ARGS(1))
badusage(_("--%s needs <name>"), argv[i] + 2);
a = alternative_new(argv[i + 1]);
+
+ alternative_check_name(a->master_name);
+
i++;
} else if (strcmp("--all", argv[i]) == 0 ||
strcmp("--get-selections", argv[i]) == 0 ||
@@ -2457,53 +2605,41 @@ main(int argc, char **argv)
if (strcmp(action, "install") == 0)
alternative_check_install_args(inst_alt, fileset);
+ if (strcmp(action, "display") == 0 ||
+ strcmp(action, "query") == 0 ||
+ strcmp(action, "list") == 0 ||
+ strcmp(action, "set") == 0 ||
+ strcmp(action, "auto") == 0 ||
+ strcmp(action, "config") == 0 ||
+ strcmp(action, "remove-all") == 0) {
+ /* Load the alternative info, stop on failure. */
+ if (!alternative_load(a, altdb_warn_parser))
+ error(_("no alternatives for %s"), a->master_name);
+ } else if (strcmp(action, "remove") == 0) {
+ /* FIXME: Be consistent for now with the case when we
+ * try to remove a non-existing path from an existing
+ * link group file. */
+ if (!alternative_load(a, altdb_warn_parser)) {
+ verbose(_("no alternatives for %s"), a->master_name);
+ exit(0);
+ }
+ } else if (strcmp(action, "install") == 0) {
+ /* Load the alternative info, ignore failures. */
+ alternative_load(a, altdb_warn_parser);
+ }
+
/* Handle actions. */
if (strcmp(action, "all") == 0) {
- config_all();
+ alternative_config_all();
exit(0);
} else if (strcmp(action, "get-selections") == 0) {
- struct alternative_map *alt_map_obj;
- struct alternative_map *am;
-
- alt_map_obj = alternative_map_new(NULL, NULL);
- alternative_map_load_names(alt_map_obj);
-
- for (am = alt_map_obj; am && am->item; am = am->next) {
- char *current;
-
- current = alternative_get_current(am->item);
- printf("%-30s %-8s %s\n", am->key,
- alternative_status_string(am->item->status),
- current ? current : "");
- free(current);
- }
-
- alternative_map_free(alt_map_obj);
-
+ alternative_get_selections();
exit(0);
} else if (strcmp(action, "set-selections") == 0) {
- struct alternative_map *alt_map_obj;
-
log_msg("run with %s", get_argv_string(argc, argv));
- alt_map_obj = alternative_map_new(NULL, NULL);
- alternative_map_load_names(alt_map_obj);
- alternative_set_selections(alt_map_obj, stdin, _("<standard input>"));
- alternative_map_free(alt_map_obj);
+ alternative_set_selections(stdin, _("<standard input>"));
exit(0);
- }
-
- /* Load the alternative info, stop on failure except for --install. */
- if (!alternative_load(a, false) && strcmp(action, "install") != 0) {
- /* FIXME: Be consistent for now with the case when we try to remove a
- * non-existing path from an existing link group file. */
- if (strcmp(action, "remove") == 0) {
- verbose(_("no alternatives for %s."), a->master_name);
- exit(0);
- }
- error(_("no alternatives for %s."), a->master_name);
- }
-
- if (strcmp(action, "display") == 0) {
+ } else if (strcmp(action, "display") == 0) {
alternative_display_user(a);
exit(0);
} else if (strcmp(action, "query") == 0) {
@@ -2516,40 +2652,15 @@ main(int argc, char **argv)
/* Actions below might modify the system. */
log_msg("run with %s", get_argv_string(argc, argv));
- if (alternative_has_current_link(a)) {
- current_choice = alternative_get_current(a);
- /* Detect manually modified alternative, switch to manual. */
- if (!alternative_has_choice(a, current_choice)) {
- struct stat st;
-
- errno = 0;
- if (stat(current_choice, &st) == -1 && errno != ENOENT)
- syserr(_("cannot stat file '%s'"), current_choice);
-
- if (errno == ENOENT) {
- warning(_("%s/%s is dangling, it will be updated "
- "with best choice."), altdir, a->master_name);
- alternative_set_status(a, ALT_ST_AUTO);
- } else if (a->status != ALT_ST_MANUAL) {
- warning(_("%s/%s has been changed (manually or by "
- "a script). Switching to manual "
- "updates only."), altdir, a->master_name);
- alternative_set_status(a, ALT_ST_MANUAL);
- }
- }
- } else {
- /* Lack of alternative link => automatic mode. */
- verbose(_("setting up automatic selection of %s."),
- a->master_name);
- alternative_set_status(a, ALT_ST_AUTO);
- }
+ current_choice = alternative_get_current(a);
+ alternative_select_mode(a, current_choice);
if (strcmp(action, "set") == 0) {
if (alternative_has_choice(a, path))
new_choice = path;
else
- error(_("alternative %s for %s not registered, "
- "not setting."), path, a->master_name);
+ error(_("alternative %s for %s not registered; "
+ "not setting"), path, a->master_name);
alternative_set_status(a, ALT_ST_MANUAL);
} else if (strcmp(action, "auto") == 0) {
alternative_set_status(a, ALT_ST_AUTO);
@@ -2567,13 +2678,10 @@ main(int argc, char **argv)
alternative_display_user(a);
} else if (alternative_choices_count(a) == 1 &&
a->status == ALT_ST_AUTO &&
- alternative_has_current_link(a)) {
- char *cur = alternative_get_current(a);
-
- pr(_("There is only one alternative in link group %s: %s"),
- a->master_name, cur);
+ current_choice != NULL) {
+ pr(_("There is only one alternative in link group %s (providing %s): %s"),
+ a->master_name, a->master_link, current_choice);
pr(_("Nothing to configure."));
- free(cur);
} else {
new_choice = alternative_select_choice(a);
}
@@ -2581,8 +2689,8 @@ main(int argc, char **argv)
if (alternative_has_choice(a, path))
alternative_remove_choice(a, path);
else
- verbose(_("alternative %s for %s not registered, not "
- "removing."), path, a->master_name);
+ verbose(_("alternative %s for %s not registered; not "
+ "removing"), path, a->master_name);
if (current_choice && strcmp(current_choice, path) == 0) {
struct fileset *best;
@@ -2614,60 +2722,14 @@ main(int argc, char **argv)
if (a->status == ALT_ST_AUTO) {
new_choice = alternative_get_best(a)->master_file;
} else {
- verbose(_("automatic updates of %s/%s are disabled, "
- "leaving it alone."), altdir, a->master_name);
+ verbose(_("automatic updates of %s/%s are disabled; "
+ "leaving it alone"), altdir, a->master_name);
verbose(_("to return to automatic updates use "
- "'%s --auto %s'."), PROGNAME, a->master_name);
- }
- }
-
- /* No choice left, remove everything. */
- if (!alternative_choices_count(a)) {
- log_msg("link group %s fully removed", a->master_name);
- alternative_remove(a);
- exit(0);
- }
-
- /* New choice wanted. */
- if (new_choice && (!current_choice ||
- strcmp(new_choice, current_choice) != 0)) {
- log_msg("link group %s updated to point to %s", a->master_name,
- new_choice);
- info(_("using %s to provide %s (%s) in %s."), new_choice,
- a->master_link, a->master_name,
- (a->status == ALT_ST_AUTO) ? _("auto mode") :
- _("manual mode"));
- debug("prepare_install(%s)", new_choice);
- alternative_prepare_install(a, new_choice);
- } else if (alternative_is_broken(a)) {
- log_msg("auto-repair link group %s", a->master_name);
- warning(_("forcing reinstallation of alternative %s because "
- "link group %s is broken."), current_choice,
- a->master_name);
-
- if (current_choice && !alternative_has_choice(a, current_choice)) {
- struct fileset *best = alternative_get_best(a);
-
- warning(_("current alternative %s is unknown, "
- "switching to %s for link group %s."),
- current_choice, best->master_file,
- a->master_name);
- current_choice = best->master_file;
- alternative_set_status(a, ALT_ST_AUTO);
+ "'%s --auto %s'"), PROGNAME, a->master_name);
}
-
- if (current_choice)
- alternative_prepare_install(a, current_choice);
}
- /* Save administrative file if needed. */
- if (a->modified) {
- debug("%s is modified and will be saved", a->master_name);
- alternative_save(a);
- }
-
- /* Replace all symlinks in one pass. */
- alternative_commit(a);
+ alternative_update(a, current_choice, new_choice);
return 0;
}