main.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
parent 129 d221757574c1
child 151 ae6ceb604f54
permissions -rw-r--r--
implement file dependencies for installs

removes are trickier because there are no backlinks from the files array
the properties array, so there's currently no way to efficiently determine
what packages are affected by the removal of a particular file
krh@43
     1
#include <stdlib.h>
krh@43
     2
#include <stddef.h>
krh@43
     3
#include <stdio.h>
krh@43
     4
#include <string.h>
krh@72
     5
#include <sys/types.h>
krh@72
     6
#include <sys/stat.h>
krh@43
     7
#include <unistd.h>
krh@75
     8
#include <dirent.h>
krh@71
     9
#include <curl/curl.h>
krh@94
    10
#include <fnmatch.h>
krh@43
    11
#include "razor.h"
krh@43
    12
krh@43
    13
static const char *repo_filename = "system.repo";
krh@44
    14
static const char *rawhide_repo_filename = "rawhide.repo";
krh@44
    15
static const char *updated_repo_filename = "system-updated.repo";
krh@43
    16
krh@43
    17
static int
krh@43
    18
command_list(int argc, const char *argv[])
krh@43
    19
{
krh@43
    20
	struct razor_set *set;
krh@92
    21
	struct razor_package_iterator *pi;
krh@92
    22
	struct razor_package *package;
krh@92
    23
	const char *pattern = argv[0], *name, *version;
krh@43
    24
krh@43
    25
	set = razor_set_open(repo_filename);
krh@92
    26
	pi = razor_package_iterator_create(set);
krh@92
    27
	while (razor_package_iterator_next(pi, &package, &name, &version)) {
krh@92
    28
		if (pattern && fnmatch(pattern, name, 0) != 0)
krh@92
    29
			continue;
krh@92
    30
krh@92
    31
		printf("%s-%s\n", name, version);
krh@92
    32
	}
krh@92
    33
	razor_package_iterator_destroy(pi);
krh@92
    34
	razor_set_destroy(set);
krh@92
    35
krh@92
    36
	return 0;
krh@92
    37
}
krh@92
    38
krh@92
    39
static int
krh@92
    40
list_properties(const char *package_name,
krh@92
    41
		enum razor_property_type required_type)
krh@92
    42
{
krh@92
    43
	struct razor_set *set;
krh@92
    44
	struct razor_property *property;
krh@92
    45
	struct razor_package *package;
krh@92
    46
	struct razor_property_iterator *pi;
krh@92
    47
	const char *name, *version;
krh@92
    48
	enum razor_property_type type;
danw@109
    49
	enum razor_version_relation relation;
krh@92
    50
krh@92
    51
	set = razor_set_open(repo_filename);
krh@92
    52
	if (package_name)
krh@92
    53
		package = razor_set_get_package(set, package_name);
krh@92
    54
	else
krh@92
    55
		package = NULL;
krh@92
    56
krh@92
    57
	pi = razor_property_iterator_create(set, package);
krh@92
    58
	while (razor_property_iterator_next(pi, &property,
danw@109
    59
					    &name, &relation, &version,
danw@109
    60
					    &type)) {
krh@92
    61
		if (type != required_type)
krh@92
    62
			continue;
krh@92
    63
		if (version[0] == '\0')
krh@92
    64
			printf("%s\n", name);
krh@92
    65
		else
danw@137
    66
			printf("%s %s %s\n", name,
danw@137
    67
			       razor_version_relations[relation], version);
krh@92
    68
	}
krh@92
    69
	razor_property_iterator_destroy(pi);
krh@92
    70
krh@43
    71
	razor_set_destroy(set);
krh@43
    72
krh@43
    73
	return 0;
krh@43
    74
}
krh@43
    75
krh@43
    76
static int
krh@43
    77
command_list_requires(int argc, const char *argv[])
krh@43
    78
{
krh@92
    79
	return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES);
krh@43
    80
}
krh@43
    81
krh@43
    82
static int
krh@43
    83
command_list_provides(int argc, const char *argv[])
krh@43
    84
{
krh@92
    85
	return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES);
krh@43
    86
}
krh@43
    87
