archive_cmdline.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*-
  2. * Copyright (c) 2012 Michihiro NAKAJIMA
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "archive_platform.h"
  26. __FBSDID("$FreeBSD$");
  27. #ifdef HAVE_STRING_H
  28. # include <string.h>
  29. #endif
  30. #ifdef HAVE_STDLIB_H
  31. # include <stdlib.h>
  32. #endif
  33. #include "archive.h"
  34. #include "archive_cmdline_private.h"
  35. #include "archive_string.h"
  36. static int cmdline_set_path(struct archive_cmdline *, const char *);
  37. static int cmdline_add_arg(struct archive_cmdline *, const char *);
  38. static ssize_t
  39. extract_quotation(struct archive_string *as, const char *p)
  40. {
  41. const char *s;
  42. for (s = p + 1; *s;) {
  43. if (*s == '\\') {
  44. if (s[1] != '\0') {
  45. archive_strappend_char(as, s[1]);
  46. s += 2;
  47. } else
  48. s++;
  49. } else if (*s == '"')
  50. break;
  51. else {
  52. archive_strappend_char(as, s[0]);
  53. s++;
  54. }
  55. }
  56. if (*s != '"')
  57. return (ARCHIVE_FAILED);/* Invalid sequence. */
  58. return ((ssize_t)(s + 1 - p));
  59. }
  60. static ssize_t
  61. get_argument(struct archive_string *as, const char *p)
  62. {
  63. const char *s = p;
  64. archive_string_empty(as);
  65. /* Skip beginning space characters. */
  66. while (*s != '\0' && *s == ' ')
  67. s++;
  68. /* Copy non-space characters. */
  69. while (*s != '\0' && *s != ' ') {
  70. if (*s == '\\') {
  71. if (s[1] != '\0') {
  72. archive_strappend_char(as, s[1]);
  73. s += 2;
  74. } else {
  75. s++;/* Ignore this character.*/
  76. break;
  77. }
  78. } else if (*s == '"') {
  79. ssize_t q = extract_quotation(as, s);
  80. if (q < 0)
  81. return (ARCHIVE_FAILED);/* Invalid sequence. */
  82. s += q;
  83. } else {
  84. archive_strappend_char(as, s[0]);
  85. s++;
  86. }
  87. }
  88. return ((ssize_t)(s - p));
  89. }
  90. /*
  91. * Set up command line arguments.
  92. * Returns ARChIVE_OK if everything okey.
  93. * Returns ARChIVE_FAILED if there is a lack of the `"' terminator or an
  94. * empty command line.
  95. * Returns ARChIVE_FATAL if no memory.
  96. */
  97. int
  98. __archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
  99. {
  100. struct archive_string as;
  101. const char *p;
  102. ssize_t al;
  103. int r;
  104. archive_string_init(&as);
  105. /* Get first argument as a command path. */
  106. al = get_argument(&as, cmd);
  107. if (al < 0) {
  108. r = ARCHIVE_FAILED;/* Invalid sequence. */
  109. goto exit_function;
  110. }
  111. if (archive_strlen(&as) == 0) {
  112. r = ARCHIVE_FAILED;/* An empty command path. */
  113. goto exit_function;
  114. }
  115. r = cmdline_set_path(data, as.s);
  116. if (r != ARCHIVE_OK)
  117. goto exit_function;
  118. p = strrchr(as.s, '/');
  119. if (p == NULL)
  120. p = as.s;
  121. else
  122. p++;
  123. r = cmdline_add_arg(data, p);
  124. if (r != ARCHIVE_OK)
  125. goto exit_function;
  126. cmd += al;
  127. for (;;) {
  128. al = get_argument(&as, cmd);
  129. if (al < 0) {
  130. r = ARCHIVE_FAILED;/* Invalid sequence. */
  131. goto exit_function;
  132. }
  133. if (al == 0)
  134. break;
  135. cmd += al;
  136. if (archive_strlen(&as) == 0 && *cmd == '\0')
  137. break;
  138. r = cmdline_add_arg(data, as.s);
  139. if (r != ARCHIVE_OK)
  140. goto exit_function;
  141. }
  142. r = ARCHIVE_OK;
  143. exit_function:
  144. archive_string_free(&as);
  145. return (r);
  146. }
  147. /*
  148. * Set the program path.
  149. */
  150. static int
  151. cmdline_set_path(struct archive_cmdline *data, const char *path)
  152. {
  153. char *newptr;
  154. newptr = realloc(data->path, strlen(path) + 1);
  155. if (newptr == NULL)
  156. return (ARCHIVE_FATAL);
  157. data->path = newptr;
  158. strcpy(data->path, path);
  159. return (ARCHIVE_OK);
  160. }
  161. /*
  162. * Add a argument for the program.
  163. */
  164. static int
  165. cmdline_add_arg(struct archive_cmdline *data, const char *arg)
  166. {
  167. char **newargv;
  168. if (data->path == NULL)
  169. return (ARCHIVE_FAILED);
  170. newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *));
  171. if (newargv == NULL)
  172. return (ARCHIVE_FATAL);
  173. data->argv = newargv;
  174. data->argv[data->argc] = strdup(arg);
  175. if (data->argv[data->argc] == NULL)
  176. return (ARCHIVE_FATAL);
  177. /* Set the terminator of argv. */
  178. data->argv[++data->argc] = NULL;
  179. return (ARCHIVE_OK);
  180. }
  181. struct archive_cmdline *
  182. __archive_cmdline_allocate(void)
  183. {
  184. return (struct archive_cmdline *)
  185. calloc(1, sizeof(struct archive_cmdline));
  186. }
  187. /*
  188. * Release the resources.
  189. */
  190. int
  191. __archive_cmdline_free(struct archive_cmdline *data)
  192. {
  193. if (data) {
  194. free(data->path);
  195. if (data->argv != NULL) {
  196. int i;
  197. for (i = 0; data->argv[i] != NULL; i++)
  198. free(data->argv[i]);
  199. free(data->argv);
  200. }
  201. free(data);
  202. }
  203. return (ARCHIVE_OK);
  204. }