1183218Skaiw%{ 2183218Skaiw/*- 3183218Skaiw * Copyright (c) 2008 Kai Wang 4183218Skaiw * All rights reserved. 5183218Skaiw * 6183218Skaiw * Redistribution and use in source and binary forms, with or without 7183218Skaiw * modification, are permitted provided that the following conditions 8183218Skaiw * are met: 9183218Skaiw * 1. Redistributions of source code must retain the above copyright 10183218Skaiw * notice, this list of conditions and the following disclaimer 11183218Skaiw * in this position and unchanged. 12183218Skaiw * 2. Redistributions in binary form must reproduce the above copyright 13183218Skaiw * notice, this list of conditions and the following disclaimer in the 14183218Skaiw * documentation and/or other materials provided with the distribution. 15183218Skaiw * 16183218Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17183218Skaiw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18183218Skaiw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19183218Skaiw * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20183218Skaiw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21183218Skaiw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22183218Skaiw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23183218Skaiw * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24183218Skaiw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25183218Skaiw * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26183218Skaiw */ 27183218Skaiw 28183218Skaiw#include <sys/cdefs.h> 29183218Skaiw__FBSDID("$FreeBSD$"); 30183218Skaiw 31183218Skaiw#include <sys/mman.h> 32183218Skaiw#include <sys/param.h> 33183218Skaiw#include <sys/queue.h> 34183218Skaiw#include <sys/stat.h> 35183218Skaiw#include <archive.h> 36183218Skaiw#include <archive_entry.h> 37183218Skaiw#include <dirent.h> 38183218Skaiw#include <errno.h> 39183218Skaiw#include <fcntl.h> 40183218Skaiw#include <stdio.h> 41183218Skaiw#include <stdlib.h> 42183218Skaiw#include <string.h> 43183218Skaiw#include <sysexits.h> 44183218Skaiw#include <unistd.h> 45183218Skaiw 46183218Skaiw#include "ar.h" 47183218Skaiw 48183218Skaiw#define TEMPLATE "arscp.XXXXXXXX" 49183218Skaiw 50183218Skaiwstruct list { 51183218Skaiw char *str; 52183218Skaiw struct list *next; 53183218Skaiw}; 54183218Skaiw 55183218Skaiw 56183218Skaiwextern int yylex(void); 57183218Skaiwextern int yyparse(void); 58183218Skaiw 59183218Skaiwstatic void yyerror(const char *); 60183218Skaiwstatic void arscp_addlib(char *archive, struct list *list); 61183218Skaiwstatic void arscp_addmod(struct list *list); 62183218Skaiwstatic void arscp_clear(void); 63183218Skaiwstatic int arscp_copy(int ifd, int ofd); 64183218Skaiwstatic void arscp_create(char *in, char *out); 65183218Skaiwstatic void arscp_delete(struct list *list); 66183218Skaiwstatic void arscp_dir(char *archive, struct list *list, char *rlt); 67183218Skaiwstatic void arscp_end(int eval); 68183218Skaiwstatic void arscp_extract(struct list *list); 69183218Skaiwstatic void arscp_free_argv(void); 70183218Skaiwstatic void arscp_free_mlist(struct list *list); 71183218Skaiwstatic void arscp_list(void); 72183218Skaiwstatic struct list *arscp_mlist(struct list *list, char *str); 73183218Skaiwstatic void arscp_mlist2argv(struct list *list); 74183218Skaiwstatic int arscp_mlist_len(struct list *list); 75183218Skaiwstatic void arscp_open(char *fname); 76183218Skaiwstatic void arscp_prompt(void); 77183218Skaiwstatic void arscp_replace(struct list *list); 78183218Skaiwstatic void arscp_save(void); 79183218Skaiwstatic int arscp_target_exist(void); 80183218Skaiw 81183218Skaiwextern int lineno; 82183218Skaiw 83183218Skaiwstatic struct bsdar *bsdar; 84183218Skaiwstatic char *target; 85183218Skaiwstatic char *tmpac; 86183218Skaiwstatic int interactive; 87183218Skaiwstatic int verbose; 88183218Skaiw 89183218Skaiw%} 90183218Skaiw 91183218Skaiw%token ADDLIB 92183218Skaiw%token ADDMOD 93183218Skaiw%token CLEAR 94183218Skaiw%token CREATE 95183218Skaiw%token DELETE 96183218Skaiw%token DIRECTORY 97183218Skaiw%token END 98183218Skaiw%token EXTRACT 99183218Skaiw%token LIST 100183218Skaiw%token OPEN 101183218Skaiw%token REPLACE 102183218Skaiw%token VERBOSE 103183218Skaiw%token SAVE 104183218Skaiw%token LP 105183218Skaiw%token RP 106183218Skaiw%token COMMA 107183218Skaiw%token EOL 108183218Skaiw%token <str> FNAME 109183218Skaiw%type <list> mod_list 110183218Skaiw 111183218Skaiw%union { 112183218Skaiw char *str; 113183218Skaiw struct list *list; 114183218Skaiw} 115183218Skaiw 116183218Skaiw%% 117183218Skaiw 118183218Skaiwbegin 119183218Skaiw : { arscp_prompt(); } ar_script 120183218Skaiw ; 121183218Skaiw 122183218Skaiwar_script 123183218Skaiw : cmd_list 124183218Skaiw | 125183218Skaiw ; 126183218Skaiw 127183218Skaiwmod_list 128183218Skaiw : FNAME { $$ = arscp_mlist(NULL, $1); } 129183218Skaiw | mod_list separator FNAME { $$ = arscp_mlist($1, $3); } 130183218Skaiw ; 131183218Skaiw 132183218Skaiwseparator 133183218Skaiw : COMMA 134183218Skaiw | 135183218Skaiw ; 136183218Skaiw 137183218Skaiwcmd_list 138183218Skaiw : rawcmd 139183218Skaiw | cmd_list rawcmd 140183218Skaiw ; 141183218Skaiw 142183218Skaiwrawcmd 143183218Skaiw : cmd EOL { arscp_prompt(); } 144183218Skaiw ; 145183218Skaiw 146183218Skaiwcmd 147183218Skaiw : addlib_cmd 148183218Skaiw | addmod_cmd 149183218Skaiw | clear_cmd 150183218Skaiw | create_cmd 151183218Skaiw | delete_cmd 152183218Skaiw | directory_cmd 153183218Skaiw | end_cmd 154183218Skaiw | extract_cmd 155183218Skaiw | list_cmd 156183218Skaiw | open_cmd 157183218Skaiw | replace_cmd 158183218Skaiw | verbose_cmd 159183218Skaiw | save_cmd 160183218Skaiw | invalid_cmd 161183218Skaiw | empty_cmd 162183218Skaiw | error 163183218Skaiw ; 164183218Skaiw 165183218Skaiwaddlib_cmd 166183218Skaiw : ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); } 167183218Skaiw | ADDLIB FNAME { arscp_addlib($2, NULL); } 168183218Skaiw ; 169183218Skaiw 170183218Skaiwaddmod_cmd 171183218Skaiw : ADDMOD mod_list { arscp_addmod($2); } 172183218Skaiw ; 173183218Skaiw 174183218Skaiwclear_cmd 175183218Skaiw : CLEAR { arscp_clear(); } 176183218Skaiw ; 177183218Skaiw 178183218Skaiwcreate_cmd 179183218Skaiw : CREATE FNAME { arscp_create(NULL, $2); } 180183218Skaiw ; 181183218Skaiw 182183218Skaiwdelete_cmd 183183218Skaiw : DELETE mod_list { arscp_delete($2); } 184183218Skaiw ; 185183218Skaiw 186183218Skaiwdirectory_cmd 187183218Skaiw : DIRECTORY FNAME { arscp_dir($2, NULL, NULL); } 188183218Skaiw | DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); } 189183218Skaiw | DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); } 190183218Skaiw ; 191183218Skaiw 192183218Skaiwend_cmd 193183218Skaiw : END { arscp_end(EX_OK); } 194183218Skaiw ; 195183218Skaiw 196183218Skaiwextract_cmd 197183218Skaiw : EXTRACT mod_list { arscp_extract($2); } 198183218Skaiw ; 199183218Skaiw 200183218Skaiwlist_cmd 201183218Skaiw : LIST { arscp_list(); } 202183218Skaiw ; 203183218Skaiw 204183218Skaiwopen_cmd 205183218Skaiw : OPEN FNAME { arscp_open($2); } 206183218Skaiw ; 207183218Skaiw 208183218Skaiwreplace_cmd 209183218Skaiw : REPLACE mod_list { arscp_replace($2); } 210183218Skaiw ; 211183218Skaiw 212183218Skaiwsave_cmd 213183218Skaiw : SAVE { arscp_save(); } 214183218Skaiw ; 215183218Skaiw 216183218Skaiwverbose_cmd 217183218Skaiw : VERBOSE { verbose = !verbose; } 218183218Skaiw ; 219183218Skaiw 220183218Skaiwempty_cmd 221183218Skaiw : 222183218Skaiw ; 223183218Skaiw 224183218Skaiwinvalid_cmd 225183218Skaiw : FNAME { yyerror(NULL); } 226183218Skaiw ; 227183218Skaiw 228183218Skaiw%% 229183218Skaiw 230183218Skaiw/* ARGSUSED */ 231183218Skaiwstatic void 232183218Skaiwyyerror(const char *s) 233183218Skaiw{ 234183218Skaiw 235183218Skaiw (void) s; 236183218Skaiw printf("Syntax error in archive script, line %d\n", lineno); 237183218Skaiw} 238183218Skaiw 239183218Skaiw/* 240183218Skaiw * arscp_open first open an archive and check its validity. If the archive 241183218Skaiw * format is valid, it calls arscp_create to create a temporary copy of 242183218Skaiw * the archive. 243183218Skaiw */ 244183218Skaiwstatic void 245183218Skaiwarscp_open(char *fname) 246183218Skaiw{ 247183218Skaiw struct archive *a; 248183218Skaiw struct archive_entry *entry; 249183218Skaiw int r; 250183218Skaiw 251183218Skaiw if ((a = archive_read_new()) == NULL) 252183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed"); 253208189Skaiw archive_read_support_compression_none(a); 254201166Skientzle archive_read_support_format_ar(a); 255183218Skaiw AC(archive_read_open_file(a, fname, DEF_BLKSZ)); 256183218Skaiw if ((r = archive_read_next_header(a, &entry))) 257183218Skaiw bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); 258183218Skaiw AC(archive_read_close(a)); 259183218Skaiw AC(archive_read_finish(a)); 260183218Skaiw if (r != ARCHIVE_OK) 261183218Skaiw return; 262183218Skaiw arscp_create(fname, fname); 263183218Skaiw} 264183218Skaiw 265183218Skaiw/* 266183218Skaiw * Create archive. in != NULL indicate it's a OPEN cmd, and resulting 267183218Skaiw * archive is based on modification of an existing one. If in == NULL, 268183218Skaiw * we are in CREATE cmd and a new empty archive will be created. 269183218Skaiw */ 270183218Skaiwstatic void 271183218Skaiwarscp_create(char *in, char *out) 272183218Skaiw{ 273183218Skaiw struct archive *a; 274183218Skaiw int ifd, ofd; 275183218Skaiw 276183218Skaiw /* Delete previously created temporary archive, if any. */ 277183218Skaiw if (tmpac) { 278183218Skaiw if (unlink(tmpac) < 0) 279183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, "unlink failed"); 280183218Skaiw free(tmpac); 281183218Skaiw } 282183218Skaiw 283183218Skaiw tmpac = strdup(TEMPLATE); 284183218Skaiw if (tmpac == NULL) 285183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); 286183218Skaiw if ((ofd = mkstemp(tmpac)) < 0) 287183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, "mkstemp failed"); 288183218Skaiw 289183218Skaiw if (in) { 290183218Skaiw /* 291183218Skaiw * Command OPEN creates a temporary copy of the 292183218Skaiw * input archive. 293183218Skaiw */ 294183218Skaiw if ((ifd = open(in, O_RDONLY)) < 0) { 295183218Skaiw bsdar_warnc(bsdar, errno, "open failed"); 296183218Skaiw return; 297183218Skaiw } 298183218Skaiw if (arscp_copy(ifd, ofd)) { 299183218Skaiw bsdar_warnc(bsdar, 0, "arscp_copy failed"); 300183218Skaiw return; 301183218Skaiw } 302183218Skaiw close(ifd); 303183218Skaiw close(ofd); 304183218Skaiw } else { 305183218Skaiw /* 306183218Skaiw * Command CREATE creates an "empty" archive. 307183218Skaiw * (archive with only global header) 308183218Skaiw */ 309183218Skaiw if ((a = archive_write_new()) == NULL) 310183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, 0, 311183218Skaiw "archive_write_new failed"); 312183218Skaiw archive_write_set_format_ar_svr4(a); 313183218Skaiw AC(archive_write_open_fd(a, ofd)); 314183218Skaiw AC(archive_write_close(a)); 315183218Skaiw AC(archive_write_finish(a)); 316183218Skaiw } 317183218Skaiw 318183218Skaiw /* Override previous target, if any. */ 319183218Skaiw if (target) 320183218Skaiw free(target); 321183218Skaiw 322183218Skaiw target = out; 323183218Skaiw bsdar->filename = tmpac; 324183218Skaiw} 325183218Skaiw 326183218Skaiw/* A file copying implementation using mmap. */ 327183218Skaiwstatic int 328183218Skaiwarscp_copy(int ifd, int ofd) 329183218Skaiw{ 330183218Skaiw struct stat sb; 331183218Skaiw char *buf, *p; 332183218Skaiw ssize_t w; 333183218Skaiw size_t bytes; 334183218Skaiw 335183218Skaiw if (fstat(ifd, &sb) < 0) { 336183218Skaiw bsdar_warnc(bsdar, errno, "fstate failed"); 337183218Skaiw return (1); 338183218Skaiw } 339183218Skaiw if ((p = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, ifd, 340183218Skaiw (off_t)0)) == MAP_FAILED) { 341183218Skaiw bsdar_warnc(bsdar, errno, "mmap failed"); 342183218Skaiw return (1); 343183218Skaiw } 344183218Skaiw for (buf = p, bytes = sb.st_size; bytes > 0; bytes -= w) { 345183218Skaiw w = write(ofd, buf, bytes); 346183218Skaiw if (w <= 0) { 347183218Skaiw bsdar_warnc(bsdar, errno, "write failed"); 348183218Skaiw break; 349183218Skaiw } 350183218Skaiw } 351183218Skaiw if (munmap(p, sb.st_size) < 0) 352183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, errno, "munmap failed"); 353183218Skaiw if (bytes > 0) 354183218Skaiw return (1); 355183218Skaiw 356183218Skaiw return (0); 357183218Skaiw} 358183218Skaiw 359183218Skaiw/* 360183218Skaiw * Add all modules of archive to current archive, if list != NULL, 361222122Sbcr * only those modules specified in 'list' will be added. 362183218Skaiw */ 363183218Skaiwstatic void 364183218Skaiwarscp_addlib(char *archive, struct list *list) 365183218Skaiw{ 366183218Skaiw 367183218Skaiw if (!arscp_target_exist()) 368183218Skaiw return; 369183218Skaiw arscp_mlist2argv(list); 370183218Skaiw bsdar->addlib = archive; 371183218Skaiw ar_mode_A(bsdar); 372183218Skaiw arscp_free_argv(); 373183218Skaiw arscp_free_mlist(list); 374183218Skaiw} 375183218Skaiw 376183218Skaiw/* Add modules into current archive. */ 377183218Skaiwstatic void 378183218Skaiwarscp_addmod(struct list *list) 379183218Skaiw{ 380183218Skaiw 381183218Skaiw if (!arscp_target_exist()) 382183218Skaiw return; 383183218Skaiw arscp_mlist2argv(list); 384183218Skaiw ar_mode_q(bsdar); 385183218Skaiw arscp_free_argv(); 386183218Skaiw arscp_free_mlist(list); 387183218Skaiw} 388183218Skaiw 389183218Skaiw/* Delete modules from current archive. */ 390183218Skaiwstatic void 391183218Skaiwarscp_delete(struct list *list) 392183218Skaiw{ 393183218Skaiw 394183218Skaiw if (!arscp_target_exist()) 395183218Skaiw return; 396183218Skaiw arscp_mlist2argv(list); 397183218Skaiw ar_mode_d(bsdar); 398183218Skaiw arscp_free_argv(); 399183218Skaiw arscp_free_mlist(list); 400183218Skaiw} 401183218Skaiw 402183218Skaiw/* Extract modules from current archive. */ 403183218Skaiwstatic void 404183218Skaiwarscp_extract(struct list *list) 405183218Skaiw{ 406183218Skaiw 407183218Skaiw if (!arscp_target_exist()) 408183218Skaiw return; 409183218Skaiw arscp_mlist2argv(list); 410183218Skaiw ar_mode_x(bsdar); 411183218Skaiw arscp_free_argv(); 412183218Skaiw arscp_free_mlist(list); 413183218Skaiw} 414183218Skaiw 415183218Skaiw/* List modules of archive. (Simple Mode) */ 416183218Skaiwstatic void 417201382Sedarscp_list(void) 418183218Skaiw{ 419183218Skaiw 420183218Skaiw if (!arscp_target_exist()) 421183218Skaiw return; 422183218Skaiw bsdar->argc = 0; 423183218Skaiw bsdar->argv = NULL; 424183218Skaiw /* Always verbose. */ 425183218Skaiw bsdar->options |= AR_V; 426183218Skaiw ar_mode_t(bsdar); 427183218Skaiw bsdar->options &= ~AR_V; 428183218Skaiw} 429183218Skaiw 430183218Skaiw/* List modules of archive. (Advance Mode) */ 431183218Skaiwstatic void 432183218Skaiwarscp_dir(char *archive, struct list *list, char *rlt) 433183218Skaiw{ 434183218Skaiw FILE *out; 435183218Skaiw 436183218Skaiw /* If rlt != NULL, redirect output to it */ 437183218Skaiw out = NULL; 438183218Skaiw if (rlt) { 439183218Skaiw out = stdout; 440183218Skaiw if ((stdout = fopen(rlt, "w")) == NULL) 441183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, 442183218Skaiw "fopen %s failed", rlt); 443183218Skaiw } 444183218Skaiw 445183218Skaiw bsdar->filename = archive; 446183218Skaiw if (list) 447183218Skaiw arscp_mlist2argv(list); 448183218Skaiw else { 449183218Skaiw bsdar->argc = 0; 450183218Skaiw bsdar->argv = NULL; 451183218Skaiw } 452183218Skaiw if (verbose) 453183218Skaiw bsdar->options |= AR_V; 454183218Skaiw ar_mode_t(bsdar); 455183218Skaiw bsdar->options &= ~AR_V; 456183218Skaiw 457183218Skaiw if (rlt) { 458183218Skaiw if (fclose(stdout) == EOF) 459183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, 460183218Skaiw "fclose %s failed", rlt); 461183218Skaiw stdout = out; 462183218Skaiw free(rlt); 463183218Skaiw } 464183218Skaiw free(archive); 465183218Skaiw bsdar->filename = tmpac; 466183218Skaiw arscp_free_argv(); 467183218Skaiw arscp_free_mlist(list); 468183218Skaiw} 469183218Skaiw 470183218Skaiw 471183218Skaiw/* Replace modules of current archive. */ 472183218Skaiwstatic void 473183218Skaiwarscp_replace(struct list *list) 474183218Skaiw{ 475183218Skaiw 476183218Skaiw if (!arscp_target_exist()) 477183218Skaiw return; 478183218Skaiw arscp_mlist2argv(list); 479183218Skaiw ar_mode_r(bsdar); 480183218Skaiw arscp_free_argv(); 481183218Skaiw arscp_free_mlist(list); 482183218Skaiw} 483183218Skaiw 484183218Skaiw/* Rename the temporary archive to the target archive. */ 485183218Skaiwstatic void 486201382Sedarscp_save(void) 487183218Skaiw{ 488183218Skaiw mode_t mask; 489183218Skaiw 490183218Skaiw if (target) { 491183218Skaiw if (rename(tmpac, target) < 0) 492183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, "rename failed"); 493183218Skaiw /* 494183218Skaiw * mkstemp creates temp files with mode 0600, here we 495183218Skaiw * set target archive mode per process umask. 496183218Skaiw */ 497183218Skaiw mask = umask(0); 498183218Skaiw umask(mask); 499183218Skaiw if (chmod(target, 0666 & ~mask) < 0) 500183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, "chmod failed"); 501183218Skaiw free(tmpac); 502183218Skaiw free(target); 503183218Skaiw tmpac = NULL; 504183218Skaiw target= NULL; 505183218Skaiw bsdar->filename = NULL; 506183218Skaiw } else 507183218Skaiw bsdar_warnc(bsdar, 0, "no open output archive"); 508183218Skaiw} 509183218Skaiw 510183218Skaiw/* 511183218Skaiw * Discard all the contents of current archive. This is achieved by 512183218Skaiw * invoking CREATE cmd on current archive. 513183218Skaiw */ 514183218Skaiwstatic void 515201382Sedarscp_clear(void) 516183218Skaiw{ 517183218Skaiw char *new_target; 518183218Skaiw 519183218Skaiw if (target) { 520183218Skaiw new_target = strdup(target); 521183218Skaiw if (new_target == NULL) 522183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); 523183218Skaiw arscp_create(NULL, new_target); 524183218Skaiw } 525183218Skaiw} 526183218Skaiw 527183218Skaiw/* 528183218Skaiw * Quit ar(1). Note that END cmd will not SAVE current archive 529183218Skaiw * before exit. 530183218Skaiw */ 531183218Skaiwstatic void 532183218Skaiwarscp_end(int eval) 533183218Skaiw{ 534183218Skaiw 535183218Skaiw if (target) 536183218Skaiw free(target); 537183218Skaiw if (tmpac) { 538183218Skaiw if (unlink(tmpac) == -1) 539183218Skaiw bsdar_errc(bsdar, EX_IOERR, errno, "unlink %s failed", 540183218Skaiw tmpac); 541183218Skaiw free(tmpac); 542183218Skaiw } 543183218Skaiw 544183218Skaiw exit(eval); 545183218Skaiw} 546183218Skaiw 547183218Skaiw/* 548222122Sbcr * Check if target specified, i.e, whether OPEN or CREATE has been 549183218Skaiw * issued by user. 550183218Skaiw */ 551183218Skaiwstatic int 552201382Sedarscp_target_exist(void) 553183218Skaiw{ 554183218Skaiw 555183218Skaiw if (target) 556183218Skaiw return (1); 557183218Skaiw 558183218Skaiw bsdar_warnc(bsdar, 0, "no open output archive"); 559183218Skaiw return (0); 560183218Skaiw} 561183218Skaiw 562183218Skaiw/* Construct module list. */ 563183218Skaiwstatic struct list * 564183218Skaiwarscp_mlist(struct list *list, char *str) 565183218Skaiw{ 566183218Skaiw struct list *l; 567183218Skaiw 568183218Skaiw l = malloc(sizeof(*l)); 569183218Skaiw if (l == NULL) 570183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); 571183218Skaiw l->str = str; 572183218Skaiw l->next = list; 573183218Skaiw 574183218Skaiw return (l); 575183218Skaiw} 576183218Skaiw 577183218Skaiw/* Calculate the length of a mlist. */ 578183218Skaiwstatic int 579183218Skaiwarscp_mlist_len(struct list *list) 580183218Skaiw{ 581183218Skaiw int len; 582183218Skaiw 583183218Skaiw for(len = 0; list; list = list->next) 584183218Skaiw len++; 585183218Skaiw 586183218Skaiw return (len); 587183218Skaiw} 588183218Skaiw 589183218Skaiw/* Free the space allocated for mod_list. */ 590183218Skaiwstatic void 591183218Skaiwarscp_free_mlist(struct list *list) 592183218Skaiw{ 593183218Skaiw struct list *l; 594183218Skaiw 595183218Skaiw /* Note that list->str was freed in arscp_free_argv. */ 596183218Skaiw for(; list; list = l) { 597183218Skaiw l = list->next; 598183218Skaiw free(list); 599183218Skaiw } 600183218Skaiw} 601183218Skaiw 602183218Skaiw/* Convert mlist to argv array. */ 603183218Skaiwstatic void 604183218Skaiwarscp_mlist2argv(struct list *list) 605183218Skaiw{ 606183218Skaiw char **argv; 607183218Skaiw int i, n; 608183218Skaiw 609183218Skaiw n = arscp_mlist_len(list); 610183218Skaiw argv = malloc(n * sizeof(*argv)); 611183218Skaiw if (argv == NULL) 612183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); 613183218Skaiw 614183218Skaiw /* Note that module names are stored in reverse order in mlist. */ 615183218Skaiw for(i = n - 1; i >= 0; i--, list = list->next) { 616183218Skaiw if (list == NULL) 617183218Skaiw bsdar_errc(bsdar, EX_SOFTWARE, errno, "invalid mlist"); 618183218Skaiw argv[i] = list->str; 619183218Skaiw } 620183218Skaiw 621183218Skaiw bsdar->argc = n; 622183218Skaiw bsdar->argv = argv; 623183218Skaiw} 624183218Skaiw 625183218Skaiw/* Free space allocated for argv array and its elements. */ 626183218Skaiwstatic void 627201382Sedarscp_free_argv(void) 628183218Skaiw{ 629183218Skaiw int i; 630183218Skaiw 631183218Skaiw for(i = 0; i < bsdar->argc; i++) 632183218Skaiw free(bsdar->argv[i]); 633183218Skaiw 634183218Skaiw free(bsdar->argv); 635183218Skaiw} 636183218Skaiw 637183218Skaiw/* Show a prompt if we are in interactive mode */ 638183218Skaiwstatic void 639201382Sedarscp_prompt(void) 640183218Skaiw{ 641183218Skaiw 642183218Skaiw if (interactive) { 643183218Skaiw printf("AR >"); 644183218Skaiw fflush(stdout); 645183218Skaiw } 646183218Skaiw} 647183218Skaiw 648183218Skaiw/* Main function for ar script mode. */ 649183218Skaiwvoid 650183218Skaiwar_mode_script(struct bsdar *ar) 651183218Skaiw{ 652183218Skaiw 653183218Skaiw bsdar = ar; 654183218Skaiw interactive = isatty(fileno(stdin)); 655183218Skaiw while(yyparse()) { 656183218Skaiw if (!interactive) 657183218Skaiw arscp_end(1); 658183218Skaiw } 659183218Skaiw 660183218Skaiw /* Script ends without END */ 661183218Skaiw arscp_end(EX_OK); 662183218Skaiw} 663