subst/000075500000000000000000000000001060652566700122315ustar00rootroot00000000000000subst/Makefile000064400000000000000000000027461060652566700137020ustar00rootroot00000000000000# # $Id: Makefile,v 1.2 2002/08/28 16:26:40 ldv Exp $ # Copyright (C) 2002 Dmitry V. Levin # # Makefile for subst, sed-based in-place files editor. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # CFLAGS = $(RPM_OPT_FLAGS) -D_GNU_SOURCE INSTALL = install -p DESTDIR = $(RPM_BUILD_ROOT) BINDIR = $(DESTDIR)/usr/bin SRC = sed.c subst.c OBJ = $(SRC:.c=.o) DEP = $(SRC:.c=.d) TARGET = subst .PHONY: all install clean all: $(TARGET) $(TARGET): $(OBJ) install: all $(INSTALL) -D -m755 $(TARGET) $(BINDIR)/$(TARGET) clean: $(RM) $(TARGET) *.d *.o *~ core # We need dependencies only if goal isn't "clean" ifneq ($(MAKECMDGOALS),clean) %.d: %.c @echo Making dependences for $< @$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed 's|\($*\)\.o[ :]*|\1.o $@ : |g' > $@; [ -s $@ ] || $(RM) $@" ifneq ($(DEP),) -include $(DEP) endif endif subst/sed.c000064400000000000000000000116661060652566700131620ustar00rootroot00000000000000 /* $Id: sed.c,v 1.1.1.1 2002/08/28 16:10:20 ldv Exp $ Copyright (C) 2002 Dmitry V. Levin Editor method for subst, the sed-based in-place files editor. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include "subst.h" static int sed (const char *pattern, int fd_in, int fd_out) { pid_t pid = fork (); if (pid < 0) { error (EXIT_SUCCESS, errno, "fork"); return EXIT_FAILURE; } if (!pid) { /* Child */ const char *path = "/bin/sed"; const char *const av[] = { "subst: sed", "-e", pattern, 0 }; /* Since fd_in <= fd_out, we dup fd_in first. */ if (fd_in != STDIN_FILENO) { if (dup2 (fd_in, STDIN_FILENO) != STDIN_FILENO) error (EXIT_FAILURE, errno, "dup2 (%d, %d)", fd_in, STDIN_FILENO); if (close (fd_in) < 0) error (EXIT_FAILURE, errno, "child: close(%d)", fd_in); } if (fd_out != STDOUT_FILENO) { if (dup2 (fd_out, STDOUT_FILENO) != STDOUT_FILENO) error (EXIT_FAILURE, errno, "dup2 (%d, %d)", fd_out, STDOUT_FILENO); if (close (fd_out) < 0) error (EXIT_FAILURE, errno, "child: close(%d)", fd_out); } execv (path, (char *const *) av); error (EXIT_FAILURE, errno, "execv: %s", path); } else { /* Parent */ int status; if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) { error (EXIT_SUCCESS, errno, "waitpid: %d", pid); return EXIT_FAILURE; } if (!WIFEXITED (status) || WEXITSTATUS (status)) return EXIT_FAILURE; } return EXIT_SUCCESS; } int subst (const char *pattern, const char *fname, int preserve) { const char *saved_fname = fname; int fd_in, fd_out = -1; struct stat st; char *resolved = 0, *tname = 0; #ifdef DEBUG error (0, 0, "DEBUG: pattern=%s, fname=%s, preserve=%d", pattern, fname, preserve); #endif if ((fd_in = open (fname, O_RDONLY | O_NOFOLLOW)) < 0) { if (ELOOP != errno) { error (EXIT_SUCCESS, errno, "open: %s", saved_fname); goto failure; } if (!(resolved = canonicalize_file_name (fname))) { error (EXIT_SUCCESS, errno, "canonicalize_file_name: %s", saved_fname); goto failure; } fname = resolved; if ((fd_in = open (fname, O_RDONLY)) < 0) { error (EXIT_SUCCESS, errno, "open: %s", saved_fname); goto failure; } } if (fstat (fd_in, &st) < 0) { error (EXIT_SUCCESS, errno, "fstat: %s", saved_fname); goto failure; } if (!S_ISREG (st.st_mode)) { error (EXIT_SUCCESS, 0, "%s: not a regular file", saved_fname); goto failure; } if (asprintf (&tname, "%s.XXXXXX", fname) < 0) { tname = 0; error (EXIT_SUCCESS, errno ? : ENAMETOOLONG, "%s.XXXXXX", fname); goto failure; } if ((fd_out = mkstemp (tname)) < 0) { error (EXIT_SUCCESS, errno, "open: %s", tname); goto failure; } if (sed (pattern, fd_in, fd_out) != EXIT_SUCCESS) { error (EXIT_SUCCESS, errno, "fork"); goto failure; } if (close (fd_in) < 0) { error (EXIT_SUCCESS, errno, "close in(%d)", fd_in); fd_in = -1; goto failure; } fd_in = -1; if ((fchown (fd_out, st.st_uid, st.st_gid) < 0) && (EPERM != errno)) { error (EXIT_SUCCESS, errno, "fchown: %s", tname); goto failure; } if (fchmod (fd_out, st.st_mode) < 0) { error (EXIT_SUCCESS, errno, "fchmod: %s", tname); goto failure; } if (rename (tname, fname) < 0) { error (EXIT_SUCCESS, errno, "rename (%s, %s)", tname, fname); goto failure; } tname[0] = '\0'; if (close (fd_out) < 0) { error (EXIT_SUCCESS, errno, "close out(%d)", fd_out); fd_out = -1; goto failure; } fd_out = -1; if (preserve) { struct utimbuf utm = { st.st_atime, st.st_mtime }; if (utime (fname, &utm) < 0) error (EXIT_SUCCESS, errno, "utime: %s", fname); /* ignore possible error */ } free (tname); free (resolved); return EXIT_SUCCESS; failure: if (fd_in >= 0) { if (close (fd_in) < 0) error (EXIT_SUCCESS, errno, "close in(%d)", fd_in); } if (fd_out >= 0) { if (close (fd_out) < 0) error (EXIT_SUCCESS, errno, "close out(%d)", fd_out); if (*tname) { if (unlink (tname) < 0) error (EXIT_SUCCESS, errno, "unlink: %s", tname); } } free (tname); free (resolved); return EXIT_FAILURE; } subst/subst.c000064400000000000000000000051621060652566700135410ustar00rootroot00000000000000 /* $Id: subst.c,v 1.1.1.1 2002/08/28 16:10:20 ldv Exp $ Copyright (C) 2002 Dmitry V. Levin The sed-based in-place files editor. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This program tends to be equivalent of the following shell script: #!/bin/sh -e SUBST=$1 && shift || { echo "Usage: $0 PATTERN [FILES...]" exit 1 } for FILE in "$@"; do if [ -L "$FILE" ]; then FILE=`realpath "$FILE"` fi TMPFILE=`/bin/mktemp -- "$FILE.XXXXXXXX"` /bin/cp -p -- "$FILE" "$TMPFILE" && /bin/sed -e "$SUBST" <"$FILE" >"$TMPFILE" && /bin/mv -f -- "$TMPFILE" "$FILE" || { /bin/rm -- "$TMPFILE" exit 1 } done */ #include #include #include #include #include #include #include "subst.h" static struct option const longopts[] = { {"preserve", no_argument, 0, 'p'}, {"help", no_argument, 0, 'h'}, {0, no_argument, 0, 0} }; static void __attribute__ ((__noreturn__)) usage (FILE * stream, int status) { fprintf (stream, "\ %s - the sed-based in-place files editor.\n\ Usage: %s [-p | --preserve] files...\n\ %s [-h | --help]\n\ \nReport bugs to http://bugs.altlinux.ru/\n", __progname, __progname, __progname); exit (status); } int main (int ac, char *const av[]) { int c; int preserve = 0; const char *pattern; while ((c = getopt_long (ac, av, "ph", longopts, 0)) != -1) switch (c) { case 'p': preserve = 1; break; case 'h': usage (stdout, EXIT_SUCCESS); default: usage (stderr, EXIT_FAILURE); } if (optind >= ac) { error (EXIT_SUCCESS, 0, "no pattern specified."); usage (stderr, EXIT_FAILURE); } pattern = av[optind++]; #ifdef DEBUG error (0, 0, "DEBUG: pattern=%s", pattern); #endif if (optind >= ac) { error (EXIT_SUCCESS, 0, "no files specified."); usage (stderr, EXIT_FAILURE); } while (optind < ac) { int rc = subst (pattern, av[optind++], preserve); if (rc != EXIT_SUCCESS) return rc; } return EXIT_SUCCESS; } subst/subst.h000064400000000000000000000017231060652566700135450ustar00rootroot00000000000000 /* $Id: subst.h,v 1.1.1.1 2002/08/28 16:10:20 ldv Exp $ Copyright (C) 2002 Dmitry V. Levin Header for subst, the sed-based in-place files editor. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ extern int subst (const char *pattern, const char *fname, int preserve); extern const char *__progname;