allow to run spkg by the non-root user for some commands
[spkg.git] / src / main.c
blob39377db74c69744708130ac35c3e5b8c9c6d1cd5
1 /*----------------------------------------------------------------------*\
2 |* spkg - The Unofficial Slackware Linux Package Manager *|
3 |* designed by Ondøej Jirman, 2005 *|
4 |*----------------------------------------------------------------------*|
5 |* No copy/usage restrictions are imposed on anybody. *|
6 \*----------------------------------------------------------------------*/
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
12 #include <popt.h>
14 #include "config.h"
16 #include "commands.h"
17 #include "pkgdb.h"
18 #include "sigtrap.h"
19 #include "message.h"
20 #include "misc.h"
22 /* commands
23 ************************************************************************/
25 static guint command = 0;
26 #define CMD_INSTALL (1<<0)
27 #define CMD_UPGRADE (1<<1)
28 #define CMD_REMOVE (1<<2)
29 #define CMD_LIST (1<<3)
31 static struct poptOption optsCommands[] = {
33 "install", 'i', POPT_ARG_NONE|POPT_BIT_SET, &command, CMD_INSTALL,
34 "Install packages.", NULL
37 "upgrade", 'u', POPT_ARG_NONE|POPT_BIT_SET, &command, CMD_UPGRADE,
38 "Upgrade packages", NULL
41 "remove", 'd', POPT_ARG_NONE|POPT_BIT_SET, &command, CMD_REMOVE,
42 "Remove packages.", NULL
45 "list", 'l', POPT_ARG_NONE|POPT_BIT_SET, &command, CMD_LIST,
46 "List all packages. You can add package names to the command line "
47 "to limit listed packages. This command supports glob matching.", NULL
49 POPT_TABLEEND
52 /* options
53 ************************************************************************/
55 static struct cmd_options cmd_opts = {
56 .root = "/",
57 .dryrun = 0,
58 .verbosity = 2,
59 .safe = 0,
60 .no_optsyms = 0,
61 .no_scripts = 0,
62 .no_ldconfig = 0,
63 .reinstall = 0
66 static gint verbose = 0;
67 static gint quiet = 0;
68 static gint install_new = 0;
70 static struct poptOption optsOptions[] = {
72 "root", 'r', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &cmd_opts.root, 0,
73 "Set altrernate root directory for package operations.", "ROOT"
76 "safe", 's', 0, &cmd_opts.safe, 0,
77 "Play it safe. Don't replace existing files during --install or --upgrade. "
78 "Don't run post-installation scripts. Don't remove changed files on "
79 "--remove.", NULL
82 "dry-run", 'n', 0, &cmd_opts.dryrun, 0,
83 "Don't modify filesystem or database. This may be useful when used along "
84 "with -v option to check what exactly would given command do.", NULL
87 "verbose", 'v', 0, 0, 1,
88 "Increase verbosity level. This option enables notices when used once. "
89 "When used twice it will also enable debug messages.", NULL
92 "quiet", 'q', 0, 0, 2,
93 "Decrease verbosity level. Default verbosity level is 2 (show info "
94 "messages and warnings). This option disables warnings when used once. "
95 "When used twice it will completely disable output. "
96 "Please note, that error messages can't be disabled.", NULL
99 "reinstall", 0, 0, &cmd_opts.reinstall, 0,
100 "When upgrading package and package already exists in the database, "
101 "force reinstall.", NULL
104 "install-new", 0, 0, &install_new, 0,
105 "When upgrading package that does not yet exist in the database, "
106 "install it instead.", NULL
109 "no-fast-symlinks", 0, 0, &cmd_opts.no_optsyms, 0,
110 "Spkg by default parses doinst.sh for symlink creation code and removes "
111 "it from the script. This improves execution times of doinst.sh. Use "
112 "this option to disable such optimizations.", NULL
115 "no-scripts", 0, 0, &cmd_opts.no_scripts, 0,
116 "Disable postinstallation script.", NULL
119 "no-ldconfig", 0, 0, &cmd_opts.no_ldconfig, 0,
120 "Don't execute ldconfig after installation and upgrade.", NULL
122 POPT_TABLEEND
125 /* help
126 ************************************************************************/
128 static gint help = 0;
129 static gint usage = 0;
130 static gint version = 0;
132 static struct poptOption optsHelp[] = {
134 "usage", '\0', POPT_ARG_NONE, &usage, 0,
135 "Display brief usage message.", NULL
138 "help", 'h', POPT_ARG_NONE, &help, 0,
139 "Show this help message.", NULL
142 "version", 'V', POPT_ARG_NONE, &version, 0,
143 "Display spkg version.", NULL
145 POPT_TABLEEND
148 /* main table
149 ************************************************************************/
151 static struct poptOption opts[] = {
152 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &optsCommands, 0, "Commands:", NULL },
153 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &optsOptions, 0, "Options:", NULL },
154 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &optsHelp, 0, "Help options:", NULL },
155 POPT_TABLEEND
158 /* main
159 ************************************************************************/
161 gboolean is_root()
163 return getuid() == 0;
166 int main(const int ac, const char* av[])
168 poptContext optCon=0;
169 gint rc;
170 gint status = 0;
171 const gchar* arg;
172 struct error* err;
174 #ifdef __DEBUG
175 g_mem_set_vtable(glib_mem_profiler_table);
176 #endif
178 err = e_new();
179 /* check if we have enough privileges */
180 unsetenv("LD_LIBRARY_PATH");
182 /* initialize popt context */
183 optCon = poptGetContext("spkg", ac, av, opts, 0);
184 poptSetOtherOptionHelp(optCon, "<command> [options] [packages...]");
186 /* parse options */
187 while ((rc = poptGetNextOpt(optCon)) != -1)
189 if (rc == 1)
190 verbose++;
191 else if (rc == 2)
192 quiet++;
193 if (rc < -1)
195 fprintf(stderr, "ERROR: Invalid argument: %s (%s)\n",
196 poptStrerror(rc),
197 poptBadOption(optCon, POPT_BADOPTION_NOALIAS));
198 goto err_1;
202 /* these are help handlers */
203 if (help)
205 printf(
206 PACKAGE_STRING "\n"
207 "\n"
208 "Written by Ondrej Jirman, 2005-2006.\n"
209 "\n"
210 "This is free software. Not like a beer or like in a \"freedom\",\n"
211 "but like in \"I don't care what you are going to do with it.\"\n"
212 "\n"
214 poptPrintHelp(optCon, stdout, 0);
215 printf(
216 "\n"
217 "Examples:\n"
218 " spkg -i <packages> [--install]\n"
219 " spkg -u <packages> [--upgrade]\n"
220 " spkg -vd <packages> [--verbose --remove]\n"
221 " spkg -l kde* [--list]\n"
222 " spkg -vnu <packages> [--upgrade --verbose --dry-run]\n"
223 "\n"
224 "Official website: http://spkg.megous.com\n"
225 "Bug reports can be sent to <megous@megous.com>.\n"
227 goto out;
229 if (usage)
231 printf("Usage: spkg [-i|-u|-d|-l] [-r ROOT] [-n] [-s] [-q] [-v] [packages...]\n");
232 goto out;
234 if (version)
236 printf("%s\n", PACKAGE_STRING);
237 goto out;
240 /* got command? */
241 if (command == 0)
243 /* check if we are run as Xpkg */
244 if (av[0] != 0)
246 gchar* b = g_path_get_basename(av[0]);
247 if (!strcmp(b, "ipkg"))
248 command |= CMD_INSTALL;
249 else if (!strcmp(b, "rpkg"))
250 command |= CMD_REMOVE;
251 else if (!strcmp(b, "upkg"))
252 command |= CMD_UPGRADE;
253 else if (!strcmp(b, "lpkg"))
254 command |= CMD_LIST;
255 g_free(b);
256 if (command)
257 goto got_command;
259 printf("Usage: spkg [-i|-u|-d|-l] [-r ROOT] [-n] [-s] [-q] [-v] [packages...]\n");
260 printf("For more help use --help command line option.\n");
261 goto err_1;
264 got_command:
265 /* check verbosity options */
266 if (verbose && quiet)
268 fprintf(stderr, "ERROR: Verbose or quiet?\n");
269 goto err_1;
271 cmd_opts.verbosity += verbose;
272 cmd_opts.verbosity -= quiet;
274 /* check command options */
275 switch (command)
277 case CMD_INSTALL:
278 if (!cmd_opts.dryrun && !is_root())
279 goto err_noroot;
280 if (poptPeekArg(optCon) == 0)
281 goto err_nopackages;
282 break;
283 case CMD_UPGRADE:
284 if (!cmd_opts.dryrun && !is_root())
285 goto err_noroot;
286 if (poptPeekArg(optCon) == 0)
287 goto err_nopackages;
288 break;
289 case CMD_REMOVE:
290 if (!cmd_opts.dryrun && !is_root())
291 goto err_noroot;
292 if (poptPeekArg(optCon) == 0)
293 goto err_nopackages;
294 break;
295 case CMD_LIST:
296 break;
297 default:
298 fprintf(stderr, "ERROR: Schizofrenic command usage.\n");
299 goto err_1;
302 /* init signal trap */
303 if (sig_trap(err))
304 goto err_2;
306 /* open db */
307 gboolean readonly = cmd_opts.dryrun || !is_root();
308 if (db_open(cmd_opts.root, readonly, err))
309 goto err_2;
311 switch (command)
313 case CMD_INSTALL:
315 while ((arg = poptGetArg(optCon)) != 0 && !sig_break)
317 if (cmd_install(arg, &cmd_opts, err))
319 if (e_errno(err) & CMD_EXIST)
321 gchar* pkgname = parse_pkgname(arg, 5);
322 _inform("Skipping package %s (already installed)...", pkgname ? pkgname : arg);
323 g_free(pkgname);
324 e_clean(err);
326 else
328 e_print(err);
329 e_clean(err);
330 status = 2;
335 break;
336 case CMD_UPGRADE:
338 while ((arg = poptGetArg(optCon)) != 0 && !sig_break)
340 if (cmd_upgrade(arg, &cmd_opts, err))
342 if (install_new && (e_errno(err) & CMD_NOTEX))
344 e_clean(err);
345 if (cmd_install(arg, &cmd_opts, err))
347 e_print(err);
348 e_clean(err);
349 status = 2;
352 else if (e_errno(err) & CMD_NOTEX)
354 gchar* pkgname = parse_pkgname(arg, 5);
355 _inform("Skipping package %s (not installed)...", pkgname ? pkgname : arg);
356 g_free(pkgname);
357 e_clean(err);
359 else if (e_errno(err) & CMD_EXIST)
361 gchar* pkgname = parse_pkgname(arg, 5);
362 _inform("Skipping package %s (already installed)...", pkgname ? pkgname : arg);
363 g_free(pkgname);
364 e_clean(err);
366 else
368 e_print(err);
369 e_clean(err);
370 status = 2;
375 break;
376 case CMD_REMOVE:
378 while ((arg = poptGetArg(optCon)) != 0 && !sig_break)
380 if (cmd_remove(arg, &cmd_opts, err))
382 e_print(err);
383 e_clean(err);
384 status = 2;
388 break;
389 case CMD_LIST:
391 GSList* arglist = NULL;
392 while ((arg = poptGetArg(optCon)) != 0)
393 arglist = g_slist_append(arglist, g_strdup(arg));
394 if (cmd_list(arglist, &cmd_opts, err))
396 e_print(err);
397 e_clean(err);
398 status = 2;
400 g_slist_foreach(arglist, (GFunc)g_free, 0);
401 g_slist_free(arglist);
403 break;
406 db_close();
408 out:
409 poptFreeContext(optCon);
410 e_free(err);
412 #ifdef __DEBUG
413 g_mem_profile();
414 #endif
416 /* 0 = all ok
417 * 1 = command line error
418 * 2 = package manager error
420 return status;
421 err_1:
422 status = 1;
423 goto out;
424 err_2:
425 status = 2;
426 e_print(err);
427 goto out;
428 err_nopackages:
429 fprintf(stderr, "ERROR: No packages specified.\n");
430 goto err_1;
431 err_noroot:
432 fprintf(stderr, "ERROR: You need root privileges to run this command. Try using --dry-run.\n");
433 goto err_1;