source: vendor/current/lib/texpect/texpect.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 9.3 KB
Line 
1/*
2 * Copyright (c) 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "replace.h"
35#include "system/filesys.h"
36#include "system/wait.h"
37
38#ifdef HAVE_PTY_H
39#include <pty.h>
40#endif
41#ifdef HAVE_UTIL_H
42#include <util.h>
43#endif
44#ifdef HAVE_BSD_LIBUTIL_H
45#include <bsd/libutil.h>
46#elif defined HAVE_LIBUTIL_H
47#include <libutil.h>
48#endif
49
50#ifdef STREAMSPTY
51#include <stropts.h>
52#endif /* STREAMPTY */
53
54#include <popt.h>
55
56#ifdef HAVE_ERR_H
57#include <err.h>
58#else
59const char progname[] = "unknown program";
60
61static void err(int eval, const char *fmt, ...)
62{
63 int err_errno = errno;
64 va_list ap;
65
66 fprintf(stderr, "%s: ", progname);
67 va_start(ap, fmt);
68 vfprintf(stderr, fmt, ap);
69 va_end(ap);
70 fprintf(stderr, ": %s\n", strerror(err_errno));
71 exit(eval);
72}
73
74static void errx(int eval, const char *fmt, ...)
75{
76 va_list ap;
77
78 fprintf(stderr, "%s: ", progname);
79 va_start(ap, fmt);
80 vfprintf(stderr, fmt, ap);
81 va_end(ap);
82 fprintf(stderr, "\n");
83 exit(eval);
84}
85
86#endif
87
88struct command {
89 enum { CMD_EXPECT = 0, CMD_SEND, CMD_PASSWORD } type;
90 unsigned int lineno;
91 char *str;
92 struct command *next;
93};
94
95/*
96 *
97 */
98
99static struct command *commands, **next = &commands;
100
101static sig_atomic_t alarmset = 0;
102
103static int opt_timeout = 10;
104static int opt_verbose;
105
106static int master;
107static int slave;
108static char line[256] = { 0 };
109
110static void caught_signal(int signo)
111{
112 alarmset = signo;
113}
114
115
116static void open_pty(void)
117{
118#ifdef _AIX
119 printf("implement open_pty\n");
120 exit(77);
121#endif
122#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
123 if(openpty(&master, &slave, line, 0, 0) == 0)
124 return;
125#endif /* HAVE_OPENPTY .... */
126#ifdef STREAMSPTY
127 {
128 char *clone[] = {
129 "/dev/ptc",
130 "/dev/ptmx",
131 "/dev/ptm",
132 "/dev/ptym/clone",
133 NULL
134 };
135 char **q;
136
137 for(q = clone; *q; q++){
138 master = open(*q, O_RDWR);
139 if(master >= 0){
140#ifdef HAVE_GRANTPT
141 grantpt(master);
142#endif
143#ifdef HAVE_UNLOCKPT
144 unlockpt(master);
145#endif
146 strlcpy(line, ptsname(master), sizeof(line));
147 slave = open(line, O_RDWR);
148 if (slave < 0)
149 errx(1, "failed to open slave when using %s", *q);
150 ioctl(slave, I_PUSH, "ptem");
151 ioctl(slave, I_PUSH, "ldterm");
152
153 return;
154 }
155 }
156 }
157#endif /* STREAMSPTY */
158
159 /* more cases, like open /dev/ptmx, etc */
160
161 exit(77);
162}
163
164/*
165 *
166 */
167
168static char *iscmd(const char *buf, const char *s)
169{
170 size_t len = strlen(s);
171
172 if (strncmp(buf, s, len) != 0) {
173 return NULL;
174 }
175
176 return strdup(buf + len);
177}
178
179/*******************************************************************
180A write wrapper that will deal with EINTR.
181********************************************************************/
182
183static ssize_t sys_write(int fd, const void *buf, size_t count)
184{
185 ssize_t ret;
186
187 do {
188 ret = write(fd, buf, count);
189#if defined(EWOULDBLOCK)
190 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
191#else
192 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
193#endif
194 return ret;
195}
196
197static void parse_configuration(const char *fn)
198{
199 struct command *c;
200 char s[1024];
201 char *str;
202 unsigned int lineno = 0;
203 FILE *cmd;
204
205 cmd = fopen(fn, "r");
206 if (cmd == NULL)
207 err(1, "open: %s", fn);
208
209 while (fgets(s, sizeof(s), cmd) != NULL) {
210
211 s[strcspn(s, "#\n")] = '\0';
212 lineno++;
213
214 c = calloc(1, sizeof(*c));
215 if (c == NULL)
216 errx(1, "malloc");
217
218 c->lineno = lineno;
219 (*next) = c;
220 next = &(c->next);
221
222 if ((str = iscmd(s, "expect ")) != NULL) {
223 c->type = CMD_EXPECT;
224 c->str = str;
225 } else if ((str = iscmd(s, "send ")) != NULL) {
226 c->type = CMD_SEND;
227 c->str = str;
228 } else if ((str = iscmd(s, "password ")) != NULL) {
229 c->type = CMD_PASSWORD;
230 c->str = str;
231 } else
232 errx(1, "Invalid command on line %d: %s", lineno, s);
233 }
234
235 fclose(cmd);
236}
237
238/* A wrapper to close als file descriptors above the given fd */
239static int sys_closefrom(int fd)
240{
241 int num = getdtablesize();
242
243 if (num < 0) {
244 num = 1024;
245 }
246
247 for (; fd <= num; fd++) {
248 close(fd);
249 }
250
251 return 0;
252}
253
254
255/*
256 *
257 */
258
259static int eval_parent(pid_t pid)
260{
261 struct command *c;
262 char in;
263 size_t len = 0;
264 ssize_t sret;
265
266 for (c = commands; c != NULL; c = c->next) {
267 switch(c->type) {
268 case CMD_EXPECT:
269 if (opt_verbose) {
270 printf("[expecting %s]\n", c->str);
271 }
272 len = 0;
273 alarm(opt_timeout);
274 while((sret = read(master, &in, sizeof(in))) > 0) {
275 alarm(opt_timeout);
276 printf("%c", in);
277 if (c->str[len] != in) {
278 len = 0;
279 continue;
280 }
281 len++;
282 if (c->str[len] == '\0') {
283 break;
284 }
285 }
286 alarm(0);
287 if (alarmset == SIGALRM) {
288 errx(1, "timeout waiting for %s (line %u)",
289 c->str, c->lineno);
290 } else if (alarmset) {
291 errx(1, "got a signal %d waiting for %s (line %u)",
292 (int)alarmset, c->str, c->lineno);
293 }
294
295 if (sret <= 0) {
296 errx(1, "end command while waiting for %s (line %u)",
297 c->str, c->lineno);
298 }
299 break;
300 case CMD_SEND:
301 case CMD_PASSWORD: {
302 size_t i = 0;
303 const char *msg = (c->type == CMD_PASSWORD) ? "****" : c->str;
304
305 if (opt_verbose) {
306 printf("[send %s]\n", msg);
307 }
308
309 len = strlen(c->str);
310
311 while (i < len) {
312 if (c->str[i] == '\\' && i < len - 1) {
313 char ctrl;
314 i++;
315 switch(c->str[i]) {
316 case 'n':
317 ctrl = '\n';
318 break;
319 case 'r':
320 ctrl = '\r';
321 break;
322 case 't':
323 ctrl = '\t';
324 break;
325 default:
326 errx(1,
327 "unknown control char %c (line %u)",
328 c->str[i],
329 c->lineno);
330 }
331 if (sys_write(master, &ctrl, 1) != 1) {
332 errx(1, "command refused input (line %u)", c->lineno);
333 }
334 } else {
335 if (sys_write(master, &c->str[i], 1) != 1) {
336 errx(1, "command refused input (line %u)", c->lineno);
337 }
338 }
339 i++;
340 }
341 break;
342 }
343 default:
344 abort();
345 }
346 }
347
348 while(read(master, &in, sizeof(in)) > 0) {
349 printf("%c", in);
350 }
351
352 if (opt_verbose) {
353 printf("[end of program]\n");
354 }
355
356 /*
357 * Fetch status from child
358 */
359 {
360 int ret, status;
361
362 ret = waitpid(pid, &status, 0);
363 if (ret == -1) {
364 err(1, "waitpid");
365 }
366
367 if (WIFEXITED(status) && WEXITSTATUS(status)) {
368 return WEXITSTATUS(status);
369 } else if (WIFSIGNALED(status)) {
370 printf("killed by signal: %d\n", WTERMSIG(status));
371 return 1;
372 }
373 }
374
375 return 0;
376}
377
378/*
379 *
380 */
381struct poptOption long_options[] = {
382 POPT_AUTOHELP
383 {"timeout", 't', POPT_ARG_INT, &opt_timeout, 't'},
384 {"verbose", 'v', POPT_ARG_NONE, &opt_verbose, 'v'},
385 POPT_TABLEEND
386};
387
388int main(int argc, const char **argv)
389{
390 int optidx = 0;
391 pid_t pid;
392 poptContext pc;
393 const char *instruction_file;
394 const char **args;
395 const char *program;
396 char * const *program_args;
397
398 pc = poptGetContext("texpect",
399 argc,
400 argv,
401 long_options,
402 POPT_CONTEXT_POSIXMEHARDER);
403
404 if (argc == 1) {
405 poptPrintHelp(pc, stderr, 0);
406 return 1;
407 }
408
409 while ((optidx = poptGetNextOpt(pc)) != -1) {
410 ;;
411 }
412
413 instruction_file = poptGetArg(pc);
414 args = poptGetArgs(pc);
415 program_args = (char * const *)discard_const_p(char *, args);
416 program = program_args[0];
417
418 if (opt_verbose) {
419 int i;
420
421 printf("Using instruction_file: %s\n", instruction_file);
422 printf("Executing '%s' ", program);
423 for (i = 0; program_args && program_args[i] != NULL; i++) {
424 printf("'%s' ", program_args[i]);
425 }
426 printf("\n");
427 }
428
429 parse_configuration(instruction_file);
430
431 open_pty();
432
433 pid = fork();
434 switch (pid) {
435 case -1:
436 err(1, "Failed to fork");
437 case 0:
438
439 if(setsid()<0)
440 err(1, "setsid");
441
442 dup2(slave, STDIN_FILENO);
443 dup2(slave, STDOUT_FILENO);
444 dup2(slave, STDERR_FILENO);
445
446 sys_closefrom(STDERR_FILENO + 1);
447
448 /* texpect <expect_instructions> <progname> [<args>] */
449 execvp(program, program_args);
450 err(1, "Failed to exec: %s", program);
451 default:
452 close(slave);
453 {
454 struct sigaction sa;
455
456 sa.sa_handler = caught_signal;
457 sa.sa_flags = 0;
458 sigemptyset (&sa.sa_mask);
459
460 sigaction(SIGALRM, &sa, NULL);
461 }
462
463 return eval_parent(pid);
464 }
465}
Note: See TracBrowser for help on using the repository browser.