f9...
[util-vserver.git] / vserver-start / scriptlets.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "vserver-start.h"
24
25 #include <pathconfig.h>
26 #include <lib_internal/command.h>
27 #include <lib_internal/util.h>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/param.h>
32 #include <unistd.h>
33 #include <dirent.h>
34
35 #define HAS_SUFFIX(STR, LEN, SUF) \
36   (LEN>sizeof(SUF) && strcmp(STR+LEN-sizeof(SUF), SUF)==0)
37
38 static bool
39 visitFile(char const *fname, char const *vname, char const *style)
40 {
41   struct stat           st;
42   struct Command        cmd;
43
44   if (stat(fname, &st)==-1 ||
45       !S_ISREG(st.st_mode))
46     return false;
47
48   if ((st.st_mode & 0111)==0) {
49     WRITE_MSG(2,
50               "!!!LEGACY ALERT!!!\n"
51               "The special handling of non-executable scriptlets which allows to\n"
52               "override environment variables is not supported anymore. This change\n"
53               "was needed as 'vserver ... start' is done by a native C program now.\n"
54               "If you need the old functionality please fill a bugreport so that\n"
55               "workarounds can be found/implemented.\n"
56               "The file triggering this message was\n"
57               "    '");
58     WRITE_STR(2, fname);
59     WRITE_MSG(2, "'\n");
60
61     return false;
62   }
63
64   char const *par[] = { fname, style, vname, 0 };
65   Command_setParams(&cmd, par);
66
67   if (!Command_exec(&cmd, true) ||
68       !Command_wait(&cmd, true)) {
69     WRITE_MSG(2, "vserver-start: exec('");
70     WRITE_STR(2, fname);
71     WRITE_MSG(2, "'): ");
72     WRITE_STR(2, strerror(cmd.err));
73     WRITE_MSG(2, "; aborting...\n");
74
75     exit(1);
76   }
77
78   if (cmd.rc!=0) {
79     WRITE_MSG(2, "vserver-start: scriptlet '");
80     WRITE_STR(2, fname);
81     WRITE_MSG(2, "' failed; aborting...\n");
82     
83     exit (1);
84   }
85
86   Command_free(&cmd);
87
88   return true;
89 }
90
91 static bool
92 visitDirentry(PathInfo const *basepath, char const *d_name,
93               char const *vname,
94               char const *style)
95 {
96   size_t                l = strlen(d_name);
97   char                  path[basepath->l + l + 1];
98   char *                ptr;
99
100   if (isDotfile(d_name) ||
101       HAS_SUFFIX(d_name, l, ".rpmnew") ||
102       HAS_SUFFIX(d_name, l, ".rpmsave") ||
103       HAS_SUFFIX(d_name, l, ".rpmorig") ||
104       HAS_SUFFIX(d_name, l, ".cfsaved"))
105     return false;
106
107   ptr  = Xmemcpy(path, basepath->d, basepath->l);
108   ptr  = Xmemcpy(ptr,  d_name,      l);
109   *ptr = '\0';
110   
111   return visitFile(path, vname, style);
112 }
113
114 static bool
115 visitPath(PathInfo const *basepath,
116           char const *vname,
117           PathInfo const *style)
118 {
119   char          tmp[basepath->l + style->l + sizeof(".d/")];
120   PathInfo      path = { .d = tmp };
121   char *        ptr;
122   DIR *         dir;
123   bool          did_something = false;
124
125   ptr  = Xmemcpy(tmp, basepath->d, basepath->l);
126   ptr  = Xmemcpy(ptr, style->d,    style->l);
127   *ptr = '\0';
128   path.l = ptr-tmp;
129
130   did_something = visitFile(path.d, vname, style->d) || did_something;
131
132   ptr = Xmemcpy(ptr, ".d/", sizeof(".d/"));
133   path.l = ptr-tmp;
134   
135   dir = opendir(tmp);
136   while (dir) {
137     struct dirent *ent  =  readdir(dir);
138     if (ent==0) break;
139
140     did_something = visitDirentry(&path, ent->d_name, vname, style->d) || did_something;
141   }
142   if (dir!=0) closedir(dir);
143
144   return did_something;
145 }
146
147 void
148 execScriptlets(PathInfo const *cfgdir, char const *vname, char const *style)
149 {
150   char          path_buf[MAX(cfgdir->l, sizeof(CONFDIR "/.defaults")) +
151                          sizeof("/scripts/")];
152   PathInfo      basepath = { .d = path_buf };
153   PathInfo      styledir = {
154     .d = style,
155     .l = strlen(style)
156   };
157   char *        ptr;
158   bool          doit = true;
159
160   ptr        = Xmemcpy(path_buf, cfgdir->d, cfgdir->l);
161   ptr        = Xmemcpy(ptr,      "/scripts/", sizeof("/scripts/"));
162   basepath.l = ptr-path_buf-1;
163   doit       = !visitPath(&basepath, vname, &styledir);
164
165   if (doit) {
166     ptr = Xmemcpy(path_buf, CONFDIR "/.defaults/scripts/",
167                   sizeof(CONFDIR "/.defaults/scripts/"));
168     basepath.l = ptr-path_buf-1;
169     doit = !visitPath(&basepath, vname, &styledir);
170   }
171 }