diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-07-24 19:42:00 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-07-24 19:42:00 +0400 |
commit | d074ec6481d79d6954d4d2a2e5c23976561aa6bf (patch) | |
tree | 6fc46fb4a63edda0cf78ac683f8832891f549ffc /utils | |
parent | 69ef23cecae6d9fe7c8f4677926b78ec2cd3bc17 (diff) | |
parent | dd13db2d657c1df1f872309b8b5bcb94018bdada (diff) | |
download | dpkg-d074ec6481d79d6954d4d2a2e5c23976561aa6bf.tar.gz |
Merge git://git.debian.org/git/dpkg/dpkg
Conflicts:
debian/changelog
dpkg-deb/main.c
scripts/Dpkg/Shlibs/SymbolFile.pm
Diffstat (limited to 'utils')
-rw-r--r-- | utils/.gitignore | 1 | ||||
-rw-r--r-- | utils/Makefile.am | 16 | ||||
-rw-r--r-- | utils/install-info.c | 66 | ||||
-rw-r--r-- | utils/start-stop-daemon.c | 375 | ||||
-rw-r--r-- | utils/t/100_update_alternatives.t | 340 | ||||
-rw-r--r-- | utils/update-alternatives.c | 135 |
6 files changed, 443 insertions, 490 deletions
diff --git a/utils/.gitignore b/utils/.gitignore index 4ba178b0c..9970040b7 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -1,4 +1,3 @@ start-stop-daemon update-alternatives -dpkg-install-info t.tmp diff --git a/utils/Makefile.am b/utils/Makefile.am index 8a743d985..068c04c5d 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -41,18 +41,6 @@ start_stop_daemon_LDADD = \ $(SSD_LIBS) endif -if BUILD_INSTALL_INFO -sbin_PROGRAMS += dpkg-install-info - -# Automake has its own install-info rule, gah -dpkg_install_info_SOURCES = install-info.c - -dpkg_install_info_LDADD = \ - ../lib/compat/libcompat.a -endif - -transform = s/dpkg-install-info/install-info/; $(program_transform_name) - install-data-local: if BUILD_UPDATE_ALTERNATIVES $(MKDIR_P) $(DESTDIR)$(sysconfdir)/alternatives @@ -62,11 +50,7 @@ endif uninstall-local: rm -f $(DESTDIR)$(sysconfdir)/alternatives/README -if BUILD_INSTALL_INFO - rm -f $(DESTDIR)$(sbindir)/install-info -endif -TEST_VERBOSE = 0 TEST_ENV_VARS = DPKG_DATADIR=$(top_srcdir) test_tmpdir = t.tmp diff --git a/utils/install-info.c b/utils/install-info.c deleted file mode 100644 index eb1679fea..000000000 --- a/utils/install-info.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * install-info.c - transitional ginstall-info wrapper - * - * Copyright © 2009 Raphaël Hertzog <hertzog@debian.org> - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <compat.h> - -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> - -#define SELF "/usr/sbin/install-info" -#define WRAPPED "/usr/bin/install-info" - -#define warn(...) fprintf(stderr, "install-info: warning: " __VA_ARGS__) -#define error(...) fprintf(stderr, "install-info: error: " __VA_ARGS__) - -int -main(int argc, char **argv) -{ - if (strcmp(argv[0], SELF) == 0) { - warn("don't call programs like install-info with an absolute path,\n"); - warn("%s provided by dpkg is deprecated and will go away soon;\n", - SELF); - warn("its replacement lives in /usr/bin/.\n"); - } - - execv(WRAPPED, argv); - if (errno == ENOENT) { - if (getenv("DPKG_RUNNING_VERSION") != NULL) { - const char *pkg; - - pkg = getenv("DPKG_MAINTSCRIPT_PACKAGE"); - - warn("maintainer scripts should not call install-info anymore,\n"); - warn("this is handled now by a dpkg trigger provided by the\n"); - warn("install-info package; package %s should be updated.\n", - pkg); - } else { - warn("nothing done since %s doesn't exist,\n", WRAPPED); - warn("you might want to install an info-browser package.\n"); - } - } else { - error("can't execute %s: %s\n", WRAPPED, strerror(errno)); - return 1; - } - - return 0; -} diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c index 2bb731fe0..61ff962a7 100644 --- a/utils/start-stop-daemon.c +++ b/utils/start-stop-daemon.c @@ -43,8 +43,6 @@ # error Unknown architecture - cannot build start-stop-daemon #endif -#define MIN_POLL_INTERVAL 20000 /* µs */ - #ifdef HAVE_SYS_SYSCALL_H #include <sys/syscall.h> #endif @@ -130,10 +128,17 @@ #define PROCESS_NAME_SIZE 19 #endif +#define MIN_POLL_INTERVAL 20000 /* µs */ + #if defined(SYS_ioprio_set) && defined(linux) #define HAVE_IOPRIO_SET #endif +#define IOPRIO_CLASS_SHIFT 13 +#define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio)) +#define IO_SCHED_PRIO_MIN 0 +#define IO_SCHED_PRIO_MAX 7 + enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, @@ -179,11 +184,6 @@ static const char *progname = ""; static int nicelevel = 0; static int umask_value = -1; -#define IOPRIO_CLASS_SHIFT 13 -#define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio)) -#define IO_SCHED_PRIO_MIN 0 -#define IO_SCHED_PRIO_MAX 7 - static struct stat exec_stat; #if defined(OSHurd) static struct proc_stat_list *procset = NULL; @@ -344,6 +344,15 @@ detach_controlling_tty(void) close(tty_fd); #endif } + +static pid_t +setsid(void) +{ + setpgid(0, 0); + detach_controlling_tty(); + + return 0; +} #endif static void @@ -361,12 +370,7 @@ daemonize(void) _exit(0); /* Create a new session. */ -#ifdef HAVE_SETSID setsid(); -#else - setpgid(0, 0); - detach_controlling_tty(); -#endif pid = fork(); if (pid < 0) @@ -979,6 +983,69 @@ parse_options(int argc, char * const *argv) badusage("--no-close is only relevant with --background"); } +static void +setup_options(void) +{ + if (execname) { + char *fullexecname; + + /* If it's a relative path, normalize it. */ + if (execname[0] != '/') + execname = newpath(changedir, execname); + + if (changeroot) + fullexecname = newpath(changeroot, execname); + else + fullexecname = execname; + + if (stat(fullexecname, &exec_stat)) + fatal("unable to stat %s", fullexecname); + + if (fullexecname != execname) + free(fullexecname); + } + + if (userspec && sscanf(userspec, "%d", &user_id) != 1) { + struct passwd *pw; + + pw = getpwnam(userspec); + if (!pw) + fatal("user '%s' not found", userspec); + + user_id = pw->pw_uid; + } + + if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) { + struct group *gr; + + gr = getgrnam(changegroup); + if (!gr) + fatal("group '%s' not found", changegroup); + changegroup = gr->gr_name; + runas_gid = gr->gr_gid; + } + if (changeuser) { + struct passwd *pw; + struct stat st; + + if (sscanf(changeuser, "%d", &runas_uid) == 1) + pw = getpwuid(runas_uid); + else + pw = getpwnam(changeuser); + if (!pw) + fatal("user '%s' not found", changeuser); + changeuser = pw->pw_name; + runas_uid = pw->pw_uid; + if (changegroup == NULL) { + /* Pass the default group of this user. */ + changegroup = ""; /* Just empty. */ + runas_gid = pw->pw_gid; + } + if (stat(pw->pw_dir, &st) == 0) + setenv("HOME", pw->pw_dir, 1); + } +} + #if defined(OSHurd) static void init_procset(void) @@ -1444,6 +1511,119 @@ do_findprocs(void) } static void +do_start(int argc, char **argv) +{ + int devnull_fd = -1; + gid_t rgid; + uid_t ruid; + + do_findprocs(); + + if (found) { + if (quietmode <= 0) + printf("%s already running.\n", execname ? execname : "process"); + exit(exitnodo); + } + if (testmode && quietmode <= 0) { + printf("Would start %s ", startas); + while (argc-- > 0) + printf("%s ", *argv++); + if (changeuser != NULL) { + printf(" (as user %s[%d]", changeuser, runas_uid); + if (changegroup != NULL) + printf(", and group %s[%d])", changegroup, runas_gid); + else + printf(")"); + } + if (changeroot != NULL) + printf(" in directory %s", changeroot); + if (nicelevel) + printf(", and add %i to the priority", nicelevel); + if (proc_sched) + printf(", with scheduling policy %s with priority %i", + proc_sched->policy_name, proc_sched->priority); + if (io_sched) + printf(", with IO scheduling class %s with priority %i", + io_sched->policy_name, io_sched->priority); + printf(".\n"); + } + if (testmode) + exit(0); + if (quietmode < 0) + printf("Starting %s...\n", startas); + *--argv = startas; + 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"); + } + if (nicelevel) { + errno = 0; + if ((nice(nicelevel) == -1) && (errno != 0)) + fatal("unable to alter nice level by %i", nicelevel); + } + if (proc_sched) + set_proc_schedule(proc_sched); + if (io_sched) + set_io_schedule(io_sched); + if (umask_value >= 0) + umask(umask_value); + if (mpidfile && pidfile != NULL) + /* User wants _us_ to make the pidfile. */ + write_pidfile(pidfile, getpid()); + if (changeroot != NULL) { + if (chdir(changeroot) < 0) + fatal("unable to chdir() to %s", changeroot); + if (chroot(changeroot) < 0) + fatal("unable to chroot() to %s", changeroot); + } + if (chdir(changedir) < 0) + fatal("unable to chdir() to %s", changedir); + + rgid = getgid(); + ruid = getuid(); + if (changegroup != NULL) { + if (rgid != (gid_t)runas_gid) + if (setgid(runas_gid)) + fatal("unable to set gid to %d", runas_gid); + } + if (changeuser != NULL) { + /* We assume that if our real user and group are the same as + * the ones we should switch to, the supplementary groups + * will be already in place. */ + if (rgid != (gid_t)runas_gid || ruid != (uid_t)runas_uid) + if (initgroups(changeuser, runas_gid)) + fatal("unable to set initgroups() with gid %d", + runas_gid); + + if (ruid != (uid_t)runas_uid) + if (setuid(runas_uid)) + fatal("unable to set uid to %s", changeuser); + } + + /* Set a default umask for dumb programs. */ + if (background && umask_value < 0) + umask(022); + + if (background && close_io) { + int i; + + dup2(devnull_fd, 0); /* stdin */ + dup2(devnull_fd, 1); /* stdout */ + dup2(devnull_fd, 2); /* stderr */ + + /* Now close all extra fds. */ + for (i = get_open_fd_max() - 1; i >= 3; --i) + close(i); + } + execv(startas, argv); + fatal("unable to start %s", startas); +} + +static void do_stop(int sig_num, int *n_killed, int *n_notkilled) { struct pid_list *p; @@ -1653,183 +1833,28 @@ run_stop_schedule(void) int main(int argc, char **argv) { - enum status_code prog_status; - int devnull_fd = -1; - gid_t rgid; - uid_t ruid; progname = argv[0]; parse_options(argc, argv); + setup_options(); + argc -= optind; argv += optind; - if (execname) { - char *fullexecname; - - /* If it's a relative path, normalize it. */ - if (execname[0] != '/') - execname = newpath(changedir, execname); - - if (changeroot) - fullexecname = newpath(changeroot, execname); - else - fullexecname = execname; - - if (stat(fullexecname, &exec_stat)) - fatal("unable to stat %s", fullexecname); - - if (fullexecname != execname) - free(fullexecname); - } - - if (userspec && sscanf(userspec, "%d", &user_id) != 1) { - struct passwd *pw; - - pw = getpwnam(userspec); - if (!pw) - fatal("user '%s' not found", userspec); - - user_id = pw->pw_uid; - } - - if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) { - struct group *gr = getgrnam(changegroup); - if (!gr) - fatal("group '%s' not found", changegroup); - changegroup = gr->gr_name; - runas_gid = gr->gr_gid; - } - if (changeuser) { - struct passwd *pw; - struct stat st; - - if (sscanf(changeuser, "%d", &runas_uid) == 1) - pw = getpwuid(runas_uid); - else - pw = getpwnam(changeuser); - if (!pw) - fatal("user '%s' not found", changeuser); - changeuser = pw->pw_name; - runas_uid = pw->pw_uid; - if (changegroup == NULL) { - /* Pass the default group of this user. */ - changegroup = ""; /* Just empty. */ - runas_gid = pw->pw_gid; - } - if (stat(pw->pw_dir, &st) == 0) - setenv("HOME", pw->pw_dir, 1); - } + if (action == action_start) + do_start(argc, argv); if (action == action_stop) { int i = run_stop_schedule(); exit(i); } - prog_status = do_findprocs(); + if (action == action_status) { + enum status_code prog_status; - if (action == action_status) + prog_status = do_findprocs(); exit(prog_status); - - if (found) { - if (quietmode <= 0) - printf("%s already running.\n", execname ? execname : "process"); - exit(exitnodo); } - if (testmode && quietmode <= 0) { - printf("Would start %s ", startas); - while (argc-- > 0) - printf("%s ", *argv++); - if (changeuser != NULL) { - printf(" (as user %s[%d]", changeuser, runas_uid); - if (changegroup != NULL) - printf(", and group %s[%d])", changegroup, runas_gid); - else - printf(")"); - } - if (changeroot != NULL) - printf(" in directory %s", changeroot); - if (nicelevel) - printf(", and add %i to the priority", nicelevel); - if (proc_sched) - printf(", with scheduling policy %s with priority %i", - proc_sched->policy_name, proc_sched->priority); - if (io_sched) - printf(", with IO scheduling class %s with priority %i", - io_sched->policy_name, io_sched->priority); - printf(".\n"); - } - if (testmode) - exit(0); - if (quietmode < 0) - printf("Starting %s...\n", startas); - *--argv = startas; - 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"); - } - if (nicelevel) { - errno = 0; - if ((nice(nicelevel) == -1) && (errno != 0)) - fatal("unable to alter nice level by %i", nicelevel); - } - if (proc_sched) - set_proc_schedule(proc_sched); - if (io_sched) - set_io_schedule(io_sched); - if (umask_value >= 0) - umask(umask_value); - if (mpidfile && pidfile != NULL) - /* User wants _us_ to make the pidfile. */ - write_pidfile(pidfile, getpid()); - if (changeroot != NULL) { - if (chdir(changeroot) < 0) - fatal("unable to chdir() to %s", changeroot); - if (chroot(changeroot) < 0) - fatal("unable to chroot() to %s", changeroot); - } - if (chdir(changedir) < 0) - fatal("unable to chdir() to %s", changedir); - - rgid = getgid(); - ruid = getuid(); - if (changegroup != NULL) { - if (rgid != (gid_t)runas_gid) - if (setgid(runas_gid)) - fatal("unable to set gid to %d", runas_gid); - } - if (changeuser != NULL) { - /* We assume that if our real user and group are the same as - * the ones we should switch to, the supplementary groups - * will be already in place. */ - if (rgid != (gid_t)runas_gid || ruid != (uid_t)runas_uid) - if (initgroups(changeuser, runas_gid)) - fatal("unable to set initgroups() with gid %d", - runas_gid); - - if (ruid != (uid_t)runas_uid) - if (setuid(runas_uid)) - fatal("unable to set uid to %s", changeuser); - } - - /* Set a default umask for dumb programs. */ - if (background && umask_value < 0) - umask(022); - - if (background && close_io) { - int i; - dup2(devnull_fd, 0); /* stdin */ - dup2(devnull_fd, 1); /* stdout */ - dup2(devnull_fd, 2); /* stderr */ - - /* Now close all extra fds. */ - for (i = get_open_fd_max() - 1; i >= 3; --i) - close(i); - } - execv(startas, argv); - fatal("unable to start %s", startas); + return 0; } diff --git a/utils/t/100_update_alternatives.t b/utils/t/100_update_alternatives.t index 4a786777f..6df050452 100644 --- a/utils/t/100_update_alternatives.t +++ b/utils/t/100_update_alternatives.t @@ -1,4 +1,4 @@ -# -*- mode: cperl;-*- +#!/usr/bin/perl # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,48 +26,48 @@ my $tmpdir = 't.tmp/900_update_alternatives'; my $admindir = File::Spec->rel2abs("$tmpdir/admindir"), my $altdir = File::Spec->rel2abs("$tmpdir/alternatives"); my $bindir = File::Spec->rel2abs("$tmpdir/bin"); -my @ua = ("$ENV{builddir}/update-alternatives", "--log", "/dev/null", - "--quiet", "--admindir", "$admindir", "--altdir", "$altdir"); +my @ua = ("$ENV{builddir}/update-alternatives", '--log', '/dev/null', + '--quiet', '--admindir', "$admindir", '--altdir', "$altdir"); my %paths = ( - true => find_command("true"), - false => find_command("false"), - yes => find_command("yes"), - cat => find_command("cat"), - date => find_command("date"), - sleep => find_command("sleep"), + true => find_command('true'), + false => find_command('false'), + yes => find_command('yes'), + cat => find_command('cat'), + date => find_command('date'), + sleep => find_command('sleep'), ); if (! -x "$ENV{builddir}/update-alternatives") { - plan skip_all => "update-alternatives not available"; + plan skip_all => 'update-alternatives not available'; exit(0); } my $main_link = "$bindir/generic-test"; -my $main_name = "generic-test"; +my $main_name = 'generic-test'; my @choices = ( { path => $paths{true}, priority => 20, slaves => [ { - "link" => "$bindir/slave2", - name => "slave2", + link => "$bindir/slave2", + name => 'slave2', path => $paths{cat}, }, { - "link" => "$bindir/slave3", - name => "slave3", + link => "$bindir/slave3", + name => 'slave3', path => $paths{cat}, }, { - "link" => "$bindir/slave1", - name => "slave1", + link => "$bindir/slave1", + name => 'slave1', path => $paths{yes}, }, { - "link" => "$bindir/slave4", - name => "slave4", + link => "$bindir/slave4", + name => 'slave4', path => $paths{cat}, }, ], @@ -77,8 +77,8 @@ my @choices = ( priority => 10, slaves => [ { - "link" => "$bindir/slave1", - name => "slave1", + link => "$bindir/slave1", + name => 'slave1', path => $paths{date}, }, ], @@ -100,11 +100,11 @@ sub cleanup { sub call_ua { my ($params, %opts) = @_; - spawn("exec" => [ @ua, @$params ], nocheck => 1, - wait_child => 1, env => { LC_ALL => "C" }, %opts); - my $test_id = ""; + spawn(exec => [ @ua, @$params ], nocheck => 1, + wait_child => 1, env => { LC_ALL => 'C' }, %opts); + my $test_id = ''; $test_id = "$opts{test_id}: " if defined $opts{test_id}; - if ($opts{"expect_failure"}) { + if ($opts{expect_failure}) { ok($? != 0, "${test_id}update-alternatives @$params should fail.") or diag("Did not fail as expected: @ua @$params"); } else { @@ -118,10 +118,10 @@ sub install_choice { my $alt = $choices[$id]; my @params; push @params, @{$opts{params}} if exists $opts{params}; - push @params, "--install", "$main_link", "$main_name", + push @params, '--install', "$main_link", "$main_name", $alt->{path}, $alt->{priority}; foreach my $slave (@{ $alt->{slaves} }) { - push @params, "--slave", $slave->{"link"}, $slave->{"name"}, $slave->{"path"}; + push @params, '--slave', $slave->{link}, $slave->{name}, $slave->{path}; } call_ua(\@params, %opts); } @@ -131,7 +131,7 @@ sub remove_choice { my $alt = $choices[$id]; my @params; push @params, @{$opts{params}} if exists $opts{params}; - push @params, "--remove", $main_name, $alt->{path}; + push @params, '--remove', $main_name, $alt->{path}; call_ua(\@params, %opts); } @@ -139,7 +139,7 @@ sub remove_all_choices { my (%opts) = @_; my @params; push @params, @{$opts{params}} if exists $opts{params}; - push @params, "--remove-all", $main_name; + push @params, '--remove-all', $main_name; call_ua(\@params, %opts); } @@ -148,25 +148,25 @@ sub set_choice { my $alt = $choices[$id]; my @params; push @params, @{$opts{params}} if exists $opts{params}; - push @params, "--set", $main_name, $alt->{path}; + push @params, '--set', $main_name, $alt->{path}; call_ua(\@params, %opts); } sub config_choice { my ($id, %opts) = @_; - my ($input, $output) = ("", ""); + my ($input, $output) = ('', ''); if ($id >= 0) { my $alt = $choices[$id]; $input = $alt->{path}; } else { - $input = "0"; + $input = '0'; } $input .= "\n"; $opts{from_string} = \$input; $opts{to_string} = \$output; my @params; push @params, @{$opts{params}} if exists $opts{params}; - push @params, "--config", $main_name; + push @params, '--config', $main_name; call_ua(\@params, %opts); } @@ -175,22 +175,24 @@ sub get_slaves_status { my %slaves; # None of the slaves are installed foreach my $alt (@choices) { - for(my $i = 0; $i < @{$alt->{slaves}}; $i++) { + for my $i (0 .. @{$alt->{slaves}} - 1) { $slaves{$alt->{slaves}[$i]{name}} = $alt->{slaves}[$i]; - $slaves{$alt->{slaves}[$i]{name}}{"installed"} = 0; + $slaves{$alt->{slaves}[$i]{name}}{installed} = 0; } } # except those of the current alternative (minus optional slaves) if (defined($id)) { my $alt = $choices[$id]; - for(my $i = 0; $i < @{$alt->{slaves}}; $i++) { + for my $i (0 .. @{$alt->{slaves}} - 1) { $slaves{$alt->{slaves}[$i]{name}} = $alt->{slaves}[$i]; if (-e $alt->{slaves}[$i]{path}) { - $slaves{$alt->{slaves}[$i]{name}}{"installed"} = 1; + $slaves{$alt->{slaves}[$i]{name}}{installed} = 1; } } } - return sort { $a->{name} cmp $b->{name} } values %slaves; + my @slaves = sort { $a->{name} cmp $b->{name} } values %slaves; + + return @slaves; } sub check_link { @@ -202,7 +204,7 @@ sub check_no_link { my ($link, $msg) = @_; lstat($link); ok(!-e _, "$msg: $link still exists."); - ok(1, "fake test"); # Same number of tests as check_link + ok(1, 'fake test'); # Same number of tests as check_link } sub check_slaves { @@ -210,10 +212,10 @@ sub check_slaves { foreach my $slave (get_slaves_status($id)) { if ($slave->{installed}) { check_link("$altdir/$slave->{name}", $slave->{path}, $msg); - check_link($slave->{"link"}, "$altdir/$slave->{name}", $msg); + check_link($slave->{link}, "$altdir/$slave->{name}", $msg); } else { check_no_link("$altdir/$slave->{name}", $msg); - check_no_link($slave->{"link"}, $msg); + check_no_link($slave->{link}, $msg); } } } @@ -223,7 +225,7 @@ sub check_choice { my $output; if (defined $id) { # Check status - call_ua([ "--query", "$main_name" ], to_string => \$output, test_id => $msg); + call_ua([ '--query', "$main_name" ], to_string => \$output, test_id => $msg); $output =~ /^Status: (.*)$/im; is($1, $mode, "$msg: status is not $mode."); # Check links @@ -232,7 +234,7 @@ sub check_choice { check_link($main_link, "$altdir/$main_name", $msg); check_slaves($id, $msg); } else { - call_ua([ "--query", "$main_name" ], error_to_string => \$output, + call_ua([ '--query', "$main_name" ], error_to_string => \$output, expect_failure => 1, test_id => $msg); ok($output =~ /no alternatives/, "$msg: bad error message for --query."); # Check that all links have disappeared @@ -248,18 +250,18 @@ cleanup(); remove_choice(0); # successive install in auto mode install_choice(1); -check_choice(1, "auto", "initial install 1"); +check_choice(1, 'auto', 'initial install 1'); install_choice(2); # 2 is lower prio, stays at 1 -check_choice(1, "auto", "initial install 2"); +check_choice(1, 'auto', 'initial install 2'); install_choice(0); # 0 is higher priority -check_choice(0, "auto", "initial install 3"); +check_choice(0, 'auto', 'initial install 3'); # verify that the administrative file is sorted properly { local $/ = undef; - open(FILE, "<", "$admindir/generic-test") or die $!; - my $content = <FILE>; - close(FILE); + open(my $db_fh, '<', "$admindir/generic-test") or die $!; + my $content = <$db_fh>; + close($db_fh); my $expected = "auto @@ -288,101 +290,101 @@ $bindir/slave4 $expected .= $alt->{path} . "\n"; $expected .= $alt->{priority} . "\n"; foreach my $slave_name (sort keys %slaves) { - $expected .= $slaves{$slave_name}{$alt->{path}}{path} || ""; + $expected .= $slaves{$slave_name}{$alt->{path}}{path} || ''; $expected .= "\n"; } } $expected .= "\n"; - is($content, $expected, "administrative file is as expected"); + is($content, $expected, 'administrative file is as expected'); } # manual change with --set-selections my $input = "doesntexist auto $paths{date}\ngeneric-test manual $paths{false}\n"; -my $output = ""; -call_ua(["--set-selections"], from_string => \$input, - to_string => \$output, test_id => "manual update with --set-selections"); -check_choice(1, "manual", "manual update with --set-selections"); +my $output = ''; +call_ua(['--set-selections'], from_string => \$input, + to_string => \$output, test_id => 'manual update with --set-selections'); +check_choice(1, 'manual', 'manual update with --set-selections'); $input = "generic-test auto $paths{true}\n"; -call_ua(["--set-selections"], from_string => \$input, - to_string => \$output, test_id => "auto update with --set-selections"); -check_choice(0, "auto", "auto update with --set-selections"); +call_ua(['--set-selections'], from_string => \$input, + to_string => \$output, test_id => 'auto update with --set-selections'); +check_choice(0, 'auto', 'auto update with --set-selections'); # manual change with set -set_choice(2, test_id => "manual update with --set"); -check_choice(2, "manual", "manual update with --set"); # test #388313 -remove_choice(2, test_id => "remove manual, back to auto"); -check_choice(0, "auto", "remove manual, back to auto"); -remove_choice(0, test_id => "remove best"); -check_choice(1, "auto", "remove best"); -remove_choice(1, test_id => "no alternative left"); -check_choice(undef, "", "no alternative left"); +set_choice(2, test_id => 'manual update with --set'); +check_choice(2, 'manual', 'manual update with --set'); # test #388313 +remove_choice(2, test_id => 'remove manual, back to auto'); +check_choice(0, 'auto', 'remove manual, back to auto'); +remove_choice(0, test_id => 'remove best'); +check_choice(1, 'auto', 'remove best'); +remove_choice(1, test_id => 'no alternative left'); +check_choice(undef, '', 'no alternative left'); # single choice in manual mode, to be removed install_choice(1); set_choice(1); -check_choice(1, "manual", "single manual choice"); +check_choice(1, 'manual', 'single manual choice'); remove_choice(1); -check_choice(undef, "", "removal single manual"); +check_choice(undef, '', 'removal single manual'); # test --remove-all install_choice(0); install_choice(1); install_choice(2); -remove_all_choices(test_id => "remove all"); -check_choice(undef, "", "no alternative left"); +remove_all_choices(test_id => 'remove all'); +check_choice(undef, '', 'no alternative left'); # check auto-recovery of user mistakes (#100135) install_choice(1); -ok(unlink("$bindir/generic-test"), "failed removal"); -ok(unlink("$bindir/slave1"), "failed removal"); +ok(unlink("$bindir/generic-test"), 'failed removal'); +ok(unlink("$bindir/slave1"), 'failed removal'); install_choice(1); -check_choice(1, "auto", "recreate links in auto mode"); +check_choice(1, 'auto', 'recreate links in auto mode'); set_choice(1); -ok(unlink("$bindir/generic-test"), "failed removal"); -ok(unlink("$bindir/slave1"), "failed removal"); +ok(unlink("$bindir/generic-test"), 'failed removal'); +ok(unlink("$bindir/slave1"), 'failed removal'); install_choice(1); -check_choice(1, "manual", "recreate links in manual mode"); +check_choice(1, 'manual', 'recreate links in manual mode'); # check recovery of /etc/alternatives/* install_choice(0); -ok(unlink("$altdir/generic-test"), "failed removal"); +ok(unlink("$altdir/generic-test"), 'failed removal'); install_choice(1); -check_choice(0, "auto", "<altdir>/generic-test lost, back to auto"); +check_choice(0, 'auto', '<altdir>/generic-test lost, back to auto'); # test --config config_choice(0); -check_choice(0, "manual", "config to best but manual"); +check_choice(0, 'manual', 'config to best but manual'); config_choice(1); -check_choice(1, "manual", "config to manual"); +check_choice(1, 'manual', 'config to manual'); config_choice(-1); -check_choice(0, "auto", "config auto"); +check_choice(0, 'auto', 'config auto'); # test rename of links install_choice(0); -my $old_slave = $choices[0]{"slaves"}[0]{"link"}; +my $old_slave = $choices[0]{slaves}[0]{link}; my $old_link = $main_link; -$choices[0]{"slaves"}[0]{"link"} = "$bindir/more/generic-slave"; +$choices[0]{slaves}[0]{link} = "$bindir/more/generic-slave"; $main_link = "$bindir/more/mytest"; install_choice(0); -check_choice(0, "auto", "test rename of links"); -check_no_link($old_link, "test rename of links"); -check_no_link($old_slave, "test rename of links"); +check_choice(0, 'auto', 'test rename of links'); +check_no_link($old_link, 'test rename of links'); +check_no_link($old_slave, 'test rename of links'); # rename with installing other alternatives $old_link = $main_link; $main_link = "$bindir/generic-test"; install_choice(1); -check_choice(0, "auto", "rename link"); -check_no_link($old_link, "rename link"); +check_choice(0, 'auto', 'rename link'); +check_no_link($old_link, 'rename link'); # rename with lost file unlink($old_slave); -$old_slave = $choices[0]{"slaves"}[0]{"link"}; -$choices[0]{"slaves"}[0]{"link"} = "$bindir/generic-slave-bis"; +$old_slave = $choices[0]{slaves}[0]{link}; +$choices[0]{slaves}[0]{link} = "$bindir/generic-slave-bis"; install_choice(0); -check_choice(0, "auto", "rename lost file"); -check_no_link($old_slave, "rename lost file"); +check_choice(0, 'auto', 'rename lost file'); +check_no_link($old_slave, 'rename lost file'); # update of alternative with many slaves not currently installed # and the link of the renamed slave exists while it should not set_choice(1); symlink("$paths{cat}", "$bindir/generic-slave-bis"); -$choices[0]{"slaves"}[0]{"link"} = "$bindir/slave2"; -install_choice(0, test_id => "update with non-installed slaves"); +$choices[0]{slaves}[0]{link} = "$bindir/slave2"; +install_choice(0, test_id => 'update with non-installed slaves'); check_no_link("$bindir/generic-slave-bis", - "drop renamed symlink that should not be installed"); + 'drop renamed symlink that should not be installed'); # test install with empty admin file (#457863) cleanup(); @@ -391,110 +393,110 @@ install_choice(0); # test install with garbage admin file cleanup(); system("echo garbage > $admindir/generic-test"); -install_choice(0, error_to_file => "/dev/null", expect_failure => 1); +install_choice(0, error_to_file => '/dev/null', expect_failure => 1); # test invalid usages cleanup(); install_choice(0); # try to install a slave alternative as new master -call_ua(["--install", "$bindir/testmaster", "slave1", "$paths{date}", "10"], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'slave1', "$paths{date}", '10'], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # try to install a master alternative as slave -call_ua(["--install", "$bindir/testmaster", "testmaster", "$paths{date}", "10", - "--slave", "$bindir/testslave", "generic-test", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'testmaster', "$paths{date}", '10', + '--slave', "$bindir/testslave", 'generic-test', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # try to reuse master link in slave -call_ua(["--install", "$bindir/testmaster", "testmaster", "$paths{date}", "10", - "--slave", "$bindir/testmaster", "testslave", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'testmaster', "$paths{date}", '10', + '--slave', "$bindir/testmaster", 'testslave', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # try to reuse links in master alternative -call_ua(["--install", "$bindir/slave1", "testmaster", "$paths{date}", "10"], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/slave1", 'testmaster', "$paths{date}", '10'], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # try to reuse links in slave alternative -call_ua(["--install", "$bindir/testmaster", "testmaster", "$paths{date}", "10", - "--slave", "$bindir/generic-test", "testslave", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'testmaster', "$paths{date}", '10', + '--slave', "$bindir/generic-test", 'testslave', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # try to reuse slave link in another slave alternative of another choice of # the same main alternative -call_ua(["--install", $main_link, $main_name, "$paths{date}", "10", - "--slave", "$bindir/slave1", "testslave", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', $main_link, $main_name, "$paths{date}", '10', + '--slave', "$bindir/slave1", 'testslave', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # lack of absolute filenames in links or file path, non-existing path, -call_ua(["--install", "../testmaster", "testmaster", "$paths{date}", "10"], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); -call_ua(["--install", "$bindir/testmaster", "testmaster", "./update-alternatives.pl", "10"], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', '../testmaster', 'testmaster', "$paths{date}", '10'], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); +call_ua(['--install', "$bindir/testmaster", 'testmaster', './update-alternatives.pl', '10'], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # non-existing alternative path -call_ua(["--install", "$bindir/testmaster", "testmaster", "$bindir/doesntexist", "10"], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'testmaster', "$bindir/doesntexist", '10'], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # invalid alternative name in master -call_ua(["--install", "$bindir/testmaster", "test/master", "$paths{date}", "10"], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'test/master', "$paths{date}", '10'], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # invalid alternative name in slave -call_ua(["--install", "$bindir/testmaster", "testmaster", "$paths{date}", "10", - "--slave", "$bindir/testslave", "test slave", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/testmaster", 'testmaster', "$paths{date}", '10', + '--slave', "$bindir/testslave", 'test slave', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # install in non-existing dir should fail -call_ua(["--install", "$bindir/doesntexist/testmaster", "testmaster", "$paths{date}", "10", - "--slave", "$bindir/testslave", "testslave", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); -call_ua(["--install", "$bindir/testmaster", "testmaster", "$paths{date}", "10", - "--slave", "$bindir/doesntexist/testslave", "testslave", "$paths{true}" ], - expect_failure => 1, to_file => "/dev/null", error_to_file => "/dev/null"); +call_ua(['--install', "$bindir/doesntexist/testmaster", 'testmaster', "$paths{date}", '10', + '--slave', "$bindir/testslave", 'testslave', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); +call_ua(['--install', "$bindir/testmaster", 'testmaster', "$paths{date}", '10', + '--slave', "$bindir/doesntexist/testslave", 'testslave', "$paths{true}" ], + expect_failure => 1, to_file => '/dev/null', error_to_file => '/dev/null'); # non-existing alternative path in slave is not a failure -my $old_path = $choices[0]{"slaves"}[0]{"path"}; -$old_slave = $choices[0]{"slaves"}[0]{"link"}; -$choices[0]{"slaves"}[0]{"path"} = "$bindir/doesntexist"; -$choices[0]{"slaves"}[0]{"link"} = "$bindir/baddir/slave2"; +my $old_path = $choices[0]{slaves}[0]{path}; +$old_slave = $choices[0]{slaves}[0]{link}; +$choices[0]{slaves}[0]{path} = "$bindir/doesntexist"; +$choices[0]{slaves}[0]{link} = "$bindir/baddir/slave2"; # test rename of slave link that existed but that doesn't anymore # and link is moved into non-existing dir at the same time install_choice(0); -check_choice(0, "auto", "optional renamed slave2 in non-existing dir"); +check_choice(0, 'auto', 'optional renamed slave2 in non-existing dir'); # same but on fresh install cleanup(); install_choice(0); -check_choice(0, "auto", "optional slave2 in non-existing dir"); -$choices[0]{"slaves"}[0]{"link"} = $old_slave; +check_choice(0, 'auto', 'optional slave2 in non-existing dir'); +$choices[0]{slaves}[0]{link} = $old_slave; # test fresh install with a non-existing slave file cleanup(); install_choice(0); -check_choice(0, "auto", "optional slave2"); -$choices[0]{"slaves"}[0]{"path"} = $old_path; +check_choice(0, 'auto', 'optional slave2'); +$choices[0]{slaves}[0]{path} = $old_path; # test management of pre-existing files cleanup(); system("touch $main_link $bindir/slave1"); install_choice(0); -ok(!-l $main_link, "install preserves files that should be links"); -ok(!-l "$bindir/slave1", "install preserves files that should be slave links"); +ok(!-l $main_link, 'install preserves files that should be links'); +ok(!-l "$bindir/slave1", 'install preserves files that should be slave links'); remove_choice(0); -ok(-f $main_link, "removal keeps real file installed as master link"); -ok(-f "$bindir/slave1", "removal keeps real files installed as slave links"); -install_choice(0, params => ["--force"]); -check_choice(0, "auto", "install --force replaces files with links"); +ok(-f $main_link, 'removal keeps real file installed as master link'); +ok(-f "$bindir/slave1", 'removal keeps real files installed as slave links'); +install_choice(0, params => ['--force']); +check_choice(0, 'auto', 'install --force replaces files with links'); # test management of pre-existing files #2 cleanup(); system("touch $main_link $bindir/slave2"); install_choice(0); install_choice(1); -ok(!-l $main_link, "inactive install preserves files that should be links"); -ok(!-l "$bindir/slave2", "inactive install preserves files that should be slave links"); -ok(-f $main_link, "inactive install keeps real file installed as master link"); -ok(-f "$bindir/slave2", "inactive install keeps real files installed as slave links"); +ok(!-l $main_link, 'inactive install preserves files that should be links'); +ok(!-l "$bindir/slave2", 'inactive install preserves files that should be slave links'); +ok(-f $main_link, 'inactive install keeps real file installed as master link'); +ok(-f "$bindir/slave2", 'inactive install keeps real files installed as slave links'); set_choice(1); -ok(!-l $main_link, "manual switching preserves files that should be links"); -ok(!-l "$bindir/slave2", "manual switching preserves files that should be slave links"); -ok(-f $main_link, "manual switching keeps real file installed as master link"); -ok(-f "$bindir/slave2", "manual switching keeps real files installed as slave links"); +ok(!-l $main_link, 'manual switching preserves files that should be links'); +ok(!-l "$bindir/slave2", 'manual switching preserves files that should be slave links'); +ok(-f $main_link, 'manual switching keeps real file installed as master link'); +ok(-f "$bindir/slave2", 'manual switching keeps real files installed as slave links'); remove_choice(1); -ok(!-l $main_link, "auto switching preserves files that should be links"); -ok(!-l "$bindir/slave2", "auto switching preserves files that should be slave links"); -ok(-f $main_link, "auto switching keeps real file installed as master link"); -ok(-f "$bindir/slave2", "auto switching keeps real files installed as slave links"); -remove_all_choices(params => ["--force"]); -ok(!-e "$bindir/slave2", "forced removeall drops real files installed as slave links"); +ok(!-l $main_link, 'auto switching preserves files that should be links'); +ok(!-l "$bindir/slave2", 'auto switching preserves files that should be slave links'); +ok(-f $main_link, 'auto switching keeps real file installed as master link'); +ok(-f "$bindir/slave2", 'auto switching keeps real files installed as slave links'); +remove_all_choices(params => ['--force']); +ok(!-e "$bindir/slave2", 'forced removeall drops real files installed as slave links'); # test management of pre-existing files #3 cleanup(); @@ -502,15 +504,15 @@ system("touch $main_link $bindir/slave2"); install_choice(0); install_choice(1); remove_choice(0); -ok(!-l $main_link, "removal + switching preserves files that should be links"); -ok(!-l "$bindir/slave2", "removal + switching preserves files that should be slave links"); -ok(-f $main_link, "removal + switching keeps real file installed as master link"); -ok(-f "$bindir/slave2", "removal + switching keeps real files installed as slave links"); +ok(!-l $main_link, 'removal + switching preserves files that should be links'); +ok(!-l "$bindir/slave2", 'removal + switching preserves files that should be slave links'); +ok(-f $main_link, 'removal + switching keeps real file installed as master link'); +ok(-f "$bindir/slave2", 'removal + switching keeps real files installed as slave links'); install_choice(0); -ok(!-l $main_link, "install + switching preserves files that should be links"); -ok(!-l "$bindir/slave2", "install + switching preserves files that should be slave links"); -ok(-f $main_link, "install + switching keeps real file installed as master link"); -ok(-f "$bindir/slave2", "install + switching keeps real files installed as slave links"); -set_choice(1, params => ["--force"]); -ok(!-e "$bindir/slave2", "forced switching w/o slave drops real files installed as slave links"); -check_choice(1, "manual", "set --force replaces files with links"); +ok(!-l $main_link, 'install + switching preserves files that should be links'); +ok(!-l "$bindir/slave2", 'install + switching preserves files that should be slave links'); +ok(-f $main_link, 'install + switching keeps real file installed as master link'); +ok(-f "$bindir/slave2", 'install + switching keeps real files installed as slave links'); +set_choice(1, params => ['--force']); +ok(!-e "$bindir/slave2", 'forced switching w/o slave drops real files installed as slave links'); +check_choice(1, 'manual', 'set --force replaces files with links'); diff --git a/utils/update-alternatives.c b/utils/update-alternatives.c index 5f4364b09..d88ded5b7 100644 --- a/utils/update-alternatives.c +++ b/utils/update-alternatives.c @@ -173,7 +173,9 @@ badusage(char const *fmt, ...) vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n\n"); - usage(); + fprintf(stderr, _("Use '%s --help' for program usage information."), + PROGNAME); + fprintf(stderr, "\n"); exit(2); } @@ -401,29 +403,19 @@ log_msg(const char *fmt, ...) static int spawn(const char *prog, const char *args[]) { - const char **cmd; - int i = 0; pid_t pid, r; int status; - while (args[i++]); - cmd = xmalloc(sizeof(char *) * (i + 2)); - cmd[0] = prog; - for (i = 0; args[i]; i++) - cmd[i + 1] = args[i]; - cmd[i + 1] = NULL; - pid = fork(); if (pid == -1) error(_("fork failed")); if (pid == 0) { - execvp(prog, (char *const *)cmd); + execvp(prog, (char *const *)args); syserr(_("unable to execute %s (%s)"), prog, prog); } while ((r = waitpid(pid, &status, 0)) == -1 && errno == EINTR) ; if (r != pid) error(_("wait for subprocess %s failed"), prog); - free(cmd); return status; } @@ -443,8 +435,9 @@ subcall(const char *prog, ...) va_end(args); /* Prepare table for all parameters */ - cmd = xmalloc(sizeof(*cmd) * (nb_opts + count + 1)); + cmd = xmalloc(sizeof(*cmd) * (nb_opts + count + 2)); i = 0; + cmd[i++] = prog; for (j = 0; j < nb_opts; j++) cmd[i++] = pass_opts[j]; va_start(args, prog); @@ -472,7 +465,7 @@ rename_mv(const char *src, const char *dst) return false; if (rename(src, dst) != 0) { - const char *args[3] = { src, dst, NULL }; + const char *args[] = { "mv", src, dst, NULL }; int r; r = spawn("mv", args); if (WIFEXITED(r) && WEXITSTATUS(r) == 0) @@ -659,6 +652,8 @@ struct commit_operation { struct alternative { char *master_name; char *master_link; + char *current; + enum alternative_status { ALT_ST_UNKNOWN, ALT_ST_AUTO, @@ -672,6 +667,7 @@ struct alternative { int ref_count; bool modified; + bool known_current; }; static void @@ -698,11 +694,13 @@ alternative_new(const char *name) alt = xmalloc(sizeof(*alt)); alt->master_name = xstrdup(name); alt->master_link = NULL; + alt->current = NULL; alt->status = ALT_ST_UNKNOWN; alt->slaves = NULL; alt->choices = NULL; alt->commit_ops = NULL; alt->modified = false; + alt->known_current = false; alt->ref_count = 1; return alt; @@ -752,6 +750,8 @@ alternative_reset(struct alternative *alt) { struct slave_link *slave; + free(alt->current); + alt->current = NULL; free(alt->master_link); alt->master_link = NULL; while (alt->slaves) { @@ -762,6 +762,7 @@ alternative_reset(struct alternative *alt) alternative_choices_free(alt); alternative_commit_operations_free(alt); alt->modified = false; + alt->known_current = false; } static void @@ -1039,8 +1040,8 @@ struct altdb_context { char *filename; enum altdb_flags flags; bool modified; - void DPKG_ATTR_PRINTF(2) (*bad_format)(struct altdb_context *, - const char *format, ...); + void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(2) + (*bad_format)(struct altdb_context *, const char *format, ...); jmp_buf on_error; }; @@ -1197,12 +1198,10 @@ alternative_parse_fileset(struct alternative *a, struct altdb_context *ctx) return false; } - for (fs = a->choices; fs; fs = fs->next) { - if (strcmp(fs->master_file, master_file) == 0) { - free(master_file); - ctx->bad_format(ctx, _("duplicate path %s"), - fs->master_file); - } + fs = alternative_get_fileset(a, master_file); + if (fs) { + free(master_file); + ctx->bad_format(ctx, _("duplicate path %s"), master_file); } if (stat(master_file, &st)) { @@ -1410,30 +1409,30 @@ alternative_save(struct alternative *a) free(file); } -static struct fileset * -alternative_get_best(struct alternative *a) +static const char * +alternative_set_current(struct alternative *a, char *new_choice) { - struct fileset *fs, *best; - - for (best = fs = a->choices; fs; fs = fs->next) - if (fs->priority > best->priority) - best = fs; + a->known_current = true; + a->current = new_choice; - return best; + return new_choice; } -static char * +static const char * alternative_get_current(struct alternative *a) { struct stat st; char *curlink; char *file; + if (a->known_current) + return a->current; + xasprintf(&curlink, "%s/%s", altdir, a->master_name); if (lstat(curlink, &st)) { if (errno == ENOENT) { free(curlink); - return NULL; + return alternative_set_current(a, NULL); } syserr(_("cannot stat file '%s'"), curlink); } @@ -1441,7 +1440,29 @@ alternative_get_current(struct alternative *a) file = xreadlink(curlink); free(curlink); - return file; + return alternative_set_current(a, file); +} + +static struct fileset * +alternative_get_best(struct alternative *a) +{ + struct fileset *fs, *best; + const char *current; + + current = alternative_get_current(a); + if (current) + best = alternative_get_fileset(a, current); + else + best = NULL; + + if (best == NULL) + best = a->choices; + + for (fs = a->choices; fs; fs = fs->next) + if (fs->priority > best->priority) + best = fs; + + return best; } static void @@ -1449,7 +1470,7 @@ alternative_display_query(struct alternative *a) { struct fileset *best, *fs; struct slave_link *sl; - char *current; + const char *current; pr("Name: %s", a->master_name); pr("Link: %s", a->master_link); @@ -1464,7 +1485,6 @@ alternative_display_query(struct alternative *a) pr("Best: %s", best->master_file); current = alternative_get_current(a); pr("Value: %s", current ? current : "none"); - free(current); for (fs = a->choices; fs; fs = fs->next) { printf("\n"); @@ -1484,7 +1504,7 @@ alternative_display_query(struct alternative *a) static void alternative_display_user(struct alternative *a) { - char *current; + const char *current; struct fileset *fs; struct slave_link *sl; @@ -1493,7 +1513,6 @@ alternative_display_user(struct alternative *a) current = alternative_get_current(a); if (current) { pr(_(" link currently points to %s"), current); - free(current); } else { pr(_(" link currently absent")); } @@ -1526,7 +1545,8 @@ alternative_display_list(struct alternative *a) static const char * alternative_select_choice(struct alternative *a) { - char *current, *ret, selection[_POSIX_PATH_MAX]; + const char *current; + char *ret, selection[_POSIX_PATH_MAX]; struct fileset *best, *fs; int len, idx; @@ -1573,7 +1593,6 @@ alternative_select_choice(struct alternative *a) "or type selection number: ")); ret = fgets(selection, sizeof(selection), stdin); if (ret == NULL || strlen(selection) == 0) { - free(current); return NULL; } selection[strlen(selection) - 1] = '\0'; @@ -1587,7 +1606,6 @@ alternative_select_choice(struct alternative *a) /* Look up by index */ if (idx == 0) { alternative_set_status(a, ALT_ST_AUTO); - free(current); return xstrdup(best->master_file); } idx--; @@ -1595,17 +1613,14 @@ alternative_select_choice(struct alternative *a) fs = fs->next; if (fs) { alternative_set_status(a, ALT_ST_MANUAL); - free(current); return xstrdup(fs->master_file); } } else { /* Look up by name */ - for (fs = a->choices; fs; fs = fs->next) { - if (strcmp(fs->master_file, selection) == 0) { - alternative_set_status(a, ALT_ST_MANUAL); - free(current); - return xstrdup(selection); - } + fs = alternative_get_fileset(a, selection); + if (fs) { + alternative_set_status(a, ALT_ST_MANUAL); + return xstrdup(selection); } } } @@ -1826,7 +1841,8 @@ alternative_remove(struct alternative *a) static bool alternative_is_broken(struct alternative *a) { - char *altlnk, *wanted, *current; + const char *current; + char *altlnk, *wanted; struct fileset *fs; struct slave_link *sl; @@ -1848,12 +1864,10 @@ alternative_is_broken(struct alternative *a) if (current == NULL) return true; - if (!alternative_has_choice(a, current)) { - free(current); + if (!alternative_has_choice(a, current)) return false; - } + fs = alternative_get_fileset(a, current); - free(current); /* Check slaves */ for (sl = a->slaves; sl; sl = sl->next) { @@ -2042,13 +2056,12 @@ alternative_get_selections(void) alternative_map_load_names(alt_map_obj); for (am = alt_map_obj; am && am->item; am = am->next) { - char *current; + const 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); @@ -2252,7 +2265,7 @@ alternative_evolve(struct alternative *a, struct alternative *b, static void alternative_update(struct alternative *a, - char *current_choice, const char *new_choice) + const char *current_choice, const char *new_choice) { /* No choice left, remove everything. */ if (!alternative_choices_count(a)) { @@ -2436,7 +2449,8 @@ main(int argc, char **argv) /* Set of files to install in the alternative. */ struct fileset *fileset = NULL; /* Path of alternative we are offering. */ - char *path = NULL, *current_choice = NULL; + char *path = NULL; + const char *current_choice = NULL; const char *new_choice = NULL; int i = 0; @@ -2483,13 +2497,8 @@ main(int argc, char **argv) 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); - } + if (prio < INT_MIN || prio > INT_MAX || errno == ERANGE) + badusage(_("priority is out of range")); a = alternative_new(argv[i + 2]); inst_alt = alternative_new(argv[i + 2]); |