PageRenderTime 59ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

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

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