See Changelog
[nfs-utils.git] / support / nfs / cacheio.c
1 /*
2  * support/nfs/cacheio.c
3  * support IO on the cache channel files in 2.5 and beyond.
4  * These use 'qwords' which are like words, but with a little quoting.
5  *
6  */
7
8
9 /*
10  * Support routines for text-based upcalls.
11  * Fields are separated by spaces.
12  * Fields are either mangled to quote space tab newline slosh with slosh
13  * or a hexified with a leading \x
14  * Record is terminated with newline.
15  *
16  */
17
18 #include <nfslib.h>
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <unistd.h>
22
23 void qword_add(char **bpp, int *lp, char *str)
24 {
25         char *bp = *bpp;
26         int len = *lp;
27         char c;
28
29         if (len < 0) return;
30
31         while ((c=*str++) && len)
32                 switch(c) {
33                 case ' ':
34                 case '\t':
35                 case '\n':
36                 case '\\':
37                         if (len >= 4) {
38                                 *bp++ = '\\';
39                                 *bp++ = '0' + ((c & 0300)>>6);
40                                 *bp++ = '0' + ((c & 0070)>>3);
41                                 *bp++ = '0' + ((c & 0007)>>0);
42                         }
43                         len -= 4;
44                         break;
45                 default:
46                         *bp++ = c;
47                         len--;
48                 }
49         if (c || len <1) len = -1;
50         else {
51                 *bp++ = ' ';
52                 len--;
53         }
54         *bpp = bp;
55         *lp = len;
56 }
57
58 void qword_addhex(char **bpp, int *lp, char *buf, int blen)
59 {
60         char *bp = *bpp;
61         int len = *lp;
62
63         if (len < 0) return;
64
65         if (len > 2) {
66                 *bp++ = '\\';
67                 *bp++ = 'x';
68                 len -= 2;
69                 while (blen && len >= 2) {
70                         unsigned char c = *buf++;
71                         *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
72                         *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
73                         len -= 2;
74                         blen--;
75                 }
76         }
77         if (blen || len<1) len = -1;
78         else {
79                 *bp++ = ' ';
80                 len--;
81         }
82         *bpp = bp;
83         *lp = len;
84 }
85
86 static char qword_buf[8192];
87 void qword_print(FILE *f, char *str)
88 {
89         char *bp = qword_buf;
90         int len = sizeof(qword_buf);
91         qword_add(&bp, &len, str);
92         fwrite(qword_buf, bp-qword_buf, 1, f);
93 }
94
95 void qword_printhex(FILE *f, char *str, int slen)
96 {
97         char *bp = qword_buf;
98         int len = sizeof(qword_buf);
99         qword_addhex(&bp, &len, str, slen);
100         fwrite(qword_buf, bp-qword_buf, 1, f);
101 }
102
103 void qword_printint(FILE *f, int num)
104 {
105         fprintf(f, "%d ", num);
106 }
107
108 void qword_eol(FILE *f)
109 {
110         fprintf(f,"\n");
111         fflush(f);
112 }
113
114
115
116 #define isodigit(c) (isdigit(c) && c <= '7')
117 int qword_get(char **bpp, char *dest, int bufsize)
118 {
119         /* return bytes copied, or -1 on error */
120         char *bp = *bpp;
121         int len = 0;
122
123         while (*bp == ' ') bp++;
124
125         if (bp[0] == '\\' && bp[1] == 'x') {
126                 /* HEX STRING */
127                 bp += 2;
128                 while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
129                         int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
130                         bp++;
131                         byte <<= 4;
132                         byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
133                         *dest++ = byte;
134                         bp++;
135                         len++;
136                 }
137         } else {
138                 /* text with \nnn octal quoting */
139                 while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
140                         if (*bp == '\\' &&
141                             isodigit(bp[1]) && (bp[1] <= '3') &&
142                             isodigit(bp[2]) &&
143                             isodigit(bp[3])) {
144                                 int byte = (*++bp -'0');
145                                 bp++;
146                                 byte = (byte << 3) | (*bp++ - '0');
147                                 byte = (byte << 3) | (*bp++ - '0');
148                                 *dest++ = byte;
149                                 len++;
150                         } else {
151                                 *dest++ = *bp++;
152                                 len++;
153                         }
154                 }
155         }
156
157         if (*bp != ' ' && *bp != '\n' && *bp != '\0')
158                 return -1;
159         while (*bp == ' ') bp++;
160         *bpp = bp;
161         *dest = '\0';
162         return len;
163 }
164
165 int qword_get_int(char **bpp, int *anint)
166 {
167         char buf[50];
168         char *ep;
169         int rv;
170         int len = qword_get(bpp, buf, 50);
171         if (len < 0) return -1;
172         if (len ==0) return -1;
173         rv = strtol(buf, &ep, 0);
174         if (*ep) return -1;
175         *anint = rv;
176         return 0;
177 }
178
179 int readline(int fd, char **buf, int *lenp)
180 {
181         /* read a line into *buf, which is malloced *len long
182          * realloc if needed until we find a \n
183          * nul out the \n and return
184          * 0 of eof, 1 of success 
185          */
186         int len = *lenp;
187
188         if (len == 0) {
189                 char *b = malloc(128);
190                 if (b == NULL)
191                         return 0;
192                 *buf = b;
193                 *lenp = 128;
194         }
195         len = read(fd, *buf, len);
196         if (len <= 0)
197                 return 0;
198         while ((*buf)[len-1] != '\n') {
199         /* now the less common case.  There was no newline,
200          * so we have to keep reading after re-alloc
201          */
202                 char *new;
203                 int nl;
204                 *lenp += 128;
205                 new = realloc(*buf, *lenp);
206                 if (new == NULL)
207                         return 0;
208                 nl = read(fd, *buf +len, *lenp - len);
209                 if (nl <= 0 )
210                         return 0;
211                 new += nl;
212         }
213         (*buf)[len-1] = 0;
214         return 1;
215 }
216