merged in Marc's new build code
[platform/upstream/rpm.git] / build / misc.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <signal.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <errno.h>
10
11 #include "misc.h"
12 #include "spec.h"
13 #include "rpmlib.h"
14 #include "header.h"
15 #include "popt/popt.h"
16
17 void addOrAppendListEntry(Header h, int_32 tag, char *line)
18 {
19     int argc;
20     char **argv;
21
22     poptParseArgvString(line, &argc, &argv);
23     if (argc) {
24         headerAddOrAppendEntry(h, tag, RPM_STRING_ARRAY_TYPE, argv, argc);
25     }
26     FREE(argv);
27 }
28
29 /* Parse a simple part line that only take -n <pkg> or <pkg> */
30 /* <pkg> is return in name as a pointer into a static buffer */
31
32 int parseSimplePart(char *line, char **name, int *flag)
33 {
34     char *tok;
35     char linebuf[BUFSIZ];
36     static char buf[BUFSIZ];
37
38     strcpy(linebuf, line);
39
40     /* Throw away the first token (the %xxxx) */
41     strtok(linebuf, " \t\n");
42     
43     if (!(tok = strtok(NULL, " \t\n"))) {
44         *name = NULL;
45         return 0;
46     }
47     
48     if (!strcmp(tok, "-n")) {
49         if (!(tok = strtok(NULL, " \t\n"))) {
50             return 1;
51         }
52         *flag = PART_NAME;
53     } else {
54         *flag = PART_SUBNAME;
55     }
56     strcpy(buf, tok);
57     *name = buf;
58
59     return (strtok(NULL, " \t\n")) ? 1 : 0;
60 }
61
62 int parseYesNo(char *s)
63 {
64     if (!s || (s[0] == 'n' || s[0] == 'N') ||
65         !strcasecmp(s, "false") ||
66         !strcasecmp(s, "off") ||
67         !strcmp(s, "0")) {
68         return 0;
69     }
70
71     return 1;
72 }
73
74 char *findLastChar(char *s)
75 {
76     char *res = s;
77
78     while (*s) {
79         if (! isspace(*s)) {
80             res = s;
81         }
82         s++;
83     }
84
85     return res;
86 }
87
88 int parseNum(char *line, int *res)
89 {
90     char *s1;
91     
92     s1 = NULL;
93     *res = strtoul(line, &s1, 10);
94     if ((*s1) || (s1 == line) || (*res == ULONG_MAX)) {
95         return 1;
96     }
97
98     return 0;
99 }
100
101 StringBuf getOutputFrom(char *dir, char *argv[],
102                         char *writePtr, int writeBytesLeft,
103                         int failNonZero)
104 {
105     int progPID;
106     int progDead;
107     int toProg[2];
108     int fromProg[2];
109     int status;
110     void *oldhandler;
111     int bytesWritten;
112     StringBuf readBuff;
113     int bytes;
114     unsigned char buf[8193];
115
116     oldhandler = signal(SIGPIPE, SIG_IGN);
117
118     pipe(toProg);
119     pipe(fromProg);
120     
121     if (!(progPID = fork())) {
122         close(toProg[1]);
123         close(fromProg[0]);
124         
125         dup2(toProg[0], 0);   /* Make stdin the in pipe */
126         dup2(fromProg[1], 1); /* Make stdout the out pipe */
127
128         close(toProg[0]);
129         close(fromProg[1]);
130
131         if (dir) {
132             chdir(dir);
133         }
134         
135         execvp(argv[0], argv);
136         rpmError(RPMERR_EXEC, "Couldn't exec %s", argv[0]);
137         _exit(RPMERR_EXEC);
138     }
139     if (progPID < 0) {
140         rpmError(RPMERR_FORK, "Couldn't fork %s", argv[0]);
141         return NULL;
142     }
143
144     close(toProg[0]);
145     close(fromProg[1]);
146
147     /* Do not block reading or writing from/to prog. */
148     fcntl(fromProg[0], F_SETFL, O_NONBLOCK);
149     fcntl(toProg[1], F_SETFL, O_NONBLOCK);
150     
151     readBuff = newStringBuf();
152
153     progDead = 0;
154     do {
155         if (waitpid(progPID, &status, WNOHANG)) {
156             progDead = 1;
157         }
158
159         /* Write some stuff to the process if possible */
160         if (writeBytesLeft) {
161             if ((bytesWritten =
162                   write(toProg[1], writePtr,
163                     (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
164                 if (errno != EAGAIN) {
165                     perror("getOutputFrom()");
166                     exit(1);
167                 }
168                 bytesWritten = 0;
169             }
170             writeBytesLeft -= bytesWritten;
171             writePtr += bytesWritten;
172         } else {
173             close(toProg[1]);
174         }
175         
176         /* Read any data from prog */
177         bytes = read(fromProg[0], buf, sizeof(buf)-1);
178         while (bytes > 0) {
179             buf[bytes] = '\0';
180             appendStringBuf(readBuff, buf);
181             bytes = read(fromProg[0], buf, sizeof(buf)-1);
182         }
183
184         /* terminate when prog dies */
185     } while (!progDead);
186
187     close(toProg[1]);
188     close(fromProg[0]);
189     signal(SIGPIPE, oldhandler);
190
191     if (writeBytesLeft) {
192         rpmError(RPMERR_EXEC, "failed to write all data to %s", argv[0]);
193         return NULL;
194     }
195     waitpid(progPID, &status, 0);
196     if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) {
197         rpmError(RPMERR_EXEC, "%s failed", argv[0]);
198         return NULL;
199     }
200
201     return readBuff;
202 }