krh@43
    88
static int
krh@67
    89
command_list_obsoletes(int argc, const char *argv[])
krh@67
    90
{
krh@92
    91
	return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES);
krh@67
    92
}
krh@67
    93
krh@67
    94
static int
krh@67
    95
command_list_conflicts(int argc, const char *argv[])
krh@67
    96
{
krh@92
    97
	return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS);
krh@67
    98
}
krh@67
    99
krh@67
   100
static int
krh@48
   101
command_list_files(int argc, const char *argv[])
krh@48
   102
{
krh@48
   103
	struct razor_set *set;
krh@48
   104
krh@48
   105
	set = razor_set_open(repo_filename);
krh@48
   106
	if (set == NULL)
krh@48
   107
		return 1;
krh@49
   108
	razor_set_list_files(set, argv[0]);
krh@48
   109
	razor_set_destroy(set);
krh@48
   110
krh@48
   111
	return 0;
krh@48
   112
}
krh@48
   113
krh@48
   114
static int
krh@52
   115
command_list_file_packages(int argc, const char *argv[])
krh@52
   116
{
krh@52
   117
	struct razor_set *set;
krh@102
   118
	struct razor_package_iterator *pi;
krh@102
   119
	struct razor_package *package;
krh@102
   120
	const char *name, *version;
krh@52
   121
krh@52
   122
	set = razor_set_open(repo_filename);
krh@52
   123
	if (set == NULL)
krh@52
   124
		return 1;
krh@102
   125
krh@102
   126
	pi = razor_package_iterator_create_for_file(set, argv[0]);
krh@102
   127
	while (razor_package_iterator_next(pi, &package, &name, &version))
krh@102
   128
		printf("%s-%s\n", name, version);
krh@102
   129
	razor_package_iterator_destroy(pi);
krh@102
   130
krh@52
   131
	razor_set_destroy(set);
krh@52
   132
krh@52
   133
	return 0;
krh@52
   134
}
krh@52
   135
krh@56
   136
static int
krh@56
   137
command_list_package_files(int argc, const char *argv[])
krh@56
   138
{
krh@56
   139
	struct razor_set *set;
krh@56
   140
krh@56
   141
	set = razor_set_open(repo_filename);
krh@56
   142
	if (set == NULL)
krh@56
   143
		return 1;
krh@56
   144
	razor_set_list_package_files(set, argv[0]);
krh@56
   145
	razor_set_destroy(set);
krh@56
   146
krh@56
   147
	return 0;
krh@56
   148
}
krh@52
   149
krh@101
   150
static void
krh@101
   151
list_packages_for_property(struct razor_set *set,
krh@101
   152
			   struct razor_property *property)
krh@101
   153
{
krh@101
   154
	struct razor_package_iterator *pi;
krh@101
   155
	struct razor_package *package;
krh@101
   156
	const char *name, *version;
krh@101
   157
krh@101
   158
	pi = razor_package_iterator_create_for_property(set, property);
krh@101
   159
	while (razor_package_iterator_next(pi, &package, &name, &version))
krh@101
   160
		printf("%s-%s\n", name, version);
krh@101
   161
	razor_package_iterator_destroy(pi);
krh@101
   162
}
krh@101
   163
krh@52
   164
static int
krh@100
   165
list_property_packages(const char *ref_name,
krh@100
   166
		       const char *ref_version,
krh@100
   167
		       enum razor_property_type ref_type)
