mssh.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <getopt.h>
  5. #include <gtk/gtk.h>
  6. #include "config.h"
  7. #include "mssh-window.h"
  8. #define CONFFILE ".mssh_clusters"
  9. #define PKGINFO PACKAGE_NAME " " VERSION
  10. #define COPYRIGHT "Copyright (C) 2009 Bradley Smith <[email protected]>"
  11. static void on_mssh_destroy(GtkWidget *widget, gpointer data)
  12. {
  13. gtk_widget_hide(widget);
  14. gtk_main_quit();
  15. }
  16. void usage(const char *argv0)
  17. {
  18. fprintf(stderr, "%s\n", PKGINFO);
  19. fprintf(stderr, "%s\n", COPYRIGHT);
  20. fprintf(stderr, "An ssh client to issue the same commands to multiple servers\n\n");
  21. fprintf(stderr, "Usage: %s [OPTION]... (-a ALIAS | HOSTS)\n\n",
  22. argv0);
  23. fprintf(stderr,
  24. " -a, --alias=ALIAS Open hosts associated with named alias\n");
  25. fprintf(stderr,
  26. " -h, --help Display this help and exit\n");
  27. fprintf(stderr,
  28. " -V, --version Output version information and exit\n");
  29. fprintf(stderr, "\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
  30. exit(EXIT_FAILURE);
  31. }
  32. static char *fgetline(FILE *stream)
  33. {
  34. size_t len = 64;
  35. size_t pos = 0;
  36. char c;
  37. char *buf;
  38. if((buf = malloc(len)) == NULL)
  39. {
  40. perror("malloc");
  41. exit(EXIT_FAILURE);
  42. }
  43. while((c = fgetc(stream)) != EOF)
  44. {
  45. if(pos >= len)
  46. {
  47. len *= 2;
  48. if((buf = realloc(buf, len)) == NULL)
  49. {
  50. perror("realloc");
  51. exit(EXIT_FAILURE);
  52. }
  53. }
  54. if(c == '\n')
  55. {
  56. buf[pos++] = '\0';
  57. break;
  58. }
  59. else
  60. {
  61. buf[pos++] = c;
  62. }
  63. }
  64. if(c == EOF)
  65. {
  66. free(buf);
  67. return NULL;
  68. }
  69. return buf;
  70. }
  71. void append_alias(char *alias, GArray *hosts, GData **aliases, int lineno)
  72. {
  73. int i;
  74. GArray *fetched;
  75. if((fetched = g_datalist_get_data(aliases, alias)) == NULL)
  76. {
  77. printf("Line %d: Alias '%s' not defined\n", lineno, alias);
  78. exit(EXIT_FAILURE);
  79. }
  80. for(i = 0; i < fetched->len; i++)
  81. {
  82. g_array_append_val(hosts, g_array_index(fetched, char*, i));
  83. }
  84. }
  85. GData **parse_aliases(char *conffile)
  86. {
  87. FILE *file;
  88. char *line;
  89. int lineno = 0;
  90. GData **aliases = malloc(sizeof(GData*));
  91. g_datalist_init(aliases);
  92. if((file = fopen(conffile, "r")) == NULL)
  93. return aliases;
  94. while((line = fgetline(file)) != NULL)
  95. {
  96. char *sep, *alias, *hoststr, *tmp;
  97. GArray *hosts;
  98. lineno++;
  99. if(strcmp(line, "") == 0)
  100. continue;
  101. if((sep = strchr(line, ':')) == NULL)
  102. {
  103. printf("Line %d: Failed to parse line '%s'\n", lineno, line);
  104. exit(EXIT_FAILURE);
  105. }
  106. *sep = '\0';
  107. alias = line;
  108. hoststr = sep + 1;
  109. if((tmp = strtok(hoststr, " ")) == NULL)
  110. {
  111. printf("Line %d: Alias '%s' specifies no hosts\n", lineno,
  112. alias);
  113. exit(EXIT_FAILURE);
  114. }
  115. hosts = g_array_new(FALSE, TRUE, sizeof(char*));
  116. do
  117. {
  118. if(tmp[0] == '[' && tmp[strlen(tmp) - 1] == ']')
  119. {
  120. tmp++;
  121. tmp[strlen(tmp) - 1] = '\0';
  122. append_alias(tmp, hosts, aliases, lineno);
  123. }
  124. else
  125. g_array_append_val(hosts, tmp);
  126. }
  127. while((tmp = strtok(NULL, " ")) != NULL);
  128. g_datalist_set_data(aliases, alias, hosts);
  129. }
  130. return aliases;
  131. }
  132. int main(int argc, char* argv[], char* env[])
  133. {
  134. GtkWidget* window;
  135. int c, option_index = 0;
  136. char *home, *conffile;
  137. GData **aliases = NULL;
  138. GArray *hosts = NULL;
  139. static struct option long_options[] =
  140. {
  141. {"alias", required_argument, 0, 'a'},
  142. {"help", no_argument, 0, 'h'},
  143. {"version", no_argument, 0, 'V'},
  144. {0, 0, 0, 0}
  145. };
  146. if((home = getenv("HOME")) != NULL)
  147. {
  148. int len = strlen(home) + strlen(CONFFILE) + 2;
  149. conffile = malloc(len);
  150. snprintf(conffile, len, "%s/%s", home, CONFFILE);
  151. aliases = parse_aliases(conffile);
  152. free(conffile);
  153. }
  154. else
  155. {
  156. fprintf(stderr,
  157. "Warning: $HOME not set, not reading config file\n");
  158. }
  159. for(;;)
  160. {
  161. c = getopt_long(argc, argv, "a:hV", long_options, &option_index);
  162. if(c == -1)
  163. break;
  164. switch(c)
  165. {
  166. case 'a':
  167. if(aliases && (hosts = g_datalist_get_data(aliases,
  168. optarg)) == NULL)
  169. {
  170. fprintf(stderr, "Alias '%s' not found\n", optarg);
  171. usage(argv[0]);
  172. }
  173. break;
  174. case 'h':
  175. usage(argv[0]);
  176. break;
  177. case 'V':
  178. printf("%s\n\n", PKGINFO);
  179. printf("%s\n\n", COPYRIGHT);
  180. printf("Redistribution and use in source and binary forms, with or without\n");
  181. printf("modification, are permitted provided that the following conditions are met:\n");
  182. printf("\n");
  183. printf(" 1. Redistributions of source code must retain the copyright notice,\n");
  184. printf(" this list of conditions and the following disclaimer.\n");
  185. printf(" 2. Redistributions in binary form must reproduce the copyright notice,\n");
  186. printf(" this list of conditions and the following disclaimer in the\n");
  187. printf(" documentation and/or other materials provided with the distribution.\n");
  188. printf(" 3. The name of the author may not be used to endorse or promote\n");
  189. printf(" products derived from this software without specific prior written\n");
  190. printf(" permission.\n");
  191. printf("\n");
  192. printf("THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n");
  193. printf("IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n");
  194. printf("OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN\n");
  195. printf("NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n");
  196. printf("SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n");
  197. printf("TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n");
  198. printf("PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n");
  199. printf("LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n");
  200. printf("NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n");
  201. printf("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n");
  202. exit(EXIT_SUCCESS);
  203. break;
  204. case '?':
  205. printf("\n");
  206. usage(argv[0]);
  207. exit(EXIT_FAILURE);
  208. break;
  209. default:
  210. abort();
  211. }
  212. }
  213. if(hosts == NULL)
  214. {
  215. hosts = g_array_new(FALSE, TRUE, sizeof(char*));
  216. if (optind < argc)
  217. {
  218. while (optind < argc)
  219. {
  220. char *host = strdup(argv[optind++]);
  221. g_array_append_val(hosts, host);
  222. }
  223. }
  224. else
  225. {
  226. fprintf(stderr, "No hosts specified\n\n");
  227. usage(argv[0]);
  228. }
  229. }
  230. gtk_init(&argc, &argv);
  231. window = GTK_WIDGET(mssh_window_new());
  232. g_signal_connect(G_OBJECT(window), "destroy",
  233. G_CALLBACK(on_mssh_destroy), NULL);
  234. mssh_window_start_session(MSSH_WINDOW(window), env, hosts);
  235. gtk_widget_show_all(window);
  236. gtk_main();
  237. return 0;
  238. }