1919#include "alloc-util.h"
2020#include "build.h"
2121#include "device-nodes.h"
22+ #include "extract-word.h"
2223#include "fd-util.h"
2324#include "scsi_id.h"
2425#include "string-util.h"
26+ #include "strv.h"
2527#include "strxcpyx.h"
2628#include "udev-util.h"
2729
@@ -90,50 +92,6 @@ static void set_type(const char *from, char *to, size_t len) {
9092 strscpy (to , len , type );
9193}
9294
93- /*
94- * get_value:
95- *
96- * buf points to an '=' followed by a quoted string ("foo") or a string ending
97- * with a space or ','.
98- *
99- * Return a pointer to the NUL terminated string, returns NULL if no
100- * matches.
101- */
102- static char * get_value (char * * buffer ) {
103- static const char * quote_string = "\"\n" ;
104- static const char * comma_string = ",\n" ;
105- char * val ;
106- const char * end ;
107-
108- if (* * buffer == '"' ) {
109- /*
110- * skip leading quote, terminate when quote seen
111- */
112- (* buffer )++ ;
113- end = quote_string ;
114- } else
115- end = comma_string ;
116- val = strsep (buffer , end );
117- if (val && end == quote_string )
118- /*
119- * skip trailing quote
120- */
121- (* buffer )++ ;
122-
123- while (isspace (* * buffer ))
124- (* buffer )++ ;
125-
126- return val ;
127- }
128-
129- static int argc_count (char * opts ) {
130- int i = 0 ;
131- while (* opts != '\0' )
132- if (* opts ++ == ' ' )
133- i ++ ;
134- return i ;
135- }
136-
13795/*
13896 * get_file_options:
13997 *
@@ -145,14 +103,12 @@ static int argc_count(char *opts) {
145103 */
146104static int get_file_options (const char * vendor , const char * model ,
147105 int * argc , char * * * newargv ) {
148- _cleanup_free_ char * buffer = NULL ;
106+ _cleanup_free_ char * buffer = NULL ,
107+ * vendor_in = NULL , * model_in = NULL , * options_in = NULL ; /* read in from file */
108+ _cleanup_strv_free_ char * * options_argv = NULL ;
149109 _cleanup_fclose_ FILE * f ;
150- char * buf ;
151- char * str1 ;
152- char * vendor_in , * model_in , * options_in ; /* read in from file */
153- int lineno ;
154- int c ;
155- int retval = 0 ;
110+ const char * buf ;
111+ int lineno , r ;
156112
157113 f = fopen (config_file , "re" );
158114 if (!f ) {
@@ -176,16 +132,16 @@ static int get_file_options(const char *vendor, const char *model,
176132 * newargv = NULL ;
177133 lineno = 0 ;
178134 for (;;) {
135+ _cleanup_free_ char * key = NULL , * value = NULL ;
136+
179137 vendor_in = model_in = options_in = NULL ;
180138
181139 buf = fgets (buffer , MAX_BUFFER_LEN , f );
182140 if (!buf )
183141 break ;
184142 lineno ++ ;
185- if (buf [strlen (buffer ) - 1 ] != '\n' ) {
186- log_error ("Config file line %d too long" , lineno );
187- break ;
188- }
143+ if (buf [strlen (buffer ) - 1 ] != '\n' )
144+ return log_error_errno (SYNTHETIC_ERRNO (EINVAL ), "Config file line %d too long" , lineno );
189145
190146 while (isspace (* buf ))
191147 buf ++ ;
@@ -198,44 +154,36 @@ static int get_file_options(const char *vendor, const char *model,
198154 if (* buf == '#' )
199155 continue ;
200156
201- str1 = strsep (& buf , "=" );
202- if (str1 && strcaseeq (str1 , "VENDOR" )) {
203- str1 = get_value (& buf );
204- if (!str1 ) {
205- retval = log_oom ();
206- break ;
207- }
208- vendor_in = str1 ;
209-
210- str1 = strsep (& buf , "=" );
211- if (str1 && strcaseeq (str1 , "MODEL" )) {
212- str1 = get_value (& buf );
213- if (!str1 ) {
214- retval = log_oom ();
215- break ;
216- }
217- model_in = str1 ;
218- str1 = strsep (& buf , "=" );
219- }
220- }
157+ r = extract_many_words (& buf , "=\",\n" , 0 , & key , & value , NULL );
158+ if (r < 2 )
159+ return log_error_errno (SYNTHETIC_ERRNO (EINVAL ), "Error parsing config file line %d '%s'" , lineno , buffer );
221160
222- if (str1 && strcaseeq (str1 , "OPTIONS" )) {
223- str1 = get_value (& buf );
224- if (!str1 ) {
225- retval = log_oom ();
226- break ;
161+ if (strcaseeq (key , "VENDOR" )) {
162+ vendor_in = TAKE_PTR (value );
163+
164+ key = mfree (key );
165+ r = extract_many_words (& buf , "=\",\n" , 0 , & key , & value , NULL );
166+ if (r < 2 )
167+ return log_error_errno (SYNTHETIC_ERRNO (EINVAL ), "Error parsing config file line %d '%s'" , lineno , buffer );
168+
169+ if (strcaseeq (key , "MODEL" )) {
170+ model_in = TAKE_PTR (value );
171+
172+ key = mfree (key );
173+ r = extract_many_words (& buf , "=\",\n" , 0 , & key , & value , NULL );
174+ if (r < 2 )
175+ return log_error_errno (SYNTHETIC_ERRNO (EINVAL ), "Error parsing config file line %d '%s'" , lineno , buffer );
227176 }
228- options_in = str1 ;
229177 }
230178
179+ if (strcaseeq (key , "OPTIONS" ))
180+ options_in = TAKE_PTR (value );
181+
231182 /*
232183 * Only allow: [vendor=foo[,model=bar]]options=stuff
233184 */
234- if (!options_in || (!vendor_in && model_in )) {
235- log_error ("Error parsing config file line %d '%s'" , lineno , buffer );
236- retval = -1 ;
237- break ;
238- }
185+ if (!options_in || (!vendor_in && model_in ))
186+ return log_error_errno (SYNTHETIC_ERRNO (EINVAL ), "Error parsing config file line %d '%s'" , lineno , buffer );
239187 if (!vendor ) {
240188 if (!vendor_in )
241189 break ;
@@ -251,39 +199,30 @@ static int get_file_options(const char *vendor, const char *model,
251199 */
252200 break ;
253201 }
254- }
255202
256- if (retval == 0 ) {
257- if (vendor_in != NULL || model_in != NULL ||
258- options_in != NULL ) {
259- /*
260- * Something matched. Allocate newargv, and store
261- * values found in options_in.
262- */
263- strcpy (buffer , options_in );
264- c = argc_count (buffer ) + 2 ;
265- * newargv = calloc (c , sizeof (* * newargv ));
266- if (!* newargv )
267- retval = log_oom ();
268- else {
269- * argc = c ;
270- c = 0 ;
271- /*
272- * argv[0] at 0 is skipped by getopt, but
273- * store the buffer address there for
274- * later freeing
275- */
276- (* newargv )[c ] = buffer ;
277- for (c = 1 ; c < * argc ; c ++ )
278- (* newargv )[c ] = strsep (& buffer , " \t" );
279- buffer = NULL ;
280- }
281- } else {
282- /* No matches */
283- retval = 1 ;
284- }
203+ vendor_in = mfree (vendor_in );
204+ model_in = mfree (model_in );
205+ options_in = mfree (options_in );
206+
285207 }
286- return retval ;
208+
209+ if (vendor_in == NULL && model_in == NULL && options_in == NULL )
210+ return 1 ; /* No matches */
211+
212+ /*
213+ * Something matched. Allocate newargv, and store
214+ * values found in options_in.
215+ */
216+ options_argv = strv_split (options_in , " \t" );
217+ if (!options_argv )
218+ return log_oom ();
219+ r = strv_prepend (& options_argv , "" ); /* getopt skips over argv[0] */
220+ if (r < 0 )
221+ return r ;
222+ * newargv = TAKE_PTR (options_argv );
223+ * argc = strv_length (* newargv );
224+
225+ return 0 ;
287226}
288227
289228static void help (void ) {
@@ -391,9 +330,9 @@ static int set_options(int argc, char **argv,
391330}
392331
393332static int per_dev_options (struct scsi_id_device * dev_scsi , int * good_bad , int * page_code ) {
333+ _cleanup_strv_free_ char * * newargv = NULL ;
394334 int retval ;
395335 int newargc ;
396- char * * newargv = NULL ;
397336 int option ;
398337
399338 * good_bad = all_good ;
@@ -436,10 +375,6 @@ static int per_dev_options(struct scsi_id_device *dev_scsi, int *good_bad, int *
436375 }
437376 }
438377
439- if (newargv ) {
440- free (newargv [0 ]);
441- free (newargv );
442- }
443378 return retval ;
444379}
445380
@@ -543,10 +478,10 @@ static int scsi_id(char *maj_min_dev) {
543478}
544479
545480int main (int argc , char * * argv ) {
481+ _cleanup_strv_free_ char * * newargv = NULL ;
546482 int retval = 0 ;
547483 char maj_min_dev [MAX_PATH_LEN ];
548484 int newargc ;
549- char * * newargv = NULL ;
550485
551486 log_set_target (LOG_TARGET_AUTO );
552487 udev_parse_config ();
@@ -585,10 +520,6 @@ int main(int argc, char **argv) {
585520 retval = scsi_id (maj_min_dev );
586521
587522exit :
588- if (newargv ) {
589- free (newargv [0 ]);
590- free (newargv );
591- }
592523 log_close ();
593524 return retval ;
594525}
0 commit comments