krh@43
   168
{
krh@43
   169
	struct razor_set *set;
krh@100
   170
	struct razor_property *property;
krh@100
   171
	struct razor_property_iterator *pi;
krh@100
   172
	const char *name, *version;
krh@100
   173
	enum razor_property_type type;
danw@109
   174
	enum razor_version_relation relation;
krh@100
   175
krh@100
   176
	if (ref_name == NULL)
krh@100
   177
		return 0;
krh@43
   178
krh@43
   179
	set = razor_set_open(repo_filename);
krh@100
   180
	if (set == NULL)
krh@100
   181
		return 1;
krh@100
   182
krh@100
   183
	pi = razor_property_iterator_create(set, NULL);
krh@100
   184
	while (razor_property_iterator_next(pi, &property,
danw@109
   185
					    &name, &relation, &version,
danw@109
   186
					    &type)) {
krh@100
   187
		if (strcmp(ref_name, name) != 0)
krh@100
   188
			continue;
danw@109
   189
		if (ref_version && relation == RAZOR_VERSION_EQUAL &&
danw@109
   190
		    strcmp(ref_version, version) != 0)
krh@100
   191
			continue;
krh@100
   192
		if (ref_type != type)
krh@100
   193
			continue;
krh@100
   194
krh@101
   195
		list_packages_for_property(set, property);
krh@100
   196
	}
krh@100
   197
	razor_property_iterator_destroy(pi);
krh@43
   198
krh@43
   199
	return 0;
krh@43
   200
}
krh@43
   201
krh@43
   202
static int
krh@100
   203
command_what_requires(int argc, const char *argv[])
krh@100
   204
{
krh@100
   205
	return list_property_packages(argv[0], argv[1],
krh@100
   206
				      RAZOR_PROPERTY_REQUIRES);
krh@100
   207
}
krh@100
   208
krh@100
   209
static int
krh@43
   210
command_what_provides(int argc, const char *argv[])
krh@43
   211
{
krh@100
   212
	return list_property_packages(argv[0], argv[1],
krh@100
   213
				      RAZOR_PROPERTY_PROVIDES);
krh@43
   214
}
krh@43
   215
krh@73
   216
static int
krh@73
   217
show_progress(void *clientp,
krh@73
   218
	      double dltotal, double dlnow, double ultotal, double ulnow)
krh@73
   219
{
krh@73
   220
	const char *file = clientp;
krh@73
   221
krh@73
   222
	if (!dlnow < dltotal)
krh@73
   223
		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
krh@73
   224
			file, (int) dlnow / 1024, (int) dltotal / 1024);
krh@73
   225
	else
krh@73
   226
		fprintf(stderr, "\n");
krh@73
   227
krh@73
   228
	return 0;
krh@73
   229
}
krh@73
   230
krh@73
   231
static int
krh@73
   232
download_if_missing(CURL *curl, const char *url, const char *file)
krh@73
   233
{
krh@73
   234
	struct stat buf;
krh@73
   235
	char error[256];
krh@73
   236
	FILE *fp;
krh@73
   237
	CURLcode res;
krh@73
   238
	char buffer[256];
krh@73
   239
krh@73
   240
	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
krh@73
   241
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
krh@73
   242
	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
krh@73
   243
	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
krh@73
   244
krh@73
   245
	if (stat(file, &buf) < 0) {
krh@73
   246
		fp = fopen(file, "w");
krh@73
   247
		snprintf(buffer, sizeof buffer, "%s/%s", url, file);
krh@73
   248
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
krh@73
   249
		curl_easy_setopt(curl, CURLOPT_URL, buffer);
krh@73
   250
		res = curl_easy_perform(curl);
krh@73
   251
		fclose(fp);
krh@73
   252
		if (res != CURLE_OK) {
krh@73
   253
			fprintf(stderr, "curl error: %s\n", error);
krh@73
   254
			unlink(file);
krh@73
   255
			return -1;
krh@73
   256
		}
krh@73
   257
	}
krh@73
   258
krh@73
   259
	return 0;
krh@73
   260
}
krh@73
   261
krh@71
   262
#define REPO_URL "http://download.fedora.redhat.com" \
krh@71
   263
	"/pub/fedora/linux/development/i386/os/repodata"
krh@71
   264
krh@43
   265
static int
krh@43
   266
