mssh.c 8.2 KB

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