PageRenderTime 52ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/amanda261p2/server-src/cmdline.c

#
C | 261 lines | 194 code | 31 blank | 36 comment | 76 complexity | 0ea74536d1f36319f5dbba975bc16514 MD5 | raw file
  1. /*
  2. * Copyright (c) 2005-2008 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 Mathlida 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 <ctype.h>
  28. #include "amanda.h"
  29. #include "cmdline.h"
  30. #include "holding.h"
  31. dumpspec_t *
  32. dumpspec_new(
  33. char *host,
  34. char *disk,
  35. char *datestamp,
  36. char *level)
  37. {
  38. dumpspec_t *rv;
  39. rv = g_new0(dumpspec_t, 1);
  40. if (host) rv->host = stralloc(host);
  41. if (disk) rv->disk = stralloc(disk);
  42. if (datestamp) rv->datestamp = stralloc(datestamp);
  43. if (level) rv->level = stralloc(level);
  44. return rv;
  45. }
  46. void
  47. dumpspec_free(
  48. dumpspec_t *dumpspec)
  49. {
  50. if (!dumpspec) return;
  51. if (dumpspec->host) free(dumpspec->host);
  52. if (dumpspec->disk) free(dumpspec->disk);
  53. if (dumpspec->datestamp) free(dumpspec->datestamp);
  54. if (dumpspec->level) free(dumpspec->level);
  55. free(dumpspec);
  56. }
  57. void
  58. dumpspec_list_free(
  59. GSList *dumpspec_list)
  60. {
  61. /* first free all of the individual dumpspecs */
  62. g_slist_foreach_nodata(dumpspec_list, dumpspec_free);
  63. /* then free the list itself */
  64. g_slist_free(dumpspec_list);
  65. }
  66. GSList *
  67. cmdline_parse_dumpspecs(
  68. int argc,
  69. char **argv,
  70. int flags)
  71. {
  72. dumpspec_t *dumpspec = NULL;
  73. GSList *list = NULL;
  74. char *errstr;
  75. char *name;
  76. int optind = 0;
  77. enum { ARG_GET_HOST, ARG_GET_DISK, ARG_GET_DATESTAMP, ARG_GET_LEVEL } arg_state = ARG_GET_HOST;
  78. while (optind < argc) {
  79. name = argv[optind];
  80. switch (arg_state) {
  81. case ARG_GET_HOST:
  82. arg_state = ARG_GET_DISK;
  83. if (name[0] != '\0'
  84. && (errstr=validate_regexp(name)) != NULL) {
  85. error(_("bad hostname regex \"%s\": %s\n"), name, errstr);
  86. }
  87. dumpspec = dumpspec_new(name, 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. if (name[0] != '\0'
  93. && (errstr=validate_regexp(name)) != NULL) {
  94. error(_("bad diskname regex \"%s\": %s\n"), name, errstr);
  95. }
  96. dumpspec->disk = stralloc(name);
  97. break;
  98. case ARG_GET_DATESTAMP:
  99. arg_state = ARG_GET_LEVEL;
  100. if (!(flags & CMDLINE_PARSE_DATESTAMP)) continue;
  101. if (name[0] != '\0'
  102. && (errstr=validate_regexp(name)) != NULL) {
  103. error(_("bad datestamp regex \"%s\": %s\n"), name, errstr);
  104. }
  105. dumpspec->datestamp = stralloc(name);
  106. break;
  107. case ARG_GET_LEVEL:
  108. arg_state = ARG_GET_HOST;
  109. if (!(flags & CMDLINE_PARSE_LEVEL)) continue;
  110. if (name[0] != '\0'
  111. && (errstr=validate_regexp(name)) != NULL) {
  112. error(_("bad level regex \"%s\": %s\n"), name, errstr);
  113. }
  114. dumpspec->level = stralloc(name);
  115. break;
  116. }
  117. optind++;
  118. }
  119. /* if nothing was processed and the caller has requested it,
  120. * then add an "empty" element */
  121. if (list == NULL && (flags & CMDLINE_EMPTY_TO_WILDCARD)) {
  122. dumpspec = dumpspec_new("", "",
  123. (flags & CMDLINE_PARSE_DATESTAMP)?"":NULL,
  124. (flags & CMDLINE_PARSE_LEVEL)?"":NULL);
  125. list = g_slist_append(list, (gpointer)dumpspec);
  126. }
  127. return list;
  128. }
  129. char *
  130. cmdline_format_dumpspec(
  131. dumpspec_t *dumpspec)
  132. {
  133. if (!dumpspec) return NULL;
  134. return cmdline_format_dumpspec_components(
  135. dumpspec->host,
  136. dumpspec->disk,
  137. dumpspec->datestamp,
  138. dumpspec->level);
  139. }
  140. /* Quote str for shell interpretation, being conservative.
  141. * Any non-alphanumeric charcacters other than '.' and '/'
  142. * trigger surrounding single quotes, and single quotes and
  143. * backslashes within those single quotes are escaped.
  144. */
  145. static char *
  146. quote_dumpspec_string(char *str)
  147. {
  148. char *rv;
  149. char *p, *q;
  150. int len = 0;
  151. int need_single_quotes = 0;
  152. if (!str[0])
  153. return stralloc("''"); /* special-case the empty string */
  154. for (p = str; *p; p++) {
  155. if (!isalnum((int)*p) && *p != '.' && *p != '/') need_single_quotes=1;
  156. if (*p == '\'' || *p == '\\') len++; /* extra byte for '\' */
  157. len++;
  158. }
  159. if (need_single_quotes) len += 2;
  160. q = rv = malloc(len+1);
  161. if (need_single_quotes) *(q++) = '\'';
  162. for (p = str; *p; p++) {
  163. if (*p == '\'' || *p == '\\') *(q++) = '\\';
  164. *(q++) = *p;
  165. }
  166. if (need_single_quotes) *(q++) = '\'';
  167. *(q++) = '\0';
  168. return rv;
  169. }
  170. char *
  171. cmdline_format_dumpspec_components(
  172. char *host,
  173. char *disk,
  174. char *datestamp,
  175. char *level)
  176. {
  177. char *rv = NULL;
  178. host = host? quote_dumpspec_string(host):NULL;
  179. disk = disk? quote_dumpspec_string(disk):NULL;
  180. datestamp = datestamp? quote_dumpspec_string(datestamp):NULL;
  181. level = level? quote_dumpspec_string(level):NULL;
  182. if (host) {
  183. rv = host;
  184. host = NULL;
  185. if (disk) {
  186. rv = newvstralloc(rv, rv, " ", disk, NULL);
  187. if (datestamp) {
  188. rv = newvstralloc(rv, rv, " ", datestamp, NULL);
  189. if (level) {
  190. rv = newvstralloc(rv, rv, " ", level, NULL);
  191. }
  192. }
  193. }
  194. }
  195. if (host) amfree(host);
  196. if (disk) amfree(disk);
  197. if (datestamp) amfree(datestamp);
  198. if (level) amfree(level);
  199. return rv;
  200. }
  201. GSList *
  202. cmdline_match_holding(
  203. GSList *dumpspec_list)
  204. {
  205. dumpspec_t *de;
  206. GSList *li, *hi;
  207. GSList *holding_files;
  208. GSList *matching_files = NULL;
  209. dumpfile_t file;
  210. holding_files = holding_get_files(NULL, 1);
  211. for (hi = holding_files; hi != NULL; hi = hi->next) {
  212. /* TODO add level */
  213. if (!holding_file_get_dumpfile((char *)hi->data, &file)) continue;
  214. if (file.type != F_DUMPFILE) {
  215. dumpfile_free_data(&file);
  216. continue;
  217. }
  218. for (li = dumpspec_list; li != NULL; li = li->next) {
  219. de = (dumpspec_t *)(li->data);
  220. if (de->host && de->host[0] && !match_host(de->host, file.name)) continue;
  221. if (de->disk && de->disk[0] && !match_disk(de->disk, file.disk)) continue;
  222. if (de->datestamp && de->datestamp[0] && !match_datestamp(de->datestamp, file.datestamp)) continue;
  223. matching_files = g_slist_append(matching_files, g_strdup((char *)hi->data));
  224. break;
  225. }
  226. dumpfile_free_data(&file);
  227. }
  228. g_slist_free_full(holding_files);
  229. return matching_files;
  230. }