10c099281SKai Wang %{ 20c099281SKai Wang /*- 31de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 41de7b4b8SPedro F. Giffuni * 50c099281SKai Wang * Copyright (c) 2008 Kai Wang 60c099281SKai Wang * All rights reserved. 70c099281SKai Wang * 80c099281SKai Wang * Redistribution and use in source and binary forms, with or without 90c099281SKai Wang * modification, are permitted provided that the following conditions 100c099281SKai Wang * are met: 110c099281SKai Wang * 1. Redistributions of source code must retain the above copyright 1225f82d56SEd Maste * notice, this list of conditions and the following disclaimer. 130c099281SKai Wang * 2. Redistributions in binary form must reproduce the above copyright 140c099281SKai Wang * notice, this list of conditions and the following disclaimer in the 150c099281SKai Wang * documentation and/or other materials provided with the distribution. 160c099281SKai Wang * 1725f82d56SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1825f82d56SEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1925f82d56SEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2025f82d56SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2125f82d56SEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2225f82d56SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2325f82d56SEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2425f82d56SEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2525f82d56SEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2625f82d56SEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2725f82d56SEd Maste * SUCH DAMAGE. 280c099281SKai Wang */ 290c099281SKai Wang 300c099281SKai Wang #include <sys/cdefs.h> 310c099281SKai Wang __FBSDID("$FreeBSD$"); 320c099281SKai Wang 330c099281SKai Wang #include <sys/mman.h> 340c099281SKai Wang #include <sys/param.h> 350c099281SKai Wang #include <sys/queue.h> 360c099281SKai Wang #include <sys/stat.h> 370c099281SKai Wang #include <archive.h> 380c099281SKai Wang #include <archive_entry.h> 390c099281SKai Wang #include <dirent.h> 400c099281SKai Wang #include <errno.h> 410c099281SKai Wang #include <fcntl.h> 420c099281SKai Wang #include <stdio.h> 430c099281SKai Wang #include <stdlib.h> 440c099281SKai Wang #include <string.h> 450c099281SKai Wang #include <sysexits.h> 460c099281SKai Wang #include <unistd.h> 470c099281SKai Wang 480c099281SKai Wang #include "ar.h" 490c099281SKai Wang 500c099281SKai Wang #define TEMPLATE "arscp.XXXXXXXX" 510c099281SKai Wang 520c099281SKai Wang struct list { 530c099281SKai Wang char *str; 540c099281SKai Wang struct list *next; 550c099281SKai Wang }; 560c099281SKai Wang 570c099281SKai Wang 580c099281SKai Wang extern int yylex(void); 590c099281SKai Wang 600c099281SKai Wang static void yyerror(const char *); 610c099281SKai Wang static void arscp_addlib(char *archive, struct list *list); 620c099281SKai Wang static void arscp_addmod(struct list *list); 630c099281SKai Wang static void arscp_clear(void); 640c099281SKai Wang static int arscp_copy(int ifd, int ofd); 650c099281SKai Wang static void arscp_create(char *in, char *out); 660c099281SKai Wang static void arscp_delete(struct list *list); 670c099281SKai Wang static void arscp_dir(char *archive, struct list *list, char *rlt); 680c099281SKai Wang static void arscp_end(int eval); 690c099281SKai Wang static void arscp_extract(struct list *list); 700c099281SKai Wang static void arscp_free_argv(void); 710c099281SKai Wang static void arscp_free_mlist(struct list *list); 720c099281SKai Wang static void arscp_list(void); 730c099281SKai Wang static struct list *arscp_mlist(struct list *list, char *str); 740c099281SKai Wang static void arscp_mlist2argv(struct list *list); 750c099281SKai Wang static int arscp_mlist_len(struct list *list); 760c099281SKai Wang static void arscp_open(char *fname); 770c099281SKai Wang static void arscp_prompt(void); 780c099281SKai Wang static void arscp_replace(struct list *list); 790c099281SKai Wang static void arscp_save(void); 800c099281SKai Wang static int arscp_target_exist(void); 810c099281SKai Wang 820c099281SKai Wang extern int lineno; 830c099281SKai Wang 840c099281SKai Wang static struct bsdar *bsdar; 850c099281SKai Wang static char *target; 860c099281SKai Wang static char *tmpac; 870c099281SKai Wang static int interactive; 880c099281SKai Wang static int verbose; 890c099281SKai Wang 900c099281SKai Wang %} 910c099281SKai Wang 920c099281SKai Wang %token ADDLIB 930c099281SKai Wang %token ADDMOD 940c099281SKai Wang %token CLEAR 950c099281SKai Wang %token CREATE 960c099281SKai Wang %token DELETE 970c099281SKai Wang %token DIRECTORY 980c099281SKai Wang %token END 990c099281SKai Wang %token EXTRACT 1000c099281SKai Wang %token LIST 1010c099281SKai Wang %token OPEN 1020c099281SKai Wang %token REPLACE 1030c099281SKai Wang %token VERBOSE 1040c099281SKai Wang %token SAVE 1050c099281SKai Wang %token LP 1060c099281SKai Wang %token RP 1070c099281SKai Wang %token COMMA 1080c099281SKai Wang %token EOL 1090c099281SKai Wang %token <str> FNAME 1100c099281SKai Wang %type <list> mod_list 1110c099281SKai Wang 1120c099281SKai Wang %union { 1130c099281SKai Wang char *str; 1140c099281SKai Wang struct list *list; 1150c099281SKai Wang } 1160c099281SKai Wang 1170c099281SKai Wang %% 1180c099281SKai Wang 1190c099281SKai Wang begin 1200c099281SKai Wang : { arscp_prompt(); } ar_script 1210c099281SKai Wang ; 1220c099281SKai Wang 1230c099281SKai Wang ar_script 1240c099281SKai Wang : cmd_list 1250c099281SKai Wang | 1260c099281SKai Wang ; 1270c099281SKai Wang 1280c099281SKai Wang mod_list 1290c099281SKai Wang : FNAME { $$ = arscp_mlist(NULL, $1); } 1300c099281SKai Wang | mod_list separator FNAME { $$ = arscp_mlist($1, $3); } 1310c099281SKai Wang ; 1320c099281SKai Wang 1330c099281SKai Wang separator 1340c099281SKai Wang : COMMA 1350c099281SKai Wang | 1360c099281SKai Wang ; 1370c099281SKai Wang 1380c099281SKai Wang cmd_list 1390c099281SKai Wang : rawcmd 1400c099281SKai Wang | cmd_list rawcmd 1410c099281SKai Wang ; 1420c099281SKai Wang 1430c099281SKai Wang rawcmd 1440c099281SKai Wang : cmd EOL { arscp_prompt(); } 1450c099281SKai Wang ; 1460c099281SKai Wang 1470c099281SKai Wang cmd 1480c099281SKai Wang : addlib_cmd 1490c099281SKai Wang | addmod_cmd 1500c099281SKai Wang | clear_cmd 1510c099281SKai Wang | create_cmd 1520c099281SKai Wang | delete_cmd 1530c099281SKai Wang | directory_cmd 1540c099281SKai Wang | end_cmd 1550c099281SKai Wang | extract_cmd 1560c099281SKai Wang | list_cmd 1570c099281SKai Wang | open_cmd 1580c099281SKai Wang | replace_cmd 1590c099281SKai Wang | verbose_cmd 1600c099281SKai Wang | save_cmd 1610c099281SKai Wang | invalid_cmd 1620c099281SKai Wang | empty_cmd 1630c099281SKai Wang | error 1640c099281SKai Wang ; 1650c099281SKai Wang 1660c099281SKai Wang addlib_cmd 1670c099281SKai Wang : ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); } 1680c099281SKai Wang | ADDLIB FNAME { arscp_addlib($2, NULL); } 1690c099281SKai Wang ; 1700c099281SKai Wang 1710c099281SKai Wang addmod_cmd 1720c099281SKai Wang : ADDMOD mod_list { arscp_addmod($2); } 1730c099281SKai Wang ; 1740c099281SKai Wang 1750c099281SKai Wang clear_cmd 1760c099281SKai Wang : CLEAR { arscp_clear(); } 1770c099281SKai Wang ; 1780c099281SKai Wang 1790c099281SKai Wang create_cmd 1800c099281SKai Wang : CREATE FNAME { arscp_create(NULL, $2); } 1810c099281SKai Wang ; 1820c099281SKai Wang 1830c099281SKai Wang delete_cmd 1840c099281SKai Wang : DELETE mod_list { arscp_delete($2); } 1850c099281SKai Wang ; 1860c099281SKai Wang 1870c099281SKai Wang directory_cmd 1880c099281SKai Wang : DIRECTORY FNAME { arscp_dir($2, NULL, NULL); } 1890c099281SKai Wang | DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); } 1900c099281SKai Wang | DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); } 1910c099281SKai Wang ; 1920c099281SKai Wang 1930c099281SKai Wang end_cmd 19438911b3cSEd Maste : END { arscp_end(EXIT_SUCCESS); } 1950c099281SKai Wang ; 1960c099281SKai Wang 1970c099281SKai Wang extract_cmd 1980c099281SKai Wang : EXTRACT mod_list { arscp_extract($2); } 1990c099281SKai Wang ; 2000c099281SKai Wang 2010c099281SKai Wang list_cmd 2020c099281SKai Wang : LIST { arscp_list(); } 2030c099281SKai Wang ; 2040c099281SKai Wang 2050c099281SKai Wang open_cmd 2060c099281SKai Wang : OPEN FNAME { arscp_open($2); } 2070c099281SKai Wang ; 2080c099281SKai Wang 2090c099281SKai Wang replace_cmd 2100c099281SKai Wang : REPLACE mod_list { arscp_replace($2); } 2110c099281SKai Wang ; 2120c099281SKai Wang 2130c099281SKai Wang save_cmd 2140c099281SKai Wang : SAVE { arscp_save(); } 2150c099281SKai Wang ; 2160c099281SKai Wang 2170c099281SKai Wang verbose_cmd 2180c099281SKai Wang : VERBOSE { verbose = !verbose; } 2190c099281SKai Wang ; 2200c099281SKai Wang 2210c099281SKai Wang empty_cmd 2220c099281SKai Wang : 2230c099281SKai Wang ; 2240c099281SKai Wang 2250c099281SKai Wang invalid_cmd 2260c099281SKai Wang : FNAME { yyerror(NULL); } 2270c099281SKai Wang ; 2280c099281SKai Wang 2290c099281SKai Wang %% 2300c099281SKai Wang 2310c099281SKai Wang /* ARGSUSED */ 2320c099281SKai Wang static void 2330c099281SKai Wang yyerror(const char *s) 2340c099281SKai Wang { 2350c099281SKai Wang 2360c099281SKai Wang (void) s; 2370c099281SKai Wang printf("Syntax error in archive script, line %d\n", lineno); 2380c099281SKai Wang } 2390c099281SKai Wang 2400c099281SKai Wang /* 2410c099281SKai Wang * arscp_open first open an archive and check its validity. If the archive 2420c099281SKai Wang * format is valid, it calls arscp_create to create a temporary copy of 2430c099281SKai Wang * the archive. 2440c099281SKai Wang */ 2450c099281SKai Wang static void 2460c099281SKai Wang arscp_open(char *fname) 2470c099281SKai Wang { 2480c099281SKai Wang struct archive *a; 2490c099281SKai Wang struct archive_entry *entry; 2500c099281SKai Wang int r; 2510c099281SKai Wang 2520c099281SKai Wang if ((a = archive_read_new()) == NULL) 2530c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed"); 254dc7c0661STim Kientzle archive_read_support_format_ar(a); 255ebb8fc42SMartin Matuska AC(archive_read_open_filename(a, fname, DEF_BLKSZ)); 2560c099281SKai Wang if ((r = archive_read_next_header(a, &entry))) 257ccd8660bSEd Maste bsdar_warnc(bsdar, archive_errno(a), "%s", 258ccd8660bSEd Maste archive_error_string(a)); 2590c099281SKai Wang AC(archive_read_close(a)); 260ebb8fc42SMartin Matuska AC(archive_read_free(a)); 2610c099281SKai Wang if (r != ARCHIVE_OK) 2620c099281SKai Wang return; 2630c099281SKai Wang arscp_create(fname, fname); 2640c099281SKai Wang } 2650c099281SKai Wang 2660c099281SKai Wang /* 2670c099281SKai Wang * Create archive. in != NULL indicate it's a OPEN cmd, and resulting 2680c099281SKai Wang * archive is based on modification of an existing one. If in == NULL, 2690c099281SKai Wang * we are in CREATE cmd and a new empty archive will be created. 2700c099281SKai Wang */ 2710c099281SKai Wang static void 2720c099281SKai Wang arscp_create(char *in, char *out) 2730c099281SKai Wang { 2740c099281SKai Wang struct archive *a; 2750c099281SKai Wang int ifd, ofd; 2760c099281SKai Wang 2770c099281SKai Wang /* Delete previously created temporary archive, if any. */ 2780c099281SKai Wang if (tmpac) { 2790c099281SKai Wang if (unlink(tmpac) < 0) 2800c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, "unlink failed"); 2810c099281SKai Wang free(tmpac); 2820c099281SKai Wang } 2830c099281SKai Wang 2840c099281SKai Wang tmpac = strdup(TEMPLATE); 2850c099281SKai Wang if (tmpac == NULL) 2860c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); 2870c099281SKai Wang if ((ofd = mkstemp(tmpac)) < 0) 2880c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, "mkstemp failed"); 2890c099281SKai Wang 2900c099281SKai Wang if (in) { 2910c099281SKai Wang /* 2920c099281SKai Wang * Command OPEN creates a temporary copy of the 2930c099281SKai Wang * input archive. 2940c099281SKai Wang */ 2950c099281SKai Wang if ((ifd = open(in, O_RDONLY)) < 0) { 2960c099281SKai Wang bsdar_warnc(bsdar, errno, "open failed"); 2970c099281SKai Wang return; 2980c099281SKai Wang } 2990c099281SKai Wang if (arscp_copy(ifd, ofd)) { 3000c099281SKai Wang bsdar_warnc(bsdar, 0, "arscp_copy failed"); 3010c099281SKai Wang return; 3020c099281SKai Wang } 3030c099281SKai Wang close(ifd); 3040c099281SKai Wang close(ofd); 3050c099281SKai Wang } else { 3060c099281SKai Wang /* 3070c099281SKai Wang * Command CREATE creates an "empty" archive. 3080c099281SKai Wang * (archive with only global header) 3090c099281SKai Wang */ 3100c099281SKai Wang if ((a = archive_write_new()) == NULL) 3110c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, 0, 3120c099281SKai Wang "archive_write_new failed"); 3130c099281SKai Wang archive_write_set_format_ar_svr4(a); 3140c099281SKai Wang AC(archive_write_open_fd(a, ofd)); 3150c099281SKai Wang AC(archive_write_close(a)); 316ebb8fc42SMartin Matuska AC(archive_write_free(a)); 3170c099281SKai Wang } 3180c099281SKai Wang 3190c099281SKai Wang /* Override previous target, if any. */ 3200c099281SKai Wang if (target) 3210c099281SKai Wang free(target); 3220c099281SKai Wang 3230c099281SKai Wang target = out; 3240c099281SKai Wang bsdar->filename = tmpac; 3250c099281SKai Wang } 3260c099281SKai Wang 3270c099281SKai Wang /* A file copying implementation using mmap. */ 3280c099281SKai Wang static int 3290c099281SKai Wang arscp_copy(int ifd, int ofd) 3300c099281SKai Wang { 3310c099281SKai Wang struct stat sb; 3320c099281SKai Wang char *buf, *p; 3330c099281SKai Wang ssize_t w; 3340c099281SKai Wang size_t bytes; 3350c099281SKai Wang 3360c099281SKai Wang if (fstat(ifd, &sb) < 0) { 3370c099281SKai Wang bsdar_warnc(bsdar, errno, "fstate failed"); 3380c099281SKai Wang return (1); 3390c099281SKai Wang } 3400c099281SKai Wang if ((p = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, ifd, 3410c099281SKai Wang (off_t)0)) == MAP_FAILED) { 3420c099281SKai Wang bsdar_warnc(bsdar, errno, "mmap failed"); 3430c099281SKai Wang return (1); 3440c099281SKai Wang } 3450c099281SKai Wang for (buf = p, bytes = sb.st_size; bytes > 0; bytes -= w) { 3460c099281SKai Wang w = write(ofd, buf, bytes); 3470c099281SKai Wang if (w <= 0) { 3480c099281SKai Wang bsdar_warnc(bsdar, errno, "write failed"); 3490c099281SKai Wang break; 3500c099281SKai Wang } 3510c099281SKai Wang } 3520c099281SKai Wang if (munmap(p, sb.st_size) < 0) 3530c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, errno, "munmap failed"); 3540c099281SKai Wang if (bytes > 0) 3550c099281SKai Wang return (1); 3560c099281SKai Wang 3570c099281SKai Wang return (0); 3580c099281SKai Wang } 3590c099281SKai Wang 3600c099281SKai Wang /* 3610c099281SKai Wang * Add all modules of archive to current archive, if list != NULL, 3626bef5d28SBenedict Reuschling * only those modules specified in 'list' will be added. 3630c099281SKai Wang */ 3640c099281SKai Wang static void 3650c099281SKai Wang arscp_addlib(char *archive, struct list *list) 3660c099281SKai Wang { 3670c099281SKai Wang 3680c099281SKai Wang if (!arscp_target_exist()) 3690c099281SKai Wang return; 3700c099281SKai Wang arscp_mlist2argv(list); 3710c099281SKai Wang bsdar->addlib = archive; 3720c099281SKai Wang ar_mode_A(bsdar); 3730c099281SKai Wang arscp_free_argv(); 3740c099281SKai Wang arscp_free_mlist(list); 3750c099281SKai Wang } 3760c099281SKai Wang 3770c099281SKai Wang /* Add modules into current archive. */ 3780c099281SKai Wang static void 3790c099281SKai Wang arscp_addmod(struct list *list) 3800c099281SKai Wang { 3810c099281SKai Wang 3820c099281SKai Wang if (!arscp_target_exist()) 3830c099281SKai Wang return; 3840c099281SKai Wang arscp_mlist2argv(list); 3850c099281SKai Wang ar_mode_q(bsdar); 3860c099281SKai Wang arscp_free_argv(); 3870c099281SKai Wang arscp_free_mlist(list); 3880c099281SKai Wang } 3890c099281SKai Wang 3900c099281SKai Wang /* Delete modules from current archive. */ 3910c099281SKai Wang static void 3920c099281SKai Wang arscp_delete(struct list *list) 3930c099281SKai Wang { 3940c099281SKai Wang 3950c099281SKai Wang if (!arscp_target_exist()) 3960c099281SKai Wang return; 3970c099281SKai Wang arscp_mlist2argv(list); 3980c099281SKai Wang ar_mode_d(bsdar); 3990c099281SKai Wang arscp_free_argv(); 4000c099281SKai Wang arscp_free_mlist(list); 4010c099281SKai Wang } 4020c099281SKai Wang 4030c099281SKai Wang /* Extract modules from current archive. */ 4040c099281SKai Wang static void 4050c099281SKai Wang arscp_extract(struct list *list) 4060c099281SKai Wang { 4070c099281SKai Wang 4080c099281SKai Wang if (!arscp_target_exist()) 4090c099281SKai Wang return; 4100c099281SKai Wang arscp_mlist2argv(list); 4110c099281SKai Wang ar_mode_x(bsdar); 4120c099281SKai Wang arscp_free_argv(); 4130c099281SKai Wang arscp_free_mlist(list); 4140c099281SKai Wang } 4150c099281SKai Wang 4160c099281SKai Wang /* List modules of archive. (Simple Mode) */ 4170c099281SKai Wang static void 418ef636796SEd Schouten arscp_list(void) 4190c099281SKai Wang { 4200c099281SKai Wang 4210c099281SKai Wang if (!arscp_target_exist()) 4220c099281SKai Wang return; 4230c099281SKai Wang bsdar->argc = 0; 4240c099281SKai Wang bsdar->argv = NULL; 4250c099281SKai Wang /* Always verbose. */ 4260c099281SKai Wang bsdar->options |= AR_V; 4270c099281SKai Wang ar_mode_t(bsdar); 4280c099281SKai Wang bsdar->options &= ~AR_V; 4290c099281SKai Wang } 4300c099281SKai Wang 4310c099281SKai Wang /* List modules of archive. (Advance Mode) */ 4320c099281SKai Wang static void 4330c099281SKai Wang arscp_dir(char *archive, struct list *list, char *rlt) 4340c099281SKai Wang { 4350c099281SKai Wang FILE *out; 4360c099281SKai Wang 4370c099281SKai Wang /* If rlt != NULL, redirect output to it */ 4380c099281SKai Wang out = NULL; 4390c099281SKai Wang if (rlt) { 4400c099281SKai Wang out = stdout; 4410c099281SKai Wang if ((stdout = fopen(rlt, "w")) == NULL) 4420c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, 4430c099281SKai Wang "fopen %s failed", rlt); 4440c099281SKai Wang } 4450c099281SKai Wang 4460c099281SKai Wang bsdar->filename = archive; 4470c099281SKai Wang if (list) 4480c099281SKai Wang arscp_mlist2argv(list); 4490c099281SKai Wang else { 4500c099281SKai Wang bsdar->argc = 0; 4510c099281SKai Wang bsdar->argv = NULL; 4520c099281SKai Wang } 4530c099281SKai Wang if (verbose) 4540c099281SKai Wang bsdar->options |= AR_V; 4550c099281SKai Wang ar_mode_t(bsdar); 4560c099281SKai Wang bsdar->options &= ~AR_V; 4570c099281SKai Wang 4580c099281SKai Wang if (rlt) { 4590c099281SKai Wang if (fclose(stdout) == EOF) 4600c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, 4610c099281SKai Wang "fclose %s failed", rlt); 4620c099281SKai Wang stdout = out; 4630c099281SKai Wang free(rlt); 4640c099281SKai Wang } 4650c099281SKai Wang free(archive); 4660c099281SKai Wang bsdar->filename = tmpac; 4670c099281SKai Wang arscp_free_argv(); 4680c099281SKai Wang arscp_free_mlist(list); 4690c099281SKai Wang } 4700c099281SKai Wang 4710c099281SKai Wang 4720c099281SKai Wang /* Replace modules of current archive. */ 4730c099281SKai Wang static void 4740c099281SKai Wang arscp_replace(struct list *list) 4750c099281SKai Wang { 4760c099281SKai Wang 4770c099281SKai Wang if (!arscp_target_exist()) 4780c099281SKai Wang return; 4790c099281SKai Wang arscp_mlist2argv(list); 4800c099281SKai Wang ar_mode_r(bsdar); 4810c099281SKai Wang arscp_free_argv(); 4820c099281SKai Wang arscp_free_mlist(list); 4830c099281SKai Wang } 4840c099281SKai Wang 4850c099281SKai Wang /* Rename the temporary archive to the target archive. */ 4860c099281SKai Wang static void 487ef636796SEd Schouten arscp_save(void) 4880c099281SKai Wang { 4890c099281SKai Wang mode_t mask; 4900c099281SKai Wang 4910c099281SKai Wang if (target) { 4920c099281SKai Wang if (rename(tmpac, target) < 0) 4930c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, "rename failed"); 4940c099281SKai Wang /* 4950c099281SKai Wang * mkstemp creates temp files with mode 0600, here we 4960c099281SKai Wang * set target archive mode per process umask. 4970c099281SKai Wang */ 4980c099281SKai Wang mask = umask(0); 4990c099281SKai Wang umask(mask); 5000c099281SKai Wang if (chmod(target, 0666 & ~mask) < 0) 5010c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, "chmod failed"); 5020c099281SKai Wang free(tmpac); 5030c099281SKai Wang free(target); 5040c099281SKai Wang tmpac = NULL; 5050c099281SKai Wang target= NULL; 5060c099281SKai Wang bsdar->filename = NULL; 5070c099281SKai Wang } else 5080c099281SKai Wang bsdar_warnc(bsdar, 0, "no open output archive"); 5090c099281SKai Wang } 5100c099281SKai Wang 5110c099281SKai Wang /* 5120c099281SKai Wang * Discard all the contents of current archive. This is achieved by 5130c099281SKai Wang * invoking CREATE cmd on current archive. 5140c099281SKai Wang */ 5150c099281SKai Wang static void 516ef636796SEd Schouten arscp_clear(void) 5170c099281SKai Wang { 5180c099281SKai Wang char *new_target; 5190c099281SKai Wang 5200c099281SKai Wang if (target) { 5210c099281SKai Wang new_target = strdup(target); 5220c099281SKai Wang if (new_target == NULL) 5230c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); 5240c099281SKai Wang arscp_create(NULL, new_target); 5250c099281SKai Wang } 5260c099281SKai Wang } 5270c099281SKai Wang 5280c099281SKai Wang /* 5290c099281SKai Wang * Quit ar(1). Note that END cmd will not SAVE current archive 5300c099281SKai Wang * before exit. 5310c099281SKai Wang */ 5320c099281SKai Wang static void 5330c099281SKai Wang arscp_end(int eval) 5340c099281SKai Wang { 5350c099281SKai Wang 5360c099281SKai Wang if (target) 5370c099281SKai Wang free(target); 5380c099281SKai Wang if (tmpac) { 5390c099281SKai Wang if (unlink(tmpac) == -1) 5400c099281SKai Wang bsdar_errc(bsdar, EX_IOERR, errno, "unlink %s failed", 5410c099281SKai Wang tmpac); 5420c099281SKai Wang free(tmpac); 5430c099281SKai Wang } 5440c099281SKai Wang 5450c099281SKai Wang exit(eval); 5460c099281SKai Wang } 5470c099281SKai Wang 5480c099281SKai Wang /* 5496bef5d28SBenedict Reuschling * Check if target specified, i.e, whether OPEN or CREATE has been 5500c099281SKai Wang * issued by user. 5510c099281SKai Wang */ 5520c099281SKai Wang static int 553ef636796SEd Schouten arscp_target_exist(void) 5540c099281SKai Wang { 5550c099281SKai Wang 5560c099281SKai Wang if (target) 5570c099281SKai Wang return (1); 5580c099281SKai Wang 5590c099281SKai Wang bsdar_warnc(bsdar, 0, "no open output archive"); 5600c099281SKai Wang return (0); 5610c099281SKai Wang } 5620c099281SKai Wang 5630c099281SKai Wang /* Construct module list. */ 5640c099281SKai Wang static struct list * 5650c099281SKai Wang arscp_mlist(struct list *list, char *str) 5660c099281SKai Wang { 5670c099281SKai Wang struct list *l; 5680c099281SKai Wang 5690c099281SKai Wang l = malloc(sizeof(*l)); 5700c099281SKai Wang if (l == NULL) 5710c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); 5720c099281SKai Wang l->str = str; 5730c099281SKai Wang l->next = list; 5740c099281SKai Wang 5750c099281SKai Wang return (l); 5760c099281SKai Wang } 5770c099281SKai Wang 5780c099281SKai Wang /* Calculate the length of a mlist. */ 5790c099281SKai Wang static int 5800c099281SKai Wang arscp_mlist_len(struct list *list) 5810c099281SKai Wang { 5820c099281SKai Wang int len; 5830c099281SKai Wang 5840c099281SKai Wang for(len = 0; list; list = list->next) 5850c099281SKai Wang len++; 5860c099281SKai Wang 5870c099281SKai Wang return (len); 5880c099281SKai Wang } 5890c099281SKai Wang 5900c099281SKai Wang /* Free the space allocated for mod_list. */ 5910c099281SKai Wang static void 5920c099281SKai Wang arscp_free_mlist(struct list *list) 5930c099281SKai Wang { 5940c099281SKai Wang struct list *l; 5950c099281SKai Wang 5960c099281SKai Wang /* Note that list->str was freed in arscp_free_argv. */ 5970c099281SKai Wang for(; list; list = l) { 5980c099281SKai Wang l = list->next; 5990c099281SKai Wang free(list); 6000c099281SKai Wang } 6010c099281SKai Wang } 6020c099281SKai Wang 6030c099281SKai Wang /* Convert mlist to argv array. */ 6040c099281SKai Wang static void 6050c099281SKai Wang arscp_mlist2argv(struct list *list) 6060c099281SKai Wang { 6070c099281SKai Wang char **argv; 6080c099281SKai Wang int i, n; 6090c099281SKai Wang 6100c099281SKai Wang n = arscp_mlist_len(list); 6110c099281SKai Wang argv = malloc(n * sizeof(*argv)); 6120c099281SKai Wang if (argv == NULL) 6130c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); 6140c099281SKai Wang 6150c099281SKai Wang /* Note that module names are stored in reverse order in mlist. */ 6160c099281SKai Wang for(i = n - 1; i >= 0; i--, list = list->next) { 6170c099281SKai Wang if (list == NULL) 6180c099281SKai Wang bsdar_errc(bsdar, EX_SOFTWARE, errno, "invalid mlist"); 6190c099281SKai Wang argv[i] = list->str; 6200c099281SKai Wang } 6210c099281SKai Wang 6220c099281SKai Wang bsdar->argc = n; 6230c099281SKai Wang bsdar->argv = argv; 6240c099281SKai Wang } 6250c099281SKai Wang 6260c099281SKai Wang /* Free space allocated for argv array and its elements. */ 6270c099281SKai Wang static void 628ef636796SEd Schouten arscp_free_argv(void) 6290c099281SKai Wang { 6300c099281SKai Wang int i; 6310c099281SKai Wang 6320c099281SKai Wang for(i = 0; i < bsdar->argc; i++) 6330c099281SKai Wang free(bsdar->argv[i]); 6340c099281SKai Wang 6350c099281SKai Wang free(bsdar->argv); 6360c099281SKai Wang } 6370c099281SKai Wang 6380c099281SKai Wang /* Show a prompt if we are in interactive mode */ 6390c099281SKai Wang static void 640ef636796SEd Schouten arscp_prompt(void) 6410c099281SKai Wang { 6420c099281SKai Wang 6430c099281SKai Wang if (interactive) { 6440c099281SKai Wang printf("AR >"); 6450c099281SKai Wang fflush(stdout); 6460c099281SKai Wang } 6470c099281SKai Wang } 6480c099281SKai Wang 6490c099281SKai Wang /* Main function for ar script mode. */ 6500c099281SKai Wang void 6510c099281SKai Wang ar_mode_script(struct bsdar *ar) 6520c099281SKai Wang { 6530c099281SKai Wang 6540c099281SKai Wang bsdar = ar; 6550c099281SKai Wang interactive = isatty(fileno(stdin)); 6560c099281SKai Wang while(yyparse()) { 6570c099281SKai Wang if (!interactive) 65838911b3cSEd Maste arscp_end(EXIT_FAILURE); 6590c099281SKai Wang } 6600c099281SKai Wang 6610c099281SKai Wang /* Script ends without END */ 66238911b3cSEd Maste arscp_end(EXIT_SUCCESS); 6630c099281SKai Wang } 664