2007-04-05 16:48:42 +05:30
|
|
|
/*
|
|
|
|
rc-update
|
|
|
|
Manage init scripts and runlevels
|
|
|
|
*/
|
|
|
|
|
2008-01-14 10:35:22 +05:30
|
|
|
/*
|
2008-01-15 15:20:14 +05:30
|
|
|
* Copyright 2007-2008 Roy Marples
|
2007-11-14 20:52:04 +05:30
|
|
|
* All rights reserved
|
|
|
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <errno.h>
|
2007-08-09 15:23:47 +05:30
|
|
|
#include <getopt.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <limits.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2007-08-04 20:35:12 +05:30
|
|
|
#include "builtins.h"
|
2008-01-07 19:50:13 +05:30
|
|
|
#include "einfo.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
#include "rc.h"
|
2008-01-07 19:50:13 +05:30
|
|
|
#include "rc-misc.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-02-12 01:44:09 +05:30
|
|
|
extern const char *applet;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-09-25 22:33:19 +05:30
|
|
|
/* Return the number of changes made:
|
|
|
|
* -1 = no changes (error)
|
|
|
|
* 0 = no changes (nothing to do)
|
|
|
|
* 1+ = number of runlevels updated
|
|
|
|
*/
|
2007-12-15 01:39:53 +05:30
|
|
|
static int add (const char *runlevel, const char *service)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-12-15 01:39:53 +05:30
|
|
|
int retval = -1;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-09-25 23:00:07 +05:30
|
|
|
if (! rc_service_exists (service))
|
2007-08-09 15:23:47 +05:30
|
|
|
eerror ("%s: service `%s' does not exist", applet, service);
|
2007-09-25 23:00:07 +05:30
|
|
|
else if (rc_service_in_runlevel (service, runlevel)) {
|
2007-08-09 15:23:47 +05:30
|
|
|
ewarn ("%s: %s already installed in runlevel `%s'; skipping",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, service, runlevel);
|
2007-09-25 22:33:19 +05:30
|
|
|
retval = 0;
|
2007-09-25 23:00:07 +05:30
|
|
|
} else if (rc_service_add (runlevel, service)) {
|
2007-04-11 18:14:47 +05:30
|
|
|
einfo ("%s added to runlevel %s", service, runlevel);
|
2007-09-25 22:33:19 +05:30
|
|
|
retval = 1;
|
2007-08-09 04:05:32 +05:30
|
|
|
} else
|
2007-04-11 18:14:47 +05:30
|
|
|
eerror ("%s: failed to add service `%s' to runlevel `%s': %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, service, runlevel, strerror (errno));
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return retval;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2007-12-15 01:39:53 +05:30
|
|
|
static int delete (const char *runlevel, const char *service)
|
2007-08-09 04:05:32 +05:30
|
|
|
{
|
2007-12-15 01:39:53 +05:30
|
|
|
int retval = -1;
|
2007-08-09 04:05:32 +05:30
|
|
|
|
2007-12-14 17:54:16 +05:30
|
|
|
errno = 0;
|
|
|
|
if (rc_service_delete (runlevel, service)) {
|
|
|
|
einfo ("%s removed from runlevel %s", service, runlevel);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errno == ENOENT)
|
|
|
|
eerror ("%s: service `%s' is not in the runlevel `%s'",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, service, runlevel);
|
2008-01-14 10:35:22 +05:30
|
|
|
else
|
2007-12-14 17:54:16 +05:30
|
|
|
eerror ("%s: failed to remove service `%s' from runlevel `%s': %s",
|
2008-01-11 21:21:40 +05:30
|
|
|
applet, service, runlevel, strerror (errno));
|
2007-09-25 22:33:19 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return retval;
|
2007-08-09 04:05:32 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void show (RC_STRINGLIST *runlevels, bool verbose)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
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;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(service, services, entries) {
|
|
|
|
in = rc_stringlist_new();
|
|
|
|
inone = false;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(runlevel, runlevels, entries) {
|
|
|
|
if (rc_service_in_runlevel(service->value,
|
|
|
|
runlevel->value))
|
|
|
|
{
|
|
|
|
rc_stringlist_add(in, runlevel->value);
|
2007-08-09 15:23:47 +05:30
|
|
|
inone = true;
|
|
|
|
} else {
|
2008-03-16 22:30:56 +05:30
|
|
|
l = strlen(runlevel->value);
|
|
|
|
memset (buffer, ' ', l);
|
|
|
|
buffer[l] = 0;
|
|
|
|
rc_stringlist_add (in, buffer);
|
2007-08-09 15:23:47 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (inone || verbose) {
|
|
|
|
printf(" %20s |", service->value);
|
|
|
|
TAILQ_FOREACH(runlevel, in, entries)
|
|
|
|
printf (" %s", runlevel->value);
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
rc_stringlist_free(in);
|
2007-08-09 15:23:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free (services);
|
2007-08-09 15:23:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
#include "_usage.h"
|
2008-01-15 15:20:14 +05:30
|
|
|
#define usagestring "" \
|
2008-02-28 02:49:14 +05:30
|
|
|
"Usage: rc-update [options] add service <runlevel>\n" \
|
2008-01-15 15:20:14 +05:30
|
|
|
" rc-update [options] del service <runlevel>\n" \
|
|
|
|
" rc-update [options] show"
|
|
|
|
#define getoptstring getoptstring_COMMON
|
2008-02-02 01:24:46 +05:30
|
|
|
static const struct option longopts[] = {
|
2007-08-09 15:23:47 +05:30
|
|
|
longopts_COMMON
|
|
|
|
};
|
2007-09-25 21:51:38 +05:30
|
|
|
static const char * const longopts_help[] = {
|
|
|
|
longopts_help_COMMON
|
|
|
|
};
|
2007-08-09 15:23:47 +05:30
|
|
|
#include "_usage.c"
|
|
|
|
|
2007-12-18 23:31:05 +05:30
|
|
|
#define DOADD (1 << 1)
|
|
|
|
#define DODELETE (1 << 2)
|
|
|
|
#define DOSHOW (1 << 3)
|
2007-08-09 15:23:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
int rc_update(int argc, char **argv)
|
2007-08-09 15:23:47 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *runlevels;
|
|
|
|
RC_STRING *runlevel;
|
2007-08-09 15:23:47 +05:30
|
|
|
char *service = NULL;
|
2008-03-16 22:30:56 +05:30
|
|
|
char *p;
|
2007-08-09 15:23:47 +05:30
|
|
|
int action = 0;
|
|
|
|
bool verbose = false;
|
|
|
|
int opt;
|
|
|
|
int retval = EXIT_FAILURE;
|
2008-03-16 22:30:56 +05:30
|
|
|
int num_updated = 0;
|
|
|
|
int (*actfunc)(const char *, const char *);
|
|
|
|
int ret;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
while ((opt = getopt_long(argc, argv, getoptstring,
|
2008-01-11 21:21:40 +05:30
|
|
|
longopts, (int *) 0)) != -1)
|
2007-08-09 15:23:47 +05:30
|
|
|
switch (opt) {
|
2008-03-16 22:30:56 +05:30
|
|
|
case_RC_COMMON_GETOPT
|
2007-08-09 15:23:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
|
2007-09-26 04:47:25 +05:30
|
|
|
|
2007-08-09 15:23:47 +05:30
|
|
|
if ((action & DOSHOW && action != DOSHOW) ||
|
2008-01-11 21:21:40 +05:30
|
|
|
(action & DOADD && action != DOADD) ||
|
|
|
|
(action & DODELETE && action != DODELETE))
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("%s: cannot mix commands", applet);
|
2007-08-09 15:23:47 +05:30
|
|
|
|
|
|
|
/* We need to be backwards compatible */
|
2008-01-15 15:20:14 +05:30
|
|
|
if (optind < argc) {
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(argv[optind], "add") == 0)
|
2008-01-15 15:20:14 +05:30
|
|
|
action = DOADD;
|
2008-03-16 22:30:56 +05:30
|
|
|
else if (strcmp(argv[optind], "delete") == 0 ||
|
|
|
|
strcmp(argv[optind], "del") == 0)
|
2008-01-15 15:20:14 +05:30
|
|
|
action = DODELETE;
|
2008-03-16 22:30:56 +05:30
|
|
|
else if (strcmp(argv[optind], "show") == 0)
|
2008-01-15 15:20:14 +05:30
|
|
|
action = DOSHOW;
|
|
|
|
if (action)
|
|
|
|
optind++;
|
|
|
|
else
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("%s: invalid command `%s'", applet, argv[optind]);
|
2007-08-09 15:23:47 +05:30
|
|
|
}
|
2008-01-15 15:20:14 +05:30
|
|
|
if (! action)
|
|
|
|
action = DOSHOW;
|
2007-08-09 15:23:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
runlevels = rc_stringlist_new();
|
|
|
|
|
2007-08-09 15:23:47 +05:30
|
|
|
if (optind >= argc) {
|
|
|
|
if (! action & DOSHOW)
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("%s: no service specified", applet);
|
2007-08-09 15:23:47 +05:30
|
|
|
} else {
|
|
|
|
service = argv[optind];
|
|
|
|
optind++;
|
|
|
|
|
|
|
|
while (optind < argc)
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_runlevel_exists(argv[optind]))
|
|
|
|
rc_stringlist_add(runlevels, argv[optind++]);
|
2007-08-09 15:23:47 +05:30
|
|
|
else {
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(runlevels);
|
|
|
|
eerrorx ("%s: `%s' is not a valid runlevel",
|
|
|
|
applet, argv[optind]);
|
2007-08-09 15:23:47 +05:30
|
|
|
}
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-09-25 22:33:19 +05:30
|
|
|
retval = EXIT_SUCCESS;
|
2007-08-09 15:23:47 +05:30
|
|
|
if (action & DOSHOW) {
|
|
|
|
if (service)
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_add(runlevels, service);
|
|
|
|
if (! TAILQ_FIRST(runlevels)) {
|
|
|
|
free(runlevels);
|
|
|
|
runlevels = rc_runlevel_list();
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-08-09 15:23:47 +05:30
|
|
|
show (runlevels, verbose);
|
|
|
|
} else {
|
|
|
|
if (! service)
|
|
|
|
eerror ("%s: no service specified", applet);
|
|
|
|
else {
|
2007-12-08 17:40:45 +05:30
|
|
|
if (action & DOADD) {
|
2007-09-25 22:33:19 +05:30
|
|
|
actfunc = add;
|
2007-12-08 17:40:45 +05:30
|
|
|
} else if (action & DODELETE) {
|
2007-09-25 22:33:19 +05:30
|
|
|
actfunc = delete;
|
2008-03-16 22:30:56 +05:30
|
|
|
} else {
|
|
|
|
rc_stringlist_free(runlevels);
|
2007-09-25 22:33:19 +05:30
|
|
|
eerrorx ("%s: invalid action", applet);
|
2008-03-16 22:30:56 +05:30
|
|
|
}
|
2007-12-08 17:40:45 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! TAILQ_FIRST(runlevels)) {
|
|
|
|
p = rc_runlevel_get();
|
|
|
|
rc_stringlist_add(runlevels, p);
|
|
|
|
free(p);
|
|
|
|
}
|
2007-12-15 04:30:29 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! TAILQ_FIRST(runlevels)) {
|
|
|
|
free(runlevels);
|
2007-12-08 17:40:45 +05:30
|
|
|
eerrorx ("%s: no runlevels found", applet);
|
2008-03-16 22:30:56 +05:30
|
|
|
}
|
2007-12-08 17:40:45 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH (runlevel, runlevels, entries) {
|
|
|
|
if (! rc_runlevel_exists(runlevel->value)) {
|
|
|
|
eerror ("%s: runlevel `%s' does not exist",
|
|
|
|
applet, runlevel->value);
|
2007-12-14 17:54:16 +05:30
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
ret = actfunc(runlevel->value, service);
|
2007-09-25 22:33:19 +05:30
|
|
|
if (ret < 0)
|
|
|
|
retval = EXIT_FAILURE;
|
|
|
|
num_updated += ret;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2007-12-08 17:40:45 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (retval == EXIT_SUCCESS &&
|
|
|
|
num_updated == 0 && action & DODELETE)
|
|
|
|
ewarnx("%s: service `%s' not found in any"
|
|
|
|
" of the specified runlevels",
|
|
|
|
applet, service);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(runlevels);
|
|
|
|
return retval;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|