mssh.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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((sep = strchr(line, ':')) == NULL)
  105. {
  106. printf("Line %d: Failed to parse line '%s'\n", lineno, line);
  107. exit(EXIT_FAILURE);
  108. }
  109. *sep = '\0';
  110. alias = line;
  111. hoststr = sep + 1;
  112. if((tmp = strtok(hoststr, " ")) == NULL)
  113. {
  114. printf("Line %d: Alias '%s' specifies no hosts\n", lineno,
  115. alias);
  116. exit(EXIT_FAILURE);
  117. }
  118. hosts = g_array_new(FALSE, TRUE, sizeof(char*));
  119. do
  120. {
  121. if(tmp[0] == '[' && tmp[strlen(tmp) - 1] == ']')
  122. {
  123. tmp++;
  124. tmp[strlen(tmp) - 1] = '\0';
  125. append_alias(tmp, hosts, aliases, lineno);
  126. }
  127. else
  128. g_array_append_val(hosts, tmp);
  129. }
  130. while((tmp = strtok(NULL, " ")) != NULL);
  131. g_datalist_set_data(aliases, alias, hosts);
  132. }
  133. return aliases;
  134. }
  135. int main(int argc, char* argv[], char* env[])
  136. {
  137. GtkWidget* window;
  138. int c, option_index = 0;
  139. char *home, *conffile;
  140. long cols = 0;
  141. GData **aliases = NULL;
  142. GArray *hosts = NULL;
  143. static struct option long_options[] =
  144. {
  145. {"alias", required_argument, 0, 'a'},
  146. {"columns", required_argument, 0, 'c'},
  147. {"help", no_argument, 0, 'h'},
  148. {"version", no_argument, 0, 'V'},
  149. {0, 0, 0, 0}
  150. };
  151. if((home = getenv("HOME")) != NULL)
  152. {
  153. int len = strlen(home) + strlen(CONFFILE) + 2;
  154. conffile = malloc(len);
  155. snprintf(conffile, len, "%s/%s", home, CONFFILE);
  156. aliases = parse_aliases(conffile);
  157. free(conffile);
  158. }
  159. else
  160. {
  161. fprintf(stderr,
  162. "Warning: $HOME not set, not reading config file\n");
  163. }
  164. for(;;)
  165. {
  166. c = getopt_long(argc, argv, "a:c:hV", long_options, &option_index);
  167. if(c == -1)
  168. break;
  169. switch(c)
  170. {
  171. case 'a':
  172. if(aliases && (hosts = g_datalist_get_data(aliases,
  173. optarg)) == NULL)
  174. {
  175. fprintf(stderr, "Alias '%s' not found\n\n", optarg);
  176. usage(argv[0]);
  177. }
  178. break;
  179. case 'c':
  180. errno = 0;
  181. cols = strtol(optarg, NULL, 10);
  182. if(cols <= 0 || errno != 0)
  183. {
  184. fprintf(stderr, "Invalid number of columns '%s'\n\n",
  185. optarg);
  186. usage(argv[0]);
  187. }
  188. break;
  189. case 'h':
  190. usage(argv[0]);
  191. break;
  192. case 'V':
  193. printf("%s\n\n", PKGINFO);
  194. printf("%s\n\n", COPYRIGHT);
  195. printf("Redistribution and use in source and binary forms, with or without\n");
  196. printf("modification, are permitted provided that the following conditions are met:\n");
  197. printf("\n");
  198. printf(" 1. Redistributions of source code must retain the copyright notice,\n");
  199. printf(" this list of conditions and the following disclaimer.\n");
  200. printf(" 2. Redistributions in binary form must reproduce the copyright notice,\n");
  201. printf(" this list of conditions and the following disclaimer in the\n");
  202. printf(" documentation and/or other materials provided with the distribution.\n");
  203. printf(" 3. The name of the author may not be used to endorse or promote\n");
  204. printf(" products derived from this software without specific prior written\n");
  205. printf(" permission.\n");
  206. printf("\n");
  207. printf("THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n");
  208. printf("IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n");
  209. printf("OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN\n");
  210. printf("NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n");
  211. printf("SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n");
  212. printf("TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n");
  213. printf("PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n");
  214. printf("LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n");
  215. printf("NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n");
  216. printf("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n");
  217. exit(EXIT_SUCCESS);
  218. break;
  219. case '?':
  220. printf("\n");
  221. usage(argv[0]);
  222. exit(EXIT_FAILURE);
  223. break;
  224. default:
  225. abort();
  226. }
  227. }
  228. if(hosts == NULL)
  229. {
  230. hosts = g_array_new(FALSE, TRUE, sizeof(char*));
  231. if (optind < argc)
  232. {
  233. while (optind < argc)
  234. {
  235. char *host = strdup(argv[optind++]);
  236. g_array_append_val(hosts, host);
  237. }
  238. }
  239. else
  240. {
  241. fprintf(stderr, "No hosts specified\n\n");
  242. usage(argv[0]);
  243. }
  244. }
  245. gtk_init(&argc, &argv);
  246. window = GTK_WIDGET(mssh_window_new());
  247. g_signal_connect(G_OBJECT(window), "destroy",
  248. G_CALLBACK(on_mssh_destroy), NULL);
  249. mssh_window_start_session(MSSH_WINDOW(window), env, hosts, cols);
  250. gtk_widget_show_all(window);
  251. gtk_main();
  252. return 0;
  253. }