minor optimizations
[util-vserver.git] / util-vserver / 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 a done by a native C program\n"
54               "now. If you need the old functionality please fill a bugreport so\n"
55               "that 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   Command_init(&cmd, 4);
65   Command_appendParameter(&cmd, fname);
66   Command_appendParameter(&cmd, style);
67   Command_appendParameter(&cmd, vname);
68
69   if (!Command_exec(&cmd, true) ||
70       !Command_wait(&cmd, true)) {
71     WRITE_MSG(2, "vserver-start: exec('");
72     WRITE_STR(2, fname);
73     WRITE_MSG(2, "'): ");
74     WRITE_STR(2, strerror(cmd.err));
75     WRITE_MSG(2, "; aborting...\n");
76
77     exit(1);
78   }
79
80   if (cmd.rc!=0) {
81     WRITE_MSG(2, "vserver-start: scriptlet '");
82     WRITE_STR(2, fname);
83     WRITE_MSG(2, "' failed; aborting...\n");
84     
85     exit (1);
86   }
87
88   Command_free(&cmd);
89
90   return true;
91 }
92
93 static bool
94 visitDirentry(PathInfo const *basepath, char const *d_name,
95               char const *vname,
96               char const *style)
97 {
98   size_t                l = strlen(d_name);
99   char                  path[basepath->l + l + 1];
100   char *                ptr;
101
102   if (isDotfile(d_name) ||
103       HAS_SUFFIX(d_name, l, ".rpmnew") ||
104       HAS_SUFFIX(d_name, l, ".rpmsave") ||
105       HAS_SUFFIX(d_name, l, ".rpmorig") ||
106       HAS_SUFFIX(d_name, l, ".cfsaved"))
107     return false;
108
109   ptr  = Xmemcpy(path, basepath->d, basepath->l);
110   ptr  = Xmemcpy(ptr,  d_name,      l);
111   *ptr = '\0';
112   
113   return visitFile(path, vname, style);
114 }
115
116 static bool
117 visitPath(PathInfo const *basepath,
118           char const *vname,
119           PathInfo const *style)
120 {
121   char          tmp[basepath->l + style->l + sizeof(".d/")];
122   PathInfo      path = { .d = tmp };
123   char *        ptr;
124   DIR *         dir;
125   bool          did_something = false;
126
127   ptr  = Xmemcpy(tmp, basepath->d, basepath->l);
128   ptr  = Xmemcpy(ptr, style->d,    style->l);
129   *ptr = '\0';
130   path.l = ptr-tmp;
131
132   did_something = visitFile(path.d, vname, style->d) || did_something;
133
134   ptr = Xmemcpy(ptr, ".d/", sizeof(".d/"));
135   path.l = ptr-tmp;
136   
137   dir = opendir(tmp);
138   while (dir) {
139     struct dirent *ent  =  readdir(dir);
140     if (ent==0) break;
141
142     did_something = visitDirentry(&path, ent->d_name, vname, style->d) || did_something;
143   }
144   if (dir!=0) closedir(dir);
145
146   return did_something;
147 }
148
149 void
150 execScriptlets(PathInfo const *cfgdir, char const *vname, char const *style)
151 {
152   char          path_buf[MAX(cfgdir->l, sizeof(CONFDIR "/.defaults")) +
153                          sizeof("/scripts/")];
154   PathInfo      basepath = { .d = path_buf };
155   PathInfo      styledir = {
156     .d = style,
157     .l = strlen(style)
158   };
159   char *        ptr;
160   bool          doit = true;
161
162   ptr = Xmemcpy(path_buf, cfgdir->d, cfgdir->l);
163   ptr = Xmemcpy(ptr,      "/scripts/", sizeof("/scripts/"));
164   basepath.l = ptr-path_buf-1;
165   doit =   !visitPath(&basepath, vname, &styledir);
166
167   if (doit) {
168     ptr = Xmemcpy(path_buf, CONFDIR "/.defaults/scripts/",
169                   sizeof(CONFDIR "/.defaults/scripts/"));
170     doit = !visitPath(&basepath, vname, &styledir);
171   }
172 }