command_import_yum(int argc, const char *argv[])
krh@43
   267
{
krh@43
   268
	struct razor_set *set;
krh@71
   269
	CURL *curl;
krh@71
   270
krh@71
   271
	curl = curl_easy_init();
krh@71
   272
	if (curl == NULL)
krh@71
   273
		return 1;
krh@71
   274
krh@73
   275
	if (download_if_missing(curl, REPO_URL, "primary.xml.gz") < 0)
krh@73
   276
		return -1;
krh@73
   277
	if (download_if_missing(curl, REPO_URL, "filelists.xml.gz") < 0)
krh@73
   278
		return -1;
krh@71
   279
	curl_easy_cleanup(curl);
krh@43
   280
krh@70
   281
	set = razor_set_create_from_yum();
krh@43
   282
	if (set == NULL)
krh@43
   283
		return 1;
krh@43
   284
	razor_set_write(set, rawhide_repo_filename);
krh@43
   285
	razor_set_destroy(set);
krh@43
   286
	printf("wrote %s\n", rawhide_repo_filename);
krh@43
   287
krh@43
   288
	return 0;
krh@43
   289
}
krh@43
   290
krh@43
   291
static int
krh@43
   292
command_import_rpmdb(int argc, const char *argv[])
krh@43
   293
{
krh@43
   294
	struct razor_set *set;
krh@43
   295
krh@43
   296
	set = razor_set_create_from_rpmdb();
krh@43
   297
	if (set == NULL)
krh@43
   298
		return 1;
krh@43
   299
	razor_set_write(set, repo_filename);
krh@43
   300
	razor_set_destroy(set);
krh@43
   301
	printf("wrote %s\n", repo_filename);
krh@43
   302
krh@43
   303
	return 0;
krh@43
   304
}
krh@43
   305
krh@43
   306
static int
krh@43
   307
command_validate(int argc, const char *argv[])
krh@43
   308
{
krh@43
   309
	struct razor_set *set;
krh@43
   310
krh@43
   311
	set = razor_set_open(repo_filename);
krh@43
   312
	if (set == NULL)
krh@43
   313
		return 1;
krh@43
   314
	razor_set_list_unsatisfied(set);
krh@43
   315
	razor_set_destroy(set);
krh@43
   316
krh@43
   317
	return 0;
krh@43
   318
}
krh@43
   319
krh@43
   320
static int
krh@43
   321
command_update(int argc, const char *argv[])
krh@43
   322
{
krh@43
   323
	struct razor_set *set, *upstream;
danw@137
   324
	struct razor_transaction *trans;
krh@43
   325
krh@43
   326
	set = razor_set_open(repo_filename);
krh@43
   327
	upstream = razor_set_open(rawhide_repo_filename);
krh@43
   328
	if (set == NULL || upstream == NULL)
krh@43
   329
		return 1;
danw@137
   330
	trans = razor_transaction_create(set, upstream, argc, argv, 0, NULL);
danw@137
   331
	razor_transaction_describe(trans);
danw@137
   332
	if (trans->errors)
danw@137
   333
		return 1;
danw@137
   334
danw@137
   335
	set = razor_transaction_run(trans);
danw@137
   336
	razor_transaction_destroy(trans);
krh@44
   337
	razor_set_write(set, updated_repo_filename);
krh@43
   338
	razor_set_destroy(set);
krh@43
   339
	razor_set_destroy(upstream);
krh@43
   340
	printf("wrote system-updated.repo\n");
krh@43
   341
krh@43
   342
	return 0;
krh@43
   343
}
krh@43
   344
danw@129
   345
static int
danw@129
   346
command_remove(int argc, const char *argv[])
danw@129
   347
{
danw@129
   348
	struct razor_set *set;
danw@137
   349
	struct razor_transaction *trans;
danw@129
   350
danw@129
   351
	set = razor_set_open(repo_filename);
danw@129
   352
	if (set == NULL)
danw@129
   353
		return 1;
danw@137
   354
	trans = razor_transaction_create(set, NULL, 0, NULL, argc, argv);
danw@137
   355
	razor_transaction_describe(trans);
danw@137
   356
	if (trans->errors)
danw@137
   357
		return 1;
danw@137
   358
danw@137
   359
	set = razor_transaction_run(trans);
danw@137
   360
	razor_transaction_destroy(trans);
danw@129
   361
	razor_set_write(set, updated_repo_filename);
danw@129
   362
	razor_set_destroy(set);
danw@129
   363
	printf("wrote system-updated.repo\n");
danw@129
   364
danw@129
   365
	return 0;
danw@129
   366
}
danw@129
   367
krh@44
   368
static void
krh@44
   369
