PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/trunk/server-src/cmdline.c

#
C | 263 lines | 183 code | 38 blank | 42 comment | 62 complexity | f64b4a6fd5582cf2eab62b3ceff3ddb1 MD5 | raw file
  1. /*
  2. * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License version 2 as published
  6. * by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  11. * for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. *
  17. * Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
  18. * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
  19. *
  20. * Author: Dustin J. Mitchell <dustin@zmanda.com>
  21. */
  22. /*
  23. * $Id$
  24. *
  25. * Utility routines for handling command lines.
  26. */
  27. #include "amanda.h"
  28. #include <ctype.h>
  29. #include "match.h"
  30. #include "cmdline.h"
  31. #include "holding.h"
  32. dumpspec_t *
  33. dumpspec_new(
  34. char *host,
  35. char *disk,
  36. char *datestamp,
  37. char *level,
  38. char *write_timestamp)
  39. {
  40. dumpspec_t *rv;
  41. rv = g_new0(dumpspec_t, 1);
  42. if (host) rv->host = g_strdup(host);
  43. if (disk) rv->disk = g_strdup(disk);
  44. if (datestamp) rv->datestamp = g_strdup(datestamp);
  45. if (level) rv->level = g_strdup(level);
  46. if (write_timestamp) rv->write_timestamp = g_strdup(write_timestamp);
  47. return rv;
  48. }
  49. void
  50. dumpspec_free(
  51. dumpspec_t *dumpspec)
  52. {
  53. if (!dumpspec) return;
  54. if (dumpspec->host) free(dumpspec->host);
  55. if (dumpspec->disk) free(dumpspec->disk);
  56. if (dumpspec->datestamp) free(dumpspec->datestamp);
  57. if (dumpspec->level) free(dumpspec->level);
  58. if (dumpspec->write_timestamp) free(dumpspec->write_timestamp);
  59. free(dumpspec);
  60. }
  61. void
  62. dumpspec_list_free(
  63. GSList *dumpspec_list)
  64. {
  65. /* first free all of the individual dumpspecs */
  66. g_slist_foreach_nodata(dumpspec_list, dumpspec_free);
  67. /* then free the list itself */
  68. g_slist_free(dumpspec_list);
  69. }
  70. GSList *
  71. cmdline_parse_dumpspecs(
  72. int argc,
  73. char **argv,
  74. int flags)
  75. {
  76. dumpspec_t *dumpspec = NULL;
  77. GSList *list = NULL;
  78. char *errstr;
  79. char *name;
  80. int optind = 0;
  81. enum { ARG_GET_HOST, ARG_GET_DISK, ARG_GET_DATESTAMP, ARG_GET_LEVEL } arg_state = ARG_GET_HOST;
  82. while (optind < argc) {
  83. name = argv[optind];
  84. switch (arg_state) {
  85. case ARG_GET_HOST:
  86. arg_state = ARG_GET_DISK;
  87. dumpspec = dumpspec_new(name, NULL, NULL, NULL, NULL);
  88. list = g_slist_append(list, (gpointer)dumpspec);
  89. break;
  90. case ARG_GET_DISK:
  91. arg_state = ARG_GET_DATESTAMP;
  92. dumpspec->disk = g_strdup(name);
  93. break;
  94. case ARG_GET_DATESTAMP:
  95. arg_state = ARG_GET_LEVEL;
  96. if (!(flags & CMDLINE_PARSE_DATESTAMP)) continue;
  97. dumpspec->datestamp = g_strdup(name);
  98. break;
  99. case ARG_GET_LEVEL:
  100. arg_state = ARG_GET_HOST;
  101. if (!(flags & CMDLINE_PARSE_LEVEL)) continue;
  102. if (name[0] != '\0'
  103. && (errstr=validate_regexp(name)) != NULL) {
  104. error(_("bad level regex \"%s\": %s\n"), name, errstr);
  105. }
  106. dumpspec->level = g_strdup(name);
  107. break;
  108. }
  109. optind++;
  110. }
  111. /* if nothing was processed and the caller has requested it,
  112. * then add an "empty" element */
  113. if (list == NULL && (flags & CMDLINE_EMPTY_TO_WILDCARD)) {
  114. dumpspec = dumpspec_new("", "",
  115. (flags & CMDLINE_PARSE_DATESTAMP)?"":NULL,
  116. (flags & CMDLINE_PARSE_LEVEL)?"":NULL, "");
  117. list = g_slist_append(list, (gpointer)dumpspec);
  118. }
  119. return list;
  120. }
  121. char *
  122. cmdline_format_dumpspec(
  123. dumpspec_t *dumpspec)
  124. {
  125. if (!dumpspec) return NULL;
  126. return cmdline_format_dumpspec_components(
  127. dumpspec->host,
  128. dumpspec->disk,
  129. dumpspec->datestamp,
  130. dumpspec->level);
  131. }
  132. /* Quote str for shell interpretation, being conservative.
  133. * Any non-alphanumeric charcacters other than '.' and '/'
  134. * trigger surrounding single quotes, and single quotes and
  135. * backslashes within those single quotes are escaped.
  136. */
  137. static char *
  138. quote_dumpspec_string(char *str)
  139. {
  140. char *rv;
  141. char *p, *q;
  142. int len = 0;
  143. int need_single_quotes = 0;
  144. if (!str[0])
  145. return g_strdup("''"); /* special-case the empty string */
  146. for (p = str; *p; p++) {
  147. if (!isalnum((int)*p) && *p != '.' && *p != '/') need_single_quotes=1;
  148. if (*p == '\'' || *p == '\\') len++; /* extra byte for '\' */
  149. len++;
  150. }
  151. if (need_single_quotes) len += 2;
  152. q = rv = malloc(len+1);
  153. if (need_single_quotes) *(q++) = '\'';
  154. for (p = str; *p; p++) {
  155. if (*p == '\'' || *p == '\\') *(q++) = '\\';
  156. *(q++) = *p;
  157. }
  158. if (need_single_quotes) *(q++) = '\'';
  159. *(q++) = '\0';
  160. return rv;
  161. }
  162. char *
  163. cmdline_format_dumpspec_components(
  164. char *host,
  165. char *disk,
  166. char *datestamp,
  167. char *level)
  168. {
  169. GPtrArray *array = g_ptr_array_new();
  170. gchar **strings;
  171. char *ret = NULL;
  172. if (!host)
  173. goto out;
  174. g_ptr_array_add(array, quote_dumpspec_string(host));
  175. if (!disk)
  176. goto out;
  177. g_ptr_array_add(array, quote_dumpspec_string(disk));
  178. if (!datestamp)
  179. goto out;
  180. g_ptr_array_add(array, quote_dumpspec_string(datestamp));
  181. if (level)
  182. g_ptr_array_add(array, quote_dumpspec_string(level));
  183. out:
  184. g_ptr_array_add(array, NULL);
  185. strings = (gchar **) g_ptr_array_free(array, FALSE);
  186. /*
  187. * Note that if the only element of the GPtrArray is a NULL pointer, the
  188. * result will be an array with only a NULL pointer, in which case
  189. * g_strjoinv() will return an empty string. But we want to return NULL to
  190. * the caller in that case.
  191. */
  192. ret = (*strings) ? g_strjoinv(" ", strings) : NULL;
  193. g_strfreev(strings);
  194. return ret;
  195. }
  196. GSList *
  197. cmdline_match_holding(
  198. GSList *dumpspec_list)
  199. {
  200. dumpspec_t *de;
  201. GSList *li, *hi;
  202. GSList *holding_files;
  203. GSList *matching_files = NULL;
  204. dumpfile_t file;
  205. holding_files = holding_get_files(NULL, 1);
  206. for (hi = holding_files; hi != NULL; hi = hi->next) {
  207. /* TODO add level */
  208. if (!holding_file_get_dumpfile((char *)hi->data, &file)) continue;
  209. if (file.type != F_DUMPFILE) {
  210. dumpfile_free_data(&file);
  211. continue;
  212. }
  213. for (li = dumpspec_list; li != NULL; li = li->next) {
  214. de = (dumpspec_t *)(li->data);
  215. if (de->host && de->host[0] && !match_host(de->host, file.name)) continue;
  216. if (de->disk && de->disk[0] && !match_disk(de->disk, file.disk)) continue;
  217. if (de->datestamp && de->datestamp[0] && !match_datestamp(de->datestamp, file.datestamp)) continue;
  218. matching_files = g_slist_append(matching_files, g_strdup((char *)hi->data));
  219. break;
  220. }
  221. dumpfile_free_data(&file);
  222. }
  223. slist_free_full(holding_files, g_free);
  224. return matching_files;
  225. }