Remove null terminated char ** lists in favour of RC_STRINGLIST, using TAILQ from queue(3). Refactor code style around the BSD KNF.

This commit is contained in:
Roy Marples
2008-03-16 17:00:56 +00:00
parent 40e12f6ba0
commit cb9da6a262
41 changed files with 4675 additions and 5322 deletions

4
src/rc/.gitignore vendored
View File

@@ -55,6 +55,7 @@ rc-abort
checkpath.o
fstabinfo.o
mountinfo.o
start-stop-daemon.o
rc-applets.o
rc-depend.o
rc-logger.o
@@ -62,8 +63,7 @@ rc-misc.o
rc-plugin.o
rc-status.o
rc-update.o
rc.o
runscript.o
start-stop-daemon.o
rc.o
rc
.depend

View File

@@ -1,8 +1,8 @@
PROG= rc
SRCS= checkpath.c fstabinfo.c mountinfo.c \
SRCS= checkpath.c fstabinfo.c mountinfo.c start-stop-daemon.c \
rc-applets.c rc-depend.c rc-logger.c \
rc-misc.c rc-plugin.c rc-status.c rc-update.c rc.c \
runscript.c start-stop-daemon.c
rc-misc.c rc-plugin.c rc-status.c rc-update.c \
runscript.c rc.c
CLEANFILES= version.h
@@ -31,8 +31,9 @@ ALL_LINKS= ${BINLINKS} ${SBINLINKS} ${RC_BINLINKS} ${RC_SBINLINKS}
CLEANFILES+= ${ALL_LINKS}
LDFLAGS+= -L../librc -L../libeinfo
#LDFLAGS+= -Wl,--rpath=../librc -Wl,--rpath=../libeinfo
LDADD+= -lutil -lrc -leinfo
#CFLAGS+= -ggdb
#LDFLAGS+= -Wl,--rpath=../librc -Wl,--rpath=../libeinfo
MK= ../../mk
include ${MK}/cc.mk

View File

