/* Bash (wallclock-time) profiler. Written by Clifford Wolf.
|
|
*
|
|
* Usage:
|
|
* gcc -shared -fPIC -Wall -o config_helper.so config_helper.c
|
|
* enable -f ./config_helper.so cfghlp
|
|
*
|
|
* Note: This builtin trusts that it is called correctly. If it is
|
|
* called the wrong way, segfaults etc. are possible.
|
|
*/
|
|
|
|
|
|
/* Some declarations copied from bash-2.05b headers */
|
|
|
|
#include <stdint.h>
|
|
|
|
typedef struct word_desc {
|
|
char *word;
|
|
int flags;
|
|
} WORD_DESC;
|
|
|
|
typedef struct word_list {
|
|
struct word_list *next;
|
|
WORD_DESC *word;
|
|
} WORD_LIST;
|
|
|
|
typedef int sh_builtin_func_t(WORD_LIST *);
|
|
|
|
#define BUILTIN_ENABLED 0x1
|
|
|
|
struct builtin {
|
|
char *name;
|
|
sh_builtin_func_t *function;
|
|
int flags;
|
|
char * const *long_doc;
|
|
const char *short_doc;
|
|
char *handle;
|
|
};
|
|
|
|
|
|
/* my hellobash builtin */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <regex.h>
|
|
|
|
struct package;
|
|
struct package {
|
|
int status;
|
|
char stages[10];
|
|
char *prio;
|
|
char *repository;
|
|
char *name;
|
|
char *alias;
|
|
char *version;
|
|
char *prefix;
|
|
/* flags must end with a space character
|
|
(for easily searching for flags). */
|
|
char *flags;
|
|
struct package *next;
|
|
};
|
|
|
|
struct package *package_list = 0;
|
|
|
|
int read_pkg_list(const char *file) {
|
|
FILE *f = fopen(file, "r");
|
|
struct package *pkg = package_list;
|
|
struct package *pkg_tmp;
|
|
char line[1024], *tok;
|
|
int i;
|
|
|
|
while (pkg) {
|
|
free(pkg->prio);
|
|
free(pkg->repository);
|
|
free(pkg->name);
|
|
free(pkg->alias);
|
|
free(pkg->version);
|
|
free(pkg->prefix);
|
|
free(pkg->flags);
|
|
pkg = (pkg_tmp=pkg)->next;
|
|
free(pkg_tmp);
|
|
}
|
|
|
|
pkg = package_list = 0;
|
|
|
|
while (fgets(line, 1024, f)) {
|
|
pkg_tmp = calloc(1, sizeof(struct package));
|
|
|
|
tok = strtok(line, " ");
|
|
pkg_tmp->status = line[0] == 'X';
|
|
|
|
tok = strtok(0, " ");
|
|
for (i=0; i<10; i++)
|
|
pkg_tmp->stages[i] = tok[i] != '-' ? tok[i] : 0;
|
|
|
|
tok = strtok(0, " ");
|
|
pkg_tmp->prio = strdup(tok);
|
|
|
|
tok = strtok(0, " ");
|
|
pkg_tmp->repository = strdup(tok);
|
|
|
|
tok = strtok(0, " ");
|
|
char *c = strchr(tok, '=');
|
|
if (c)
|
|
{
|
|
pkg_tmp->name = malloc(c-tok+1);
|
|
pkg_tmp->name[c-tok] = '\0';
|
|
strncpy(pkg_tmp->name, tok, c-tok);
|
|
pkg_tmp->alias = strdup(c+1);
|
|
}
|
|
else
|
|
{
|
|
pkg_tmp->name = strdup(tok);
|
|
pkg_tmp->alias = strdup(tok);
|
|
}
|
|
|
|
tok = strtok(0, " ");
|
|
pkg_tmp->version = strdup(tok);
|
|
|
|
tok = strtok(0, " ");
|
|
pkg_tmp->prefix = strdup(tok);
|
|
|
|
tok = strtok(0, "\n");
|
|
tok[strlen(tok)-1] = 0;
|
|
pkg_tmp->flags = strdup(tok);
|
|
|
|
if ( !package_list )
|
|
pkg=package_list=pkg_tmp;
|
|
else
|
|
pkg=pkg->next=pkg_tmp;
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int write_pkg_list(const char *file) {
|
|
FILE *f = fopen(file, "w");
|
|
struct package *pkg = package_list;
|
|
int i;
|
|
|
|
while (pkg) {
|
|
fprintf(f, "%c ", pkg->status ? 'X' : 'O');
|
|
for (i=0; i<10; i++)
|
|
fprintf(f, "%c", pkg->stages[i] ? pkg->stages[i] : '-');
|
|
fprintf(f, " %s %s %s", pkg->prio, pkg->repository, pkg->name);
|
|
if (strcmp(pkg->name, pkg->alias))
|
|
fprintf(f, "=%s", pkg->alias);
|
|
fprintf(f, " %s %s %s0\n", pkg->version, pkg->prefix, pkg->flags);
|
|
pkg = pkg->next;
|
|
}
|
|
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
regex_t * create_pkg_regex(const char* pattern)
|
|
{
|
|
char fullpattern[512];
|
|
snprintf(fullpattern, 512, "[= ]%s ", pattern);
|
|
|
|
regex_t *preg = malloc(sizeof(regex_t));
|
|
int errcode = regcomp(preg, fullpattern,
|
|
REG_EXTENDED | REG_ICASE | REG_NOSUB | REG_NEWLINE);
|
|
if (errcode)
|
|
{
|
|
int errbuf_size = regerror(errcode, preg, 0, 0);
|
|
char *errbuf = malloc(errbuf_size);
|
|
regerror(errcode, preg, errbuf, errbuf_size);
|
|
fprintf(stderr, "config_helper: create_pkg_regex(%s): %s\n",
|
|
pattern, errbuf);
|
|
free(errbuf);
|
|
return NULL;
|
|
}
|
|
return preg;
|
|
}
|
|
|
|
char * create_pkg_line(struct package *pkg)
|
|
{
|
|
char *line = calloc(1024, sizeof(char));
|
|
int i, offset = 0;
|
|
|
|
offset += snprintf(line+offset, 1024-offset, "%c ",
|
|
pkg->status ? 'X' : 'O');
|
|
for (i=0; i<10; i++)
|
|
offset += snprintf(line+offset, 1024-offset, "%c",
|
|
pkg->stages[i] ? pkg->stages[i] : '-');
|
|
offset += snprintf(line+offset, 1024-offset, " %s %s %s",
|
|
pkg->prio, pkg->repository, pkg->name);
|
|
if (strcmp(pkg->name, pkg->alias))
|
|
offset += snprintf(line+offset, 1024-offset, "=%s", pkg->alias);
|
|
offset += snprintf(line+offset, 1024-offset, " %s %s %s0\n",
|
|
pkg->version, pkg->prefix, pkg->flags);
|
|
|
|
return line;
|
|
}
|
|
|
|
int pkgcheck(const char *pattern, const char *mode)
|
|
{
|
|
struct package *pkg = package_list;
|
|
|
|
char fullpattern[512];
|
|
snprintf(fullpattern, 512, "[= ]%s ", pattern);
|
|
|
|
regex_t *preg = create_pkg_regex(pattern);
|
|
if (preg == NULL) return 0;
|
|
|
|
while (pkg) {
|
|
char *line = create_pkg_line(pkg);
|
|
int match = !regexec(preg, line, 0, 0, 0);
|
|
free(line);
|
|
|
|
if (match)
|
|
{
|
|
|
|
switch (mode[0]) {
|
|
case 'X':
|
|
if (pkg->status) goto found;
|
|
break;
|
|
case 'O':
|
|
if (!pkg->status) goto found;
|
|
break;
|
|
case '.':
|
|
goto found;
|
|
}
|
|
}
|
|
pkg = pkg->next;
|
|
}
|
|
|
|
regfree(preg);
|
|
return 1;
|
|
|
|
found:
|
|
regfree(preg);
|
|
return 0;
|
|
}
|
|
|
|
int pkgswitch(int mode, char **args)
|
|
{
|
|
struct package *pkg = package_list;
|
|
struct package *last_pkg = 0;
|
|
struct package *pkg_tmp = 0;
|
|
|
|
regex_t *preg = create_pkg_regex(args[0]);
|
|
if (preg == NULL) return 0;
|
|
|
|
while (pkg) {
|
|
char *line = create_pkg_line(pkg);
|
|
int match = !regexec(preg, line, 0, 0, 0);
|
|
free(line);
|
|
|
|
if (match) {
|
|
if ( !mode ) {
|
|
*(last_pkg ? &(last_pkg->next) : &package_list) = pkg->next;
|
|
free(pkg->prio);
|
|
free(pkg->repository);
|
|
free(pkg->name);
|
|
free(pkg->alias);
|
|
free(pkg->version);
|
|
free(pkg->prefix);
|
|
free(pkg->flags);
|
|
pkg = (pkg_tmp=pkg)->next;
|
|
free(pkg_tmp);
|
|
continue;
|
|
} else
|
|
pkg->status = mode == 1;
|
|
}
|
|
pkg = (last_pkg=pkg)->next;
|
|
}
|
|
regfree(preg);
|
|
return 0;
|
|
}
|
|
|
|
int pkgfork(char *pkgname, char *xpkg, char** opt)
|
|
{
|
|
|
|
struct package *fork, *pkg;
|
|
int i, k;
|
|
|
|
for (pkg = package_list; pkg; pkg = pkg->next)
|
|
if (!strcmp(pkg->alias, pkgname))
|
|
break;
|
|
if (!pkg) return 1;
|
|
|
|
fork = calloc(1, sizeof(struct package));
|
|
|
|
fork->status = pkg->status;
|
|
for (k=0; k<10; k++)
|
|
fork->stages[k] = pkg->stages[k];
|
|
fork->prio = strdup(pkg->prio);
|
|
fork->repository = strdup(pkg->repository);
|
|
fork->name = strdup(pkgname);
|
|
fork->alias = strdup(xpkg);
|
|
fork->version = strdup(pkg->version);
|
|
fork->prefix = strdup(pkg->prefix);
|
|
fork->flags = strdup(pkg->flags);
|
|
|
|
fork->next = pkg->next;
|
|
pkg->next = fork;
|
|
|
|
for (i=0; *opt[i] && *opt[i+1]; i+=2)
|
|
{
|
|
if (!strcmp(opt[i], "status"))
|
|
fork->status= opt[i+1][0] == 'X';
|
|
|
|
else if (!strcmp(opt[i], "stages"))
|
|
for (k=0; k<10; k++)
|
|
fork->stages[k] = opt[i+1][k] != '-' ? opt[i+1][k] : 0;
|
|
|
|
else if (!strcmp(opt[i], "priority"))
|
|
{
|
|
free(fork->prio);
|
|
fork->prio = strdup(opt[i+1]);
|
|
}
|
|
|
|
else if (!strcmp(opt[i], "version"))
|
|
{
|
|
free(fork->version);
|
|
fork->version = strdup(opt[i+1]);
|
|
}
|
|
|
|
else if (!strcmp(opt[i], "prefix"))
|
|
{
|
|
free(fork->prefix);
|
|
fork->prefix = strdup(opt[+1]);
|
|
}
|
|
|
|
else if (!strcmp(opt[i], "flag"))
|
|
{
|
|
char buf[512], flag[512];
|
|
snprintf(flag, 512, " %s ", opt[i+1]);
|
|
if (! strstr(fork->flags, flag))
|
|
{
|
|
free(fork->flags);
|
|
snprintf(buf, 512, "%s%s ", pkg->flags, opt[i+1]);
|
|
fork->flags = strdup(buf);
|
|
}
|
|
}
|
|
|
|
else if (!strcmp(opt[i], "unflag"))
|
|
{
|
|
char buf[512], flag[512];
|
|
snprintf(flag, 512, " %s ", opt[i+1]);
|
|
char *flagstart = strstr(fork->flags, flag);
|
|
if (flagstart)
|
|
{
|
|
int len = flagstart - fork->flags + 1;
|
|
strncpy(buf, fork->flags, len);
|
|
strncpy(buf+len, flagstart+strlen(flag), 512-len);
|
|
|
|
free(fork->flags);
|
|
fork->flags = strdup(buf);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int cfghlp_builtin(WORD_LIST *list)
|
|
{
|
|
char *args[10];
|
|
int i;
|
|
|
|
for (i=0; i<9 && list; i++) {
|
|
args[i] = list->word->word;
|
|
list = list->next;
|
|
}
|
|
for (; i<10; i++) {
|
|
args[i] = "";
|
|
}
|
|
|
|
if (!strcmp(args[0],"pkg_in"))
|
|
return read_pkg_list(args[1]);
|
|
|
|
else if (!strcmp(args[0],"pkg_out"))
|
|
return write_pkg_list(args[1]);
|
|
|
|
else if (!strcmp(args[0],"pkgcheck"))
|
|
return pkgcheck(args[1], args[2]);
|
|
|
|
else if (!strcmp(args[0],"pkgremove"))
|
|
return pkgswitch(0, args+1);
|
|
|
|
else if (!strcmp(args[0],"pkgenable"))
|
|
return pkgswitch(1, args+1);
|
|
|
|
else if (!strcmp(args[0],"pkgdisable"))
|
|
return pkgswitch(2, args+1);
|
|
|
|
else if (!strcmp(args[0],"pkgfork"))
|
|
return pkgfork(args[1], args[2], args+3);
|
|
|
|
return 1;
|
|
}
|
|
|
|
char *cfghlp_doc[] = {
|
|
"ROCK Linux Config Helper",
|
|
0
|
|
};
|
|
|
|
struct builtin cfghlp_struct = {
|
|
"cfghlp",
|
|
&cfghlp_builtin,
|
|
BUILTIN_ENABLED,
|
|
cfghlp_doc,
|
|
"ROCK Linux Config Helper",
|
|
0
|
|
};
|
|
|