0 | 0 |
/*
|
1 | 1 |
* insserv(.c)
|
2 | 2 |
*
|
3 | |
* Copyright 2000-2004 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany,
|
|
3 |
* Copyright 2000-2005 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany,
|
4 | 4 |
* 2003 SuSE Linux AG, Germany.
|
5 | 5 |
* 2004 SuSE LINUX AG, Germany.
|
|
6 |
* 2005 SUSE LINUX Products GmbH
|
|
7 |
* Copyright 2005 Petter Reinholdtsen
|
6 | 8 |
*
|
7 | 9 |
* This program is free software; you can redistribute it and/or modify
|
8 | 10 |
* it under the terms of the GNU General Public License as published by
|
|
27 | 29 |
#include <getopt.h>
|
28 | 30 |
#include "listing.h"
|
29 | 31 |
|
|
32 |
static char *map_runlevel_to_location(const int runlevel);
|
|
33 |
static const int map_runlevel_to_lvl (const int runlevel) __attribute__ ((unused));
|
|
34 |
static const int map_runlevel_to_seek(const int runlevel) __attribute__ ((unused));
|
|
35 |
|
30 | 36 |
#ifndef INITDIR
|
31 | 37 |
# define INITDIR "/etc/init.d"
|
32 | 38 |
#endif
|
|
191 | 197 |
list_t req, rev;
|
192 | 198 |
} sort_t;
|
193 | 199 |
|
194 | |
typedef struct serv_struct {
|
|
200 |
struct serv_struct;
|
|
201 |
typedef struct serv_struct serv_t;
|
|
202 |
|
|
203 |
struct serv_struct {
|
195 | 204 |
list_t id;
|
196 | 205 |
sort_t sort;
|
197 | 206 |
unsigned int opts;
|
198 | 207 |
char order;
|
199 | 208 |
char * name;
|
|
209 |
serv_t * main;
|
200 | 210 |
unsigned int lvls;
|
201 | 211 |
#ifndef SUSE
|
202 | 212 |
unsigned int lvlk;
|
203 | 213 |
#endif
|
204 | |
} serv_t;
|
|
214 |
};
|
205 | 215 |
#define getserv(arg) list_entry((arg), struct serv_struct, id)
|
206 | 216 |
|
207 | 217 |
static list_t serv = { &(serv), &(serv) }, *serv_start = &(serv);
|
|
234 | 244 |
|
235 | 245 |
this->opts = 0;
|
236 | 246 |
this->name = xstrdup(serv);
|
|
247 |
this->main = (serv_t *)0;
|
237 | 248 |
this->order = 0;
|
238 | 249 |
this->lvls = 0;
|
239 | 250 |
#ifndef SUSE
|
|
620 | 631 |
fprintf(start, "INTERACTIVE =");
|
621 | 632 |
list_for_each(srv, serv_start) {
|
622 | 633 |
serv_t * cur = getserv(srv);
|
623 | |
serv_t * chk;
|
624 | 634 |
|
625 | 635 |
if (!cur || list_empty(&(cur->sort.req)))
|
626 | 636 |
continue;
|
|
633 | 643 |
if ((name = getscript(cur->name)) == 0)
|
634 | 644 |
name = cur->name;
|
635 | 645 |
|
636 | |
if ((chk = findserv(name)) && (cur != chk)) {
|
637 | |
cur->opts |= SERV_DUPLET; /* Duplet */
|
638 | |
continue;
|
639 | |
}
|
|
646 |
if (cur->opts & SERV_DUPLET)
|
|
647 |
continue; /* Duplet */
|
640 | 648 |
|
641 | 649 |
if (cur->opts & SERV_ACTIVE)
|
642 | 650 |
fprintf(out, " %s", name);
|
|
675 | 683 |
continue;
|
676 | 684 |
|
677 | 685 |
/*
|
678 | |
* Skip not existing services even if they do not exist
|
|
686 |
* Skip not existing services even if they are used
|
679 | 687 |
* otherwise the make call will skip all dependencies
|
680 | 688 |
*/
|
681 | |
if (!dep || (dep->opts & SERV_DUPLET))
|
682 | |
continue; /* Duplet */
|
|
689 |
if (!dep) continue;
|
|
690 |
|
|
691 |
if ((dep->opts & SERV_DUPLET) && dep->main)
|
|
692 |
dep = dep->main; /* Duplet */
|
683 | 693 |
|
684 | 694 |
if ((name = getscript(dep->name)) == NULL)
|
685 | 695 |
name = dep->name;
|
|
701 | 711 |
reverse(req->serv, cur->name);
|
702 | 712 |
|
703 | 713 |
/*
|
704 | |
* Skip not existing services even if they do not exist
|
|
714 |
* Skip not existing services even if they are used
|
705 | 715 |
* otherwise the make call will skip all dependencies
|
706 | 716 |
*/
|
707 | |
if (!dep || (dep->opts & SERV_DUPLET))
|
708 | |
continue; /* Duplet */
|
|
717 |
if (!dep) continue;
|
|
718 |
|
|
719 |
if ((dep->opts & SERV_DUPLET) && dep->main)
|
|
720 |
dep = dep->main; /* Duplet */
|
709 | 721 |
|
710 | 722 |
if ((name = getscript(req->serv)) == NULL)
|
711 | 723 |
name = req->serv;
|
|
762 | 774 |
pr++;
|
763 | 775 |
}
|
764 | 776 |
|
765 | |
if (!dep || (dep->opts & SERV_DUPLET))
|
766 | |
continue; /* Duplet */
|
|
777 |
if (!dep) continue;
|
|
778 |
|
|
779 |
if ((dep->opts & SERV_DUPLET) && dep->main)
|
|
780 |
dep = dep->main; /* Duplet */
|
767 | 781 |
|
768 | 782 |
if ((name = getscript(rev->serv)) == NULL)
|
769 | 783 |
name = rev->serv;
|
|
849 | 863 |
error("can not stat(%s): %s\n", rcpath, strerror(errno));
|
850 | 864 |
}
|
851 | 865 |
|
852 | |
if ((rcdir = opendir(rcpath)) == NULL)
|
853 | |
error("can not opendir(%s): %s\n", rcpath, strerror(errno));
|
|
866 |
if ((rcdir = opendir(rcpath)) == NULL) {
|
|
867 |
if (dryrun)
|
|
868 |
warn ("can not opendir(%s): %s\n", rcpath, strerror(errno));
|
|
869 |
else
|
|
870 |
error("can not opendir(%s): %s\n", rcpath, strerror(errno));
|
|
871 |
}
|
854 | 872 |
|
855 | 873 |
return rcdir;
|
856 | 874 |
}
|
|
919 | 937 |
#define default_stop script_inf.default_stop
|
920 | 938 |
#define description script_inf.description
|
921 | 939 |
|
|
940 |
info("Loading %s\n", path);
|
922 | 941 |
script = fopen(path, "r");
|
923 | 942 |
if (!script)
|
924 | 943 |
error("fopen(%s): %s\n", path, strerror(errno));
|
|
1038 | 1057 |
regfree(®.desc);
|
1039 | 1058 |
}
|
1040 | 1059 |
|
|
1060 |
static struct {
|
|
1061 |
char *location;
|
|
1062 |
const int lvl;
|
|
1063 |
const int seek;
|
|
1064 |
} runlevel_locations[] = {
|
|
1065 |
#ifdef SUSE /* SuSE's SystemV link scheme */
|
|
1066 |
{"rc0.d/", LVL_HALT, LVL_NORM},
|
|
1067 |
{"rc1.d/", LVL_ONE, LVL_NORM},
|
|
1068 |
{"rc2.d/", LVL_TWO, LVL_NORM},
|
|
1069 |
{"rc3.d/", LVL_THREE, LVL_NORM},
|
|
1070 |
{"rc4.d/", LVL_FOUR, LVL_NORM},
|
|
1071 |
{"rc5.d/", LVL_FIVE, LVL_NORM},
|
|
1072 |
{"rc6.d/", LVL_REBOOT, LVL_NORM},
|
|
1073 |
{"rcS.d/", LVL_SINGLE, LVL_NORM}, /* runlevel S */
|
|
1074 |
{"boot.d/", LVL_BOOT, LVL_BOOT}, /* runlevel B */
|
|
1075 |
#else /* not SUSE (actually, Debian) */
|
|
1076 |
{"../rc0.d/", LVL_HALT, LVL_NORM},
|
|
1077 |
{"../rc1.d/", LVL_SINGLE, LVL_NORM},
|
|
1078 |
{"../rc2.d/", LVL_TWO, LVL_NORM},
|
|
1079 |
{"../rc3.d/", LVL_THREE, LVL_NORM},
|
|
1080 |
{"../rc4.d/", LVL_FOUR, LVL_NORM},
|
|
1081 |
{"../rc5.d/", LVL_FIVE, LVL_NORM},
|
|
1082 |
{"../rc6.d/", LVL_REBOOT, LVL_NORM},
|
|
1083 |
{"../rcS.d/", LVL_BOOT, LVL_BOOT}, /* runlevel S */
|
|
1084 |
/* On e.g. Debian there exist no boot.d */
|
|
1085 |
#endif
|
|
1086 |
};
|
|
1087 |
|
|
1088 |
#define RUNLEVLES (sizeof(runlevel_locations)/sizeof(runlevel_locations[0]))
|
|
1089 |
|
|
1090 |
static char *map_runlevel_to_location(const int runlevel)
|
|
1091 |
{
|
|
1092 |
return runlevel_locations[runlevel].location;
|
|
1093 |
}
|
|
1094 |
|
|
1095 |
static const int map_runlevel_to_lvl(const int runlevel)
|
|
1096 |
{
|
|
1097 |
return runlevel_locations[runlevel].lvl;
|
|
1098 |
}
|
|
1099 |
|
|
1100 |
static const int map_runlevel_to_seek(const int runlevel)
|
|
1101 |
{
|
|
1102 |
return runlevel_locations[runlevel].seek;
|
|
1103 |
}
|
|
1104 |
|
1041 | 1105 |
/*
|
1042 | 1106 |
* Scan current service structure
|
1043 | 1107 |
*/
|
|
1046 | 1110 |
int runlevel;
|
1047 | 1111 |
|
1048 | 1112 |
pushd(path);
|
1049 | |
for (runlevel = 0; runlevel < 9; runlevel++) {
|
|
1113 |
for (runlevel = 0; runlevel < RUNLEVLES; runlevel++) {
|
1050 | 1114 |
char * rcd = NULL;
|
1051 | 1115 |
DIR * rcdir;
|
1052 | 1116 |
struct dirent *d;
|
1053 | 1117 |
char * token;
|
1054 | 1118 |
struct stat st_script;
|
1055 | 1119 |
|
1056 | |
switch (runlevel) {
|
1057 | |
case 0: rcd = "rc0.d/"; break;
|
1058 | |
case 1: rcd = "rc1.d/"; break;
|
1059 | |
case 2: rcd = "rc2.d/"; break;
|
1060 | |
case 3: rcd = "rc3.d/"; break;
|
1061 | |
case 4: rcd = "rc4.d/"; break;
|
1062 | |
case 5: rcd = "rc5.d/"; break;
|
1063 | |
case 6: rcd = "rc6.d/"; break;
|
1064 | |
case 7: rcd = "rcS.d/"; break; /* runlevel S */
|
1065 | |
case 8: rcd = "boot.d/"; break; /* runlevel B */
|
1066 | |
default:
|
1067 | |
error("Wrong runlevel %d\n", runlevel);
|
1068 | |
}
|
1069 | |
|
|
1120 |
rcd = map_runlevel_to_location(runlevel);
|
1070 | 1121 |
rcdir = openrcdir(rcd); /* Creates runlevel directory if necessary */
|
|
1122 |
if (rcdir == NULL)
|
|
1123 |
break;
|
1071 | 1124 |
pushd(rcd);
|
1072 | 1125 |
while ((d = readdir(rcdir)) != NULL) {
|
1073 | 1126 |
char * ptr = d->d_name;
|
|
1163 | 1216 |
regcompiler(®_conf, CONFLINE, REG_EXTENDED|REG_ICASE);
|
1164 | 1217 |
regcompiler(®_conf2, CONFLINE2, REG_EXTENDED|REG_ICASE);
|
1165 | 1218 |
|
|
1219 |
info("Loading %s\n", file);
|
|
1220 |
|
1166 | 1221 |
do {
|
1167 | 1222 |
const char * fptr = file;
|
1168 | 1223 |
if (*fptr == '/')
|
|
1255 | 1310 |
if ((end = strrchr(d->d_name, '.'))) {
|
1256 | 1311 |
end++;
|
1257 | 1312 |
if (!strcmp(end, "local") ||
|
1258 | |
!strncmp(end, "rpm", 3) || /* .rmporig, .rpmnew, .rmpsave, ... */
|
|
1313 |
!strncmp(end, "rpm", 3) || /* .rpmorig, .rpmnew, .rmpsave, ... */
|
1259 | 1314 |
!strncmp(end, "ba", 2) || /* .bak, .backup, ... */
|
1260 | 1315 |
!strcmp(end, "old") ||
|
1261 | 1316 |
!strcmp(end, "new") ||
|
|
1525 | 1580 |
pushd(path);
|
1526 | 1581 |
while ((d = readdir(initdir)) != NULL) {
|
1527 | 1582 |
serv_t * service = NULL;
|
1528 | |
char * end;
|
1529 | 1583 |
char * token;
|
1530 | 1584 |
char* begin = (char*)NULL; /* Remember address of ptr handled by strsep() */
|
1531 | 1585 |
boolean lsb = false;
|
|
1572 | 1626 |
continue;
|
1573 | 1627 |
}
|
1574 | 1628 |
|
1575 | |
if (!strcmp(d->d_name, "boot") || !strcmp(d->d_name, "rc")) {
|
|
1629 |
#ifdef SUSE
|
|
1630 |
if (!strcmp(d->d_name, "boot") || !strcmp(d->d_name, "rc"))
|
|
1631 |
#else
|
|
1632 |
if (!strcmp(d->d_name, "rcS") || !strcmp(d->d_name, "rc"))
|
|
1633 |
#endif
|
|
1634 |
{
|
1576 | 1635 |
if (chkfor(d->d_name, argv, argc))
|
1577 | 1636 |
warn("script name %s is not valid, skipped!\n", d->d_name);
|
1578 | 1637 |
continue;
|
1579 | 1638 |
}
|
1580 | 1639 |
|
1581 | |
if ((end = strrchr(d->d_name, '.'))) {
|
1582 | |
end++;
|
1583 | |
if (!strcmp(end, "local") ||
|
1584 | |
!strncmp(end, "rpm", 3) || /* .rmporig, .rpmnew, .rmpsave, ... */
|
1585 | |
!strncmp(end, "ba", 2) || /* .bak, .backup, ... */
|
1586 | |
!strcmp(end, "old") ||
|
1587 | |
!strcmp(end, "new") ||
|
1588 | |
!strcmp(end, "save") ||
|
1589 | |
!strcmp(end, "swp") || /* Used by vi like editors */
|
1590 | |
!strcmp(end, "core")) /* modern core dump */
|
1591 | |
{
|
1592 | |
if (chkfor(d->d_name, argv, argc))
|
1593 | |
warn("script name %s is not valid, skipped!\n", d->d_name);
|
1594 | |
continue;
|
1595 | |
}
|
|
1640 |
if (cfgfile_filter(d) == 0) {
|
|
1641 |
if (chkfor(d->d_name, argv, argc))
|
|
1642 |
warn("script name %s is not valid, skipped!\n", d->d_name);
|
|
1643 |
continue;
|
1596 | 1644 |
}
|
1597 | 1645 |
|
1598 | 1646 |
/* Leaved by emacs like editors */
|
|
1704 | 1752 |
* (by using the list from the first scan for script locations).
|
1705 | 1753 |
*/
|
1706 | 1754 |
if (!service) {
|
|
1755 |
int count = 0;
|
1707 | 1756 |
char * provides = xstrdup(script_inf.provides);
|
1708 | 1757 |
|
1709 | 1758 |
begin = provides;
|
|
1736 | 1785 |
|
1737 | 1786 |
if (!(service = findserv(token)))
|
1738 | 1787 |
service = addserv(token);
|
|
1788 |
count++; /* Count token */
|
1739 | 1789 |
|
1740 | 1790 |
if (service) {
|
1741 | 1791 |
boolean known = (service->opts & SERV_KNOWN);
|
1742 | 1792 |
service->opts |= SERV_KNOWN;
|
|
1793 |
|
|
1794 |
if (!provides && (count > 1)) { /* Last token */
|
|
1795 |
const char * script = getscript(service->name);
|
|
1796 |
|
|
1797 |
if (script) {
|
|
1798 |
list_t * srv;
|
|
1799 |
|
|
1800 |
list_for_each(srv, serv_start) {
|
|
1801 |
serv_t * cur = getserv(srv);
|
|
1802 |
const char * chk;
|
|
1803 |
|
|
1804 |
if (!cur || !(chk = getscript(cur->name)))
|
|
1805 |
continue;
|
|
1806 |
|
|
1807 |
if (!strcmp(chk, script) && (service != cur)) {
|
|
1808 |
cur->opts |= SERV_DUPLET;
|
|
1809 |
cur->main = service; /* Remember main service */
|
|
1810 |
}
|
|
1811 |
}
|
|
1812 |
}
|
|
1813 |
}
|
1743 | 1814 |
|
1744 | 1815 |
if (!known && script_inf.required_start && script_inf.required_start != empty) {
|
1745 | 1816 |
rememberreq(service, REQ_MUST, script_inf.required_start);
|
|
1911 | 1982 |
/*
|
1912 | 1983 |
* default_stop arn't used in SuSE Linux.
|
1913 | 1984 |
*/
|
1914 | |
if (!service || !del)
|
1915 | |
service->lvlk = str2lvl(script_inf.default_stop);
|
|
1985 |
if (script_inf.default_stop && script_inf.default_stop != empty) {
|
|
1986 |
if (!service || !del)
|
|
1987 |
service->lvlk = str2lvl(script_inf.default_stop);
|
|
1988 |
}
|
1916 | 1989 |
#endif
|
1917 | 1990 |
}
|
1918 | 1991 |
script_inf.provides = begin;
|
|
2003 | 2076 |
char * rcd = NULL;
|
2004 | 2077 |
DIR * rcdir;
|
2005 | 2078 |
|
2006 | |
switch (runlevel) {
|
2007 | |
case 0: rcd = "rc0.d/"; break;
|
2008 | |
case 1: rcd = "rc1.d/"; break;
|
2009 | |
case 2: rcd = "rc2.d/"; break;
|
2010 | |
case 3: rcd = "rc3.d/"; break;
|
2011 | |
case 4: rcd = "rc4.d/"; break;
|
2012 | |
case 5: rcd = "rc5.d/"; break;
|
2013 | |
case 6: rcd = "rc6.d/"; break;
|
2014 | |
case 7: rcd = "rcS.d/"; break; /* runlevel S */
|
2015 | |
case 8: rcd = "boot.d/"; break; /* runlevel B */
|
2016 | |
default:
|
2017 | |
error("Wrong runlevel %d\n", runlevel);
|
2018 | |
}
|
|
2079 |
rcd = map_runlevel_to_location(runlevel);
|
2019 | 2080 |
|
2020 | 2081 |
script = NULL;
|
2021 | 2082 |
rcdir = openrcdir(rcd); /* Creates runlevel directory if necessary */
|
|
2083 |
if (rcdir == NULL)
|
|
2084 |
break;
|
2022 | 2085 |
pushd(rcd);
|
2023 | 2086 |
|
2024 | 2087 |
/*
|
|
2151 | 2214 |
* a traditional standard SystemV link scheme. Maybe for such an
|
2152 | 2215 |
* approach a new directory halt.d/ whould be an idea.
|
2153 | 2216 |
*/
|
2154 | |
# ifndef RUNLEVLES
|
2155 | |
# define RUNLEVLES 8 /* On e.g. Debian there exist no boot.d */
|
2156 | |
# endif
|
2157 | 2217 |
pushd(path);
|
2158 | 2218 |
for (runlevel = 0; runlevel < RUNLEVLES; runlevel++) {
|
2159 | 2219 |
int lvl = 0, seek = 0;
|
|
2162 | 2222 |
char * rcd = NULL;
|
2163 | 2223 |
DIR * rcdir;
|
2164 | 2224 |
|
2165 | |
switch (runlevel) { /* LVL_NORM: nearly all but not BOOT and not SINGLE */
|
2166 | |
case 0: rcd = "rc0.d/"; lvl = LVL_HALT; seek = LVL_NORM; break;
|
2167 | |
case 1: rcd = "rc1.d/"; lvl = LVL_ONE; seek = LVL_NORM; break;
|
2168 | |
case 2: rcd = "rc2.d/"; lvl = LVL_TWO; seek = LVL_NORM; break;
|
2169 | |
case 3: rcd = "rc3.d/"; lvl = LVL_THREE; seek = LVL_NORM; break;
|
2170 | |
case 4: rcd = "rc4.d/"; lvl = LVL_FOUR; seek = LVL_NORM; break;
|
2171 | |
case 5: rcd = "rc5.d/"; lvl = LVL_FIVE; seek = LVL_NORM; break;
|
2172 | |
case 6: rcd = "rc6.d/"; lvl = LVL_REBOOT; seek = LVL_NORM; break;
|
2173 | |
case 7: rcd = "rcS.d/"; lvl = LVL_SINGLE; seek = LVL_NORM; break; /* runlevel S */
|
2174 | |
# if defined(RUNLEVLES) && (RUNLEVLES > 8)
|
2175 | |
case 8: rcd = "boot.d/"; lvl = LVL_BOOT; seek = LVL_BOOT; break; /* runlevel B */
|
2176 | |
# endif
|
2177 | |
default:
|
2178 | |
error("Wrong runlevel %d\n", runlevel);
|
2179 | |
}
|
|
2225 |
rcd = map_runlevel_to_location(runlevel);
|
|
2226 |
lvl = map_runlevel_to_lvl(runlevel);
|
|
2227 |
seek = map_runlevel_to_seek(runlevel);
|
2180 | 2228 |
|
2181 | 2229 |
script = NULL;
|
2182 | 2230 |
rcdir = openrcdir(rcd); /* Creates runlevel directory if necessary */
|
|
2231 |
if (rcdir == NULL)
|
|
2232 |
break;
|
2183 | 2233 |
pushd(rcd);
|
2184 | 2234 |
|
2185 | 2235 |
/*
|