File: custom.c

package info (click to toggle)
limo 0.3.2-2
  • links: PTS
  • area: main
  • in suites: woody
  • size: 144 kB
  • ctags: 159
  • sloc: ansic: 1,666; makefile: 80
file content (177 lines) | stat: -rw-r--r-- 4,898 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* $Id: custom.c,v 1.2 1999/07/01 01:39:58 fraserm Exp $
   $Log: custom.c,v $
   Revision 1.2  1999/07/01 01:39:58  fraserm
   word 0

   Revision 1.1  1999/05/26 23:51:20  fraserm
   Initial revision

*/

/* custom fields - i.e. incorporate external commands */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include "limo.h"

/* execute the command in cmdfmt with the file fname; assumes fname is a valid
   filename from current location */
char *get_custom(int argc, char *argv[], struct custcmd *cmdfmt, char *fname)
{
  char cmdbuf[CMDMAX];
  char output[CMDOUTMAX];
  char *retbuf = NULL;
  int p[2]; /* pipe file descriptors */
  FILE *f; /* the stdio'd version of the read side (p[0]) of the pipe */
  pid_t child;
  int status; /* status return of the child process */
  char *my_argv[4];
  int ch;
  int i, curr;
/*  ssize_t rv; */

  /* make the command */
  if (snprintf(cmdbuf, CMDMAX, cmdfmt->cmd, fname) == -1) {
    retbuf = "Bad-Command";
  }
  else { /* made command ok */
    /* create a pipe */
    if (pipe(p) == -1) {
      fprintf(stderr, "%s: pipe: %s\n", argv[0], strerror(errno));
      retbuf =  "Pipe Error";
    }
    else { /* made pipe ok */
      /* printf("Pipe fds %d & %d\n", p[0], p[1]); */
      /* split into two processes */
      if ((child = fork()) == -1) {
	fprintf(stderr, "%s: fork: %s\n", argv[0], strerror(errno));
      }
      else { /* forked ok */
	if (child == 0) { /* in the child, dup() all the fds and run the
			     command */
	  /* make the writing end of the pipe the standard out and err for
	     this process */
	  if (dup2(p[1], 1) == -1 || dup2(p[1], 2) == -1) {
	    fprintf(stderr, "%s: dup2: %s\n", argv[0], strerror(errno));
	    close(p[1]);
	    exit(0); /* just exits the sub-process, mind! */
	  }
	  /* execute the command */
	  my_argv[0] = "sh";
	  my_argv[1] = "-c";
	  my_argv[2] = cmdbuf;
	  my_argv[3] = NULL;
	  execv("/bin/sh", my_argv);
	  exit(127);
	}
	else { /* in the parent, read the child's output */
	  /* let's make it into a standard IO object to make things simpler */
	  if ((f = fdopen(p[0], "r")) == NULL) {
	    fprintf(stderr, "%s: fdopen: %s\n", argv[0], strerror(errno));
	    retbuf = "Bad-Pipe-Read";
	  }
	  else { /* fdopened ok */
	    /* skip lines as required */
	    ch = fgetc(f);
	    for (curr = 1; curr < cmdfmt->linenum; ++curr) {
	      while (ch != EOF && ch != '\n') {
		ch = fgetc(f);
	      }
	    }
	    if (ch == EOF) {
	      retbuf = "Not-Enough-Lines";
	    }
	    else {
	      /* right, skip whitespace first */
	      while (ch != EOF
		     && (ch == ' ' || ch == '\r' || ch == '\t')) {
		ch = fgetc(f);
	      }
	      if (ch == EOF || ch == '\n') {
		retbuf = "Not-Enough-Lines";
	      }
	      else {
		if (cmdfmt->wordnum != 0) { /* 0 means the whole line */
		  /* skip enough words */
		  for (curr = 1; curr < cmdfmt->wordnum; ++curr) {
		    /* skip a word */
		    while (ch != EOF
			   && ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') {
		      ch = fgetc(f);
		    }
		    if (ch == EOF || ch == '\n') {
		      break; /* EOF or end-of-line is game over */
		    }
		    /* skip the whitespace following it */
		    while (ch  != EOF &&
			   (ch == ' ' || ch == '\r' || ch == '\t')) {
		      ch = fgetc(f);
		    }
		    if (ch == EOF || ch == '\n') {
		      break;
		    }
		  }
		}
		if (ch == EOF || ch == '\n') { /* must have hit something we
						  don't want */
		  retbuf = "Not-Enough-Words";
		}
		else {
		  if (ch != EOF) {
		    ungetc(ch, f); /* push the last one back */
		    /* read into the output buffer until we get a whitespace
		       or run out of buffer, or if wordnum is 0, until the
		       end of the line */
		    for (i = 0;
			 i < CMDOUTMAX-1 && (ch = fgetc(f)) != EOF;
			 ++i) {
		      if (ch == '\n' || ch == '\r'
			  || (cmdfmt->wordnum > 0
			      && (ch == ' ' || ch == '\t'))) {
			break;
		      }
		      output[i] = ch;
		    }
		    output[i] = '\0'; /* terminate the string properly */
		  }
		}
	      }
	    }
	    /* close this end of the pipe */
	    fclose(f);
	    /* wait for the process to terminate */
	    if (waitpid(child, &status, 0) != child) {
	      fprintf(stderr, "%s: waitpid: %s\n", argv[0], strerror(errno));
	    }
	    /* did command succeed? */
	    if (WEXITSTATUS(status) != 0) {
	      retbuf = "-";
	    }
	    else {
	      if (retbuf == NULL) {
		/* get a char buffer to return the output in */
		if ((retbuf = (char *) malloc(i+1)) == NULL) {
		  fprintf(stderr, "%s: malloc: %s\n", argv[0],
			  strerror(errno));
		  retbuf = "Bad-malloc";
		}
		else { /* malloced ok */
		  strcpy(retbuf, output);
		}
	      }
	    }
	  }
	}
      }
      close(p[0]); /* the reading side */
      close(p[1]); /* the writing side */
    }
  }
  return retbuf;
}