@@ -33,35 +33,36 @@
# define _noreturn
#endif
_noreturn static void usage (int exit_status)
_noreturn static void usage(int exit_status)
{
const char * const has_arg[] = { "", "<arg>", "[arg]" };
int i;
int len;
char *lo;
char *p;
char *token;
#ifdef usagestring
printf (usagestring);
printf(usagestring);
#else
printf ("Usage: %s [options] ", applet);
printf("Usage: %s [options] ", applet);
#endif
#ifdef extraopts
printf (extraopts);
printf(extraopts);
#endif
printf ("\n\nOptions: [" getoptstring "]\n");
printf("\n\nOptions: [" getoptstring "]\n");
for (i = 0; longopts[i].name; ++i) {
int len = printf (" -%c, --%s %s", longopts[i].val, longopts[i].name,
has_arg[longopts[i].has_arg]);
len = printf(" -%c, --%s %s", longopts[i].val, longopts[i].name,
has_arg[longopts[i].has_arg]);
char *lo = xstrdup (longopts_help[i]);
char *p = lo;
char *token;
while ((token = strsep (&p, "\n"))) {
lo = p = xstrdup(longopts_help[i]);
while ((token = strsep(&p, "\n"))) {
while (++len < 37)
printf (" ");
puts (token);
printf(" ");
puts(token);
len = 0;
}
free (lo);
free(lo);
}
exit (exit_status);
exit(exit_status);
}

View File

@@ -38,4 +38,4 @@ int start_stop_daemon (int argc, char **argv);
void run_applets (int argc, char **argv);
/* Handy function so we can wrap einfo around our deptree */
rc_depinfo_t *_rc_deptree_load (int *regen);
RC_DEPTREE *_rc_deptree_load (int *regen);

View File

@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -48,84 +49,84 @@
extern const char *applet;
static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, int file)
{
struct stat st;
int fd;
memset (&st, 0, sizeof (st));
if (stat (path, &st)) {
if (stat(path, &st)) {
if (file) {
int fd;
einfo ("%s: creating file", path);
if ((fd = open (path, O_CREAT)) == -1) {
eerror ("%s: open: %s", applet, strerror (errno));
return (-1);
einfo("%s: creating file", path);
if ((fd = open(path, O_CREAT)) == -1) {
eerror("%s: open: %s", applet, strerror(errno));
return -1;
}
close (fd);
} else {
einfo ("%s: creating directory", path);
einfo("%s: creating directory", path);
if (! mode)
mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
if (mkdir (path, mode)) {
eerror ("%s: mkdir: %s", applet, strerror (errno));
return (-1);
if (mkdir(path, mode)) {
eerror("%s: mkdir: %s", applet, strerror (errno));
return -1;
}
mode = 0;
}
} else {
if ((file && S_ISDIR (st.st_mode)) ||
(! file && ! S_ISDIR (st.st_mode)))
if ((file && S_ISDIR(st.st_mode)) ||
(! file && ! S_ISDIR(st.st_mode)))
{
if (file)
eerror ("%s: is a directory", path);
eerror("%s: is a directory", path);
else
eerror ("%s: is a file", path);
return (-1);
eerror("%s: is a file", path);
return -1;
}
}
if (mode && (st.st_mode & 0777) != mode) {
einfo ("%s: correcting mode", applet);
if (chmod (path, mode)) {
eerror ("%s: chmod: %s", applet, strerror (errno));
return (-1);
einfo("%s: correcting mode", applet);
if (chmod(path, mode)) {
eerror("%s: chmod: %s", applet, strerror(errno));
return -1;
}
}
if (st.st_uid != uid || st.st_gid != gid) {
if (st.st_dev || st.st_ino)
einfo ("%s: correcting owner", path);
if (chown (path, uid, gid)) {
eerror ("%s: chown: %s", applet, strerror (errno));
return (-1);
einfo("%s: correcting owner", path);
if (chown(path, uid, gid)) {
eerror("%s: chown: %s", applet, strerror(errno));
return -1;
}
}
return (0);
return 0;
}
/* Based on busybox */
static int parse_mode (mode_t *mode, char *text)
{
char *p;
unsigned long l;
/* Check for a numeric mode */
if ((*text - '0') < 8) {
char *p;
unsigned long l = strtoul (text, &p, 8);
l = strtoul(text, &p, 8);
if (*p || l > 07777U) {
errno = EINVAL;
return (-1);
return -1;
}
*mode = (mode_t) l;
return (0);
return 0;
}
/* We currently don't check g+w type stuff */
errno = EINVAL;
return (-1);
return -1;
}
static int parse_owner (struct passwd **user, struct group **group,
static int parse_owner(struct passwd **user, struct group **group,
const char *owner)
{
char *u = xstrdup (owner);
@@ -137,25 +138,25 @@ static int parse_owner (struct passwd **user, struct group **group,
*g++ = '\0';
if (user && *u) {
if (sscanf (u, "%d", &id) == 1)
*user = getpwuid ((uid_t) id);
if (sscanf(u, "%d", &id) == 1)
*user = getpwuid((uid_t) id);
else
*user = getpwnam (u);
*user = getpwnam(u);
if (! *user)
retval = -1;
}
if (group && g && *g) {
if (sscanf (g, "%d", &id) == 1)
*group = getgrgid ((gid_t) id);
if (sscanf(g, "%d", &id) == 1)
*group = getgrgid((gid_t) id);
else
*group = getgrnam (g);
*group = getgrnam(g);
if (! *group)
retval = -1;
}
free (u);
return (retval);
free(u);
return retval;
}
#include "_usage.h"
@@ -177,7 +178,7 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int checkpath (int argc, char **argv)
int checkpath(int argc, char **argv)
{
int opt;
uid_t uid = geteuid();
@@ -188,33 +189,31 @@ int checkpath (int argc, char **argv)
bool file = 0;
int retval = EXIT_SUCCESS;
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'd':
file = 0;
break;
case 'f':
file = 1;
break;
case 'm':
if (parse_mode (&mode, optarg) != 0)
eerrorx ("%s: invalid mode `%s'",
applet, optarg);
break;
case 'o':
if (parse_owner (&pw, &gr, optarg) != 0)
eerrorx ("%s: owner `%s' not found",
applet, optarg);
break;
case 'd':
file = 0;
break;
case 'f':
file = 1;
break;
case 'm':
if (parse_mode(&mode, optarg) != 0)
eerrorx("%s: invalid mode `%s'", applet, optarg);
break;
case 'o':
if (parse_owner(&pw, &gr, optarg) != 0)
eerrorx("%s: owner `%s' not found", applet, optarg);
break;
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
if (optind >= argc)
usage (EXIT_FAILURE);
usage(EXIT_FAILURE);
if (pw) {
uid = pw->pw_uid;
@@ -224,11 +223,11 @@ int checkpath (int argc, char **argv)
gid = gr->gr_gid;
while (optind < argc) {
if (do_check (argv[optind], uid, gid, mode, file))
if (do_check(argv[optind], uid, gid, mode, file))
retval = EXIT_FAILURE;
optind++;
}
exit (retval);
exit(retval);
/* NOTREACHED */
}

View File

@@ -30,6 +30,7 @@
*/
#include <sys/wait.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
@@ -72,27 +73,26 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
#ifdef HAVE_GETMNTENT
static struct mntent *getmntfile (const char *file)
static struct mntent *getmntfile(const char *file)
{
struct mntent *ent = NULL;
struct mntent *ent;
FILE *fp;
START_ENT;
while ((ent = getmntent (fp)))
if (strcmp (file, ent->mnt_dir) == 0)
while ((ent = getmntent(fp)))
if (strcmp(file, ent->mnt_dir) == 0)
break;
END_ENT;
return (ent);
return ent;
}
#endif
extern const char *applet;
static int do_mount (struct ENT *ent)
static int do_mount(struct ENT *ent)
{
char *argv[8];
pid_t pid;
@@ -100,29 +100,27 @@ static int do_mount (struct ENT *ent)
argv[0] = (char *) "mount";
argv[1] = (char *) "-o";
argv[2] = ENT_OPTS (*ent);
argv[2] = ENT_OPTS(*ent);
argv[3] = (char *) "-t";
argv[4] = ENT_TYPE (*ent);
argv[5] = ENT_BLOCKDEVICE (*ent);
argv[6] = ENT_FILE (*ent);
argv[4] = ENT_TYPE(*ent);
argv[5] = ENT_BLOCKDEVICE(*ent);
argv[6] = ENT_FILE(*ent);
argv[7] = NULL;
switch (pid = vfork()) {
case -1:
eerrorx ("%s: vfork: %s", applet,
strerror (errno));
eerrorx("%s: vfork: %s", applet, strerror(errno));
/* NOTREACHED */
case 0:
execvp (argv[0], argv);
eerror ("%s: execv: %s", applet,
strerror (errno));
execvp(argv[0], argv);
eerror("%s: execv: %s", applet, strerror(errno));
_exit(EXIT_FAILURE);
/* NOTREACHED */
default:
waitpid (pid, &status, 0);
if (WIFEXITED (status))
return (WEXITSTATUS(status));
waitpid(pid, &status, 0);
if (WIFEXITED(status))
return WEXITSTATUS(status);
else
return (-1);
return -1;
/* NOTREACHED */
}
}
@@ -155,7 +153,7 @@ static const char * const longopts_help[] = {
#define OUTPUT_BLOCKDEV (1 << 5)
#define OUTPUT_MOUNT (1 << 6)
int fstabinfo (int argc, char **argv)
int fstabinfo(int argc, char **argv)
{
struct ENT *ent;
int result = EXIT_SUCCESS;
@@ -163,8 +161,8 @@ int fstabinfo (int argc, char **argv)
int i;
int opt;
int output = OUTPUT_FILE;
char **files = NULL;
char *file;
RC_STRINGLIST *files = rc_stringlist_new();
RC_STRING *file;
bool filtered = false;
#ifdef HAVE_GETMNTENT
@@ -172,125 +170,126 @@ int fstabinfo (int argc, char **argv)
#endif
/* Ensure that we are only quiet when explicitly told to be */
unsetenv ("EINFO_QUIET");
unsetenv("EINFO_QUIET");
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'M':
output = OUTPUT_MOUNT;
break;
case 'b':
output = OUTPUT_BLOCKDEV;
break;
case 'o':
output = OUTPUT_OPTIONS;
break;
case 'm':
output = OUTPUT_MOUNTARGS;
break;
case 'M':
output = OUTPUT_MOUNT;
break;
case 'b':
output = OUTPUT_BLOCKDEV;
break;
case 'o':
output = OUTPUT_OPTIONS;
break;
case 'm':
output = OUTPUT_MOUNTARGS;
break;
case 'p':
switch (optarg[0]) {
case '=':
case '<':
case '>':
if (sscanf (optarg + 1, "%d", &i) != 1)
eerrorx ("%s: invalid passno %s", argv[0], optarg + 1);
case 'p':
switch (optarg[0]) {
case '=':
case '<':
case '>':
if (sscanf(optarg + 1, "%d", &i) != 1)
eerrorx("%s: invalid passno %s",
argv[0], optarg + 1);
filtered = true;
START_ENT;
while ((ent = GET_ENT)) {
if (((optarg[0] == '=' && i == ENT_PASS (ent)) ||
(optarg[0] == '<' && i > ENT_PASS (ent)) ||
(optarg[0] == '>' && i < ENT_PASS (ent))) &&
strcmp (ENT_FILE (ent), "none") != 0)
rc_strlist_add (&files, ENT_FILE (ent));
}
END_ENT;
break;
default:
rc_strlist_add (&files, optarg);
output = OUTPUT_PASSNO;
break;
}
break;
case 't':
filtered = true;
while ((token = strsep (&optarg, ","))) {
START_ENT;
while ((ent = GET_ENT))
if (strcmp (token, ENT_TYPE (ent)) == 0)
rc_strlist_add (&files, ENT_FILE (ent));
END_ENT;
START_ENT;
while ((ent = GET_ENT)) {
if (((optarg[0] == '=' && i == ENT_PASS(ent)) ||
(optarg[0] == '<' && i > ENT_PASS(ent)) ||
(optarg[0] == '>' && i < ENT_PASS(ent))) &&
strcmp(ENT_FILE(ent), "none") != 0)
rc_stringlist_add(files, ENT_FILE(ent));
}
END_ENT;
break;
case_RC_COMMON_GETOPT
default:
rc_stringlist_add(files, optarg);
output = OUTPUT_PASSNO;
break;
}
break;
case 't':
filtered = true;
while ((token = strsep(&optarg, ","))) {
START_ENT;
while ((ent = GET_ENT))
if (strcmp(token, ENT_TYPE(ent)) == 0)
rc_stringlist_add(files, ENT_FILE(ent));
END_ENT;
}
break;
case_RC_COMMON_GETOPT
}
}
while (optind < argc)
rc_strlist_add (&files, argv[optind++]);
if (! files && ! filtered) {
if (optind < argc) {
while (optind < argc)
rc_stringlist_add(files, argv[optind++]);
} else if (! filtered) {
START_ENT;
while ((ent = GET_ENT))
rc_strlist_add (&files, ENT_FILE (ent));
rc_stringlist_add(files, ENT_FILE(ent));
END_ENT;
if (! files)
eerrorx ("%s: emtpy fstab", argv[0]);
if (! TAILQ_FIRST(files))
eerrorx("%s: emtpy fstab", argv[0]);
}
/* Ensure we always display something */
START_ENT;
STRLIST_FOREACH (files, file, i) {
if (! (ent = GET_ENT_FILE (file))) {
TAILQ_FOREACH(file, files, entries) {
if (! (ent = GET_ENT_FILE(file->value))) {
result = EXIT_FAILURE;
continue;
}
/* No point in outputting if quiet */
if (rc_yesno (getenv ("EINFO_QUIET")))
if (rc_yesno(getenv("EINFO_QUIET")))
continue;
switch (output) {
case OUTPUT_BLOCKDEV:
printf ("%s\n", ENT_BLOCKDEVICE (ent));
break;
case OUTPUT_BLOCKDEV:
printf("%s\n", ENT_BLOCKDEVICE(ent));
break;
case OUTPUT_MOUNT:
result += do_mount (ent);
break;
case OUTPUT_MOUNT:
result += do_mount(ent);
break;
case OUTPUT_MOUNTARGS:
printf ("-o %s -t %s %s %s\n",
ENT_OPTS (ent),
ENT_TYPE (ent),
ENT_BLOCKDEVICE (ent),
file);
break;
case OUTPUT_MOUNTARGS:
printf("-o %s -t %s %s %s\n",
ENT_OPTS(ent),
ENT_TYPE(ent),
ENT_BLOCKDEVICE(ent),
file->value);
break;
case OUTPUT_OPTIONS:
printf ("%s\n", ENT_OPTS (ent));
break;
case OUTPUT_OPTIONS:
printf("%s\n", ENT_OPTS(ent));
break;
case OUTPUT_FILE:
printf ("%s\n", file);
break;
case OUTPUT_FILE:
printf("%s\n", file->value);
break;
case OUTPUT_PASSNO:
printf ("%d\n", ENT_PASS (ent));
break;
case OUTPUT_PASSNO:
printf("%d\n", ENT_PASS(ent));
break;
}
}
END_ENT;
rc_strlist_free (files);
exit (result);
rc_stringlist_free(files);
exit(result);
/* NOTREACHED */
}

View File

@@ -47,16 +47,15 @@
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include "builtins.h"
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
extern const char *applet;
@@ -80,93 +79,93 @@ struct args {
regex_t *skip_fstype_regex;
regex_t *options_regex;
regex_t *skip_options_regex;
char **mounts;
RC_STRINGLIST *mounts;
mount_type mount_type;
net_opts netdev;
};
static int process_mount (char ***list, struct args *args,
char *from, char *to, char *fstype, char *options,
int netdev)
static int process_mount(RC_STRINGLIST *list, struct args *args,
char *from, char *to, char *fstype, char *options,
int netdev)
{
char *p;
RC_STRING *s;
errno = ENOENT;
#ifdef __linux__
/* Skip the really silly rootfs */
if (strcmp (fstype, "rootfs") == 0)
return (-1);
if (strcmp(fstype, "rootfs") == 0)
return -1;
#endif
if (args->netdev == net_yes && (netdev != -1 || args->mounts)) {
if (args->netdev == net_yes &&
(netdev != -1 || TAILQ_FIRST(args->mounts)))
{
if (netdev != 0)
return (1);
} else if (args->netdev == net_no && (netdev != -1 || args->mounts)) {
return 1;
} else if (args->netdev == net_no &&
(netdev != -1 || TAILQ_FIRST(args->mounts)))
{
if (netdev != 1)
return (1);
return 1;
} else {
if (args->node_regex &&
regexec (args->node_regex, from, 0, NULL, 0) != 0)
return (1);
regexec(args->node_regex, from, 0, NULL, 0) != 0)
return 1;
if (args->skip_node_regex &&
regexec (args->skip_node_regex, from, 0, NULL, 0) == 0)
return (1);
regexec(args->skip_node_regex, from, 0, NULL, 0) == 0)
return 1;
if (args->fstype_regex &&
regexec (args->fstype_regex, fstype, 0, NULL, 0) != 0)
return (-1);
regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0)
return -1;
if (args->skip_fstype_regex &&
regexec (args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
return (-1);
regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
return -1;
if (args->options_regex &&
regexec (args->options_regex, options, 0, NULL, 0) != 0)
return (-1);
regexec(args->options_regex, options, 0, NULL, 0) != 0)
return -1;
if (args->skip_options_regex &&
regexec (args->skip_options_regex, options, 0, NULL, 0) == 0)
return (-1);
regexec(args->skip_options_regex, options, 0, NULL, 0) == 0)
return -1;
}
if (args->mounts) {
bool found = false;
int j;
char *mnt;
STRLIST_FOREACH (args->mounts, mnt, j)
if (strcmp (mnt, to) == 0) {
found = true;
if (TAILQ_FIRST(args->mounts)) {
TAILQ_FOREACH(s, args->mounts, entries)
if (strcmp(s->value, to) == 0)
break;
}
if (! found)
return (-1);
if (! s)
return -1;
}
switch (args->mount_type) {
case mount_from:
p = from;
break;
case mount_to:
p = to;
break;
case mount_fstype:
p = fstype;
break;
case mount_options:
p = options;
break;
default:
p = NULL;
errno = EINVAL;
break;
case mount_from:
p = from;
break;
case mount_to:
p = to;
break;
case mount_fstype:
p = fstype;
break;
case mount_options:
p = options;
break;
default:
p = NULL;
errno = EINVAL;
break;
}
if (p) {
errno = 0;
rc_strlist_addsortc (list, p);
return (0);
rc_stringlist_add(list, p);
return 0;
}
return (-1);
return -1;
}
#ifdef BSD
@@ -212,70 +211,73 @@ static struct opt {
{ 0, NULL }
};
static char **find_mounts (struct args *args)
static RC_STRINGLIST *find_mounts(struct args *args)
{
struct statfs *mnts;
int nmnts;
int i;
char **list = NULL;
RC_STRINGLIST *list;
char *options = NULL;
uint64_t flags;
struct opt *o;
int netdev;
char *tmp;
size_t l;
if ((nmnts = getmntinfo (&mnts, MNT_NOWAIT)) == 0)
eerrorx ("getmntinfo: %s", strerror (errno));
if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0)
eerrorx("getmntinfo: %s", strerror (errno));
list = rc_stringlist_new();
for (i = 0; i < nmnts; i++) {
int netdev = 0;
netdev = 0;
flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK;
for (o = optnames; flags && o->o_opt; o++) {
if (flags & o->o_opt) {
if (o->o_opt == MNT_LOCAL)
netdev = 1;
if (! options)
options = xstrdup (o->o_name);
options = xstrdup(o->o_name);
else {
char *tmp = NULL;
size_t l = strlen (options) + strlen (o->o_name) + 2;
tmp = xmalloc (sizeof (char) * l);
snprintf (tmp, l, "%s,%s", options, o->o_name);
free (options);
l = strlen(options) + strlen(o->o_name) + 2;
tmp = xmalloc(sizeof (char) * l);
snprintf(tmp, l, "%s,%s", options, o->o_name);
free(options);
options = tmp;
}
}
flags &= ~o->o_opt;
}
process_mount (&list, args,
mnts[i].f_mntfromname,
mnts[i].f_mntonname,
mnts[i].f_fstypename,
options,
netdev);
process_mount(list, args,
mnts[i].f_mntfromname,
mnts[i].f_mntonname,
mnts[i].f_fstypename,
options,
netdev);
free (options);
free(options);
options = NULL;
}
return (list);
return list;
}
#elif defined (__linux__)
static struct mntent *getmntfile (const char *file)
static struct mntent *getmntfile(const char *file)
{
struct mntent *ent = NULL;
FILE *fp;
fp = setmntent ("/etc/fstab", "r");
while ((ent = getmntent (fp)))
if (strcmp (file, ent->mnt_dir) == 0)
fp = setmntent("/etc/fstab", "r");
while ((ent = getmntent(fp)))
if (strcmp(file, ent->mnt_dir) == 0)
break;
endmntent (fp);
endmntent(fp);
return (ent);
return ent;
}
static char **find_mounts (struct args *args)
static RC_STRINGLIST *find_mounts(struct args *args)
{
FILE *fp;
char *buffer;
@@ -284,52 +286,54 @@ static char **find_mounts (struct args *args)
char *to;
char *fst;
char *opts;
char **list = NULL;
struct mntent *ent;
int netdev;
RC_STRINGLIST *list;
if ((fp = fopen ("/proc/mounts", "r")) == NULL)
eerrorx ("getmntinfo: %s", strerror (errno));
if ((fp = fopen("/proc/mounts", "r")) == NULL)
eerrorx("getmntinfo: %s", strerror(errno));
buffer = xmalloc (sizeof (char) * PATH_MAX * 3);
while (fgets (buffer, PATH_MAX * 3, fp)) {
list = rc_stringlist_new();
buffer = xmalloc(sizeof(char) * PATH_MAX * 3);
while (fgets(buffer, PATH_MAX * 3, fp)) {
netdev = -1;
p = buffer;
from = strsep (&p, " ");
to = strsep (&p, " ");
fst = strsep (&p, " ");
opts = strsep (&p, " ");
from = strsep(&p, " ");
to = strsep(&p, " ");
fst = strsep(&p, " ");
opts = strsep(&p, " ");
if ((ent = getmntfile (to))) {
if (strstr (ent->mnt_opts, "_netdev"))
if ((ent = getmntfile(to))) {
if (strstr(ent->mnt_opts, "_netdev"))
netdev = 0;
}
process_mount (&list, args, from, to, fst, opts, netdev);
process_mount(list, args, from, to, fst, opts, netdev);
}
free (buffer);
fclose (fp);
free(buffer);
fclose(fp);
return (list);
return list;
}
#else
# error "Operating system not supported!"
#endif
static regex_t *get_regex (const char *string)
static regex_t *get_regex(const char *string)
{
regex_t *reg = xmalloc (sizeof (*reg));
regex_t *reg = xmalloc(sizeof (*reg));
int result;
char buffer[256];
if ((result = regcomp (reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
if ((result = regcomp(reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
{
regerror (result, reg, buffer, sizeof (buffer));
eerrorx ("%s: invalid regex `%s'", applet, buffer);
regerror(result, reg, buffer, sizeof(buffer));
eerrorx("%s: invalid regex `%s'", applet, buffer);
}
return (reg);
return reg;
}
#include "_usage.h"
@@ -347,7 +351,7 @@ static const struct option longopts[] = {
{ "options", 0, NULL, 'i'},
{ "fstype", 0, NULL, 's'},
{ "node", 0, NULL, 't'},
{ "netdev", 0, NULL, 'e'},
{ "netdev", 0, NULL, 'e'},
{ "nonetdev", 0, NULL, 'E'},
longopts_COMMON
};
@@ -369,112 +373,113 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int mountinfo (int argc, char **argv)
int mountinfo(int argc, char **argv)
{
int i;
struct args args;
regex_t *point_regex = NULL;
regex_t *skip_point_regex = NULL;
char **nodes = NULL;
char *n;
RC_STRINGLIST *nodes;
RC_STRING *s;
int opt;
int result;
bool quiet;
/* Ensure that we are only quiet when explicitly told to be */
unsetenv ("EINFO_QUIET");
unsetenv("EINFO_QUIET");
#define DO_REG(_var) \
if (_var) free (_var); \
_var = get_regex (optarg);
if (_var) free(_var); \
_var = get_regex(optarg);
#define REG_FREE(_var) \
if (_var) { regfree (_var); free (_var); }
if (_var) { regfree(_var); free(_var); }
memset (&args, 0, sizeof (args));
memset (&args, 0, sizeof(args));
args.mount_type = mount_to;
args.netdev = net_ignore;
args.mounts = rc_stringlist_new();
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'e':
args.netdev = net_yes;
break;
case 'E':
args.netdev = net_no;
break;
case 'f':
DO_REG (args.fstype_regex);
break;
case 'F':
DO_REG (args.skip_fstype_regex);
break;
case 'n':
DO_REG (args.node_regex);
break;
case 'N':
DO_REG (args.skip_node_regex);
break;
case 'o':
DO_REG (args.options_regex);
break;
case 'O':
DO_REG (args.skip_options_regex);
break;
case 'p':
DO_REG (point_regex);
break;
case 'P':
DO_REG (skip_point_regex);
break;
case 'i':
args.mount_type = mount_options;
break;
case 's':
args.mount_type = mount_fstype;
break;
case 't':
args.mount_type = mount_from;
break;
case 'e':
args.netdev = net_yes;
break;
case 'E':
args.netdev = net_no;
break;
case 'f':
DO_REG(args.fstype_regex);
break;
case 'F':
DO_REG(args.skip_fstype_regex);
break;
case 'n':
DO_REG(args.node_regex);
break;
case 'N':
DO_REG(args.skip_node_regex);
break;
case 'o':
DO_REG(args.options_regex);
break;
case 'O':
DO_REG(args.skip_options_regex);
break;
case 'p':
DO_REG(point_regex);
break;
case 'P':
DO_REG(skip_point_regex);
break;
case 'i':
args.mount_type = mount_options;
break;
case 's':
args.mount_type = mount_fstype;
break;
case 't':
args.mount_type = mount_from;
break;
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
while (optind < argc) {
if (argv[optind][0] != '/')
eerrorx ("%s: `%s' is not a mount point", argv[0], argv[optind]);
rc_strlist_add (&args.mounts, argv[optind++]);
eerrorx("%s: `%s' is not a mount point", argv[0], argv[optind]);
rc_stringlist_add(args.mounts, argv[optind++]);
}
nodes = find_mounts(&args);
rc_stringlist_free(args.mounts);
rc_stringlist_sort(&nodes);
nodes = find_mounts (&args);
REG_FREE (args.fstype_regex);
REG_FREE (args.skip_fstype_regex);
REG_FREE (args.node_regex);
REG_FREE (args.skip_node_regex);
REG_FREE (args.options_regex);
REG_FREE (args.skip_options_regex);
rc_strlist_reverse (nodes);
REG_FREE(args.fstype_regex);
REG_FREE(args.skip_fstype_regex);
REG_FREE(args.node_regex);
REG_FREE(args.skip_node_regex);
REG_FREE(args.options_regex);
REG_FREE(args.skip_options_regex);
result = EXIT_FAILURE;
quiet = rc_yesno (getenv ("EINFO_QUIET"));
STRLIST_FOREACH (nodes, n, i) {
if (point_regex && regexec (point_regex, n, 0, NULL, 0) != 0)
quiet = rc_yesno(getenv("EINFO_QUIET"));
TAILQ_FOREACH_REVERSE(s, nodes, rc_stringlist, entries) {
if (point_regex &&
regexec(point_regex, s->value, 0, NULL, 0) != 0)
continue;
if (skip_point_regex && regexec (skip_point_regex, n, 0, NULL, 0) == 0)
if (skip_point_regex &&
regexec(skip_point_regex, s->value, 0, NULL, 0) == 0)
continue;
if (! quiet)
printf ("%s\n", n);
printf("%s\n", s->value);
result = EXIT_SUCCESS;
}
rc_strlist_free (nodes);
rc_stringlist_free(nodes);
REG_FREE (point_regex);
REG_FREE (skip_point_regex);
REG_FREE(point_regex);
REG_FREE(skip_point_regex);
exit (result);
exit(result);
/* NOTREACHED */
}

View File

@@ -35,6 +35,7 @@
#define SYSLOG_NAMES
#include <sys/types.h>
#include <errno.h>
#include <ctype.h>
#include <inttypes.h>
@@ -49,26 +50,25 @@
#include "builtins.h"
#include "einfo.h"
#include "rc-misc.h"
#include "strlist.h"
/* Applet is first parsed in rc.c - no point in doing it again */
extern const char *applet;
static int syslog_decode (char *name, CODE *codetab)
static int syslog_decode(char *name, CODE *codetab)
{
CODE *c;
if (isdigit ((int) *name))
return (atoi (name));
if (isdigit((int) *name))
return atoi(name);
for (c = codetab; c->c_name; c++)
if (! strcasecmp (name, c->c_name))
return (c->c_val);
if (! strcasecmp(name, c->c_name))
return c->c_val;
return (-1);
return -1;
}
static int do_e (int argc, char **argv)
static int do_e(int argc, char **argv)
{
int retval = EXIT_SUCCESS;
int i;
@@ -82,42 +82,42 @@ static int do_e (int argc, char **argv)
argc--;
argv++;
if (strcmp (applet, "eval_ecolors") == 0) {
printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
ecolor (ECOLOR_GOOD),
ecolor (ECOLOR_WARN),
ecolor (ECOLOR_BAD),
ecolor (ECOLOR_HILITE),
ecolor (ECOLOR_BRACKET),
ecolor (ECOLOR_NORMAL));
exit (EXIT_SUCCESS);
if (strcmp(applet, "eval_ecolors") == 0) {
printf("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
ecolor(ECOLOR_GOOD),
ecolor(ECOLOR_WARN),
ecolor(ECOLOR_BAD),
ecolor(ECOLOR_HILITE),
ecolor(ECOLOR_BRACKET),
ecolor(ECOLOR_NORMAL));
exit(EXIT_SUCCESS);
}
if (argc > 0) {
if (strcmp (applet, "eend") == 0 ||
strcmp (applet, "ewend") == 0 ||
strcmp (applet, "veend") == 0 ||
strcmp (applet, "vweend") == 0)
if (strcmp(applet, "eend") == 0 ||
strcmp(applet, "ewend") == 0 ||
strcmp(applet, "veend") == 0 ||
strcmp(applet, "vweend") == 0)
{
errno = 0;
retval = (int) strtoimax (argv[0], NULL, 0);
retval = (int) strtoimax(argv[0], NULL, 0);
if (errno != 0)
retval = EXIT_FAILURE;
else {
argc--;
argv++;
}
} else if (strcmp (applet, "esyslog") == 0 ||
strcmp (applet, "elog") == 0) {
char *dot = strchr (argv[0], '.');
if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
eerrorx ("%s: invalid log level `%s'", applet, argv[0]);
} else if (strcmp(applet, "esyslog") == 0 ||
strcmp(applet, "elog") == 0) {
p = strchr(argv[0], '.');
if ((level = syslog_decode(p + 1, prioritynames)) == -1)
eerrorx("%s: invalid log level `%s'", applet, argv[0]);
if (argc < 3)
eerrorx ("%s: not enough arguments", applet);
eerrorx("%s: not enough arguments", applet);
unsetenv ("EINFO_LOG");
setenv ("EINFO_LOG", argv[1], 1);
unsetenv("EINFO_LOG");
setenv("EINFO_LOG", argv[1], 1);
argc -= 2;
argv += 2;
@@ -126,16 +126,17 @@ static int do_e (int argc, char **argv)
if (argc > 0) {
for (i = 0; i < argc; i++)
l += strlen (argv[i]) + 1;
l += strlen(argv[i]) + 1;
message = xmalloc (l);
message = xmalloc(l);
p = message;
for (i = 0; i < argc; i++) {
if (i > 0)
*p++ = ' ';
memcpy (p, argv[i], strlen (argv[i]));
p += strlen (argv[i]);
l = strlen(argv[i]);
memcpy(p, argv[i], l);
p += l;
}
*p = 0;
}
@@ -143,300 +144,302 @@ static int do_e (int argc, char **argv)
if (! message)
fmt = "";
if (strcmp (applet, "einfo") == 0)
einfo (fmt, message);
else if (strcmp (applet, "einfon") == 0)
einfon (fmt, message);
else if (strcmp (applet, "ewarn") == 0)
ewarn (fmt, message);
else if (strcmp (applet, "ewarnn") == 0)
ewarnn (fmt, message);
else if (strcmp (applet, "eerror") == 0) {
eerror (fmt, message);
if (strcmp(applet, "einfo") == 0)
einfo(fmt, message);
else if (strcmp(applet, "einfon") == 0)
einfon(fmt, message);
else if (strcmp(applet, "ewarn") == 0)
ewarn(fmt, message);
else if (strcmp(applet, "ewarnn") == 0)
ewarnn(fmt, message);
else if (strcmp(applet, "eerror") == 0) {
eerror(fmt, message);
retval = 1;
} else if (strcmp (applet, "eerrorn") == 0) {
eerrorn (fmt, message);
} else if (strcmp(applet, "eerrorn") == 0) {
eerrorn(fmt, message);
retval = 1;
} else if (strcmp (applet, "ebegin") == 0)
ebegin (fmt, message);
else if (strcmp (applet, "eend") == 0)
eend (retval, fmt, message);
else if (strcmp (applet, "ewend") == 0)
ewend (retval, fmt, message);
else if (strcmp (applet, "esyslog") == 0)
elog (level, fmt, message);
else if (strcmp (applet, "veinfo") == 0)
einfov (fmt, message);
else if (strcmp (applet, "veinfon") == 0)
einfovn (fmt, message);
else if (strcmp (applet, "vewarn") == 0)
ewarnv (fmt, message);
else if (strcmp (applet, "vewarnn") == 0)
ewarnvn (fmt, message);
else if (strcmp (applet, "vebegin") == 0)
ebeginv (fmt, message);
else if (strcmp (applet, "veend") == 0)
eendv (retval, fmt, message);
else if (strcmp (applet, "vewend") == 0)
ewendv (retval, fmt, message);
else if (strcmp (applet, "eindent") == 0)
eindent ();
else if (strcmp (applet, "eoutdent") == 0)
eoutdent ();
else if (strcmp (applet, "veindent") == 0)
eindentv ();
else if (strcmp (applet, "veoutdent") == 0)
eoutdentv ();
} else if (strcmp(applet, "ebegin") == 0)
ebegin(fmt, message);
else if (strcmp(applet, "eend") == 0)
eend(retval, fmt, message);
else if (strcmp(applet, "ewend") == 0)
ewend(retval, fmt, message);
else if (strcmp(applet, "esyslog") == 0)
elog(level, fmt, message);
else if (strcmp(applet, "veinfo") == 0)
einfov(fmt, message);
else if (strcmp(applet, "veinfon") == 0)
einfovn(fmt, message);
else if (strcmp(applet, "vewarn") == 0)
ewarnv(fmt, message);
else if (strcmp(applet, "vewarnn") == 0)
ewarnvn(fmt, message);
else if (strcmp(applet, "vebegin") == 0)
ebeginv(fmt, message);
else if (strcmp(applet, "veend") == 0)
eendv(retval, fmt, message);
else if (strcmp(applet, "vewend") == 0)
ewendv(retval, fmt, message);
else if (strcmp(applet, "eindent") == 0)
eindent();
else if (strcmp(applet, "eoutdent") == 0)
eoutdent();
else if (strcmp(applet, "veindent") == 0)
eindentv();
else if (strcmp(applet, "veoutdent") == 0)
eoutdentv();
else {
eerror ("%s: unknown applet", applet);
eerror("%s: unknown applet", applet);
retval = EXIT_FAILURE;
}
free (message);
return (retval);
free(message);
return retval;
}
static int do_service (int argc, char **argv)
static int do_service(int argc, char **argv)
{
bool ok = false;
char *service = NULL;
int idx = 0;
char *d[] = { NULL, NULL };
if (argc > 1)
service = argv[1];
else
service = getenv ("SVCNAME");
service = getenv("SVCNAME");
if (! service || *service == '\0')
eerrorx ("%s: no service specified", applet);
eerrorx("%s: no service specified", applet);
if (strcmp (applet, "service_started") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STARTED);
else if (strcmp (applet, "service_stopped") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STOPPED);
else if (strcmp (applet, "service_inactive") == 0)
ok = (rc_service_state (service) & RC_SERVICE_INACTIVE);
else if (strcmp (applet, "service_starting") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STARTING);
else if (strcmp (applet, "service_stopping") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STOPPING);
else if (strcmp (applet, "service_coldplugged") == 0)
ok = (rc_service_state (service) & RC_SERVICE_COLDPLUGGED);
else if (strcmp (applet, "service_wasinactive") == 0)
ok = (rc_service_state (service) & RC_SERVICE_WASINACTIVE);
else if (strcmp (applet, "service_started_daemon") == 0) {
int idx = 0;
char *d[] = { argv[1], NULL };
if (strcmp(applet, "service_started") == 0)
ok = (rc_service_state(service) & RC_SERVICE_STARTED);
else if (strcmp(applet, "service_stopped") == 0)
ok = (rc_service_state(service) & RC_SERVICE_STOPPED);
else if (strcmp(applet, "service_inactive") == 0)
ok = (rc_service_state(service) & RC_SERVICE_INACTIVE);
else if (strcmp(applet, "service_starting") == 0)
ok = (rc_service_state(service) & RC_SERVICE_STARTING);
else if (strcmp(applet, "service_stopping") == 0)
ok = (rc_service_state(service) & RC_SERVICE_STOPPING);
else if (strcmp(applet, "service_coldplugged") == 0)
ok = (rc_service_state(service) & RC_SERVICE_COLDPLUGGED);
else if (strcmp(applet, "service_wasinactive") == 0)
ok = (rc_service_state(service) & RC_SERVICE_WASINACTIVE);
else if (strcmp(applet, "service_started_daemon") == 0) {
d[0] = argv[1];
service = getenv ("SVCNAME");
service = getenv("SVCNAME");
if (argc > 3) {
service = argv[1];
d[0] = argv[2];
sscanf (argv[3], "%d", &idx);
sscanf(argv[3], "%d", &idx);
} else if (argc == 3) {
if (sscanf (argv[2], "%d", &idx) != 1) {
if (sscanf(argv[2], "%d", &idx) != 1) {
service = argv[1];
*d = argv[2];
d[0] = argv[2];
}
}
ok = rc_service_started_daemon (service,
(const char * const *)d, idx);
ok = rc_service_started_daemon(service,
(const char * const *)d, idx);
} else
eerrorx ("%s: unknown applet", applet);
eerrorx("%s: unknown applet", applet);
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int do_mark_service (int argc, char **argv)
static int do_mark_service(int argc, char **argv)
{
bool ok = false;
char *svcname = getenv ("SVCNAME");
char *svcname = getenv("SVCNAME");
char *service = NULL;
char *runscript_pid;
char *mtime;
pid_t pid;
size_t l;
if (argc > 1)
service = argv[1];
else
service = getenv ("SVCNAME");
service = getenv("SVCNAME");
if (! service || *service == '\0')
eerrorx ("%s: no service specified", applet);
eerrorx("%s: no service specified", applet);
if (strcmp (applet, "mark_service_started") == 0)
ok = rc_service_mark (service, RC_SERVICE_STARTED);
else if (strcmp (applet, "mark_service_stopped") == 0)
ok = rc_service_mark (service, RC_SERVICE_STOPPED);
else if (strcmp (applet, "mark_service_inactive") == 0)
ok = rc_service_mark (service, RC_SERVICE_INACTIVE);
else if (strcmp (applet, "mark_service_starting") == 0)
ok = rc_service_mark (service, RC_SERVICE_STARTING);
else if (strcmp (applet, "mark_service_stopping") == 0)
ok = rc_service_mark (service, RC_SERVICE_STOPPING);
else if (strcmp (applet, "mark_service_coldplugged") == 0)
ok = rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
else if (strcmp (applet, "mark_service_failed") == 0)
ok = rc_service_mark (service, RC_SERVICE_FAILED);
if (strcmp(applet, "mark_service_started") == 0)
ok = rc_service_mark(service, RC_SERVICE_STARTED);
else if (strcmp(applet, "mark_service_stopped") == 0)
ok = rc_service_mark(service, RC_SERVICE_STOPPED);
else if (strcmp(applet, "mark_service_inactive") == 0)
ok = rc_service_mark(service, RC_SERVICE_INACTIVE);
else if (strcmp(applet, "mark_service_starting") == 0)
ok = rc_service_mark(service, RC_SERVICE_STARTING);
else if (strcmp(applet, "mark_service_stopping") == 0)
ok = rc_service_mark(service, RC_SERVICE_STOPPING);
else if (strcmp(applet, "mark_service_coldplugged") == 0)
ok = rc_service_mark(service, RC_SERVICE_COLDPLUGGED);
else if (strcmp(applet, "mark_service_failed") == 0)
ok = rc_service_mark(service, RC_SERVICE_FAILED);
else
eerrorx ("%s: unknown applet", applet);
eerrorx("%s: unknown applet", applet);
/* If we're marking ourselves then we need to inform our parent runscript
process so they do not mark us based on our exit code */
if (ok && svcname && strcmp (svcname, service) == 0) {
char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
char *mtime;
pid_t pid = 0;
size_t l;
if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
if (kill (pid, SIGHUP) != 0)
eerror ("%s: failed to signal parent %d: %s",
applet, pid, strerror (errno));
if (ok && svcname && strcmp(svcname, service) == 0) {
runscript_pid = getenv("RC_RUNSCRIPT_PID");
if (runscript_pid && sscanf(runscript_pid, "%d", &pid) == 1)
if (kill(pid, SIGHUP) != 0)
eerror("%s: failed to signal parent %d: %s",
applet, pid, strerror(errno));
/* Remove the exclusive time test. This ensures that it's not
in control as well */
l = strlen (RC_SVCDIR "exclusive") +
strlen (svcname) +
strlen (runscript_pid) +
4;
mtime = xmalloc (l);
snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
svcname, runscript_pid);
if (exists (mtime) && unlink (mtime) != 0)
eerror ("%s: unlink: %s", applet, strerror (errno));
free (mtime);
l = strlen(RC_SVCDIR "exclusive") + strlen(svcname) +
strlen(runscript_pid) + 4;
mtime = xmalloc(l);
snprintf(mtime, l, RC_SVCDIR "exclusive/%s.%s",
svcname, runscript_pid);
if (exists(mtime) && unlink(mtime) != 0)
eerror("%s: unlink: %s", applet, strerror(errno));
free(mtime);
}
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int do_value (int argc, char **argv)
static int do_value(int argc, char **argv)
{
bool ok = false;
char *service = getenv ("SVCNAME");
char *service = getenv("SVCNAME");
char *option;
if (! service)
eerrorx ("%s: no service specified", applet);
eerrorx("%s: no service specified", applet);
if (argc < 2 || ! argv[1] || *argv[1] == '\0')
eerrorx ("%s: no option specified", applet);
eerrorx("%s: no option specified", applet);
if (strcmp (applet, "service_get_value") == 0 ||
strcmp (applet, "get_options") == 0)
if (strcmp(applet, "service_get_value") == 0 ||
strcmp(applet, "get_options") == 0)
{
char *option = rc_service_value_get (service, argv[1]);
option = rc_service_value_get(service, argv[1]);
if (option) {
printf ("%s", option);
free (option);
printf("%s", option);
free(option);
ok = true;
}
} else if (strcmp (applet, "service_set_value") == 0 ||
strcmp (applet, "save_options") == 0)
ok = rc_service_value_set (service, argv[1], argv[2]);
} else if (strcmp(applet, "service_set_value") == 0 ||
strcmp(applet, "save_options") == 0)
ok = rc_service_value_set(service, argv[1], argv[2]);
else
eerrorx ("%s: unknown applet", applet);
eerrorx("%s: unknown applet", applet);
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int do_shell_var (int argc, char **argv)
static int do_shell_var(int argc, char **argv)
{
int i;
char *p;
int c;
for (i = 1; i < argc; i++) {
char *p = argv[i];
p = argv[i];
if (i != 1)
putchar (' ');
putchar(' ');
while (*p) {
char c = *p++;
if (! isalnum ((int) c))
c = *p++;
if (! isalnum(c))
c = '_';
putchar (c);
putchar(c);
}
}
putchar ('\n');
putchar('\n');
return (EXIT_SUCCESS);
return EXIT_SUCCESS;
}
void run_applets (int argc, char **argv)
void run_applets(int argc, char **argv)
{
int i = 2;
bool match = false;
char *p;
pid_t pid = 0;
/* These are designed to be applications in their own right */
if (strcmp (applet, "fstabinfo") == 0)
exit (fstabinfo (argc, argv));
else if (strcmp (applet, "mountinfo") == 0)
exit (mountinfo (argc, argv));
else if (strcmp (applet, "rc-depend") == 0)
exit (rc_depend (argc, argv));
else if (strcmp (applet, "rc-status") == 0)
exit (rc_status (argc, argv));
else if (strcmp (applet, "rc-update") == 0 ||
strcmp (applet, "update-rc") == 0)
exit (rc_update (argc, argv));
else if (strcmp (applet, "runscript") == 0)
exit (runscript (argc, argv));
else if (strcmp (applet, "start-stop-daemon") == 0)
exit (start_stop_daemon (argc, argv));
if (strcmp(applet, "fstabinfo") == 0)
exit(fstabinfo(argc, argv));
else if (strcmp(applet, "mountinfo") == 0)
exit(mountinfo(argc, argv));
else if (strcmp(applet, "rc-depend") == 0)
exit(rc_depend(argc, argv));
else if (strcmp(applet, "rc-status") == 0)
exit(rc_status(argc, argv));
else if (strcmp(applet, "rc-update") == 0 ||
strcmp(applet, "update-rc") == 0)
exit(rc_update(argc, argv));
else if (strcmp(applet, "runscript") == 0)
exit(runscript(argc, argv));
else if (strcmp(applet, "start-stop-daemon") == 0)
exit(start_stop_daemon(argc, argv));
else if (strcmp (applet, "checkpath") == 0)
exit (checkpath (argc, argv));
exit(checkpath(argc, argv));
/* These could also be applications in their own right */
if (strcmp (applet, "shell_var") == 0)
exit (do_shell_var (argc, argv));
if (strcmp(applet, "shell_var") == 0)
exit(do_shell_var(argc, argv));
if (strcmp (applet, "is_newer_than") == 0 ||
strcmp (applet, "is_older_than") == 0)
if (strcmp(applet, "is_newer_than") == 0 ||
strcmp(applet, "is_older_than") == 0)
{
bool match = false;
int i = 2;
if (argc < 3)
exit (EXIT_FAILURE);
if (strcmp (applet, "is_newer_than") == 0)
if (strcmp(applet, "is_newer_than") == 0)
match = true;
while (i < argc) {
if (rc_newer_than (argv[1], argv[i++]) != match)
if (rc_newer_than(argv[1], argv[i++]) != match)
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
exit(EXIT_SUCCESS);
};
if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
exit (do_e (argc, argv));
exit(do_e(argc, argv));
/* These are purely for init scripts and do not make sense as
* anything else */
if (strcmp (applet, "service_get_value") == 0 ||
strcmp (applet, "service_set_value") == 0 ||
strcmp (applet, "get_options") == 0 ||
strcmp (applet, "save_options") == 0)
exit (do_value (argc, argv));
if (strcmp(applet, "service_get_value") == 0 ||
strcmp(applet, "service_set_value") == 0 ||
strcmp(applet, "get_options") == 0 ||
strcmp(applet, "save_options") == 0)
exit(do_value(argc, argv));
if (strncmp (applet, "service_", strlen ("service_")) == 0)
exit (do_service (argc, argv));
if (strncmp(applet, "service_", strlen("service_")) == 0)
exit(do_service(argc, argv));
if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
exit (do_mark_service (argc, argv));
if (strncmp(applet, "mark_service_", strlen("mark_service_")) == 0)
exit(do_mark_service(argc, argv));
if (strcmp (applet, "is_runlevel_start") == 0)
exit (rc_runlevel_starting () ? 0 : 1);
if (strcmp(applet, "is_runlevel_start") == 0)
exit(rc_runlevel_starting() ? 0 : 1);
else if (strcmp (applet, "is_runlevel_stop") == 0)
exit (rc_runlevel_stopping () ? 0 : 1);
exit(rc_runlevel_stopping() ? 0 : 1);
if (strcmp (applet, "rc-abort") == 0) {
char *p = getenv ("RC_PID");
pid_t pid = 0;
if (p && sscanf (p, "%d", &pid) == 1) {
if (kill (pid, SIGUSR1) != 0)
eerrorx ("rc-abort: failed to signal parent %d: %s",
pid, strerror (errno));
exit (EXIT_SUCCESS);
if (strcmp(applet, "rc-abort") == 0) {
p = getenv("RC_PID");
if (p && sscanf(p, "%d", &pid) == 1) {
if (kill(pid, SIGUSR1) != 0)
eerrorx("rc-abort: failed to signal parent %d: %s",
pid, strerror(errno));
exit(EXIT_SUCCESS);
}
exit (EXIT_FAILURE);
exit(EXIT_FAILURE);
}
if (strcmp (applet, "rc" ) != 0)
eerrorx ("%s: unknown applet", applet);
if (strcmp(applet, "rc") != 0)
eerrorx("%s: unknown applet", applet);
}

View File

@@ -45,34 +45,33 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
extern const char *applet;
rc_depinfo_t *_rc_deptree_load (int *regen) {
if (rc_deptree_update_needed ()) {
int fd;
int retval;
int serrno = errno;
int merrno;
RC_DEPTREE *_rc_deptree_load(int *regen) {
int fd;
int retval;
int serrno = errno;
int merrno;
if (rc_deptree_update_needed()) {
/* Test if we have permission to update the deptree */
fd = open (RC_DEPTREE, O_WRONLY);
fd = open(RC_DEPTREE_CACHE, O_WRONLY);
merrno = errno;
errno = serrno;
if (fd == -1 && merrno == EACCES)
return (rc_deptree_load ());
close (fd);
return rc_deptree_load();
close(fd);
if (regen)
*regen = 1;
ebegin ("Caching service dependencies");
retval = rc_deptree_update ();
ebegin("Caching service dependencies");
retval = rc_deptree_update();
eend (retval ? 0 : -1, "Failed to update the dependency tree");
}
return (rc_deptree_load ());
return rc_deptree_load();
}
#include "_usage.h"
@@ -97,117 +96,114 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int rc_depend (int argc, char **argv)
int rc_depend(int argc, char **argv)
{
char **types = NULL;
char **services = NULL;
char **depends = NULL;
char **list;
rc_depinfo_t *deptree = NULL;
char *service;
RC_STRINGLIST *list;
RC_STRINGLIST *types;
RC_STRINGLIST *services;
RC_STRINGLIST *depends;
RC_STRING *s;
RC_DEPTREE *deptree = NULL;
int options = RC_DEP_TRACE;
bool first = true;
int i;
bool update = false;
char *runlevel = xstrdup( getenv ("RC_SOFTLEVEL"));
char *runlevel = xstrdup(getenv("RC_SOFTLEVEL"));
int opt;
char *token;
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
types = rc_stringlist_new();
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'a':
options |= RC_DEP_START;
break;
case 'o':
options |= RC_DEP_STOP;
break;
case 's':
options |= RC_DEP_STRICT;
break;
case 't':
while ((token = strsep (&optarg, ",")))
rc_strlist_addu (&types, token);
break;
case 'u':
update = true;
break;
case 'T':
options &= RC_DEP_TRACE;
break;
case 'a':
options |= RC_DEP_START;
break;
case 'o':
options |= RC_DEP_STOP;
break;
case 's':
options |= RC_DEP_STRICT;
break;
case 't':
while ((token = strsep(&optarg, ",")))
rc_stringlist_add(types, token);
break;
case 'u':
update = true;
break;
case 'T':
options &= RC_DEP_TRACE;
break;
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
if (update) {
bool u = false;
ebegin ("Caching service dependencies");
u = rc_deptree_update ();
eend (u ? 0 : -1, "%s: %s", applet, strerror (errno));
if (! u)
eerrorx ("Failed to update the dependency tree");
ebegin("Caching service dependencies");
update = rc_deptree_update();
eend(update ? 0 : -1, "%s: %s", applet, strerror(errno));
if (! update)
eerrorx("Failed to update the dependency tree");
}
if (! (deptree = _rc_deptree_load (NULL)))
eerrorx ("failed to load deptree");
if (! (deptree = _rc_deptree_load(NULL)))
eerrorx("failed to load deptree");
if (! runlevel)
runlevel = rc_runlevel_get ();
runlevel = rc_runlevel_get();
services = rc_stringlist_new();
while (optind < argc) {
list = NULL;
rc_strlist_add (&list, argv[optind]);
list = rc_stringlist_new();
rc_stringlist_add(list, argv[optind]);
errno = 0;
depends = rc_deptree_depends (deptree, NULL, (const char **) list,
runlevel, 0);
depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0);
if (! depends && errno == ENOENT)
eerror ("no dependency info for service `%s'", argv[optind]);
eerror("no dependency info for service `%s'", argv[optind]);
else
rc_strlist_add (&services, argv[optind]);
rc_stringlist_add(services, argv[optind]);
rc_strlist_free (depends);
rc_strlist_free (list);
rc_stringlist_free(depends);
rc_stringlist_free(list);
optind++;
}
if (! services) {
rc_strlist_free (types);
rc_deptree_free (deptree);
free (runlevel);
if (! TAILQ_FIRST(services)) {
rc_stringlist_free(services);
rc_stringlist_free(types);
rc_deptree_free(deptree);
free(runlevel);
if (update)
return (EXIT_SUCCESS);
eerrorx ("no services specified");
return EXIT_SUCCESS;
eerrorx("no services specified");
}
/* If we don't have any types, then supply some defaults */
if (! types) {
rc_strlist_add (&types, "ineed");
rc_strlist_add (&types, "iuse");
if (! TAILQ_FIRST(types)) {
rc_stringlist_add(types, "ineed");
rc_stringlist_add(types, "iuse");
}
depends = rc_deptree_depends (deptree, (const char **) types,
(const char **) services, runlevel, options);
depends = rc_deptree_depends(deptree, types, services, runlevel, options);
if (depends) {
STRLIST_FOREACH (depends, service, i) {
if (TAILQ_FIRST(depends)) {
TAILQ_FOREACH(s, depends, entries) {
if (first)
first = false;
else
printf (" ");
if (service)
printf ("%s", service);
printf ("%s", s->value);
}
printf ("\n");
}
rc_strlist_free (types);
rc_strlist_free (services);
rc_strlist_free (depends);
rc_deptree_free (deptree);
free (runlevel);
return (EXIT_SUCCESS);
rc_stringlist_free(types);
rc_stringlist_free(services);
rc_stringlist_free(depends);
rc_deptree_free(deptree);
free(runlevel);
return EXIT_SUCCESS;
}

View File

@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
@@ -76,67 +77,67 @@ pid_t rc_logger_pid = -1;
int rc_logger_tty = -1;
bool rc_in_logger = false;
static void write_log (int logfd, const char *buffer, size_t bytes)
static void write_log(int logfd, const char *buffer, size_t bytes)
{
const char *p = buffer;
while ((size_t) (p - buffer) < bytes) {
switch (*p) {
case '\r':
goto cont;
case '\033':
in_escape = true;
in_term = false;
goto cont;
case '\n':
in_escape = in_term = false;
break;
case '[':
if (in_escape)
in_term = true;
break;
case '\r':
goto cont;
case '\033':
in_escape = true;
in_term = false;
goto cont;
case '\n':
in_escape = in_term = false;
break;
case '[':
if (in_escape)
in_term = true;
break;
}
if (! in_escape) {
write (logfd, p++, 1);
write(logfd, p++, 1);
continue;
}
if (! in_term || isalpha ((int) *p))
if (! in_term || isalpha((int) *p))
in_escape = in_term = false;
cont:
p++;
}
}
static void write_time (FILE *f, const char *s)
static void write_time(FILE *f, const char *s)
{
time_t now = time (NULL);
struct tm *tm = localtime (&now);
time_t now = time(NULL);
struct tm *tm = localtime(&now);
fprintf (f, "\nrc %s logging %s at %s\n", runlevel, s, asctime (tm));
fflush (f);
fprintf(f, "\nrc %s logging %s at %s\n", runlevel, s, asctime(tm));
fflush(f);
}
void rc_logger_close ()
void rc_logger_close(void)
{
int sig = SIGTERM;
if (signal_pipe[1] > -1) {
int sig = SIGTERM;
write (signal_pipe[1], &sig, sizeof (sig));
close (signal_pipe[1]);
write(signal_pipe[1], &sig, sizeof(sig));
close(signal_pipe[1]);
signal_pipe[1] = -1;
}
if (rc_logger_pid > 0)
waitpid (rc_logger_pid, 0, 0);
waitpid(rc_logger_pid, 0, 0);
if (fd_stdout > -1)
dup2 (fd_stdout, STDOUT_FILENO);
dup2(fd_stdout, STDOUT_FILENO);
if (fd_stderr > -1)
dup2 (fd_stderr, STDERR_FILENO);
dup2(fd_stderr, STDERR_FILENO);
}
void rc_logger_open (const char *level)
void rc_logger_open(const char *level)
{
int slave_tty;
struct termios tt;
@@ -149,125 +150,127 @@ void rc_logger_open (const char *level)
int i;
FILE *log = NULL;
if (! isatty (STDOUT_FILENO))
if (! isatty(STDOUT_FILENO))
return;
if (! rc_conf_yesno ("rc_logger"))
if (! rc_conf_yesno("rc_logger"))
return;
if (pipe (signal_pipe) == -1)
eerrorx ("pipe: %s", strerror (errno));
if (pipe(signal_pipe) == -1)
eerrorx("pipe: %s", strerror(errno));
for (i = 0; i < 2; i++)
if ((s = fcntl (signal_pipe[i], F_GETFD, 0) == -1 ||
fcntl (signal_pipe[i], F_SETFD, s | FD_CLOEXEC) == -1))
eerrorx ("fcntl: %s", strerror (errno));
eerrorx("fcntl: %s", strerror (errno));
tcgetattr (STDOUT_FILENO, &tt);
ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws);
tcgetattr(STDOUT_FILENO, &tt);
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
/* /dev/pts may not be available yet */
if (openpty (&rc_logger_tty, &slave_tty, NULL, &tt, &ws))
if (openpty(&rc_logger_tty, &slave_tty, NULL, &tt, &ws))
return;
if ((s = fcntl (rc_logger_tty, F_GETFD, 0)) == 0)
fcntl (rc_logger_tty, F_SETFD, s | FD_CLOEXEC);
if ((s = fcntl(rc_logger_tty, F_GETFD, 0)) == 0)
fcntl(rc_logger_tty, F_SETFD, s | FD_CLOEXEC);
if ((s = fcntl (slave_tty, F_GETFD, 0)) == 0)
fcntl (slave_tty, F_SETFD, s | FD_CLOEXEC);
if ((s = fcntl(slave_tty, F_GETFD, 0)) == 0)
fcntl(slave_tty, F_SETFD, s | FD_CLOEXEC);
rc_logger_pid = fork ();
rc_logger_pid = fork();
switch (rc_logger_pid) {
case -1:
eerror ("forkpty: %s", strerror (errno));
break;
case 0:
rc_in_logger = true;
close (signal_pipe[1]);
signal_pipe[1] = -1;
case -1:
eerror("fork: %s", strerror(errno));
break;
case 0:
rc_in_logger = true;
close(signal_pipe[1]);
signal_pipe[1] = -1;
runlevel = level;
if ((log = fopen (LOGFILE, "a")))
write_time (log, "started");
else {
free (logbuf);
logbuf_size = BUFSIZ * 10;
logbuf = xmalloc (sizeof (char) * logbuf_size);
logbuf_len = 0;
runlevel = level;
if ((log = fopen(LOGFILE, "a")))
write_time(log, "started");
else {
free(logbuf);
logbuf_size = BUFSIZ * 10;
logbuf = xmalloc(sizeof (char) * logbuf_size);
logbuf_len = 0;
}
buffer = xmalloc(sizeof (char) * BUFSIZ);
selfd = rc_logger_tty > signal_pipe[0] ? rc_logger_tty : signal_pipe[0];
for (;;) {
FD_ZERO(&rset);
FD_SET(rc_logger_tty, &rset);
FD_SET(signal_pipe[0], &rset);
if ((s = select(selfd + 1, &rset, NULL, NULL, NULL)) == -1) {
eerror("select: %s", strerror(errno));
break;
}
buffer = xmalloc (sizeof (char) * BUFSIZ);
selfd = rc_logger_tty > signal_pipe[0] ? rc_logger_tty : signal_pipe[0];
for (;;) {
FD_ZERO (&rset);
FD_SET (rc_logger_tty, &rset);
FD_SET (signal_pipe[0], &rset);
if (s > 0) {
if (FD_ISSET(rc_logger_tty, &rset)) {
memset(buffer, 0, BUFSIZ);
bytes = read(rc_logger_tty, buffer, BUFSIZ);
write(STDOUT_FILENO, buffer, bytes);
if ((s = select (selfd + 1, &rset, NULL, NULL, NULL)) == -1) {
eerror ("select: %s", strerror (errno));
break;
}
if (s > 0) {
if (FD_ISSET (rc_logger_tty, &rset)) {
memset (buffer, 0, BUFSIZ);
bytes = read (rc_logger_tty, buffer, BUFSIZ);
write (STDOUT_FILENO, buffer, bytes);
if (log)
write_log (fileno (log), buffer, bytes);
else {
if (logbuf_size - logbuf_len < bytes) {
logbuf_size += BUFSIZ * 10;
logbuf = xrealloc (logbuf, sizeof (char ) *
logbuf_size);
}
memcpy (logbuf + logbuf_len, buffer, bytes);
logbuf_len += bytes;
if (log)
write_log(fileno (log), buffer, bytes);
else {
if (logbuf_size - logbuf_len < bytes) {
logbuf_size += BUFSIZ * 10;
logbuf = xrealloc(logbuf,
sizeof(char ) *
logbuf_size);
}
memcpy(logbuf + logbuf_len, buffer, bytes);
logbuf_len += bytes;
}
/* Only SIGTERMS signals come down this pipe */
if (FD_ISSET (signal_pipe[0], &rset))
break;
}
}
free (buffer);
if (logbuf) {
if ((log = fopen (LOGFILE, "a"))) {
write_time (log, "started");
write_log (fileno (log), logbuf, logbuf_len);
}
free (logbuf);
}
if (log) {
write_time (log, "stopped");
fclose (log);
}
/* Try and cat our new logfile to a more permament location and then
* punt it */
system (MOVELOG);
/* Only SIGTERMS signals come down this pipe */
if (FD_ISSET(signal_pipe[0], &rset))
break;
}
}
free(buffer);
if (logbuf) {
if ((log = fopen(LOGFILE, "a"))) {
write_time(log, "started");
write_log(fileno(log), logbuf, logbuf_len);
}
free(logbuf);
}
if (log) {
write_time(log, "stopped");
fclose(log);
}
exit (0);
/* NOTREACHED */
default:
setpgid (rc_logger_pid, 0);
fd_stdout = dup (STDOUT_FILENO);
fd_stderr = dup (STDERR_FILENO);
if ((s = fcntl (fd_stdout, F_GETFD, 0)) == 0)
fcntl (fd_stdout, F_SETFD, s | FD_CLOEXEC);
/* Try and cat our new logfile to a more permament location and then
* punt it */
system(MOVELOG);
if ((s = fcntl (fd_stderr, F_GETFD, 0)) == 0)
fcntl (fd_stderr, F_SETFD, s | FD_CLOEXEC);
dup2 (slave_tty, STDOUT_FILENO);
dup2 (slave_tty, STDERR_FILENO);
if (slave_tty != STDIN_FILENO &&
slave_tty != STDOUT_FILENO &&
slave_tty != STDERR_FILENO)
close (slave_tty);
close (signal_pipe[0]);
signal_pipe[0] = -1;
break;
exit(0);
/* NOTREACHED */
default:
setpgid(rc_logger_pid, 0);
fd_stdout = dup(STDOUT_FILENO);
fd_stderr = dup(STDERR_FILENO);
if ((s = fcntl(fd_stdout, F_GETFD, 0)) == 0)
fcntl(fd_stdout, F_SETFD, s | FD_CLOEXEC);
if ((s = fcntl(fd_stderr, F_GETFD, 0)) == 0)
fcntl(fd_stderr, F_SETFD, s | FD_CLOEXEC);
dup2(slave_tty, STDOUT_FILENO);
dup2(slave_tty, STDERR_FILENO);
if (slave_tty != STDIN_FILENO &&
slave_tty != STDOUT_FILENO &&
slave_tty != STDERR_FILENO)
close(slave_tty);
close(signal_pipe[0]);
signal_pipe[0] = -1;
break;
}
}

View File

@@ -30,13 +30,13 @@
*/
#include <sys/types.h>
#include <sys/utsname.h>
#ifdef __linux__
#include <sys/sysinfo.h>
#include <regex.h>
#endif
#include <sys/utsname.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
@@ -47,7 +47,6 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
#define PROFILE_ENV SYSCONFDIR "/profile.env"
#define SYS_WHITELIST RC_LIBDIR "/conf.d/env_whitelist"
@@ -57,314 +56,253 @@
#define PATH_PREFIX RC_LIBDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"
static char **rc_conf = NULL;
static RC_STRINGLIST *rc_conf = NULL;
static void _free_rc_conf (void)
extern char** environ;
static void _free_rc_conf(void)
{
rc_strlist_free (rc_conf);
rc_stringlist_free(rc_conf);
}
char *rc_conf_value (const char *setting)
char *rc_conf_value(const char *setting)
{
if (! rc_conf) {
char *line;
int i;
RC_STRINGLIST *old;
RC_STRING *s;
char *p;
rc_conf = rc_config_load (RC_CONF);
atexit (_free_rc_conf);
if (! rc_conf) {
rc_conf = rc_config_load(RC_CONF);
atexit(_free_rc_conf);
/* Support old configs */
if (exists (RC_CONF_OLD)) {
char **old = rc_config_load (RC_CONF_OLD);
rc_strlist_join (&rc_conf, old);
rc_strlist_free (old);
if (exists(RC_CONF_OLD)) {
old = rc_config_load(RC_CONF_OLD);
if (old) {
TAILQ_CONCAT(rc_conf, old);
free(old);
}
}
/* Convert old uppercase to lowercase */
STRLIST_FOREACH (rc_conf, line, i) {
char *p = line;
TAILQ_FOREACH(s, rc_conf, entries) {
p = s->value;
while (p && *p && *p != '=') {
if (isupper ((int) *p))
*p = tolower ((int) *p);
if (isupper((int) *p))
*p = tolower((int) *p);
p++;
}
}
}
return (rc_config_value ((const char *const *)rc_conf, setting));
return rc_config_value(rc_conf, setting);
}
bool rc_conf_yesno (const char *setting)
bool rc_conf_yesno(const char *setting)
{
return (rc_yesno (rc_conf_value (setting)));
return rc_yesno(rc_conf_value (setting));
}
char **env_filter (void)
static const char *const env_whitelist[] = {
"PATH", "SHELL", "USER", "HOME", "TERM",
"LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
"LC_MONETARY", "LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS",
"LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION", "LC_ALL",
"INIT_HALT", "INIT_VERSION", "RUNLEVEL", "PREVLEVEL", "CONSOLE",
"IN_HOTPLUG", "IN_BACKGROUND", "RC_INTERFACE_KEEP_CONFIG",
NULL
};
void env_filter(void)
{
char **env = NULL;
char **whitelist = NULL;
char *env_name = NULL;
char **profile = NULL;
int count = 0;
bool got_path = false;
char *env_var;
size_t env_len;
char *token;
char *sep;
RC_STRINGLIST *env_allow;
RC_STRINGLIST *profile = NULL;
RC_STRINGLIST *env_list;
RC_STRING *env;
RC_STRING *s;
char *env_name;
char *e;
char *p;
size_t pplen = strlen (PATH_PREFIX);
/* Init a system whitelist, start with shell vars we need */
rc_strlist_add (&whitelist, "PATH");
rc_strlist_add (&whitelist, "SHELL");
rc_strlist_add (&whitelist, "USER");
rc_strlist_add (&whitelist, "HOME");
rc_strlist_add (&whitelist, "TERM");
/* Add Language vars */
rc_strlist_add (&whitelist, "LANG");
rc_strlist_add (&whitelist, "LC_CTYPE");
rc_strlist_add (&whitelist, "LC_NUMERIC");
rc_strlist_add (&whitelist, "LC_TIME");
rc_strlist_add (&whitelist, "LC_COLLATE");
rc_strlist_add (&whitelist, "LC_MONETARY");
rc_strlist_add (&whitelist, "LC_MESSAGES");
rc_strlist_add (&whitelist, "LC_PAPER");
rc_strlist_add (&whitelist, "LC_NAME");
rc_strlist_add (&whitelist, "LC_ADDRESS");
rc_strlist_add (&whitelist, "LC_TELEPHONE");
rc_strlist_add (&whitelist, "LC_MEASUREMENT");
rc_strlist_add (&whitelist, "LC_IDENTIFICATION");
rc_strlist_add (&whitelist, "LC_ALL");
/* Allow rc to override library path */
rc_strlist_add (&whitelist, "LD_LIBRARY_PATH");
/* We need to know sysvinit stuff - we emulate this for BSD too */
rc_strlist_add (&whitelist, "INIT_HALT");
rc_strlist_add (&whitelist, "INIT_VERSION");
rc_strlist_add (&whitelist, "RUNLEVEL");
rc_strlist_add (&whitelist, "PREVLEVEL");
rc_strlist_add (&whitelist, "CONSOLE");
/* Hotplug and daemon vars */
rc_strlist_add (&whitelist, "IN_HOTPLUG");
rc_strlist_add (&whitelist, "IN_BACKGROUND");
rc_strlist_add (&whitelist, "RC_INTERFACE_KEEP_CONFIG");
char *token;
size_t i = 0;
/* Add the user defined list of vars */
e = env_name = xstrdup (rc_conf_value ("rc_env_allow"));
while ((token = strsep (&e, " "))) {
env_allow = rc_stringlist_new();
e = env_name = xstrdup(rc_conf_value ("rc_env_allow"));
while ((token = strsep(&e, " "))) {
if (token[0] == '*') {
free (env_name);
return (NULL);
free(env_name);
rc_stringlist_free(env_allow);
return;
}
rc_strlist_add (&whitelist, token);
rc_stringlist_add(env_allow, token);
}
free (env_name);
free(env_name);
if (exists (PROFILE_ENV))
profile = rc_config_load (PROFILE_ENV);
if (exists(PROFILE_ENV))
profile = rc_config_load(PROFILE_ENV);
STRLIST_FOREACH (whitelist, env_name, count) {
char *space = strchr (env_name, ' ');
if (space)
*space = 0;
/* Copy the env and work from this so we can remove safely */
env_list = rc_stringlist_new();
while (environ[i])
rc_stringlist_add(env_list, environ[i++]);
env_var = getenv (env_name);
if (! env_var && profile) {
env_len = strlen (env_name) + strlen ("export ") + 1;
p = xmalloc (sizeof (char) * env_len);
snprintf (p, env_len, "export %s", env_name);
env_var = rc_config_value ((const char *const *) profile, p);
free (p);
TAILQ_FOREACH(env, env_list, entries) {
/* Check the whitelist */
i = 0;
while (env_whitelist[i]) {
if (strcmp(env_whitelist[i++], env->value))
break;
}
if (! env_var)
if (env_whitelist[i])
continue;
/* Ensure our PATH is prefixed with the system locations first
for a little extra security */
if (strcmp (env_name, "PATH") == 0 &&
strncmp (PATH_PREFIX, env_var, pplen) != 0)
{
got_path = true;
env_len = strlen (env_name) + strlen (env_var) + pplen + 3;
e = p = xmalloc (sizeof (char) * env_len);
p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX);
/* Check our user defined list */
TAILQ_FOREACH(s, env_allow, entries)
if (strcmp(s->value, env->value) == 0)
break;
if (s)
continue;
/* Now go through the env var and only add bits not in our PREFIX */
sep = env_var;
while ((token = strsep (&sep, ":"))) {
char *np = xstrdup (PATH_PREFIX);
char *npp = np;
char *tok = NULL;
while ((tok = strsep (&npp, ":")))
if (strcmp (tok, token) == 0)
break;
if (! tok)
p += snprintf (p, env_len - (p - e), ":%s", token);
free (np);
}
*p++ = 0;
} else {
env_len = strlen (env_name) + strlen (env_var) + 2;
e = xmalloc (sizeof (char) * env_len);
snprintf (e, env_len, "%s=%s", env_name, env_var);
}
/* Now check our profile */
rc_strlist_add (&env, e);
free (e);
/* OK, not allowed! */
e = strchr(env->value, '=');
*e = '\0';
unsetenv(env->value);
}
/* We filtered the env but didn't get a PATH? Very odd.
However, we do need a path, so use a default. */
if (! got_path) {
env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 1;
e = xmalloc (sizeof (char) * env_len);
snprintf (e, env_len, "PATH=%s", PATH_PREFIX);
rc_strlist_add (&env, e);
free (e);
}
rc_strlist_free (whitelist);
rc_strlist_free (profile);
return (env);
rc_stringlist_free(env_list);
rc_stringlist_free(env_allow);
rc_stringlist_free(profile);
}
char **env_config (void)
void env_config(void)
{
char **env = NULL;
char *line;
size_t pplen = strlen(PATH_PREFIX);
char *path;
char *p;
char *e;
size_t l;
const char *sys = rc_sys ();
struct utsname uts;
FILE *fp;
char *token;
char *np;
char *npp;
char *tok;
const char *sys = rc_sys();
char buffer[PATH_MAX];
char *runlevel = rc_runlevel_get ();
/* One char less to drop the trailing / */
l = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR) + 1;
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_LIBDIR=" RC_LIBDIR);
rc_strlist_add (&env, line);
free (line);
/* Ensure our PATH is prefixed with the system locations first
for a little extra security */
path = getenv("PATH");
if (! path)
setenv("PATH", PATH_PREFIX, 1);
else if (strncmp (PATH_PREFIX, path, pplen) != 0) {
l = strlen(path) + pplen + 3;
e = p = xmalloc(sizeof(char) * l);
p += snprintf(p, l, "%s", PATH_PREFIX);
/* One char less to drop the trailing / */
l = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR) + 1;
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_SVCDIR=" RC_SVCDIR);
rc_strlist_add (&env, line);
free (line);
/* Now go through the env var and only add bits not in our PREFIX */
while ((token = strsep(&path, ":"))) {
np = npp = xstrdup(PATH_PREFIX);
while ((tok = strsep(&npp, ":")))
if (strcmp(tok, token) == 0)
break;
if (! tok)
p += snprintf(p, l - (p - e), ":%s", token);
free (np);
}
*p++ = '\0';
unsetenv("PATH");
setenv("PATH", e, 1);
free(e);
}
rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
setenv("RC_LIBDIR", RC_LIBDIR, 1);
setenv("RC_SVCDIR", RC_SVCDIR, 1);
setenv("RC_BOOTLEVEL", RC_LEVEL_BOOT, 1);
e = rc_runlevel_get();
setenv("RC_RUNLEVEL", e, 1);
free(e);
l = strlen ("RC_SOFTLEVEL=") + strlen (runlevel) + 1;
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_SOFTLEVEL=%s", runlevel);
rc_strlist_add (&env, line);
free (line);
if ((fp = fopen (RC_KSOFTLEVEL, "r"))) {
memset (buffer, 0, sizeof (buffer));
if (fgets (buffer, sizeof (buffer), fp)) {
if ((fp = fopen(RC_KSOFTLEVEL, "r"))) {
memset(buffer, 0, sizeof (buffer));
if (fgets(buffer, sizeof (buffer), fp)) {
l = strlen (buffer) - 1;
if (buffer[l] == '\n')
buffer[l] = 0;
l += strlen ("RC_DEFAULTLEVEL=") + 2;
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_DEFAULTLEVEL=%s", buffer);
rc_strlist_add (&env, line);
free (line);
setenv("RC_DEFAULTLEVEL", buffer, 1);
}
fclose (fp);
fclose(fp);
} else
rc_strlist_add (&env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1);
if (sys) {
l = strlen ("RC_SYS=") + strlen (sys) + 2;
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_SYS=%s", sys);
rc_strlist_add (&env, line);
free (line);
}
if (sys)
setenv("RC_SYS", sys, 1);
/* Some scripts may need to take a different code path if Linux/FreeBSD, etc
To save on calling uname, we store it in an environment variable */
if (uname (&uts) == 0) {
l = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_UNAME=%s", uts.sysname);
rc_strlist_add (&env, line);
free (line);
}
if (uname(&uts) == 0)
setenv("RC_UNAME", uts.sysname, 1);
/* Be quiet or verbose as necessary */
if (rc_conf_yesno ("rc_quiet"))
rc_strlist_add (&env, "EINFO_QUIET=YES");
if (rc_conf_yesno ("rc_verbose"))
rc_strlist_add (&env, "EINFO_VERBOSE=YES");
if (rc_conf_yesno("rc_quiet"))
setenv("EINFO_QUIET", "YES", 1);
if (rc_conf_yesno("rc_verbose"))
setenv("EINFO_VERBOSE", "YES", 1);
errno = 0;
if ((! rc_conf_yesno ("rc_color") && errno == 0) ||
rc_conf_yesno ("rc_nocolor"))
rc_strlist_add (&env, "EINFO_COLOR=NO");
free (runlevel);
return (env);
if ((! rc_conf_yesno("rc_color") && errno == 0) ||
rc_conf_yesno("rc_nocolor"))
setenv("EINFO_COLOR", "NO", 1);
}
bool service_plugable (const char *service)
bool service_plugable(const char *service)
{
char *list;
char *p;
char *star;
char *token;
bool allow = true;
char *match = rc_conf_value ("rc_plug_services");
char *match = rc_conf_value("rc_plug_services");
bool truefalse;
if (! match)
return (true);
return true;
list = xstrdup (match);
list = xstrdup(match);
p = list;
while ((token = strsep (&p, " "))) {
bool truefalse = true;
while ((token = strsep(&p, " "))) {
if (token[0] == '!') {
truefalse = false;
token++;
}
} else
truefalse = true;
star = strchr (token, '*');
star = strchr(token, '*');
if (star) {
if (strncmp (service, token, (size_t) (star - token))
== 0)
if (strncmp(service, token, (size_t)(star - token)) == 0)
{
allow = truefalse;
break;
}
} else {
if (strcmp (service, token) == 0) {
if (strcmp(service, token) == 0) {
allow = truefalse;
break;
}
}
}
free (list);
return (allow);
free(list);
return allow;
}
int signal_setup (int sig, void (*handler)(int))
int signal_setup(int sig, void (*handler)(int))
{
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sigemptyset (&sa.sa_mask);
memset(&sa, 0, sizeof (sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
return (sigaction (sig, &sa, NULL));
return sigaction(sig, &sa, NULL);
}

View File

@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
@@ -46,7 +47,6 @@
#include "rc.h"
#include "rc-misc.h"
#include "rc-plugin.h"
#include "strlist.h"
#define RC_PLUGIN_HOOK "rc_plugin_hook"
@@ -56,129 +56,117 @@ typedef struct plugin
{
char *name;
void *handle;
int (*hook) (rc_hook_t, const char *);
struct plugin *next;
} plugin_t;
static plugin_t *plugins = NULL;
int (*hook)(RC_HOOK, const char *);
STAILQ_ENTRY(plugin) entries;
} PLUGIN;
STAILQ_HEAD(, plugin) plugins;
#ifndef __FreeBSD__
dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
dlfunc_t dlfunc(void * __restrict handle, const char * __restrict symbol)
{
union {
void *d;
dlfunc_t f;
} rv;
rv.d = dlsym (handle, symbol);
return (rv.f);
rv.d = dlsym(handle, symbol);
return rv.f;
}
#endif
void rc_plugin_load (void)
void rc_plugin_load(void)
{
DIR *dp;
struct dirent *d;
plugin_t *plugin = plugins;
PLUGIN *plugin;
char *p;
void *h;
int (*fptr) (rc_hook_t, const char *);
int (*fptr)(RC_HOOK, const char *);
/* Don't load plugins if we're in one */
if (rc_in_plugin)
return;
/* Ensure some sanity here */
rc_plugin_unload ();
STAILQ_INIT(&plugins);
if (! (dp = opendir (RC_PLUGINDIR)))
if (! (dp = opendir(RC_PLUGINDIR)))
return;
while ((d = readdir (dp))) {
while ((d = readdir(dp))) {
if (d->d_name[0] == '.')
continue;
p = rc_strcatpaths (RC_PLUGINDIR, d->d_name, NULL);
h = dlopen (p, RTLD_LAZY);
free (p);
p = rc_strcatpaths(RC_PLUGINDIR, d->d_name, NULL);
h = dlopen(p, RTLD_LAZY);
free(p);
if (! h) {
eerror ("dlopen: %s", dlerror ());
eerror("dlopen: %s", dlerror());
continue;
}
fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, RC_PLUGIN_HOOK);
fptr = (int (*)(RC_HOOK, const char*))dlfunc(h, RC_PLUGIN_HOOK);
if (! fptr) {
eerror ("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK);
dlclose (h);
eerror("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK);
dlclose(h);
} else {
if (plugin) {
plugin->next = xmalloc (sizeof (*plugin->next));
plugin = plugin->next;
} else
plugin = plugins = xmalloc (sizeof (*plugin));
plugin->name = xstrdup (d->d_name);
plugin = xmalloc(sizeof(*plugin));
plugin->name = xstrdup(d->d_name);
plugin->handle = h;
plugin->hook = fptr;
plugin->next = NULL;
STAILQ_INSERT_TAIL(&plugins, plugin, entries);
}
}
closedir (dp);
closedir(dp);
}
int rc_waitpid (pid_t pid)
int rc_waitpid(pid_t pid)
{
int status = 0;
pid_t savedpid = pid;
int retval = -1;
errno = 0;
while ((pid = waitpid (savedpid, &status, 0)) > 0) {
while ((pid = waitpid(savedpid, &status, 0)) > 0) {
if (pid == savedpid)
retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
retval = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
}
return (retval);
return retval;
}
void rc_plugin_run (rc_hook_t hook, const char *value)
void rc_plugin_run(RC_HOOK hook, const char *value)
{
plugin_t *plugin = plugins;
PLUGIN *plugin;
struct sigaction sa;
sigset_t empty;
sigset_t full;
sigset_t old;
int i;
int flags;
int pfd[2];
pid_t pid;
char *buffer;
char *token;
char *p;
ssize_t nr;
int retval;
/* Don't run plugins if we're in one */
if (rc_in_plugin)
return;
/* We need to block signals until we have forked */
memset (&sa, 0, sizeof (sa));
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigemptyset (&sa.sa_mask);
sigemptyset (&empty);
sigfillset (&full);
while (plugin) {
int i;
int flags;
int pfd[2];
pid_t pid;
char *buffer;
char *token;
char *p;
ssize_t nr;
if (! plugin->hook) {
plugin = plugin->next;
continue;
}
sigemptyset(&sa.sa_mask);
sigemptyset(&empty);
sigfillset(&full);
STAILQ_FOREACH(plugin, &plugins, entries) {
/* We create a pipe so that plugins can affect our environment
* vars, which in turn influence our scripts. */
if (pipe (pfd) == -1) {
eerror ("pipe: %s", strerror (errno));
if (pipe(pfd) == -1) {
eerror("pipe: %s", strerror(errno));
return;
}
@@ -188,81 +176,78 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
for (i = 0; i < 2; i++)
if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
eerror ("fcntl: %s", strerror (errno));
eerror("fcntl: %s", strerror(errno));
sigprocmask (SIG_SETMASK, &full, &old);
sigprocmask(SIG_SETMASK, &full, &old);
/* We run the plugin in a new process so we never crash
* or otherwise affected by it */
if ((pid = fork ()) == -1) {
eerror ("fork: %s", strerror (errno));
if ((pid = fork()) == -1) {
eerror("fork: %s", strerror(errno));
break;
}
if (pid == 0) {
int retval;
/* Restore default handlers */
sigaction (SIGCHLD, &sa, NULL);
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGINT, &sa, NULL);
sigaction (SIGQUIT, &sa, NULL);
sigaction (SIGTERM, &sa, NULL);
sigaction (SIGUSR1, &sa, NULL);
sigaction (SIGWINCH, &sa, NULL);
sigprocmask (SIG_SETMASK, &old, NULL);
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGWINCH, &sa, NULL);
sigprocmask(SIG_SETMASK, &old, NULL);
rc_in_plugin = true;
close (pfd[0]);
rc_environ_fd = fdopen (pfd[1], "w");
retval = plugin->hook (hook, value);
fclose (rc_environ_fd);
close(pfd[0]);
rc_environ_fd = fdopen(pfd[1], "w");
retval = plugin->hook(hook, value);
fclose(rc_environ_fd);
rc_environ_fd = NULL;
/* Just in case the plugin sets this to false */
rc_in_plugin = true;
exit (retval);
exit(retval);
}
sigprocmask (SIG_SETMASK, &old, NULL);
close (pfd[1]);
buffer = xmalloc (sizeof (char) * BUFSIZ);
memset (buffer, 0, BUFSIZ);
sigprocmask(SIG_SETMASK, &old, NULL);
close(pfd[1]);
buffer = xmalloc(sizeof(char) * BUFSIZ);
memset(buffer, 0, BUFSIZ);
while ((nr = read (pfd[0], buffer, BUFSIZ)) > 0) {
while ((nr = read(pfd[0], buffer, BUFSIZ)) > 0) {
p = buffer;
while (*p && p - buffer < nr) {
token = strsep (&p, "=");
token = strsep(&p, "=");
if (token) {
unsetenv (token);
unsetenv(token);
if (*p) {
setenv (token, p, 1);
p += strlen (p) + 1;
setenv(token, p, 1);
p += strlen(p) + 1;
} else
p++;
}
}
}
free (buffer);
close (pfd[0]);
free(buffer);
close(pfd[0]);
rc_waitpid (pid);
plugin = plugin->next;
rc_waitpid(pid);
}
}
void rc_plugin_unload (void)
void rc_plugin_unload(void)
{
plugin_t *plugin = plugins;
plugin_t *next;
PLUGIN *plugin = STAILQ_FIRST(&plugins);
PLUGIN *next;
while (plugin) {
next = plugin->next;
dlclose (plugin->handle);
free (plugin->name);
free (plugin);
next = STAILQ_NEXT(plugin, entries);
dlclose(plugin->handle);
free(plugin->name);
free(plugin);
plugin = next;
}
plugins = NULL;
STAILQ_INIT(&plugins);
}

View File

@@ -36,10 +36,10 @@
* Mainly used in atexit code. */
extern bool rc_in_plugin;
int rc_waitpid (pid_t pid);
void rc_plugin_load ();
void rc_plugin_unload ();
void rc_plugin_run (rc_hook_t, const char *value);
int rc_waitpid(pid_t pid);
void rc_plugin_load(void);
void rc_plugin_unload(void);
void rc_plugin_run(RC_HOOK, const char *value);
/* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */
#ifndef __FreeBSD__
@@ -47,7 +47,7 @@ struct __dlfunc_arg {
int __dlfunc_dummy;
};
typedef void (*dlfunc_t) (struct __dlfunc_arg);
typedef void (*dlfunc_t)(struct __dlfunc_arg);
dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol);
#endif

View File

@@ -39,57 +39,56 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
extern const char *applet;
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
static void print_level (char *level)
static void print_level(char *level)
{
printf ("Runlevel: ");
if (isatty (fileno (stdout)))
printf ("%s%s%s\n",
ecolor (ECOLOR_HILITE),
level,
ecolor (ECOLOR_NORMAL));
if (isatty(fileno(stdout)))
printf("%s%s%s\n",
ecolor(ECOLOR_HILITE),
level,
ecolor(ECOLOR_NORMAL));
else
printf ("%s\n", level);
printf("%s\n", level);
}
static void print_service (char *service)
static void print_service(char *service)
{
char status[10];
int cols = printf (" %s", service);
const char *c = ecolor (ECOLOR_GOOD);
rc_service_state_t state = rc_service_state (service);
einfo_color_t color = ECOLOR_BAD;
int cols = printf(" %s", service);
const char *c = ecolor(ECOLOR_GOOD);
RC_SERVICE state = rc_service_state(service);
ECOLOR color = ECOLOR_BAD;
if (state & RC_SERVICE_STOPPING)
snprintf (status, sizeof (status), "stopping ");
snprintf(status, sizeof(status), "stopping ");
else if (state & RC_SERVICE_STARTING) {
snprintf (status, sizeof (status), "starting ");
snprintf(status, sizeof(status), "starting ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_INACTIVE) {
snprintf (status, sizeof (status), "inactive ");
snprintf(status, sizeof(status), "inactive ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_STARTED) {
if (geteuid () == 0 && rc_service_daemons_crashed (service))
snprintf (status, sizeof (status), " crashed ");
if (rc_service_daemons_crashed(service))
snprintf(status, sizeof(status), " crashed ");
else {
snprintf (status, sizeof (status), " started ");
snprintf(status, sizeof(status), " started ");
color = ECOLOR_GOOD;
}
} else if (state & RC_SERVICE_SCHEDULED) {
snprintf (status, sizeof (status), "scheduled");
snprintf(status, sizeof(status), "scheduled");
color = ECOLOR_WARN;
} else
snprintf (status, sizeof (status), " stopped ");
snprintf(status, sizeof(status), " stopped ");
errno = 0;
if (c && *c && isatty (fileno (stdout)))
printf ("\n");
ebracket (cols, color, status);
if (c && *c && isatty(fileno(stdout)))
printf("\n");
ebracket(cols, color, status);
}
#include "_usage.h"
@@ -115,99 +114,100 @@ static const char * const longopts_help[] = {
int rc_status (int argc, char **argv)
{
rc_depinfo_t *deptree = NULL;
char **levels = NULL;
char **services = NULL;
char **ordered = NULL;
char *level;
char *service;
RC_DEPTREE *deptree = NULL;
RC_STRINGLIST *levels = NULL;
RC_STRINGLIST *services;
RC_STRINGLIST *types = NULL;
RC_STRINGLIST *ordered;
RC_STRING *s;
RC_STRING *l;
char *p;
int opt;
int i;
int j;
int depopts = RC_DEP_STRICT | RC_DEP_START | RC_DEP_TRACE;
while ((opt = getopt_long (argc, argv, getoptstring, longopts,
(int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1)
switch (opt) {
case 'a':
levels = rc_runlevel_list ();
break;
case 'l':
levels = rc_runlevel_list ();
STRLIST_FOREACH (levels, level, i)
printf ("%s\n", level);
rc_strlist_free (levels);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 'r':
level = rc_runlevel_get ();
printf ("%s\n", level);
free (level);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 's':
services = rc_services_in_runlevel (NULL);
STRLIST_FOREACH (services, service, i)
print_service (service);
rc_strlist_free (services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 'u':
services = rc_services_in_runlevel (NULL);
levels = rc_runlevel_list ();
STRLIST_FOREACH (services, service, i) {
bool found = false;
STRLIST_FOREACH (levels, level, j)
if (rc_service_in_runlevel (service, level)) {
found = true;
break;
}
if (! found)
print_service (service);
}
rc_strlist_free (levels);
rc_strlist_free (services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 'a':
levels = rc_runlevel_list();
break;
case 'l':
levels = rc_runlevel_list();
TAILQ_FOREACH (l, levels, entries)
printf("%s\n", l->value);
rc_stringlist_free(levels);
exit(EXIT_SUCCESS);
/* NOTREACHED */
case 'r':
p = rc_runlevel_get ();
printf("%s\n", p);
free(p);
exit(EXIT_SUCCESS);
/* NOTREACHED */
case 's':
services = rc_services_in_runlevel(NULL);
TAILQ_FOREACH(s, services, entries)
print_service(s->value);
rc_stringlist_free(services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 'u':
services = rc_services_in_runlevel(NULL);
levels = rc_runlevel_list();
TAILQ_FOREACH(s, services, entries) {
TAILQ_FOREACH(l, levels, entries)
if (rc_service_in_runlevel(s->value, l->value))
break;
if (! l)
print_service(s->value);
}
rc_stringlist_free(levels);
rc_stringlist_free(services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
if (! levels)
levels = rc_stringlist_new();
while (optind < argc)
rc_strlist_add (&levels, argv[optind++]);
if (! levels) {
level = rc_runlevel_get ();
rc_strlist_add (&levels, level);
free (level);
rc_stringlist_add(levels, argv[optind++]);
if (! TAILQ_FIRST(levels)) {
p = rc_runlevel_get();
rc_stringlist_add(levels, p);
free(p);
}
/* Output the services in the order in which they would start */
if (geteuid () == 0)
deptree = _rc_deptree_load (NULL);
else
deptree = rc_deptree_load ();
deptree = _rc_deptree_load(NULL);
STRLIST_FOREACH (levels, level, i) {
print_level (level);
services = rc_services_in_runlevel (level);
TAILQ_FOREACH(l, levels, entries) {
print_level(l->value);
services = rc_services_in_runlevel(l->value);
if (deptree) {
ordered = rc_deptree_depends (deptree, types_nua,
(const char **) services,
level, depopts);
rc_strlist_free (services);
if (! types) {
types = rc_stringlist_new();
rc_stringlist_add(types, "ineed");
rc_stringlist_add(types, "iuse");
rc_stringlist_add(types, "iafter");
}
ordered = rc_deptree_depends(deptree, types, services,
l->value, depopts);
rc_stringlist_free(services);
services = ordered;
ordered = NULL;
}
STRLIST_FOREACH (services, service, j)
if (rc_service_in_runlevel (service, level))
print_service (service);
rc_strlist_free (services);
TAILQ_FOREACH(s, services, entries)
if (rc_service_in_runlevel(s->value, l->value))
print_service(s->value);
rc_stringlist_free(services);
}
rc_strlist_free (levels);
rc_deptree_free (deptree);
rc_stringlist_free(types);
rc_stringlist_free(levels);
rc_deptree_free(deptree);
exit (EXIT_SUCCESS);
exit(EXIT_SUCCESS);
/* NOTREACHED */
}

View File

@@ -42,7 +42,6 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
extern const char *applet;
@@ -68,7 +67,7 @@ static int add (const char *runlevel, const char *service)
eerror ("%s: failed to add service `%s' to runlevel `%s': %s",
applet, service, runlevel, strerror (errno));
return (retval);
return retval;
}
static int delete (const char *runlevel, const char *service)
@@ -88,44 +87,47 @@ static int delete (const char *runlevel, const char *service)
eerror ("%s: failed to remove service `%s' from runlevel `%s': %s",
applet, service, runlevel, strerror (errno));
return (retval);
return retval;
}
static void show (char **runlevels, bool verbose)
static void show (RC_STRINGLIST *runlevels, bool verbose)
{
char *service;
char **services = rc_services_in_runlevel (NULL);
char *runlevel;
int i;
int j;
RC_STRINGLIST *services = rc_services_in_runlevel(NULL);
RC_STRING *service;
RC_STRING *runlevel;
RC_STRINGLIST *in;
bool inone;
char buffer[PATH_MAX];
size_t l;
STRLIST_FOREACH (services, service, i) {
char **in = NULL;
bool inone = false;
TAILQ_FOREACH(service, services, entries) {
in = rc_stringlist_new();
inone = false;
STRLIST_FOREACH (runlevels, runlevel, j) {
if (rc_service_in_runlevel (service, runlevel)) {
rc_strlist_add (&in, runlevel);
TAILQ_FOREACH(runlevel, runlevels, entries) {
if (rc_service_in_runlevel(service->value,
runlevel->value))
{
rc_stringlist_add(in, runlevel->value);
inone = true;
} else {
char buffer[PATH_MAX];
memset (buffer, ' ', strlen (runlevel));
buffer[strlen (runlevel)] = 0;
rc_strlist_add (&in, buffer);
l = strlen(runlevel->value);
memset (buffer, ' ', l);
buffer[l] = 0;
rc_stringlist_add (in, buffer);
}
}
if (! inone && ! verbose)
continue;
printf (" %20s |", service);
STRLIST_FOREACH (in, runlevel, j)
printf (" %s", runlevel);
printf ("\n");
rc_strlist_free (in);
if (inone || verbose) {
printf(" %20s |", service->value);
TAILQ_FOREACH(runlevel, in, entries)
printf (" %s", runlevel->value);
printf ("\n");
}
rc_stringlist_free(in);
}
rc_strlist_free (services);
rc_stringlist_free (services);
}
#include "_usage.h"
@@ -146,111 +148,124 @@ static const char * const longopts_help[] = {
#define DODELETE (1 << 2)
#define DOSHOW (1 << 3)
int rc_update (int argc, char **argv)
int rc_update(int argc, char **argv)
{
int i;
RC_STRINGLIST *runlevels;
RC_STRING *runlevel;
char *service = NULL;
char **runlevels = NULL;
char *runlevel;
char *p;
int action = 0;
bool verbose = false;
int opt;
int retval = EXIT_FAILURE;
int num_updated = 0;
int (*actfunc)(const char *, const char *);
int ret;
while ((opt = getopt_long (argc, argv, getoptstring,
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
verbose = rc_yesno (getenv ("EINFO_VERBOSE"));
verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
if ((action & DOSHOW && action != DOSHOW) ||
(action & DOADD && action != DOADD) ||
(action & DODELETE && action != DODELETE))
eerrorx ("%s: cannot mix commands", applet);
eerrorx("%s: cannot mix commands", applet);
/* We need to be backwards compatible */
if (optind < argc) {
if (strcmp (argv[optind], "add") == 0)
if (strcmp(argv[optind], "add") == 0)
action = DOADD;
else if (strcmp (argv[optind], "delete") == 0 ||
strcmp (argv[optind], "del") == 0)
else if (strcmp(argv[optind], "delete") == 0 ||
strcmp(argv[optind], "del") == 0)
action = DODELETE;
else if (strcmp (argv[optind], "show") == 0)
else if (strcmp(argv[optind], "show") == 0)
action = DOSHOW;
if (action)
optind++;
else
eerrorx ("%s: invalid command `%s'", applet, argv[optind]);
eerrorx("%s: invalid command `%s'", applet, argv[optind]);
}
if (! action)
action = DOSHOW;
runlevels = rc_stringlist_new();
if (optind >= argc) {
if (! action & DOSHOW)
eerrorx ("%s: no service specified", applet);
eerrorx("%s: no service specified", applet);
} else {
service = argv[optind];
optind++;
while (optind < argc)
if (rc_runlevel_exists (argv[optind]))
rc_strlist_add (&runlevels, argv[optind++]);
if (rc_runlevel_exists(argv[optind]))
rc_stringlist_add(runlevels, argv[optind++]);
else {
rc_strlist_free (runlevels);
eerrorx ("%s: `%s' is not a valid runlevel", applet, argv[optind]);
rc_stringlist_free(runlevels);
eerrorx ("%s: `%s' is not a valid runlevel",
applet, argv[optind]);
}
}
retval = EXIT_SUCCESS;
if (action & DOSHOW) {
if (service)
rc_strlist_add (&runlevels, service);
if (! runlevels)
runlevels = rc_runlevel_list ();
rc_stringlist_add(runlevels, service);
if (! TAILQ_FIRST(runlevels)) {
free(runlevels);
runlevels = rc_runlevel_list();
}
show (runlevels, verbose);
} else {
if (! service)
eerror ("%s: no service specified", applet);
else {
int num_updated = 0;
int (*actfunc)(const char *, const char *);
int ret;
if (action & DOADD) {
actfunc = add;
} else if (action & DODELETE) {
actfunc = delete;
} else
} else {
rc_stringlist_free(runlevels);
eerrorx ("%s: invalid action", applet);
}
if (! runlevels)
rc_strlist_add (&runlevels, rc_runlevel_get ());
if (! TAILQ_FIRST(runlevels)) {
p = rc_runlevel_get();
rc_stringlist_add(runlevels, p);
free(p);
}
if (! runlevels)
if (! TAILQ_FIRST(runlevels)) {
free(runlevels);
eerrorx ("%s: no runlevels found", applet);
}
STRLIST_FOREACH (runlevels, runlevel, i) {
if (! rc_runlevel_exists (runlevel)) {
eerror ("%s: runlevel `%s' does not exist", applet, runlevel);
TAILQ_FOREACH (runlevel, runlevels, entries) {
if (! rc_runlevel_exists(runlevel->value)) {
eerror ("%s: runlevel `%s' does not exist",
applet, runlevel->value);
continue;
}
ret = actfunc (runlevel, service);
ret = actfunc(runlevel->value, service);
if (ret < 0)
retval = EXIT_FAILURE;
num_updated += ret;
}
if (retval == EXIT_SUCCESS && num_updated == 0 && action & DODELETE)
ewarnx ("%s: service `%s' not found in any of the specified runlevels", applet, service);
if (retval == EXIT_SUCCESS &&
num_updated == 0 && action & DODELETE)
ewarnx("%s: service `%s' not found in any"
" of the specified runlevels",
applet, service);
}
}
rc_strlist_free (runlevels);
return (retval);
rc_stringlist_free(runlevels);
return retval;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff