summaryrefslogblamecommitdiff
path: root/src/apk.c
blob: 21e4359648d567623eaa71d8af7339219b1cbab3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                           
                  
                  
                   
                   
                   

                     



                        
                     
                                              

                                  
 




                                                         
                                              





                                     




                                              



                                       

                             










                                                                    











                                                                    
                                                              
 
                             
                         
              






                                     
                                          













                                             










                                                                     
                          
                                            




                                                                    



                                                                      








                                       
                                               
 


                                         
                                             

                                           





                                                                            
 

                                                              
         
 

                                                             

                                                            





                                                        


                                                                     
                            

                              
                         


                                          


                                                                                 
                              
                         



                                        
                              

                                         










                                                         
                              
                        
                                                                    




                                                                              


                 


                               


                               


                                                              



                       
                                             
 
/* apk.c - Alpine Package Keeper (APK)
 *
 * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
 * Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation. See http://www.gnu.org/ for details.
 */

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/stat.h>

#include "apk_defines.h"
#include "apk_applet.h"

const char *apk_root;
struct apk_repository_url apk_repository_list;
int apk_verbosity = 1, apk_cwd_fd;
unsigned int apk_flags = 0;

void apk_log(const char *prefix, const char *format, ...)
{
	va_list va;

	if (prefix != NULL)
		fprintf(stderr, "%s", prefix);
	va_start(va, format);
	vfprintf(stderr, format, va);
	va_end(va);
	fprintf(stderr, "\n");
}

int version(void)
{
	printf("apk-tools " APK_VERSION "\n");
	return 0;
}
int usage(void)
{
	struct apk_applet **a, *applet;

	version();
	printf("\nUsage:\n");

	for (a = &__start_apkapplets; a < &__stop_apkapplets; a++) {
		applet = *a;
		printf("    apk %s %s\n",
		       applet->name, applet->usage);
	}
	printf("\n");

	return 1;
}

static struct apk_applet *find_applet(const char *name)
{
	struct apk_applet **a;

	for (a = &__start_apkapplets; a < &__stop_apkapplets; a++) {
		if (strcmp(name, (*a)->name) == 0)
			return *a;
	}
	
	return NULL;
}

static struct apk_applet *deduce_applet(int argc, char **argv)
{
	struct apk_applet *a;
	const char *prog;
	int i;

	prog = strrchr(argv[0], '/');
	if (prog == NULL)
		prog = argv[0];
	else
		prog++;

	if (strncmp(prog, "apk_", 4) == 0)
		return find_applet(prog + 4);

	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-')
			continue;

		a = find_applet(argv[i]);
		if (a != NULL)
			return a;
	}

	return NULL;
}

static struct apk_repository_url *apk_repository_new(const char *url)
{
	struct apk_repository_url *r = calloc(1, 
			sizeof(struct apk_repository_url));
	if (r) {
		r->url = url;
		list_init(&r->list);
	}
	return r;
}

#define NUM_GENERIC_OPTS 9
static struct option generic_options[32] = {
	{ "root",		required_argument,	NULL, 'p' },
	{ "repository",		required_argument,	NULL, 'X' },
	{ "quiet",		no_argument,		NULL, 'q' },
	{ "verbose",		no_argument,		NULL, 'v' },
	{ "version",		no_argument,		NULL, 'V' },
	{ "progress",		no_argument,		NULL, 0x101 },
	{ "clean-protected",	no_argument,		NULL, 0x102 },
	{ "force",		no_argument,		NULL, 0x103 },
	{ "simulate",		no_argument,		NULL, 0x104 },
};

int main(int argc, char **argv)
{
	struct apk_applet *applet;
	char short_options[256], *sopt;
	struct option *opt;
	int r, optindex;
	void *ctx = NULL;
	struct apk_repository_url *repo = NULL;

	umask(0);
	apk_cwd_fd = open(".", O_RDONLY);
	apk_root = getenv("ROOT");
	list_init(&apk_repository_list.list);

	applet = deduce_applet(argc, argv);
	if (applet != NULL) {
		if (applet->num_options && applet->options) {
			memcpy(&generic_options[NUM_GENERIC_OPTS],
			       applet->options,
			       applet->num_options * sizeof(struct option));
		}

		if (applet->context_size != 0)
			ctx = calloc(1, applet->context_size);
	}

	for (opt = &generic_options[0], sopt = short_options;
	     opt->name != NULL; opt++) {
		if (opt->flag == NULL &&
		    opt->val <= 0xff && isalnum(opt->val)) {
			*(sopt++) = opt->val;
			if (opt->has_arg != no_argument)
				*(sopt++) = ':';
		}
	}

	optindex = 0;
	while ((r = getopt_long(argc, argv, short_options,
				generic_options, &optindex)) != -1) {
		switch (r) {
		case 0:
			break;
		case 'p':
			apk_root = optarg;
			break;
		case 'X':
			repo = apk_repository_new(optarg);
			if (repo)
				list_add(&repo->list, &apk_repository_list.list);
			break;
		case 'q':
			apk_verbosity--;
			break;
		case 'v':
			apk_verbosity++;
			break;
		case 'V':
			return version();
		case 0x101:
			apk_flags |= APK_PROGRESS;
			break;
		case 0x102:
			apk_flags |= APK_CLEAN_PROTECTED;
			break;
		case 0x103:
			apk_flags |= APK_FORCE;
			break;
		case 0x104:
			apk_flags |= APK_SIMULATE;
			break;
		default:
			if (applet == NULL || applet->parse == NULL)
				return usage();
			if (applet->parse(ctx, r, optindex - NUM_GENERIC_OPTS,
					  optarg) != 0)
				return usage();
			break;
		}
	}

	if (applet == NULL)
		return usage();

	if (apk_root == NULL)
		apk_root = "/";

	argc -= optind;
	argv += optind;
	if (argc >= 1 && strcmp(argv[0], applet->name) == 0) {
		argc--;
		argv++;
	}

	return applet->main(ctx, argc, argv);
}