PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/3_3_0beta1/server-src/cmdline.c

#
C | 253 lines | 186 code | 31 blank | 36 comment | 66 complexity | 9598dd32b784b1faa05d3143ef40c9b9 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 = stralloc(host);
  43. if (disk) rv->disk = stralloc(disk);
  44. if (datestamp) rv->datestamp = stralloc(datestamp);
  45. if (level) rv->level = stralloc(level);
  46. if (write_timestamp) rv->write_timestamp = stralloc(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 = stralloc(name);
  93. break;
  94. case ARG_GET_DATESTAMP:
  95. arg_state = ARG_GET_LEVEL;
  96. if (!(flags & CMDLINE_PARSE_DATESTAMP)) continue;
  97. dumpspec->datestamp = stralloc(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 = stralloc(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 stralloc("''"); /* 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. char *rv = NULL;
  170. host = host? quote_dumpspec_string(host):NULL;
  171. disk = disk? quote_dumpspec_string(disk):NULL;
  172. datestamp = datestamp? quote_dumpspec_string(datestamp):NULL;
  173. level = level? quote_dumpspec_string(level):NULL;
  174. if (host) {
  175. rv = host;
  176. host = NULL;
  177. if (disk) {
  178. rv = newvstralloc(rv, rv, " ", disk, NULL);
  179. if (datestamp) {
  180. rv = newvstralloc(rv, rv, " ", datestamp, NULL);
  181. if (level) {
  182. rv = newvstralloc(rv, rv, " ", level, NULL);
  183. }
  184. }
  185. }
  186. }
  187. if (host) amfree(host);
  188. if (disk) amfree(disk);
  189. if (datestamp) amfree(datestamp);
  190. if (level) amfree(level);
  191. return rv;
  192. }
  193. GSList *
  194. cmdline_match_holding(
  195. GSList *dumpspec_list)
  196. {
  197. dumpspec_t *de;
  198. GSList *li, *hi;
  199. GSList *holding_files;
  200. GSList *matching_files = NULL;
  201. dumpfile_t file;
  202. holding_files = holding_get_files(NULL, 1);
  203. for (hi = holding_files; hi != NULL; hi = hi->next) {
  204. /* TODO add level */
  205. if (!holding_file_get_dumpfile((char *)hi->data, &file)) continue;
  206. if (file.type != F_DUMPFILE) {
  207. dumpfile_free_data(&file);
  208. continue;
  209. }
  210. for (li = dumpspec_list; li != NULL; li = li->next) {
  211. de = (dumpspec_t *)(li->data);
  212. if (de->host && de->host[0] && !match_host(de->host, file.name)) continue;
  213. if (de->disk && de->disk[0] && !match_disk(de->disk, file.disk)) continue;
  214. if (de->datestamp && de->datestamp[0] && !match_datestamp(de->datestamp, file.datestamp)) continue;
  215. matching_files = g_slist_append(matching_files, g_strdup((char *)hi->data));
  216. break;
  217. }
  218. dumpfile_free_data(&file);
  219. }
  220. slist_free_full(holding_files, g_free);
  221. return matching_files;
  222. }