print_diff(const char *name,
krh@44
   370
	   const char *old_version, const char *new_version, void *data)
krh@44
   371
{
krh@44
   372
	if (old_version)
krh@44
   373
		printf("removing %s %s\n", name, old_version);
krh@44
   374
	else
krh@44
   375
		printf("install %s %s\n", name, new_version);
krh@44
   376
}
krh@44
   377
krh@44
   378
static int
krh@44
   379
command_diff(int argc, const char *argv[])
krh@44
   380
{
krh@44
   381
	struct razor_set *set, *updated;
krh@44
   382
krh@44
   383
	set = razor_set_open(repo_filename);
krh@44
   384
	updated = razor_set_open(updated_repo_filename);
krh@44
   385
	if (set == NULL || updated == NULL)
krh@44
   386
		return 1;
krh@44
   387
krh@44
   388
	razor_set_diff(set, updated, print_diff, NULL);	
krh@44
   389
krh@44
   390
	razor_set_destroy(set);
krh@44
   391
	razor_set_destroy(updated);
krh@44
   392
krh@44
   393
	return 0;
krh@44
   394
}
krh@44
   395
krh@74
   396
static int
krh@75
   397
command_import_rpms(int argc, const char *argv[])
krh@74
   398
{
krh@75
   399
	DIR *dir;
krh@75
   400
	struct dirent *de;
krh@75
   401
	struct razor_importer *importer;
krh@75
   402
	struct razor_set *set;
krh@77
   403
	struct razor_rpm *rpm;
krh@75
   404
	int len;
krh@75
   405
	char filename[256];
krh@75
   406
	const char *dirname = argv[0];
krh@75
   407
krh@75
   408
	if (dirname == NULL) {
krh@75
   409
		fprintf(stderr, "usage: razor import-rpms DIR\n");
krh@75
   410
		return -1;
krh@75
   411
	}
krh@75
   412
krh@75
   413
	dir = opendir(dirname);
krh@75
   414
	if (dir == NULL) {
krh@75
   415
		fprintf(stderr, "couldn't read dir %s\n", dirname);
krh@75
   416
		return -1;
krh@75
   417
	}
krh@75
   418
krh@75
   419
	importer = razor_importer_new();
krh@75
   420
krh@75
   421
	while (de = readdir(dir), de != NULL) {
krh@75
   422
		len = strlen(de->d_name);
krh@75
   423
		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
krh@75
   424
		    continue;
krh@75
   425
		snprintf(filename, sizeof filename,
krh@75
   426
			 "%s/%s", dirname, de->d_name);
krh@77
   427
		rpm = razor_rpm_open(filename);
krh@77
   428
		if (rpm == NULL) {
krh@77
   429
			fprintf(stderr,
krh@77
   430
				"failed to open rpm \"%s\"\n", filename);
krh@77
   431
			continue;
krh@77
   432
		}
krh@77
   433
		if (razor_importer_add_rpm(importer, rpm)) {
krh@75
   434
			fprintf(stderr, "couldn't import %s\n", filename);
krh@75
   435
			break;
krh@75
   436
		}
krh@77
   437
		razor_rpm_close(rpm);
krh@75
   438
	}
krh@75
   439
krh@75
   440
	if (de != NULL) {
krh@75
   441
		razor_importer_destroy(importer);
krh@75
   442
		return -1;
krh@75
   443
	}
krh@75
   444
krh@75
   445
	set = razor_importer_finish(importer);
krh@75
   446
krh@75
   447
	razor_set_write(set, repo_filename);
krh@75
   448
	razor_set_destroy(set);
krh@75
   449
	printf("wrote %s\n", repo_filename);
krh@74
   450
krh@74
   451
	return 0;
krh@74
   452
}
krh@74
   453
krh@77
   454
static int
krh@77
   455
