4 // Copyright (c) 2000-2005 Per Liden
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
29 void pkgadd::run(int argc
, char** argv
)
32 // Check command line options
36 bool o_upgrade
= false;
39 for (int i
= 1; i
< argc
; i
++) {
40 string
option(argv
[i
]);
41 if (option
== "-r" || option
== "--root") {
42 assert_argument(argv
, argc
, i
);
45 } else if (option
== "-u" || option
== "--upgrade") {
47 } else if (option
== "-f" || option
== "--force") {
49 } else if (option
[0] == '-' || !o_package
.empty()) {
50 throw runtime_error("invalid option " + option
);
56 if (o_package
.empty())
57 throw runtime_error("option missing");
63 throw runtime_error("only root can install/upgrade packages");
66 // Install/upgrade package
69 db_lock
lock(o_root
, true);
72 pair
<string
, pkginfo_t
> package
= pkg_open(o_package
);
73 vector
<rule_t
> config_rules
= read_config();
75 bool installed
= db_find_pkg(package
.first
);
76 if (installed
&& !o_upgrade
)
77 throw runtime_error("package " + package
.first
+ " already installed (use -u to upgrade)");
78 else if (!installed
&& o_upgrade
)
79 throw runtime_error("package " + package
.first
+ " not previously installed (skip -u to install)");
81 set
<string
> conflicting_files
= db_find_conflicts(package
.first
, package
.second
);
83 if (!conflicting_files
.empty()) {
85 set
<string
> keep_list
;
86 if (o_upgrade
) // Don't remove files matching the rules in configuration
87 keep_list
= make_keep_list(conflicting_files
, config_rules
);
88 db_rm_files(conflicting_files
, keep_list
); // Remove unwanted conflicts
90 copy(conflicting_files
.begin(), conflicting_files
.end(), ostream_iterator
<string
>(cerr
, "\n"));
91 throw runtime_error("listed file(s) already installed (use -f to ignore and overwrite)");
95 set
<string
> keep_list
;
98 keep_list
= make_keep_list(package
.second
.files
, config_rules
);
99 db_rm_pkg(package
.first
, keep_list
);
102 db_add_pkg(package
.first
, package
.second
);
104 pkg_install(o_package
, keep_list
);
109 void pkgadd::print_help() const
111 cout
<< "usage: " << utilname
<< " [options] <file>" << endl
112 << "options:" << endl
113 << " -u, --upgrade upgrade package with the same name" << endl
114 << " -f, --force force install, overwrite conflicting files" << endl
115 << " -r, --root <path> specify alternative installation root" << endl
116 << " -v, --version print version and exit" << endl
117 << " -h, --help print help and exit" << endl
;
120 vector
<rule_t
> pkgadd::read_config() const
122 vector
<rule_t
> rules
;
123 unsigned int linecount
= 0;
124 const string filename
= root
+ PKGADD_CONF
;
125 ifstream
in(filename
.c_str());
132 if (!line
.empty() && line
[0] != '#') {
133 if (line
.length() >= PKGADD_CONF_MAXLINE
)
134 throw runtime_error(filename
+ ":" + itos(linecount
) + ": line too long, aborting");
136 char event
[PKGADD_CONF_MAXLINE
];
137 char pattern
[PKGADD_CONF_MAXLINE
];
138 char action
[PKGADD_CONF_MAXLINE
];
139 char dummy
[PKGADD_CONF_MAXLINE
];
140 if (sscanf(line
.c_str(), "%s %s %s %s", event
, pattern
, action
, dummy
) != 3)
141 throw runtime_error(filename
+ ":" + itos(linecount
) + ": wrong number of arguments, aborting");
143 if (!strcmp(event
, "UPGRADE")) {
145 rule
.event
= rule_t::UPGRADE
;
146 rule
.pattern
= pattern
;
147 if (!strcmp(action
, "YES")) {
149 } else if (!strcmp(action
, "NO")) {
152 throw runtime_error(filename
+ ":" + itos(linecount
) + ": '" +
153 string(action
) + "' unknown action, should be YES or NO, aborting");
155 rules
.push_back(rule
);
157 throw runtime_error(filename
+ ":" + itos(linecount
) + ": '" +
158 string(event
) + "' unknown event, aborting");
165 cerr
<< "Configuration:" << endl
;
166 for (vector
<rule_t
>::const_iterator j
= rules
.begin(); j
!= rules
.end(); j
++) {
167 cerr
<< "\t" << (*j
).pattern
<< "\t" << (*j
).action
<< endl
;
175 set
<string
> pkgadd::make_keep_list(const set
<string
>& files
, const vector
<rule_t
>& rules
) const
177 set
<string
> keep_list
;
179 for (set
<string
>::const_iterator i
= files
.begin(); i
!= files
.end(); i
++) {
180 for (vector
<rule_t
>::const_reverse_iterator j
= rules
.rbegin(); j
!= rules
.rend(); j
++) {
181 if ((*j
).event
== rule_t::UPGRADE
) {
183 if (regcomp(&preg
, (*j
).pattern
.c_str(), REG_EXTENDED
| REG_NOSUB
))
184 throw runtime_error("error compiling regular expression '" + (*j
).pattern
+ "', aborting");
186 if (!regexec(&preg
, (*i
).c_str(), 0, 0, 0)) {
188 keep_list
.insert(keep_list
.end(), *i
);
198 cerr
<< "Keep list:" << endl
;
199 for (set
<string
>::const_iterator j
= keep_list
.begin(); j
!= keep_list
.end(); j
++) {
200 cerr
<< " " << (*j
) << endl
;