cmdline.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/lib/cmdline.c
  4. * Helper functions generally used for parsing kernel command line
  5. * and module options.
  6. *
  7. * Code and copyrights come from init/main.c and arch/i386/kernel/setup.c.
  8. *
  9. * GNU Indent formatting options for this file: -kr -i8 -npsl -pcs
  10. */
  11. #include <dragonstub/linux/const.h>
  12. #include <dragonstub/dragonstub.h>
  13. #include <dragonstub/linux/ctype.h>
  14. /*
  15. * If a hyphen was found in get_option, this will handle the
  16. * range of numbers, M-N. This will expand the range and insert
  17. * the values[M, M+1, ..., N] into the ints array in get_options.
  18. */
  19. static int get_range(char **str, int *pint, int n)
  20. {
  21. int x, inc_counter, upper_range;
  22. (*str)++;
  23. upper_range = simple_strtol((*str), NULL, 0);
  24. inc_counter = upper_range - *pint;
  25. for (x = *pint; n && x < upper_range; x++, n--)
  26. *pint++ = x;
  27. return inc_counter;
  28. }
  29. /**
  30. * get_option - Parse integer from an option string
  31. * @str: option string
  32. * @pint: (optional output) integer value parsed from @str
  33. *
  34. * Read an int from an option string; if available accept a subsequent
  35. * comma as well.
  36. *
  37. * When @pint is NULL the function can be used as a validator of
  38. * the current option in the string.
  39. *
  40. * Return values:
  41. * 0 - no int in string
  42. * 1 - int found, no subsequent comma
  43. * 2 - int found including a subsequent comma
  44. * 3 - hyphen found to denote a range
  45. *
  46. * Leading hyphen without integer is no integer case, but we consume it
  47. * for the sake of simplification.
  48. */
  49. int get_option(char **str, int *pint)
  50. {
  51. char *cur = *str;
  52. int value;
  53. if (!cur || !(*cur))
  54. return 0;
  55. if (*cur == '-')
  56. value = -simple_strtoull(++cur, str, 0);
  57. else
  58. value = simple_strtoull(cur, str, 0);
  59. if (pint)
  60. *pint = value;
  61. if (cur == *str)
  62. return 0;
  63. if (**str == ',') {
  64. (*str)++;
  65. return 2;
  66. }
  67. if (**str == '-')
  68. return 3;
  69. return 1;
  70. }
  71. /**
  72. * get_options - Parse a string into a list of integers
  73. * @str: String to be parsed
  74. * @nints: size of integer array
  75. * @ints: integer array (must have room for at least one element)
  76. *
  77. * This function parses a string containing a comma-separated
  78. * list of integers, a hyphen-separated range of _positive_ integers,
  79. * or a combination of both. The parse halts when the array is
  80. * full, or when no more numbers can be retrieved from the
  81. * string.
  82. *
  83. * When @nints is 0, the function just validates the given @str and
  84. * returns the amount of parseable integers as described below.
  85. *
  86. * Returns:
  87. *
  88. * The first element is filled by the number of collected integers
  89. * in the range. The rest is what was parsed from the @str.
  90. *
  91. * Return value is the character in the string which caused
  92. * the parse to end (typically a null terminator, if @str is
  93. * completely parseable).
  94. */
  95. char *get_options(const char *str, int nints, int *ints)
  96. {
  97. bool validate = (nints == 0);
  98. int res, i = 1;
  99. while (i < nints || validate) {
  100. int *pint = validate ? ints : ints + i;
  101. res = get_option((char **)&str, pint);
  102. if (res == 0)
  103. break;
  104. if (res == 3) {
  105. int n = validate ? 0 : nints - i;
  106. int range_nums;
  107. range_nums = get_range((char **)&str, pint, n);
  108. if (range_nums < 0)
  109. break;
  110. /*
  111. * Decrement the result by one to leave out the
  112. * last number in the range. The next iteration
  113. * will handle the upper number in the range
  114. */
  115. i += (range_nums - 1);
  116. }
  117. i++;
  118. if (res == 1)
  119. break;
  120. }
  121. ints[0] = i - 1;
  122. return (char *)str;
  123. }
  124. /**
  125. * memparse - parse a string with mem suffixes into a number
  126. * @ptr: Where parse begins
  127. * @retptr: (output) Optional pointer to next char after parse completes
  128. *
  129. * Parses a string into a number. The number stored at @ptr is
  130. * potentially suffixed with K, M, G, T, P, E.
  131. */
  132. unsigned long long memparse(const char *ptr, char **retptr)
  133. {
  134. char *endptr; /* local pointer to end of parsed string */
  135. unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
  136. switch (*endptr) {
  137. case 'E':
  138. case 'e':
  139. ret <<= 10;
  140. fallthrough;
  141. case 'P':
  142. case 'p':
  143. ret <<= 10;
  144. fallthrough;
  145. case 'T':
  146. case 't':
  147. ret <<= 10;
  148. fallthrough;
  149. case 'G':
  150. case 'g':
  151. ret <<= 10;
  152. fallthrough;
  153. case 'M':
  154. case 'm':
  155. ret <<= 10;
  156. fallthrough;
  157. case 'K':
  158. case 'k':
  159. ret <<= 10;
  160. endptr++;
  161. fallthrough;
  162. default:
  163. break;
  164. }
  165. if (retptr)
  166. *retptr = endptr;
  167. return ret;
  168. }
  169. /*
  170. * Parse a string to get a param value pair.
  171. * You can use " around spaces, but can't escape ".
  172. * Hyphens and underscores equivalent in parameter names.
  173. */
  174. char *next_arg(char *args, char **param, char **val)
  175. {
  176. unsigned int i, equals = 0;
  177. int in_quote = 0, quoted = 0;
  178. if (*args == '"') {
  179. args++;
  180. in_quote = 1;
  181. quoted = 1;
  182. }
  183. for (i = 0; args[i]; i++) {
  184. if (isspace(args[i]) && !in_quote)
  185. break;
  186. if (equals == 0) {
  187. if (args[i] == '=')
  188. equals = i;
  189. }
  190. if (args[i] == '"')
  191. in_quote = !in_quote;
  192. }
  193. *param = args;
  194. if (!equals)
  195. *val = NULL;
  196. else {
  197. args[equals] = '\0';
  198. *val = args + equals + 1;
  199. /* Don't include quotes in value. */
  200. if (**val == '"') {
  201. (*val)++;
  202. if (args[i - 1] == '"')
  203. args[i - 1] = '\0';
  204. }
  205. }
  206. if (quoted && i > 0 && args[i - 1] == '"')
  207. args[i - 1] = '\0';
  208. if (args[i]) {
  209. args[i] = '\0';
  210. args += i + 1;
  211. } else
  212. args += i;
  213. /* Chew up trailing spaces. */
  214. return skip_spaces(args);
  215. }