Index: trunk/tools/rosary/rosary.c |
— | — | @@ -0,0 +1,609 @@ |
| 2 | +/* |
| 3 | + * Rosary: SVr4/Solaris package manager. |
| 4 | + */ |
| 5 | + |
| 6 | +#include <sys/types.h> |
| 7 | +#include <sys/wait.h> |
| 8 | + |
| 9 | +#include <stdio.h> |
| 10 | +#include <string.h> |
| 11 | +#include <errno.h> |
| 12 | +#include <unistd.h> |
| 13 | +#include <stdlib.h> |
| 14 | +#include <dirent.h> |
| 15 | +#include <curses.h> |
| 16 | +#include <term.h> |
| 17 | +#include <fnmatch.h> |
| 18 | +#include <libtecla.h> |
| 19 | + |
| 20 | +#include <glib.h> |
| 21 | + |
| 22 | +#define CFGFILE "/etc/opt/rosary/rosary.conf" |
| 23 | +#define PKGFILE "/etc/opt/rosary/db.pkg" |
| 24 | +#define FILEFILE "/etc/opt/rosary/db.file" |
| 25 | + |
| 26 | +struct package; |
| 27 | +int initroot (void); |
| 28 | +int read_pkg_info (struct package *pkg, const char *dir); |
| 29 | +void pkgdb_write (gpointer, gpointer, gpointer); |
| 30 | +void pkgdb_writedep (gpointer, gpointer); |
| 31 | +void pkgsearch (gpointer, gpointer, gpointer); |
| 32 | +void print_pkghash (GHashTable *); |
| 33 | +void print_pkghash_one (gpointer, gpointer, gpointer); |
| 34 | +gboolean is_installable (gpointer, gpointer, gpointer); |
| 35 | +void print_package (struct package *); |
| 36 | +int is_installed (const char *pkg); |
| 37 | +int add_depends (struct package *pkg); |
| 38 | +void install_all (void); |
| 39 | +int install_one (struct package *pkg); |
| 40 | +int is_candidate (const char *); |
| 41 | +struct package *next_installable (void); |
| 42 | +int run_cmd (char **); |
| 43 | +int install_cmd (char **); |
| 44 | +int search_cmd (char **); |
| 45 | +int shell_cmd (char **); |
| 46 | + |
| 47 | +GHashTable *pkgs_byname; |
| 48 | +GHashTable *files_byname; |
| 49 | +GHashTable *inst_pkgs; |
| 50 | + |
| 51 | +GHashTable *to_install; |
| 52 | +GHashTable *toins_deps; |
| 53 | +char *pkgroot; |
| 54 | + |
| 55 | +struct package { |
| 56 | + char *name; |
| 57 | + char *desc; |
| 58 | + GSList *depends; |
| 59 | +}; |
| 60 | + |
| 61 | +char *progname; |
| 62 | +const char *commands = |
| 63 | + "commands:\n" |
| 64 | + " install <pkgs> install one or more packages\n" |
| 65 | + " search <term> search package names and descriptions\n" |
| 66 | + " shell enter interactive shell\n"; |
| 67 | +const char *icommands = |
| 68 | + " quit exit command shell\n"; |
| 69 | +int |
| 70 | +main(ac, av) |
| 71 | +int ac; |
| 72 | +char *av[]; |
| 73 | +{ |
| 74 | +int c; |
| 75 | +int Iflag = 0; |
| 76 | +struct package *pkg; |
| 77 | +GIOChannel *f; |
| 78 | +GError *err = NULL; |
| 79 | +char *ln; |
| 80 | +DIR *dp; |
| 81 | +struct dirent *de; |
| 82 | +static const char *usage = |
| 83 | + "usage: %s [-I -m <media location>] <command>\n" |
| 84 | + " -m\tspecify location of Solaris DVD/CD media\n" |
| 85 | + " -I\tinitialise configuration\n"; |
| 86 | + |
| 87 | + progname = av[0]; |
| 88 | + |
| 89 | + while ((c = getopt(ac, av, "Im:")) != -1) { |
| 90 | + switch (c) { |
| 91 | + case 'I': |
| 92 | + Iflag++; |
| 93 | + break; |
| 94 | + case 'm': |
| 95 | + pkgroot = optarg; |
| 96 | + break; |
| 97 | + default: |
| 98 | + fprintf(stderr, usage, av[0]); |
| 99 | + fprintf(stderr, "\n%s", commands); |
| 100 | + exit(1); |
| 101 | + } |
| 102 | + } |
| 103 | + ac -= optind; |
| 104 | + av += optind; |
| 105 | + |
| 106 | + if (Iflag) { |
| 107 | + return initroot(); |
| 108 | + } |
| 109 | + |
| 110 | + if (access(CFGFILE, F_OK) == 0) { |
| 111 | + fprintf(stderr, "Loading configuration from %s: ", CFGFILE); |
| 112 | + if ((f = g_io_channel_new_file(CFGFILE, "r", &err)) == NULL) { |
| 113 | + fprintf(stderr, "%s\n", err->message); |
| 114 | + return 1; |
| 115 | + } |
| 116 | + while (g_io_channel_read_line(f, &ln, NULL, NULL, &err) == G_IO_STATUS_NORMAL) { |
| 117 | + char *v, *o = ln; |
| 118 | + ln[strlen(ln) - 1] = '\0'; |
| 119 | + if ((v = strchr(o, '=')) == NULL) { |
| 120 | + fprintf(stderr, "format error\n"); |
| 121 | + return 1; |
| 122 | + } |
| 123 | + *v++ = '\0'; |
| 124 | + if (!strcmp(o, "pkgroot")) |
| 125 | + pkgroot = strdup(v); |
| 126 | + g_free(ln); |
| 127 | + } |
| 128 | + g_io_channel_unref(f); |
| 129 | + fprintf(stderr, "OK\n"); |
| 130 | + } else { |
| 131 | + fprintf(stderr, "No configuration exists; use -I to create.\n"); |
| 132 | + return 0; |
| 133 | + } |
| 134 | + |
| 135 | + fprintf(stderr, "package root: %s\n", pkgroot); |
| 136 | + pkgs_byname = g_hash_table_new(g_str_hash, g_str_equal); |
| 137 | + fprintf(stderr, "Reading package database from %s: ", PKGFILE); |
| 138 | + if ((f = g_io_channel_new_file(PKGFILE, "r", &err)) == NULL) { |
| 139 | + fprintf(stderr, "%s\n", err->message); |
| 140 | + return 1; |
| 141 | + } |
| 142 | + while (g_io_channel_read_line(f, &ln, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) { |
| 143 | + char *v, *o = ln; |
| 144 | + ln[strlen(ln) - 1] = '\0'; |
| 145 | + if ((v = strchr(o, ' ')) == NULL) { |
| 146 | + fprintf(stderr, "format error\n"); |
| 147 | + return 1; |
| 148 | + } |
| 149 | + *v++ = '\0'; |
| 150 | + if (!strcmp(o, "p")) { |
| 151 | + pkg = calloc(1, sizeof(struct package)); |
| 152 | + pkg->name = strdup(v); |
| 153 | + g_hash_table_insert(pkgs_byname, strdup(v), pkg); |
| 154 | + } else if (!strcmp(o, "desc")) { |
| 155 | + if (!pkg) { |
| 156 | + fprintf(stderr, "format error\n"); |
| 157 | + exit(1); |
| 158 | + } |
| 159 | + pkg->desc = strdup(v); |
| 160 | + } else if (!strcmp(o, "dep")) { |
| 161 | + if (!pkg) { |
| 162 | + fprintf(stderr, "format error\n"); |
| 163 | + exit(1); |
| 164 | + } |
| 165 | + pkg->depends = g_slist_prepend(pkg->depends, strdup(v)); |
| 166 | + } |
| 167 | + } |
| 168 | + fprintf(stderr, "OK, %d packages\n", g_hash_table_size(pkgs_byname)); |
| 169 | + g_io_channel_unref(f); |
| 170 | + |
| 171 | + fprintf(stderr, "Reading list of installed packages: "); |
| 172 | + inst_pkgs = g_hash_table_new(g_str_hash, g_str_equal); |
| 173 | + if ((dp = opendir("/var/sadm/pkg")) == NULL) { |
| 174 | + perror("/var/sadm/pkg"); |
| 175 | + return 1; |
| 176 | + } |
| 177 | + while (de = readdir(dp)) { |
| 178 | + struct package *ipkg; |
| 179 | + ipkg = calloc(1, sizeof(struct package)); |
| 180 | + ipkg->name = strdup(de->d_name); |
| 181 | + g_hash_table_insert(inst_pkgs, strdup(de->d_name), ipkg); |
| 182 | + } |
| 183 | + closedir(dp); |
| 184 | + fprintf(stderr, "OK, %d packages\n", g_hash_table_size(inst_pkgs)); |
| 185 | + |
| 186 | + fprintf(stderr, "\n"); |
| 187 | + if (!*av) { |
| 188 | + fprintf(stderr, usage, progname); |
| 189 | + fprintf(stderr, "\n%s", commands); |
| 190 | + return 1; |
| 191 | + } |
| 192 | + |
| 193 | + if (run_cmd(av) == -1) |
| 194 | + return 1; |
| 195 | + return 0; |
| 196 | +} |
| 197 | + |
| 198 | +int |
| 199 | +search_cmd(av) |
| 200 | +char **av; |
| 201 | +{ |
| 202 | +char *term; |
| 203 | + if (!*av) { |
| 204 | + printf("search: not enough arguments\n"); |
| 205 | + return -1; |
| 206 | + } |
| 207 | + printf("Packages matching \"%s\":\n", av[0]); |
| 208 | + term = g_strdup_printf("*%s*", av[0]); |
| 209 | + g_hash_table_foreach(pkgs_byname, pkgsearch, term); |
| 210 | + g_free(term); |
| 211 | + fprintf(stderr, "a = available, i = installed\n"); |
| 212 | +} |
| 213 | + |
| 214 | +int |
| 215 | +run_cmd(av) |
| 216 | +char **av; |
| 217 | +{ |
| 218 | +static int slev; |
| 219 | + if (!strcmp(av[0], "install")) |
| 220 | + return install_cmd(av + 1); |
| 221 | + if (!strcmp(av[0], "search")) |
| 222 | + return search_cmd(av + 1); |
| 223 | + if (!slev++ && !strcmp(av[0], "shell")) |
| 224 | + return shell_cmd(av + 1); |
| 225 | + if (!strcmp(av[0], "quit")) |
| 226 | + exit(0); |
| 227 | + if (!strcmp(av[0], "help")) { |
| 228 | + fprintf(stderr, "%s", commands); |
| 229 | + fprintf(stderr, "%s", icommands); |
| 230 | + return 0; |
| 231 | + } |
| 232 | + |
| 233 | + fprintf(stderr, "Unknown command '%s'\n", av[0]); |
| 234 | + return -1; |
| 235 | +} |
| 236 | + |
| 237 | +int |
| 238 | +shell_cmd(av) |
| 239 | +char **av; |
| 240 | +{ |
| 241 | +GetLine *gl; |
| 242 | + gl = new_GetLine(4096, 256); |
| 243 | + for (;;) { |
| 244 | + char *in; |
| 245 | + char **args; |
| 246 | + in = gl_get_line(gl, "rosary> ", "", 0); |
| 247 | + if (!in) |
| 248 | + return 0; |
| 249 | + in[strlen(in) - 1] = '\0'; |
| 250 | + args = g_strsplit(in, " ", 0); |
| 251 | + if (!args[0]) { |
| 252 | + g_strfreev(args); |
| 253 | + free(in); |
| 254 | + continue; |
| 255 | + } |
| 256 | + run_cmd(args); |
| 257 | + g_strfreev(args); |
| 258 | + } |
| 259 | + del_GetLine(gl); |
| 260 | +} |
| 261 | + |
| 262 | +int |
| 263 | +install_cmd(av) |
| 264 | +char **av; |
| 265 | +{ |
| 266 | +int c; |
| 267 | + to_install = g_hash_table_new(g_str_hash, g_str_equal); |
| 268 | + toins_deps = g_hash_table_new(g_str_hash, g_str_equal); |
| 269 | + while (*av) { |
| 270 | + struct package *pkg; |
| 271 | + GSList *dep; |
| 272 | + if ((pkg = g_hash_table_lookup(pkgs_byname, *av)) == NULL) { |
| 273 | + fprintf(stderr, "Nothing known about package '%s'\n", *av); |
| 274 | + return 1; |
| 275 | + } |
| 276 | + if (is_installed(pkg->name)) { |
| 277 | + fprintf(stderr, "%s is already installed\n", pkg->name); |
| 278 | + av++; |
| 279 | + continue; |
| 280 | + } |
| 281 | + g_hash_table_insert(to_install, strdup(*av), pkg); |
| 282 | + if (add_depends(pkg) == -1) { |
| 283 | + fprintf(stderr, "Cannot resolve dependencies.\n"); |
| 284 | + return 1; |
| 285 | + } |
| 286 | + av++; |
| 287 | + } |
| 288 | + |
| 289 | + if (g_hash_table_size(to_install) == 0) { |
| 290 | + printf("Nothing to do.\n"); |
| 291 | + return 0; |
| 292 | + } |
| 293 | + |
| 294 | + printf("The following packages will be installed:\n"); |
| 295 | + print_pkghash(to_install); |
| 296 | + if (g_hash_table_size(toins_deps)) { |
| 297 | + printf("The following packages will be installed to satisfy dependencies:\n"); |
| 298 | + print_pkghash(toins_deps); |
| 299 | + } |
| 300 | + |
| 301 | + printf("\nContinue? [y/N] "); |
| 302 | + c = getc(stdin); |
| 303 | + if (c != 'y') { |
| 304 | + printf("Okay, exiting\n"); |
| 305 | + return 0; |
| 306 | + } |
| 307 | + install_all(); |
| 308 | + return 0; |
| 309 | +} |
| 310 | + |
| 311 | +void |
| 312 | +install_all(void) |
| 313 | +{ |
| 314 | +struct package *next; |
| 315 | + while (next = next_installable()) { |
| 316 | + install_one(next); |
| 317 | + } |
| 318 | + if (g_hash_table_size(to_install) || g_hash_table_size(toins_deps)) |
| 319 | + fprintf(stderr, "No installable packages; possible dependency loop?\n"); |
| 320 | +} |
| 321 | + |
| 322 | +struct package * |
| 323 | +next_installable(void) |
| 324 | +{ |
| 325 | +struct package *next; |
| 326 | + next = g_hash_table_find(toins_deps, is_installable, NULL); |
| 327 | + if (next) { |
| 328 | + g_hash_table_remove(toins_deps, next->name); |
| 329 | + return next; |
| 330 | + } |
| 331 | + next = g_hash_table_find(to_install, is_installable, NULL); |
| 332 | + if (next) |
| 333 | + g_hash_table_remove(to_install, next->name); |
| 334 | + return next; |
| 335 | +} |
| 336 | + |
| 337 | +gboolean |
| 338 | +is_installable(key, value, ud) |
| 339 | +gpointer key, value, ud; |
| 340 | +{ |
| 341 | +struct package *pkg = value; |
| 342 | +GSList *dep; |
| 343 | + for (dep = pkg->depends; dep; dep = g_slist_next(dep)) { |
| 344 | + if (!is_installed(dep->data)) { |
| 345 | + return FALSE; |
| 346 | + } |
| 347 | + } |
| 348 | + return TRUE; |
| 349 | +} |
| 350 | + |
| 351 | +int |
| 352 | +install_one(pkg) |
| 353 | +struct package *pkg; |
| 354 | +{ |
| 355 | +pid_t pid; |
| 356 | +int res; |
| 357 | + fprintf(stderr, "Installing %s...\n", pkg->name); |
| 358 | + switch (pid = fork()) { |
| 359 | + case -1: |
| 360 | + fprintf(stderr, "fork: %s\n", strerror(errno)); |
| 361 | + exit(1); |
| 362 | + case 0: |
| 363 | + execl("/usr/sbin/pkgadd", "pkgadd", "-d", pkgroot, "--", pkg->name, NULL); |
| 364 | + fprintf(stderr, "execl: %s\n", strerror(errno)); |
| 365 | + _exit(1); |
| 366 | + } |
| 367 | + if (waitpid(pid, &res, 0) < 0) { |
| 368 | + fprintf(stderr, "waitpid: %s\n", strerror(errno)); |
| 369 | + exit(1); |
| 370 | + } |
| 371 | + if (WEXITSTATUS(res)) { |
| 372 | + fprintf(stderr, "pkgadd exited with return code %d\n", WEXITSTATUS(res)); |
| 373 | + exit(1); |
| 374 | + } |
| 375 | + fprintf(stderr, "%s installed okay\n", pkg->name); |
| 376 | + g_hash_table_insert(inst_pkgs, pkg->name, pkg); |
| 377 | +} |
| 378 | + |
| 379 | +int |
| 380 | +add_depends(pkg) |
| 381 | +struct package *pkg; |
| 382 | +{ |
| 383 | +GSList *dep; |
| 384 | +int n = 0; |
| 385 | + for (dep = pkg->depends; dep; dep = g_slist_next(dep)) { |
| 386 | + struct package *dpkg; |
| 387 | + if ((dpkg = g_hash_table_lookup(pkgs_byname, dep->data)) == NULL) { |
| 388 | + fprintf(stderr, "Package %s depends on unknown package %s\n", |
| 389 | + pkg->name, dep->data); |
| 390 | + return -1; |
| 391 | + } |
| 392 | + if (!is_installed(dpkg->name) && !is_candidate(dpkg->name)) { |
| 393 | + g_hash_table_insert(toins_deps, dpkg->name, dpkg); |
| 394 | + if (add_depends(dpkg) == -1) |
| 395 | + return -1; |
| 396 | + n++; |
| 397 | + } |
| 398 | + } |
| 399 | + return n; |
| 400 | +} |
| 401 | + |
| 402 | +void |
| 403 | +print_pkghash(hash) |
| 404 | +GHashTable *hash; |
| 405 | +{ |
| 406 | + g_hash_table_foreach(hash, print_pkghash_one, NULL); |
| 407 | +} |
| 408 | + |
| 409 | +void |
| 410 | +print_pkghash_one(key, value, ud) |
| 411 | +gpointer key, value, ud; |
| 412 | +{ |
| 413 | + print_package(value); |
| 414 | +} |
| 415 | + |
| 416 | +void |
| 417 | +print_package(pkg) |
| 418 | +struct package *pkg; |
| 419 | +{ |
| 420 | + printf("%c %-30s %s\n", is_installed(pkg->name) ? 'i' : 'a', |
| 421 | + pkg->name, pkg->desc ? pkg->desc : "<no description>"); |
| 422 | +} |
| 423 | + |
| 424 | +int |
| 425 | +is_installed(name) |
| 426 | +const char *name; |
| 427 | +{ |
| 428 | + return g_hash_table_lookup(inst_pkgs, name) != NULL; |
| 429 | +} |
| 430 | + |
| 431 | +int |
| 432 | +is_candidate(name) |
| 433 | +const char *name; |
| 434 | +{ |
| 435 | + return g_hash_table_lookup(to_install, name) |
| 436 | + || g_hash_table_lookup(toins_deps, name); |
| 437 | +} |
| 438 | + |
| 439 | +void |
| 440 | +pkgsearch(key, value, data) |
| 441 | +gpointer key, value, data; |
| 442 | +{ |
| 443 | +const char *term = data; |
| 444 | +struct package *pkg = value; |
| 445 | +char *lterm, *lname, *ldesc; |
| 446 | + lname = g_ascii_strdown(pkg->name, -1); |
| 447 | + ldesc = g_ascii_strdown(pkg->desc, -1); |
| 448 | + lterm = g_ascii_strdown(term, -1); |
| 449 | + if (fnmatch(lterm, ldesc, 0) == 0 || fnmatch(lterm, lname, 0) == 0) |
| 450 | + print_package(pkg); |
| 451 | + g_free(lname); |
| 452 | + g_free(ldesc); |
| 453 | + g_free(lterm); |
| 454 | +} |
| 455 | + |
| 456 | +int |
| 457 | +initroot(void) |
| 458 | +{ |
| 459 | +int npkg = 0, nign = 0; |
| 460 | +char *tieol; |
| 461 | +GHashTable *pkgs; |
| 462 | +DIR *pd; |
| 463 | +struct dirent *de; |
| 464 | +FILE *f; |
| 465 | + if (!pkgroot) { |
| 466 | + fprintf(stderr, "Package root not specified (use -m <root>)\n"); |
| 467 | + return 1; |
| 468 | + } |
| 469 | + |
| 470 | + if ((pd = opendir(pkgroot)) == NULL) { |
| 471 | + fprintf(stderr, "Cannot open package root %s: %s\n", pkgroot, strerror(errno)); |
| 472 | + return 1; |
| 473 | + } |
| 474 | + |
| 475 | + fprintf(stderr, "Initialising package database from %s...\n", pkgroot); |
| 476 | + setupterm(NULL, 1, NULL); |
| 477 | + tieol = tigetstr("el"); |
| 478 | + pkgs_byname = g_hash_table_new(g_str_hash, g_str_equal); |
| 479 | + pkgs = g_hash_table_new(g_str_hash, g_str_equal); |
| 480 | + chdir(pkgroot); |
| 481 | + while (de = readdir(pd)) { |
| 482 | + struct package *pkg; |
| 483 | + if (de->d_name[0] == '.') |
| 484 | + continue; |
| 485 | + if (chdir(de->d_name) == -1) { |
| 486 | + nign++; |
| 487 | + continue; |
| 488 | + } |
| 489 | + if (access("pkgmap", F_OK) != 0) { |
| 490 | + nign++; |
| 491 | + continue; |
| 492 | + } |
| 493 | + fprintf(stderr, "\r%s%s", tieol, de->d_name); |
| 494 | + npkg++; |
| 495 | + pkg = calloc(1, sizeof(struct package)); |
| 496 | + if (read_pkg_info(pkg, ".") == -1) { |
| 497 | + fprintf(stderr, "%s: cannot read package information\n", de->d_name); |
| 498 | + return 1; |
| 499 | + } |
| 500 | + g_hash_table_insert(pkgs_byname, pkg->name, pkg); |
| 501 | + if (chdir(pkgroot) == -1) { |
| 502 | + fprintf(stderr, "chdir(%s): %s\n", pkgroot, strerror(errno)); |
| 503 | + return 1; |
| 504 | + } |
| 505 | + } |
| 506 | + closedir(pd); |
| 507 | + fprintf(stderr, "\r%sFound %d packages (%d ignored)\n", tieol, npkg, nign); |
| 508 | + |
| 509 | + fprintf(stderr, "Writing configuration file %s: ", CFGFILE); |
| 510 | + if ((f = fopen(CFGFILE, "w")) == NULL) { |
| 511 | + fprintf(stderr, "%s\n", strerror(errno)); |
| 512 | + return 1; |
| 513 | + } |
| 514 | + fprintf(f, "pkgroot=%s\n", pkgroot); |
| 515 | + fclose(f); |
| 516 | + fprintf(stderr, "OK\n"); |
| 517 | + |
| 518 | + fprintf(stderr, "Writing package database %s: ", PKGFILE); |
| 519 | + if ((f = fopen(PKGFILE, "w")) == NULL) { |
| 520 | + fprintf(stderr, "%s\n", strerror(errno)); |
| 521 | + return 1; |
| 522 | + } |
| 523 | + g_hash_table_foreach(pkgs_byname, pkgdb_write, f); |
| 524 | + fclose(f); |
| 525 | + fprintf(stderr, "OK\n"); |
| 526 | + return 0; |
| 527 | +} |
| 528 | + |
| 529 | +void |
| 530 | +pkgdb_write(key, value, ud) |
| 531 | +gpointer key, value, ud; |
| 532 | +{ |
| 533 | +FILE *f = ud; |
| 534 | +const char *name = key; |
| 535 | +struct package *pkg = value; |
| 536 | + fprintf(f, "p %s\n", name); |
| 537 | + fprintf(f, "desc %s\n", pkg->desc); |
| 538 | + g_slist_foreach(pkg->depends, pkgdb_writedep, f); |
| 539 | +} |
| 540 | + |
| 541 | +void |
| 542 | +pkgdb_writedep(data, ud) |
| 543 | +gpointer data, ud; |
| 544 | +{ |
| 545 | +const char *dep = data; |
| 546 | +FILE *f = ud; |
| 547 | + fprintf(f, "dep %s\n", dep); |
| 548 | +} |
| 549 | + |
| 550 | +int |
| 551 | +read_pkg_info(pkg, dir) |
| 552 | +struct package *pkg; |
| 553 | +const char *dir; |
| 554 | +{ |
| 555 | +GIOChannel *f; |
| 556 | +GError *err = NULL; |
| 557 | +char *ln; |
| 558 | + if ((f = g_io_channel_new_file("pkginfo", "r", &err)) == NULL) { |
| 559 | + fprintf(stderr, "\rpkginfo: %s\n", err->message); |
| 560 | + return -1; |
| 561 | + } |
| 562 | + while (g_io_channel_read_line(f, &ln, NULL, NULL, &err) == G_IO_STATUS_NORMAL) { |
| 563 | + char *o, *v, *p; |
| 564 | + ln[strlen(ln) - 1] = '\0'; |
| 565 | + if (*ln == '#') { |
| 566 | + g_free(ln); |
| 567 | + continue; |
| 568 | + } |
| 569 | + if ((v = strchr(ln, '=')) == NULL) { |
| 570 | + g_free(ln); |
| 571 | + continue; |
| 572 | + } |
| 573 | + o = ln; |
| 574 | + *v++ = '\0'; |
| 575 | + if (!strcmp(o, "NAME")) |
| 576 | + pkg->desc = strdup(v); |
| 577 | + else if (!strcmp(o, "PKG")) { |
| 578 | + if (p = strpbrk(v, " \t")) |
| 579 | + *p = '\0'; |
| 580 | + pkg->name = strdup(v); |
| 581 | + } |
| 582 | + g_free(ln); |
| 583 | + } |
| 584 | + g_io_channel_unref(f); |
| 585 | + if (!pkg->name) { |
| 586 | + fprintf(stderr, "\rpkginfo: no package name\n"); |
| 587 | + return -1; |
| 588 | + } |
| 589 | + if ((f = g_io_channel_new_file("install/depend", "r", &err)) == NULL) |
| 590 | + return 0; |
| 591 | + while (g_io_channel_read_line(f, &ln, NULL, NULL, &err) == G_IO_STATUS_NORMAL) { |
| 592 | + char *v, *p; |
| 593 | + ln[strlen(ln) - 1] = '\0'; |
| 594 | + if (*ln != 'P' || strlen(ln) < 3) { |
| 595 | + g_free(ln); |
| 596 | + continue; |
| 597 | + } |
| 598 | + ln += 2; |
| 599 | + if (v = strpbrk(ln, " \t")) |
| 600 | + *v = '\0'; |
| 601 | + if (p = strpbrk(v, " \t")) |
| 602 | + *p = '\0'; |
| 603 | + pkg->depends = g_slist_prepend(pkg->depends, strdup(ln)); |
| 604 | + g_free(ln); |
| 605 | + } |
| 606 | + g_io_channel_unref(f); |
| 607 | + |
| 608 | + return 0; |
| 609 | +} |
| 610 | + |
Property changes on: trunk/tools/rosary/rosary.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 611 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 612 | + native |
Index: trunk/tools/rosary/Makefile |
— | — | @@ -0,0 +1,10 @@ |
| 2 | +default: all |
| 3 | +all: rosary |
| 4 | +rosary.o: rosary.c |
| 5 | + cc `pkg-config --cflags glib-2.0` -g -c rosary.c -o $@ |
| 6 | +rosary: rosary.o |
| 7 | + cc -g rosary.o -o rosary `pkg-config --libs glib-2.0` -lcurses -ltecla |
| 8 | +clean: |
| 9 | + rm -f rosary rosary.o |
| 10 | + |
| 11 | +.KEEP_STATE: |
Property changes on: trunk/tools/rosary/Makefile |
___________________________________________________________________ |
Added: svn:keywords |
1 | 12 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 13 | + native |
Index: trunk/tools/rosary/README |
— | — | @@ -0,0 +1,12 @@ |
| 2 | +To use: |
| 3 | + |
| 4 | + 1) make |
| 5 | + 2) cp rosary /usr/local/sbin |
| 6 | + 3) rosary -I -m /path/to/Solaris_10/Product |
| 7 | + |
| 8 | +To search for a package: |
| 9 | + rosary search <glob> |
| 10 | +To install a package: |
| 11 | + rosary install <name> [<name> <name>...] |
| 12 | +To open a command shell: |
| 13 | + rosary shell |
Property changes on: trunk/tools/rosary/README |
___________________________________________________________________ |
Added: svn:keywords |
1 | 14 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 15 | + native |