command_install(int argc, const char *argv[])
krh@77
   456
{
krh@77
   457
	struct razor_rpm *rpm;
krh@77
   458
	const char *filename = argv[0];
krh@77
   459
	struct stat buf;
krh@77
   460
	const char root[] = "install";
krh@77
   461
krh@77
   462
	if (stat(root, &buf) < 0) {
krh@77
   463
		if (mkdir(root, 0777) < 0) {
krh@77
   464
			fprintf(stderr,
krh@77
   465
				"could not create install root \"%s\"\n",
krh@77
   466
				root);
krh@77
   467
			return -1;
krh@77
   468
		}
krh@77
   469
		fprintf(stderr, "created install root \"%s\"\n", root);
krh@77
   470
	} else if (!S_ISDIR(buf.st_mode)) {
krh@77
   471
		fprintf(stderr,
krh@77
   472
			"install root \"%s\" exists, but is not a directory\n",
krh@77
   473
			root);
krh@77
   474
		return -1;
krh@77
   475
	}
krh@77
   476
krh@77
   477
	rpm = razor_rpm_open(filename);
krh@77
   478
	if (rpm == NULL) {
krh@77
   479
		fprintf(stderr, "failed to open rpm %s\n", filename);
krh@77
   480
		return -1;
krh@77
   481
	}
krh@77
   482
	if (razor_rpm_install(rpm, root) < 0) {
krh@77
   483
		fprintf(stderr, "failed to install rpm %s\n", filename);
krh@77
   484
		return -1;
krh@77
   485
	}
krh@77
   486
	
krh@77
   487
	razor_rpm_close(rpm);
krh@77
   488
krh@77
   489
	return 0;
krh@77
   490
}
krh@77
   491
krh@43
   492
static struct {
krh@43
   493
	const char *name;
krh@43
   494
	const char *description;
krh@43
   495
	int (*func)(int argc, const char *argv[]);
krh@43
   496
} razor_commands[] = {
krh@43
   497
	{ "list", "list all packages", command_list },
krh@67
   498
	{ "list-requires", "list all requires for the given package", command_list_requires },
krh@75
   499
	{ "list-provides", "list all provides for the given package", command_list_provides },
krh@75
   500
	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
krh@75
   501
	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
krh@48
   502
	{ "list-files", "list files for package set", command_list_files },
krh@52
   503
	{ "list-file-packages", "list packages owning file", command_list_file_packages },
krh@56
   504
	{ "list-package-files", "list files in package", command_list_package_files },
krh@43
   505
	{ "what-requires", "list the packages that have the given requires", command_what_requires },
krh@43
   506
	{ "what-provides", "list the packages that have the given provides", command_what_provides },
krh@75
   507
	{ "import-yum", "import yum metadata files", command_import_yum },
krh@43
   508
	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
krh@75
   509
	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
krh@43
   510
	{ "validate", "validate a package set", command_validate },
krh@44
   511
	{ "update", "update all or specified packages", command_update },
danw@129
   512
	{ "remove", "remove specified packages", command_remove },
krh@77
   513
	{ "diff", "show diff between two package sets", command_diff },
krh@77
   514
	{ "install", "install rpm", command_install }
krh@43
   515
};
krh@43
   516
krh@43
   517
static int
krh@43
   518
usage(void)
krh@43
   519
{
krh@43
   520
	int i;
krh@43
   521
krh@43
   522
	printf("usage:\n");
krh@43
   523
	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
krh@43
   524
		printf("  %-20s%s\n",
krh@43
   525
		       razor_commands[i].name, razor_commands[i].description);
krh@43
   526
krh@43
   527
	return 1;
krh@43
   528
}
krh@43
   529
krh@43
   530
int
krh@43
   531
main(int argc, const char *argv[])
krh@43
   532
{
krh@43
   533
	char *repo;
krh@43
   534
	int i;
krh@43
   535
krh@43
   536
	repo = getenv("RAZOR_REPO");
krh@43
   537
	if (repo != NULL)
krh@43
   538
		repo_filename = repo;
krh@43
   539
krh@43
   540
	if (argc < 2)
krh@43
   541
		return usage();
krh@43
   542
krh@43
   543
	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
krh@43
   544
		if (strcmp(razor_commands[i].name, argv[1]) == 0)
krh@43
   545
			return razor_commands[i].func(argc - 2, argv + 2);
krh@43
   546
krh@43
   547
	return usage();
krh@43
   548
}