[11903] | 1 | /* Copyright 1998 by the Massachusetts Institute of Technology. |
---|
| 2 | * |
---|
| 3 | * Permission to use, copy, modify, and distribute this |
---|
| 4 | * software and its documentation for any purpose and without |
---|
| 5 | * fee is hereby granted, provided that the above copyright |
---|
| 6 | * notice appear in all copies and that both that copyright |
---|
| 7 | * notice and this permission notice appear in supporting |
---|
| 8 | * documentation, and that the name of M.I.T. not be used in |
---|
| 9 | * advertising or publicity pertaining to distribution of the |
---|
| 10 | * software without specific, written prior permission. |
---|
| 11 | * M.I.T. makes no representations about the suitability of |
---|
| 12 | * this software for any purpose. It is provided "as is" |
---|
| 13 | * without express or implied warranty. |
---|
| 14 | */ |
---|
| 15 | |
---|
| 16 | /* This program presents reports generated by larvnetd to stdout |
---|
| 17 | * according to a command line from stdin. |
---|
| 18 | */ |
---|
| 19 | |
---|
[13837] | 20 | static const char rcsid[] = "$Id: cviewd.c,v 1.5 1999-11-01 19:51:08 ghudson Exp $"; |
---|
[11903] | 21 | |
---|
| 22 | #include <sys/types.h> |
---|
| 23 | #include <sys/stat.h> |
---|
| 24 | #include <stdio.h> |
---|
| 25 | #include <stdlib.h> |
---|
| 26 | #include <string.h> |
---|
| 27 | #include <ctype.h> |
---|
[13837] | 28 | #include <time.h> |
---|
[11903] | 29 | #include "larvnet.h" |
---|
| 30 | |
---|
| 31 | struct outof { |
---|
| 32 | int nfree; |
---|
| 33 | int total; |
---|
| 34 | }; |
---|
| 35 | |
---|
| 36 | struct cluster { |
---|
| 37 | char *name; |
---|
| 38 | char *phone; |
---|
| 39 | int public; |
---|
| 40 | struct outof *stats; |
---|
| 41 | }; |
---|
| 42 | |
---|
| 43 | struct clusterfile { |
---|
| 44 | char **archnames; |
---|
| 45 | int narch; |
---|
| 46 | struct cluster *clusters; |
---|
| 47 | int nclusters; |
---|
| 48 | time_t mtime; |
---|
| 49 | }; |
---|
| 50 | |
---|
| 51 | struct printer { |
---|
| 52 | char *name; |
---|
| 53 | char *cluster; |
---|
| 54 | int up; |
---|
| 55 | int jobs; |
---|
| 56 | }; |
---|
| 57 | |
---|
| 58 | struct printerfile { |
---|
| 59 | struct printer *printers; |
---|
| 60 | int nprinters; |
---|
| 61 | time_t mtime; |
---|
| 62 | }; |
---|
| 63 | |
---|
| 64 | struct cgcluster { |
---|
| 65 | char *name; |
---|
| 66 | char *phone; |
---|
| 67 | }; |
---|
| 68 | |
---|
| 69 | struct cgroup { |
---|
| 70 | char *name; |
---|
| 71 | int x; |
---|
| 72 | int y; |
---|
| 73 | struct cgcluster *clusters; |
---|
| 74 | int nclusters; |
---|
| 75 | char **printers; |
---|
| 76 | int nprinters; |
---|
| 77 | }; |
---|
| 78 | |
---|
| 79 | struct cgroupfile { |
---|
| 80 | struct cgroup *cgroups; |
---|
| 81 | int ncgroups; |
---|
| 82 | time_t mtime; |
---|
| 83 | }; |
---|
| 84 | |
---|
| 85 | static void display_printers(void); |
---|
| 86 | static void display_phones(void); |
---|
| 87 | static void display_cluster_ints(void); |
---|
| 88 | static void display_ints(int limit); |
---|
| 89 | static void display_cgroups(void); |
---|
| 90 | static void display_clusters(const char *s); |
---|
| 91 | static void display_help(void); |
---|
| 92 | static void read_clusters(struct clusterfile *file); |
---|
| 93 | static void read_printers(struct printerfile *file); |
---|
| 94 | static void read_cgroups(struct cgroupfile *file); |
---|
| 95 | static int first_field_matches(const char *s, const char *word); |
---|
| 96 | static int cluster_matches(const char *s, struct cluster *cluster); |
---|
| 97 | static int read_line(FILE *fp, char **buf, int *bufsize); |
---|
| 98 | static const char *skip_spaces(const char *p); |
---|
| 99 | static const char *skip_nonspaces(const char *p); |
---|
| 100 | static void *emalloc(size_t size); |
---|
| 101 | static void *erealloc(void *ptr, size_t size); |
---|
| 102 | static char *estrndup(const char *s, size_t n); |
---|
| 103 | |
---|
[13769] | 104 | int main(int argc, char **argv) |
---|
[11903] | 105 | { |
---|
| 106 | char *line = NULL; |
---|
| 107 | const char *p; |
---|
| 108 | int linesize; |
---|
| 109 | |
---|
| 110 | if (read_line(stdin, &line, &linesize) != 0) |
---|
| 111 | return 1; |
---|
| 112 | |
---|
| 113 | p = skip_spaces(line); |
---|
| 114 | |
---|
| 115 | if (first_field_matches(p, "printers")) |
---|
| 116 | display_printers(); |
---|
| 117 | else if (first_field_matches(p, "phones")) |
---|
| 118 | display_phones(); |
---|
| 119 | else if (first_field_matches(p, "intsonlyplease")) |
---|
| 120 | display_cluster_ints(); |
---|
| 121 | else if (first_field_matches(p, "intsonlyplease2")) |
---|
| 122 | display_ints(1); |
---|
| 123 | else if (first_field_matches(p, "intsonlyplease3")) |
---|
| 124 | display_ints(0); |
---|
| 125 | else if (first_field_matches(p, "configplease2") |
---|
| 126 | || first_field_matches(p, "configplease3")) |
---|
| 127 | display_cgroups(); |
---|
| 128 | else if (first_field_matches(p, "help")) |
---|
| 129 | display_help(); |
---|
| 130 | else |
---|
| 131 | display_clusters(p); |
---|
| 132 | |
---|
| 133 | return 0; |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | /* Display printer status in a user-readable format. */ |
---|
| 137 | static void display_printers(void) |
---|
| 138 | { |
---|
| 139 | struct printerfile file; |
---|
| 140 | struct printer *printer; |
---|
| 141 | int i; |
---|
| 142 | char *ct; |
---|
| 143 | |
---|
| 144 | read_printers(&file); |
---|
| 145 | ct = ctime(&file.mtime); |
---|
| 146 | ct[strlen(ct) - 1] = 0; |
---|
| 147 | |
---|
| 148 | printf(" -- Printer status as of %s: --\n", ct); |
---|
| 149 | printf("PRINTER CLUSTER STATUS JOBS " |
---|
| 150 | "PRINTER CLUSTER STATUS JOBS\n"); |
---|
| 151 | printf("--------------------------------------------" |
---|
| 152 | "----------------------------------\n"); |
---|
| 153 | for (i = 0; i < file.nprinters; i++) |
---|
| 154 | { |
---|
| 155 | printer = &file.printers[i]; |
---|
| 156 | printf("%-11.11s %7.7s %-7.7s %3d", printer->name, printer->cluster, |
---|
| 157 | (printer->up) ? "up" : "down", printer->jobs); |
---|
| 158 | |
---|
| 159 | /* Drop to the next line or display separating spaces as appropriate. */ |
---|
| 160 | if (i % 2) |
---|
| 161 | printf("\n"); |
---|
| 162 | else |
---|
| 163 | printf(" "); |
---|
| 164 | } |
---|
| 165 | if (i % 2) |
---|
| 166 | printf("\n"); |
---|
| 167 | } |
---|
| 168 | |
---|
| 169 | /* Display cluster phone numbers in a user-readable format. */ |
---|
| 170 | static void display_phones(void) |
---|
| 171 | { |
---|
| 172 | struct clusterfile file; |
---|
| 173 | int i; |
---|
| 174 | |
---|
| 175 | read_clusters(&file); |
---|
| 176 | printf("CLUSTER PHONE NUMBER\n"); |
---|
| 177 | printf("----------------------\n"); |
---|
| 178 | for (i = 0; i < file.nclusters; i++) |
---|
[12064] | 179 | { |
---|
| 180 | if (file.clusters[i].public) |
---|
| 181 | printf("%-8.8s %s\n", file.clusters[i].name, file.clusters[i].phone); |
---|
| 182 | } |
---|
[11903] | 183 | } |
---|
| 184 | |
---|
| 185 | /* Display a list of free cluster machines in the format: |
---|
| 186 | * <clustername> {<free> <busy>} ... |
---|
| 187 | * At most five columns of free and busy numbers are given. |
---|
| 188 | */ |
---|
| 189 | static void display_cluster_ints(void) |
---|
| 190 | { |
---|
| 191 | struct clusterfile file; |
---|
| 192 | struct cluster *cluster; |
---|
| 193 | int i, j; |
---|
| 194 | |
---|
| 195 | read_clusters(&file); |
---|
| 196 | for (i = 0; i < file.nclusters; i++) |
---|
| 197 | { |
---|
| 198 | cluster = &file.clusters[i]; |
---|
| 199 | printf("%-8.8s", cluster->name); |
---|
| 200 | for (j = 0; j < file.narch && j < 5; j++) |
---|
| 201 | { |
---|
| 202 | printf((j == 0) ? " " : " "); |
---|
| 203 | printf("%3d %3d", cluster->stats[j].nfree, |
---|
| 204 | cluster->stats[j].total - cluster->stats[j].nfree); |
---|
| 205 | } |
---|
| 206 | printf("\n"); |
---|
| 207 | } |
---|
| 208 | } |
---|
| 209 | |
---|
| 210 | /* Display a list of free cluster machines and printer statuses |
---|
| 211 | * in the formats: |
---|
| 212 | * cluster <clustername> {<free> <busy>} ... |
---|
| 213 | * printer <printername> {up|down} <jobs> |
---|
| 214 | * If limit is set, display at most five column-pairs of free and |
---|
| 215 | * busy numbers. |
---|
| 216 | */ |
---|
| 217 | static void display_ints(int limit) |
---|
| 218 | { |
---|
| 219 | struct clusterfile cfile; |
---|
| 220 | struct printerfile pfile; |
---|
| 221 | struct cluster *cluster; |
---|
| 222 | struct printer *printer; |
---|
| 223 | int i, j; |
---|
| 224 | |
---|
| 225 | read_clusters(&cfile); |
---|
| 226 | read_printers(&pfile); |
---|
| 227 | for (i = 0; i < cfile.nclusters; i++) |
---|
| 228 | { |
---|
| 229 | cluster = &cfile.clusters[i]; |
---|
| 230 | printf("cluster %-8.8s", cluster->name); |
---|
| 231 | for (j = 0; j < cfile.narch && (!limit || j < 5); j++) |
---|
| 232 | { |
---|
| 233 | printf((j == 0) ? " " : " "); |
---|
| 234 | printf("%3d %3d", cluster->stats[j].nfree, |
---|
| 235 | cluster->stats[j].total - cluster->stats[j].nfree); |
---|
| 236 | } |
---|
| 237 | printf("\n"); |
---|
| 238 | } |
---|
| 239 | for (i = 0; i < pfile.nprinters; i++) |
---|
| 240 | { |
---|
| 241 | printer = &pfile.printers[i]; |
---|
| 242 | printf("printer %-11.11s %-7.7s %3d\n", printer->name, |
---|
| 243 | (printer->up) ? "up" : "down", printer->jobs); |
---|
| 244 | } |
---|
| 245 | } |
---|
| 246 | |
---|
| 247 | /* Display configuration information. The first line returned |
---|
| 248 | * has the form: |
---|
| 249 | * <number of architectures> <archname> ... |
---|
| 250 | * The remaining lines come in groups of four, with the formats: |
---|
| 251 | * <number> <cluster group name> |
---|
| 252 | * {<cluster> <phone number>} ... XXXXX |
---|
| 253 | * <x coordinate> <y coordinate> |
---|
| 254 | * <printer> ... XXXXX |
---|
| 255 | */ |
---|
| 256 | static void display_cgroups(void) |
---|
| 257 | { |
---|
| 258 | struct clusterfile cfile; |
---|
| 259 | struct cgroupfile cgfile; |
---|
| 260 | struct cgroup *cgroup; |
---|
| 261 | int i, j; |
---|
| 262 | |
---|
| 263 | read_clusters(&cfile); |
---|
| 264 | read_cgroups(&cgfile); |
---|
| 265 | |
---|
| 266 | printf("%d", cfile.narch); |
---|
| 267 | for (i = 0; i < cfile.narch; i++) |
---|
| 268 | printf(" %s", cfile.archnames[i]); |
---|
| 269 | printf("\n"); |
---|
| 270 | |
---|
| 271 | for (i = 0; i < cgfile.ncgroups; i++) |
---|
| 272 | { |
---|
| 273 | /* Line 1: cluster group number and name */ |
---|
| 274 | cgroup = &cgfile.cgroups[i]; |
---|
| 275 | printf("%d\t%s\n", i + 1, cgroup->name); |
---|
| 276 | |
---|
[12052] | 277 | /* Line 2: cluster names */ |
---|
[11903] | 278 | for (j = 0; j < cgroup->nclusters; j++) |
---|
[12052] | 279 | printf("%s %s ", cgroup->clusters[j].name, cgroup->clusters[j].phone); |
---|
[11903] | 280 | printf("XXXXX\n"); |
---|
| 281 | |
---|
| 282 | /* Line 3: X and Y coordinates */ |
---|
| 283 | printf("%d\t%d\n", cgroup->x, cgroup->y); |
---|
| 284 | |
---|
| 285 | /* Line 4: printer names */ |
---|
| 286 | for (j = 0; j < cgroup->nprinters; j++) |
---|
| 287 | printf("%s ", cgroup->printers[j]); |
---|
| 288 | printf("XXXXX\n"); |
---|
| 289 | } |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | static void display_clusters(const char *s) |
---|
| 293 | { |
---|
| 294 | struct clusterfile file; |
---|
| 295 | struct cluster *cluster; |
---|
| 296 | struct outof coltotals[6], rowtotal, *entry; |
---|
| 297 | int i, j; |
---|
| 298 | char *ct; |
---|
| 299 | |
---|
| 300 | read_clusters(&file); |
---|
| 301 | ct = ctime(&file.mtime); |
---|
| 302 | ct[strlen(ct) - 1] = 0; |
---|
| 303 | |
---|
| 304 | /* We can handle at most six architecture columns in 80 columns. */ |
---|
| 305 | if (file.narch > 6) |
---|
| 306 | file.narch = 6; |
---|
| 307 | |
---|
| 308 | /* Display the first header line. */ |
---|
| 309 | printf(" -- Cluster status as of %s: --\n", ct); |
---|
| 310 | |
---|
| 311 | /* Display the architecture names. */ |
---|
| 312 | printf(" "); |
---|
| 313 | for (i = 0; i < file.narch; i++) |
---|
| 314 | { |
---|
| 315 | printf("%-9.9s ", file.archnames[i]); |
---|
| 316 | coltotals[i].nfree = 0; |
---|
| 317 | coltotals[i].total = 0; |
---|
| 318 | } |
---|
| 319 | printf("TOTAL\n"); |
---|
| 320 | |
---|
| 321 | /* Display the fre/tot column headers. */ |
---|
| 322 | printf("CLUSTER"); |
---|
| 323 | for (i = 0; i < file.narch + 1; i++) |
---|
| 324 | printf(" fre/tot"); |
---|
| 325 | printf("\n"); |
---|
| 326 | |
---|
| 327 | /* Display the divider line. */ |
---|
| 328 | printf("--------"); |
---|
| 329 | for (i = 0; i < file.narch + 1; i++) |
---|
| 330 | printf("----------"); |
---|
| 331 | printf("\n"); |
---|
| 332 | |
---|
| 333 | /* Display the stats. */ |
---|
| 334 | for (i = 0; i < file.nclusters; i++) |
---|
| 335 | { |
---|
| 336 | cluster = &file.clusters[i]; |
---|
| 337 | if (!cluster_matches(s, cluster)) |
---|
| 338 | continue; |
---|
| 339 | printf("%-8.8s ", cluster->name); |
---|
| 340 | rowtotal.nfree = 0; |
---|
| 341 | rowtotal.total = 0; |
---|
| 342 | for (j = 0; j < file.narch; j++) |
---|
| 343 | { |
---|
| 344 | entry = &cluster->stats[j]; |
---|
| 345 | if (entry->total == 0) |
---|
| 346 | printf(" - "); |
---|
| 347 | else |
---|
| 348 | printf("%3d / %-3d ", entry->nfree, entry->total); |
---|
| 349 | coltotals[j].nfree += entry->nfree; |
---|
| 350 | coltotals[j].total += entry->total; |
---|
| 351 | rowtotal.nfree += entry->nfree; |
---|
| 352 | rowtotal.total += entry->total; |
---|
| 353 | } |
---|
| 354 | printf("%3d / %-3d\n", rowtotal.nfree, rowtotal.total); |
---|
| 355 | } |
---|
| 356 | |
---|
| 357 | /* Display the column totals. */ |
---|
| 358 | rowtotal.nfree = 0; |
---|
| 359 | rowtotal.total = 0; |
---|
| 360 | printf("TOTALS "); |
---|
| 361 | for (i = 0; i < file.narch; i++) |
---|
| 362 | { |
---|
| 363 | printf("%3d / %-3d ", coltotals[i].nfree, coltotals[i].total); |
---|
| 364 | rowtotal.nfree += coltotals[i].nfree; |
---|
| 365 | rowtotal.total += coltotals[i].total; |
---|
| 366 | } |
---|
| 367 | printf("%3d / %-3d\n", rowtotal.nfree, rowtotal.total); |
---|
| 368 | } |
---|
| 369 | |
---|
| 370 | static void display_help(void) |
---|
| 371 | { |
---|
| 372 | printf("Usage:\tcview [cluster ...]\n"); |
---|
| 373 | printf("\tcview printers\n"); |
---|
| 374 | printf("\tcview phones\n"); |
---|
| 375 | } |
---|
| 376 | |
---|
| 377 | static void read_clusters(struct clusterfile *file) |
---|
| 378 | { |
---|
| 379 | FILE *fp; |
---|
| 380 | char *line = NULL; |
---|
| 381 | int linesize, i; |
---|
| 382 | struct cluster *cluster; |
---|
| 383 | const char *p, *q; |
---|
| 384 | struct stat statbuf; |
---|
| 385 | |
---|
| 386 | fp = fopen(LARVNET_PATH_CLUSTERS, "r"); |
---|
| 387 | if (!fp) |
---|
| 388 | { |
---|
| 389 | fprintf(stderr, "Sorry, no cluster status information available.\n"); |
---|
| 390 | exit(1); |
---|
| 391 | } |
---|
| 392 | |
---|
| 393 | fstat(fileno(fp), &statbuf); |
---|
| 394 | file->mtime = statbuf.st_mtime; |
---|
| 395 | |
---|
| 396 | /* Read in the architecture names. */ |
---|
| 397 | file->archnames = NULL; |
---|
| 398 | file->narch = 0; |
---|
| 399 | while (read_line(fp, &line, &linesize) == 0) |
---|
| 400 | { |
---|
| 401 | if (*line == '-') |
---|
| 402 | break; |
---|
| 403 | |
---|
| 404 | /* Add an architecture name. */ |
---|
| 405 | file->narch++; |
---|
| 406 | file->archnames = erealloc(file->archnames, |
---|
| 407 | file->narch * sizeof(char *)); |
---|
| 408 | p = skip_spaces(line); |
---|
| 409 | q = skip_nonspaces(p); |
---|
| 410 | file->archnames[file->narch - 1] = estrndup(p, q - p); |
---|
| 411 | } |
---|
| 412 | |
---|
| 413 | /* Read in the cluster information. */ |
---|
| 414 | file->clusters = NULL; |
---|
| 415 | file->nclusters = 0; |
---|
| 416 | while (read_line(fp, &line, &linesize) == 0) |
---|
| 417 | { |
---|
| 418 | /* Make a new cluster entry. */ |
---|
| 419 | file->nclusters++; |
---|
| 420 | file->clusters = erealloc(file->clusters, |
---|
| 421 | file->nclusters * sizeof(struct cluster)); |
---|
| 422 | cluster = &file->clusters[file->nclusters - 1]; |
---|
| 423 | |
---|
| 424 | /* Read the name, public/private field, and phone. */ |
---|
| 425 | p = skip_spaces(line); |
---|
| 426 | q = skip_nonspaces(p); |
---|
| 427 | cluster->name = estrndup(p, q - p); |
---|
| 428 | p = skip_spaces(q); |
---|
| 429 | q = skip_nonspaces(p); |
---|
| 430 | cluster->public = first_field_matches(p, "public"); |
---|
| 431 | p = skip_spaces(q); |
---|
| 432 | q = skip_nonspaces(p); |
---|
| 433 | cluster->phone = estrndup(p, q - p); |
---|
| 434 | |
---|
| 435 | /* Read the stats. */ |
---|
| 436 | cluster->stats = emalloc(file->narch * sizeof(struct outof)); |
---|
| 437 | for (i = 0; i < file->narch; i++) |
---|
| 438 | { |
---|
| 439 | p = skip_spaces(q); |
---|
| 440 | q = skip_nonspaces(p); |
---|
| 441 | cluster->stats[i].nfree = atoi(p); |
---|
| 442 | p = skip_spaces(q); |
---|
| 443 | q = skip_nonspaces(p); |
---|
| 444 | cluster->stats[i].total = atoi(p); |
---|
| 445 | } |
---|
| 446 | } |
---|
| 447 | |
---|
| 448 | fclose(fp); |
---|
| 449 | } |
---|
| 450 | |
---|
| 451 | static void read_printers(struct printerfile *file) |
---|
| 452 | { |
---|
| 453 | FILE *fp; |
---|
| 454 | char *line = NULL; |
---|
| 455 | int linesize; |
---|
| 456 | struct printer *printer; |
---|
| 457 | const char *p, *q; |
---|
| 458 | struct stat statbuf; |
---|
| 459 | |
---|
| 460 | fp = fopen(LARVNET_PATH_PRINTERS, "r"); |
---|
| 461 | if (!fp) |
---|
| 462 | { |
---|
| 463 | fprintf(stderr, "Sorry, no printer status information available.\n"); |
---|
| 464 | exit(1); |
---|
| 465 | } |
---|
| 466 | |
---|
| 467 | fstat(fileno(fp), &statbuf); |
---|
| 468 | file->mtime = statbuf.st_mtime; |
---|
| 469 | |
---|
| 470 | file->printers = NULL; |
---|
| 471 | file->nprinters = 0; |
---|
| 472 | while (read_line(fp, &line, &linesize) == 0) |
---|
| 473 | { |
---|
| 474 | /* Make a new printer entry. */ |
---|
| 475 | file->nprinters++; |
---|
| 476 | file->printers = erealloc(file->printers, |
---|
| 477 | file->nprinters * sizeof(struct printer)); |
---|
| 478 | printer = &file->printers[file->nprinters - 1]; |
---|
| 479 | |
---|
| 480 | /* Read in the name, cluster name, status, and jobs. */ |
---|
| 481 | p = skip_spaces(line); |
---|
| 482 | q = skip_nonspaces(p); |
---|
| 483 | printer->name = estrndup(p, q - p); |
---|
| 484 | p = skip_spaces(q); |
---|
| 485 | q = skip_nonspaces(p); |
---|
| 486 | printer->cluster = estrndup(p, q - p); |
---|
| 487 | p = skip_spaces(q); |
---|
| 488 | q = skip_nonspaces(p); |
---|
| 489 | printer->up = first_field_matches(p, "up"); |
---|
| 490 | p = skip_spaces(q); |
---|
| 491 | printer->jobs = atoi(p); |
---|
| 492 | } |
---|
| 493 | } |
---|
| 494 | |
---|
| 495 | static void read_cgroups(struct cgroupfile *file) |
---|
| 496 | { |
---|
| 497 | FILE *fp; |
---|
| 498 | char *line = NULL; |
---|
| 499 | int linesize; |
---|
| 500 | struct cgroup *cgroup; |
---|
| 501 | struct cgcluster *cgcluster; |
---|
| 502 | const char *p, *q; |
---|
| 503 | struct stat statbuf; |
---|
| 504 | |
---|
| 505 | fp = fopen(LARVNET_PATH_CGROUPS, "r"); |
---|
| 506 | if (!fp) |
---|
| 507 | { |
---|
| 508 | fprintf(stderr, "No cluster group information available.\n"); |
---|
| 509 | exit(1); |
---|
| 510 | } |
---|
| 511 | |
---|
| 512 | fstat(fileno(fp), &statbuf); |
---|
| 513 | file->mtime = statbuf.st_mtime; |
---|
| 514 | |
---|
| 515 | file->cgroups = NULL; |
---|
| 516 | file->ncgroups = 0; |
---|
| 517 | while (read_line(fp, &line, &linesize) == 0) |
---|
| 518 | { |
---|
| 519 | /* Make a new cluster group entry. */ |
---|
| 520 | file->ncgroups++; |
---|
| 521 | file->cgroups = erealloc(file->cgroups, |
---|
| 522 | file->ncgroups * sizeof(struct cgroup)); |
---|
| 523 | cgroup = &file->cgroups[file->ncgroups - 1]; |
---|
| 524 | |
---|
| 525 | /* Read in the cluster group name and coordinates. */ |
---|
| 526 | p = skip_spaces(line); |
---|
| 527 | q = skip_nonspaces(p); |
---|
| 528 | cgroup->name = estrndup(p, q - p); |
---|
| 529 | p = skip_spaces(q); |
---|
| 530 | q = skip_nonspaces(p); |
---|
| 531 | cgroup->x = atoi(p); |
---|
| 532 | p = skip_spaces(q); |
---|
| 533 | q = skip_nonspaces(p); |
---|
| 534 | cgroup->y = atoi(p); |
---|
| 535 | |
---|
| 536 | /* Read in the cluster names. */ |
---|
| 537 | cgroup->clusters = NULL; |
---|
| 538 | cgroup->nclusters = 0; |
---|
| 539 | while (1) |
---|
| 540 | { |
---|
| 541 | p = skip_spaces(q); |
---|
| 542 | q = skip_nonspaces(p); |
---|
| 543 | if (!*p || *p == '-') |
---|
| 544 | break; |
---|
| 545 | cgroup->nclusters++; |
---|
| 546 | cgroup->clusters = erealloc(cgroup->clusters, cgroup->nclusters |
---|
| 547 | * sizeof(struct cgcluster)); |
---|
| 548 | cgcluster = &cgroup->clusters[cgroup->nclusters - 1]; |
---|
| 549 | cgcluster->name = estrndup(p, q - p); |
---|
| 550 | p = skip_spaces(q); |
---|
| 551 | q = skip_nonspaces(p); |
---|
| 552 | cgcluster->phone = estrndup(p, q - p); |
---|
| 553 | } |
---|
| 554 | |
---|
| 555 | /* Read in the printer names. */ |
---|
| 556 | cgroup->printers = NULL; |
---|
| 557 | cgroup->nprinters = 0; |
---|
| 558 | p = skip_spaces(q); |
---|
| 559 | while (*p) |
---|
| 560 | { |
---|
| 561 | q = skip_nonspaces(p); |
---|
| 562 | cgroup->nprinters++; |
---|
| 563 | cgroup->printers = erealloc(cgroup->printers, |
---|
| 564 | cgroup->nprinters * sizeof(char *)); |
---|
| 565 | cgroup->printers[cgroup->nprinters - 1] = estrndup(p, q - p); |
---|
| 566 | p = skip_spaces(q); |
---|
| 567 | } |
---|
| 568 | } |
---|
| 569 | } |
---|
| 570 | |
---|
| 571 | static int first_field_matches(const char *s, const char *word) |
---|
| 572 | { |
---|
| 573 | int len = strlen(word); |
---|
| 574 | |
---|
[13769] | 575 | return (strncasecmp(s, word, len) == 0 && |
---|
| 576 | (isspace((unsigned char)s[len]) || !s[len])); |
---|
[11903] | 577 | } |
---|
| 578 | |
---|
| 579 | static int cluster_matches(const char *s, struct cluster *cluster) |
---|
| 580 | { |
---|
| 581 | const char *p, *q; |
---|
| 582 | |
---|
| 583 | /* If no cluster names specified, match public clusters. */ |
---|
| 584 | if (!*s) |
---|
| 585 | return cluster->public; |
---|
| 586 | |
---|
| 587 | p = skip_spaces(s); |
---|
| 588 | while (*p) |
---|
| 589 | { |
---|
| 590 | if (first_field_matches(p, "public") && cluster->public) |
---|
| 591 | return 1; |
---|
| 592 | if (first_field_matches(p, "all") |
---|
| 593 | || first_field_matches(p, cluster->name)) |
---|
| 594 | return 1; |
---|
| 595 | q = skip_nonspaces(p); |
---|
| 596 | p = skip_spaces(q); |
---|
| 597 | } |
---|
| 598 | |
---|
| 599 | return 0; |
---|
| 600 | } |
---|
| 601 | |
---|
| 602 | /* Read a line from a file into a dynamically allocated buffer, |
---|
| 603 | * zeroing the trailing newline if there is one. The calling routine |
---|
| 604 | * may call read_line multiple times with the same buf and bufsize |
---|
| 605 | * pointers; *buf will be reallocated and *bufsize adjusted as |
---|
| 606 | * appropriate. The initial value of *buf should be NULL. After the |
---|
| 607 | * calling routine is done reading lines, it should free *buf. This |
---|
| 608 | * function returns 0 if a line was successfully read, 1 if the file |
---|
| 609 | * ended, and -1 if there was an I/O error. |
---|
| 610 | */ |
---|
| 611 | |
---|
| 612 | static int read_line(FILE *fp, char **buf, int *bufsize) |
---|
| 613 | { |
---|
| 614 | char *newbuf; |
---|
| 615 | int offset = 0, len; |
---|
| 616 | |
---|
| 617 | if (*buf == NULL) |
---|
| 618 | { |
---|
| 619 | *buf = emalloc(128); |
---|
| 620 | *bufsize = 128; |
---|
| 621 | } |
---|
| 622 | |
---|
| 623 | while (1) |
---|
| 624 | { |
---|
| 625 | if (!fgets(*buf + offset, *bufsize - offset, fp)) |
---|
| 626 | return (offset != 0) ? 0 : (ferror(fp)) ? -1 : 1; |
---|
| 627 | len = offset + strlen(*buf + offset); |
---|
| 628 | if ((*buf)[len - 1] == '\n') |
---|
| 629 | { |
---|
| 630 | (*buf)[len - 1] = 0; |
---|
| 631 | return 0; |
---|
| 632 | } |
---|
| 633 | offset = len; |
---|
| 634 | |
---|
| 635 | /* Allocate more space. */ |
---|
| 636 | newbuf = erealloc(*buf, *bufsize * 2); |
---|
| 637 | *buf = newbuf; |
---|
| 638 | *bufsize *= 2; |
---|
| 639 | } |
---|
| 640 | } |
---|
| 641 | |
---|
| 642 | static const char *skip_spaces(const char *p) |
---|
| 643 | { |
---|
[13769] | 644 | while (isspace((unsigned char)*p)) |
---|
[11903] | 645 | p++; |
---|
| 646 | return p; |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | static const char *skip_nonspaces(const char *p) |
---|
| 650 | { |
---|
[13769] | 651 | while (*p && !isspace((unsigned char)*p)) |
---|
[11903] | 652 | p++; |
---|
| 653 | return p; |
---|
| 654 | } |
---|
| 655 | |
---|
| 656 | static void *emalloc(size_t size) |
---|
| 657 | { |
---|
| 658 | void *ptr; |
---|
| 659 | |
---|
| 660 | ptr = malloc(size); |
---|
| 661 | if (!ptr) |
---|
| 662 | { |
---|
| 663 | fprintf(stderr, "Ran out of memory!\n"); |
---|
| 664 | exit(1); |
---|
| 665 | } |
---|
| 666 | return ptr; |
---|
| 667 | } |
---|
| 668 | |
---|
| 669 | static void *erealloc(void *ptr, size_t size) |
---|
| 670 | { |
---|
| 671 | ptr = realloc(ptr, size); |
---|
| 672 | if (!ptr) |
---|
| 673 | { |
---|
| 674 | fprintf(stderr, "Ran out of memory!\n"); |
---|
| 675 | exit(1); |
---|
| 676 | } |
---|
| 677 | return ptr; |
---|
| 678 | } |
---|
| 679 | |
---|
| 680 | static char *estrndup(const char *s, size_t n) |
---|
| 681 | { |
---|
| 682 | char *new_s; |
---|
| 683 | |
---|
| 684 | new_s = emalloc(n + 1); |
---|
| 685 | memcpy(new_s, s, n); |
---|
| 686 | new_s[n] = 0; |
---|
| 687 | return new_s; |
---|
| 688 | } |
---|