]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/iscsictl/parse.y
Add network QoS support for PCP to iscsi initiator.
[FreeBSD/FreeBSD.git] / usr.bin / iscsictl / parse.y
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2012 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * This software was developed by Edward Tomasz Napierala under sponsorship
9  * from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34
35 #include <sys/queue.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <assert.h>
39 #include <stdio.h>
40 #include <stdint.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include <libxo/xo.h>
45
46 #include "iscsictl.h"
47 #include <netinet/in.h>
48 #include <netinet/ip.h>
49
50 extern FILE *yyin;
51 extern char *yytext;
52 extern int lineno;
53
54 static struct conf *conf;
55 static struct target *target;
56
57 extern void     yyerror(const char *);
58 extern int      yylex(void);
59 extern void     yyrestart(FILE *);
60
61 %}
62
63 %token AUTH_METHOD ENABLE HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS
64 %token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET
65 %token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD
66 %token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET DSCP
67 %token AF11 AF12 AF13 AF21 AF22 AF23 AF31 AF32 AF33 AF41 AF42 AF43
68 %token BE EF CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7
69
70 %union
71 {
72         char *str;
73 }
74
75 %token <str> STR
76
77 %%
78
79 targets:
80         |
81         targets target
82         ;
83
84 target:         STR OPENING_BRACKET target_entries CLOSING_BRACKET
85         {
86                 if (target_find(conf, $1) != NULL)
87                         xo_errx(1, "duplicated target %s", $1);
88                 target->t_nickname = $1;
89                 target = target_new(conf);
90         }
91         ;
92
93 target_entries:
94         |
95         target_entries target_entry
96         |
97         target_entries target_entry SEMICOLON
98         ;
99
100 target_entry:
101         target_name
102         |
103         target_address
104         |
105         initiator_name
106         |
107         initiator_address
108         |
109         initiator_alias
110         |
111         user
112         |
113         secret
114         |
115         mutual_user
116         |
117         mutual_secret
118         |
119         auth_method
120         |
121         header_digest
122         |
123         data_digest
124         |
125         session_type
126         |
127         enable
128         |
129         offload
130         |
131         protocol
132         |
133         ignored
134         |
135         dscp
136         |
137         pcp
138         ;
139
140 target_name:    TARGET_NAME EQUALS STR
141         {
142                 if (target->t_name != NULL)
143                         xo_errx(1, "duplicated TargetName at line %d", lineno);
144                 target->t_name = $3;
145         }
146         ;
147
148 target_address: TARGET_ADDRESS EQUALS STR
149         {
150                 if (target->t_address != NULL)
151                         xo_errx(1, "duplicated TargetAddress at line %d", lineno);
152                 target->t_address = $3;
153         }
154         ;
155
156 initiator_name: INITIATOR_NAME EQUALS STR
157         {
158                 if (target->t_initiator_name != NULL)
159                         xo_errx(1, "duplicated InitiatorName at line %d", lineno);
160                 target->t_initiator_name = $3;
161         }
162         ;
163
164 initiator_address:      INITIATOR_ADDRESS EQUALS STR
165         {
166                 if (target->t_initiator_address != NULL)
167                         xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
168                 target->t_initiator_address = $3;
169         }
170         ;
171
172 initiator_alias:        INITIATOR_ALIAS EQUALS STR
173         {
174                 if (target->t_initiator_alias != NULL)
175                         xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
176                 target->t_initiator_alias = $3;
177         }
178         ;
179
180 user:           USER EQUALS STR
181         {
182                 if (target->t_user != NULL)
183                         xo_errx(1, "duplicated chapIName at line %d", lineno);
184                 target->t_user = $3;
185         }
186         ;
187
188 secret:         SECRET EQUALS STR
189         {
190                 if (target->t_secret != NULL)
191                         xo_errx(1, "duplicated chapSecret at line %d", lineno);
192                 target->t_secret = $3;
193         }
194         ;
195
196 mutual_user:    MUTUAL_USER EQUALS STR
197         {
198                 if (target->t_mutual_user != NULL)
199                         xo_errx(1, "duplicated tgtChapName at line %d", lineno);
200                 target->t_mutual_user = $3;
201         }
202         ;
203
204 mutual_secret:  MUTUAL_SECRET EQUALS STR
205         {
206                 if (target->t_mutual_secret != NULL)
207                         xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
208                 target->t_mutual_secret = $3;
209         }
210         ;
211
212 auth_method:    AUTH_METHOD EQUALS STR
213         {
214                 if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
215                         xo_errx(1, "duplicated AuthMethod at line %d", lineno);
216                 if (strcasecmp($3, "none") == 0)
217                         target->t_auth_method = AUTH_METHOD_NONE;
218                 else if (strcasecmp($3, "chap") == 0)
219                         target->t_auth_method = AUTH_METHOD_CHAP;
220                 else
221                         xo_errx(1, "invalid AuthMethod at line %d; "
222                             "must be either \"none\" or \"CHAP\"", lineno);
223         }
224         ;
225
226 header_digest:  HEADER_DIGEST EQUALS STR
227         {
228                 if (target->t_header_digest != DIGEST_UNSPECIFIED)
229                         xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
230                 if (strcasecmp($3, "none") == 0)
231                         target->t_header_digest = DIGEST_NONE;
232                 else if (strcasecmp($3, "CRC32C") == 0)
233                         target->t_header_digest = DIGEST_CRC32C;
234                 else
235                         xo_errx(1, "invalid HeaderDigest at line %d; "
236                             "must be either \"none\" or \"CRC32C\"", lineno);
237         }
238         ;
239
240 data_digest:    DATA_DIGEST EQUALS STR
241         {
242                 if (target->t_data_digest != DIGEST_UNSPECIFIED)
243                         xo_errx(1, "duplicated DataDigest at line %d", lineno);
244                 if (strcasecmp($3, "none") == 0)
245                         target->t_data_digest = DIGEST_NONE;
246                 else if (strcasecmp($3, "CRC32C") == 0)
247                         target->t_data_digest = DIGEST_CRC32C;
248                 else
249                         xo_errx(1, "invalid DataDigest at line %d; "
250                             "must be either \"none\" or \"CRC32C\"", lineno);
251         }
252         ;
253
254 session_type:   SESSION_TYPE EQUALS STR
255         {
256                 if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
257                         xo_errx(1, "duplicated SessionType at line %d", lineno);
258                 if (strcasecmp($3, "normal") == 0)
259                         target->t_session_type = SESSION_TYPE_NORMAL;
260                 else if (strcasecmp($3, "discovery") == 0)
261                         target->t_session_type = SESSION_TYPE_DISCOVERY;
262                 else
263                         xo_errx(1, "invalid SessionType at line %d; "
264                             "must be either \"normal\" or \"discovery\"", lineno);
265         }
266         ;
267
268 enable:         ENABLE EQUALS STR
269         {
270                 if (target->t_enable != ENABLE_UNSPECIFIED)
271                         xo_errx(1, "duplicated enable at line %d", lineno);
272                 target->t_enable = parse_enable($3);
273                 if (target->t_enable == ENABLE_UNSPECIFIED)
274                         xo_errx(1, "invalid enable at line %d; "
275                             "must be either \"on\" or \"off\"", lineno);
276         }
277         ;
278
279 offload:        OFFLOAD EQUALS STR
280         {
281                 if (target->t_offload != NULL)
282                         xo_errx(1, "duplicated offload at line %d", lineno);
283                 target->t_offload = $3;
284         }
285         ;
286
287 protocol:       PROTOCOL EQUALS STR
288         {
289                 if (target->t_protocol != PROTOCOL_UNSPECIFIED)
290                         xo_errx(1, "duplicated protocol at line %d", lineno);
291                 if (strcasecmp($3, "iscsi") == 0)
292                         target->t_protocol = PROTOCOL_ISCSI;
293                 else if (strcasecmp($3, "iser") == 0)
294                         target->t_protocol = PROTOCOL_ISER;
295                 else
296                         xo_errx(1, "invalid protocol at line %d; "
297                             "must be either \"iscsi\" or \"iser\"", lineno);
298         }
299         ;
300
301 ignored:        IGNORED EQUALS STR
302         {
303                 xo_warnx("obsolete statement ignored at line %d", lineno);
304         }
305         ;
306
307 dscp:           DSCP EQUALS STR
308         {
309                 uint64_t tmp;
310
311                 if (target->t_dscp != -1)
312                         xo_errx(1, "duplicated dscp at line %d", lineno);
313                 if (strcmp($3, "0x") == 0) {
314                         tmp = strtol($3 + 2, NULL, 16);
315                 } else if (expand_number($3, &tmp) != 0) {
316                         yyerror("invalid numeric value");
317                         free($3);
318                         return(1);
319                 }
320                 if (tmp >= 0x40) {
321                         yyerror("invalid dscp value");
322                         return(1);
323                 }
324
325                 target->t_dscp = tmp;
326         }
327         | DSCP EQUALS BE        { target->t_dscp = IPTOS_DSCP_CS0  >> 2 ; }
328         | DSCP EQUALS EF        { target->t_dscp = IPTOS_DSCP_EF   >> 2 ; }
329         | DSCP EQUALS CS0       { target->t_dscp = IPTOS_DSCP_CS0  >> 2 ; }
330         | DSCP EQUALS CS1       { target->t_dscp = IPTOS_DSCP_CS1  >> 2 ; }
331         | DSCP EQUALS CS2       { target->t_dscp = IPTOS_DSCP_CS2  >> 2 ; }
332         | DSCP EQUALS CS3       { target->t_dscp = IPTOS_DSCP_CS3  >> 2 ; }
333         | DSCP EQUALS CS4       { target->t_dscp = IPTOS_DSCP_CS4  >> 2 ; }
334         | DSCP EQUALS CS5       { target->t_dscp = IPTOS_DSCP_CS5  >> 2 ; }
335         | DSCP EQUALS CS6       { target->t_dscp = IPTOS_DSCP_CS6  >> 2 ; }
336         | DSCP EQUALS CS7       { target->t_dscp = IPTOS_DSCP_CS7  >> 2 ; }
337         | DSCP EQUALS AF11      { target->t_dscp = IPTOS_DSCP_AF11 >> 2 ; }
338         | DSCP EQUALS AF12      { target->t_dscp = IPTOS_DSCP_AF12 >> 2 ; }
339         | DSCP EQUALS AF13      { target->t_dscp = IPTOS_DSCP_AF13 >> 2 ; }
340         | DSCP EQUALS AF21      { target->t_dscp = IPTOS_DSCP_AF21 >> 2 ; }
341         | DSCP EQUALS AF22      { target->t_dscp = IPTOS_DSCP_AF22 >> 2 ; }
342         | DSCP EQUALS AF23      { target->t_dscp = IPTOS_DSCP_AF23 >> 2 ; }
343         | DSCP EQUALS AF31      { target->t_dscp = IPTOS_DSCP_AF31 >> 2 ; }
344         | DSCP EQUALS AF32      { target->t_dscp = IPTOS_DSCP_AF32 >> 2 ; }
345         | DSCP EQUALS AF33      { target->t_dscp = IPTOS_DSCP_AF33 >> 2 ; }
346         | DSCP EQUALS AF41      { target->t_dscp = IPTOS_DSCP_AF41 >> 2 ; }
347         | DSCP EQUALS AF42      { target->t_dscp = IPTOS_DSCP_AF42 >> 2 ; }
348         | DSCP EQUALS AF43      { target->t_dscp = IPTOS_DSCP_AF43 >> 2 ; }
349         ;
350
351 pcp:    PCP EQUALS STR
352         {
353                 uint64_t tmp;
354
355                 if (target->t_pcp != -1)
356                         xo_errx(1, "duplicated pcp at line %d", lineno);
357
358                 if (expand_number($3, &tmp) != 0) {
359                         yyerror("invalid numeric value");
360                         free($3);
361                         return(1);
362                 }
363                 if (!((tmp >=0) && (tmp <= 7))) {
364                         yyerror("invalid pcp value");
365                         return(1);
366                 }
367
368                 target->t_pcp = tmp;
369         }
370         ;
371
372 %%
373
374 void
375 yyerror(const char *str)
376 {
377
378         xo_errx(1, "error in configuration file at line %d near '%s': %s",
379             lineno, yytext, str);
380 }
381
382 static void
383 check_perms(const char *path)
384 {
385         struct stat sb;
386         int error;
387
388         error = stat(path, &sb);
389         if (error != 0) {
390                 xo_warn("stat");
391                 return;
392         }
393         if (sb.st_mode & S_IWOTH) {
394                 xo_warnx("%s is world-writable", path);
395         } else if (sb.st_mode & S_IROTH) {
396                 xo_warnx("%s is world-readable", path);
397         } else if (sb.st_mode & S_IXOTH) {
398                 /*
399                  * Ok, this one doesn't matter, but still do it,
400                  * just for consistency.
401                  */
402                 xo_warnx("%s is world-executable", path);
403         }
404
405         /*
406          * XXX: Should we also check for owner != 0?
407          */
408 }
409
410 struct conf *
411 conf_new_from_file(const char *path)
412 {
413         int error;
414
415         conf = conf_new();
416         target = target_new(conf);
417
418         yyin = fopen(path, "r");
419         if (yyin == NULL)
420                 xo_err(1, "unable to open configuration file %s", path);
421         check_perms(path);
422         lineno = 1;
423         yyrestart(yyin);
424         error = yyparse();
425         assert(error == 0);
426         fclose(yyin);
427
428         assert(target->t_nickname == NULL);
429         target_delete(target);
430
431         conf_verify(conf);
432
433         return (conf);
434 }