rpm  5.4.10
rpmtcl.c
Go to the documentation of this file.
1 #include "system.h"
2 
3 #include <argv.h>
4 
5 #if defined(MODULE_EMBED)
6 #include <tcl.h>
7 #undef WITH_TCL
8 #endif
9 
10 #if defined(WITH_TCL)
11 #include <dlfcn.h>
12 #include <rpmlog.h>
13 #endif
14 
15 #define _RPMTCL_INTERNAL
16 #include "rpmtcl.h"
17 
18 #include "debug.h"
19 
20 /*@unchecked@*/
21 int _rpmtcl_debug = 0;
22 
23 /*@unchecked@*/ /*@relnull@*/
25 
26 #if defined(WITH_TCL)
27 static int dlopened = 0;
28 static rpmtcl (*rpmtclNew_p) (char ** av, uint32_t flags);
29 static rpmRC (*rpmtclRunFile_p) (rpmtcl tcl, const char * fn, const char ** resultp);
30 static rpmRC (*rpmtclRun_p) (rpmtcl tcl, const char * str, const char ** resultp);
31 #endif
32 
33 static void rpmtclFini(void * _tcl)
34  /*@globals fileSystem @*/
35  /*@modifies *_tcl, fileSystem @*/
36 {
37  rpmtcl tcl = (rpmtcl) _tcl;
38 
39 #if defined(MODULE_EMBED)
40  Tcl_DeleteInterp((Tcl_Interp *)tcl->I);
41 #endif
42  tcl->I = NULL;
43  (void)rpmiobFree(tcl->iob);
44  tcl->iob = NULL;
45 }
46 
47 /*@unchecked@*/ /*@only@*/ /*@null@*/
49 
50 static rpmtcl rpmtclGetPool(/*@null@*/ rpmioPool pool)
51  /*@globals _rpmtclPool, fileSystem @*/
52  /*@modifies pool, _rpmtclPool, fileSystem @*/
53 {
54  rpmtcl tcl;
55 
56  if (_rpmtclPool == NULL) {
57  _rpmtclPool = rpmioNewPool("tcl", sizeof(*tcl), -1, _rpmtcl_debug,
58  NULL, NULL, rpmtclFini);
59  pool = _rpmtclPool;
60  }
61  return (rpmtcl) rpmioGetPool(pool, sizeof(*tcl));
62 }
63 
64 #if defined(MODULE_EMBED)
65 static int rpmtclIOclose(ClientData CD, Tcl_Interp *I)
66  /*@*/
67 {
68 if (_rpmtcl_debug)
69 fprintf(stderr, "==> %s(%p, %p)\n", __FUNCTION__, CD, I);
70  return 0;
71 }
72 
73 static int rpmtclIOread(ClientData CD, char *b, int nb, int *errnop)
74  /*@*/
75 {
76 if (_rpmtcl_debug)
77 fprintf(stderr, "==> %s(%p, %p[%d], %p)\n", __FUNCTION__, CD, b, nb, errnop);
78  *errnop = EINVAL;
79  return -1;
80 }
81 
82 static int rpmtclIOwrite(ClientData CD, const char *b, int nb, int *errnop)
83  /*@*/
84 {
85  rpmtcl tcl = (rpmtcl) CD;
86 if (_rpmtcl_debug)
87 fprintf(stderr, "==> %s(%p, %p[%d], %p)\n", __FUNCTION__, CD, b, nb, errnop);
88  if (nb > 0) {
89  char * t = (char *)b;
90  int c = t[nb];
91  if (c) t[nb] = '\0';
92  (void) rpmiobAppend(tcl->iob, b, 0);
93  if (c) t[nb] = c;
94  }
95  return nb;
96 }
97 
98 static int rpmtclIOseek(ClientData CD, long off, int mode, int *errnop)
99  /*@*/
100 {
101 if (_rpmtcl_debug)
102 fprintf(stderr, "==> %s(%p, %ld, %d, %p)\n", __FUNCTION__, CD, off, mode, errnop);
103  *errnop = EINVAL;
104  return -1;
105 }
106 
107 static Tcl_ChannelType rpmtclIO = {
108  (char *)"rpmtclIO", /* Type name */
109  TCL_CHANNEL_VERSION_2, /* Tcl_ChannelTypeVersion */
110  rpmtclIOclose, /* Tcl_DriverCloseProc */
111  rpmtclIOread, /* Tcl_DriverInputProc */
112  rpmtclIOwrite, /* Tcl_DriverOutputProc */
113  rpmtclIOseek, /* Tcl_DriverSeekProc */
114  NULL, /* Tcl_DriverSetOptionProc */
115  NULL, /* Tcl_DriverGetOptionProc */
116  NULL, /* Tcl_DriverWatchProc */
117  NULL, /* Tcl_DriverGetHandleProc */
118  NULL, /* Tcl_DriverClose2Proc */
119  NULL, /* Tcl_DriverBlockModeProc */
120  NULL, /* Tcl_DriverFlushProc */
121  NULL, /* Tcl_DriverHandlerProc */
122  NULL, /* Tcl_DriverWideSeekProc */
123  NULL, /* Tcl_DriverThreadActionProc */
124 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 4
125  NULL, /* Tcl_DriverTruncateProc */
126 #endif
127 };
128 #endif
129 
130 static rpmtcl rpmtclI(void)
131  /*@globals _rpmtclI @*/
132  /*@modifies _rpmtclI @*/
133 {
134  if (_rpmtclI == NULL)
135  _rpmtclI = rpmtclNew(NULL, 0);
136  return _rpmtclI;
137 }
138 
139 #if defined(WITH_TCL)
140 static void loadModule(void) {
141  const char librpmtcl[] = "rpmtcl.so";
142  void *h;
143 
144  h = dlopen (librpmtcl, RTLD_NOW|RTLD_GLOBAL);
145  if (!h)
146  {
147  rpmlog(RPMLOG_WARNING, D_("Unable to open \"%s\" (%s), "
148  "embedded tcl will not be available\n"),
149  librpmtcl, dlerror());
150  }
151  else if(!((rpmtclNew_p = dlsym(h, "rpmtclNew"))
152  && (rpmtclRunFile_p = dlsym(h, "rpmtclRunFile"))
153  && (rpmtclRun_p = dlsym(h, "rpmtclRun")))) {
154  rpmlog(RPMLOG_WARNING, D_("Opened library \"%s\" is incompatible (%s), "
155  "embedded tcl will not be available\n"),
156  librpmtcl, dlerror());
157  if (dlclose (h))
158  rpmlog(RPMLOG_WARNING, "Error closing library \"%s\": %s", librpmtcl,
159  dlerror());
160  } else
161  dlopened = 1;
162 }
163 #endif
164 
165 rpmtcl rpmtclNew(char ** av, uint32_t flags)
166 {
167 #if defined(WITH_TCL)
168  if (!dlopened) loadModule();
169  if (dlopened) return rpmtclNew_p(av, flags);
170 #endif
171  rpmtcl tcl = (flags & 0x80000000)
172  ? rpmtclI() : rpmtclGetPool(_rpmtclPool);
173 
174 #if defined(MODULE_EMBED)
175  static char * _av[] = { "rpmtcl", NULL };
176  Tcl_Interp * tclI = Tcl_CreateInterp();
177  char b[32];
178  int ac;
179 
180  if (av == NULL) av = _av;
181  ac = argvCount((ARGV_t)av);
182 
183  Tcl_SetVar(tclI, "argv", Tcl_Merge(ac-1, (const char *const *)av+1), TCL_GLOBAL_ONLY);
184  (void)sprintf(b, "%d", ac-1);
185  Tcl_SetVar(tclI, "argc", b, TCL_GLOBAL_ONLY);
186  Tcl_SetVar(tclI, "argv0", av[0], TCL_GLOBAL_ONLY);
187  Tcl_SetVar(tclI, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
188 
189  tcl->I = tclI;
190  { Tcl_Channel tclout = Tcl_GetStdChannel(TCL_STDOUT);
191  Tcl_SetChannelOption(tclI, tclout, "-translation", "auto");
192  Tcl_StackChannel(tclI, &rpmtclIO, tcl, TCL_WRITABLE, tclout);
193  tcl->tclout = (void *) tclout;
194  }
195 #endif
196 #if !defined(WITH_TCL)
197  tcl->iob = rpmiobNew(0);
198 #endif
199 
200  return rpmtclLink(tcl);
201 }
202 
203 rpmRC rpmtclRunFile(rpmtcl tcl, const char * fn, const char ** resultp)
204 {
205 #if defined(WITH_TCL)
206  if (dlopened) return rpmtclRunFile_p(tcl, fn, resultp);
207 #endif
208  rpmRC rc = RPMRC_FAIL;
209 
210 if (_rpmtcl_debug)
211 fprintf(stderr, "==> %s(%p,%s)\n", __FUNCTION__, tcl, fn);
212 
213  if (tcl == NULL) tcl = rpmtclI();
214 
215 #if defined(MODULE_EMBED)
216  if (fn != NULL && Tcl_EvalFile((Tcl_Interp *)tcl->I, fn) == TCL_OK) {
217  rc = RPMRC_OK;
218  if (resultp)
219  *resultp = rpmiobStr(tcl->iob);
220  }
221 #endif
222  return rc;
223 }
224 
225 rpmRC rpmtclRun(rpmtcl tcl, const char * str, const char ** resultp)
226 {
227 #if defined(WITH_TCL)
228  if (dlopened) return rpmtclRun_p(tcl, str, resultp);
229 #endif
230  rpmRC rc = RPMRC_FAIL;
231 
232 if (_rpmtcl_debug)
233 fprintf(stderr, "==> %s(%p,%s)\n", __FUNCTION__, tcl, str);
234 
235  if (tcl == NULL) tcl = rpmtclI();
236 
237 #if defined(MODULE_EMBED)
238  if (str != NULL && Tcl_Eval((Tcl_Interp *)tcl->I, str) == TCL_OK) {
239  rc = RPMRC_OK;
240  if (resultp)
241  *resultp = rpmiobStr(tcl->iob);
242  }
243 #endif
244  return rc;
245 }