1 /* GNU SED, a batch stream editor.
2 Copyright (C) 1989-2022 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; If not, see <https://www.gnu.org/licenses/>. */
16
17
18 #include "sed.h"
19
20
21 #include <limits.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include "binary-io.h"
28 #include "getopt.h"
29 #include "progname.h"
30 #include "version.h"
31 #include "xalloc.h"
32 #include <selinux/selinux.h>
33
34 #include "version-etc.h"
35
36 #define AUTHORS \
37 _("Jay Fenlason"), \
38 _("Tom Lord"), \
39 _("Ken Pizzini"), \
40 _("Paolo Bonzini"), \
41 _("Jim Meyering"), \
42 _("Assaf Gordon")
43
44 int extended_regexp_flags = 0;
45
46 /* one-byte buffer delimiter */
47 char buffer_delimiter = '\n';
48
49 /* If set, fflush(stdout) on every line output. */
50 bool unbuffered = false;
51
52 /* If set, don't write out the line unless explicitly told to */
53 bool no_default_output = false;
54
55 /* If set, reset line counts on every new file. */
56 bool separate_files = false;
57
58 /* If set, follow symlinks when processing in place */
59 bool follow_symlinks = false;
60
61 /* If set, opearate in 'sandbox' mode */
62 bool sandbox = false;
63
64 /* if set, print debugging information */
65 bool debug = false;
66
67 /* How do we edit files in-place? (we don't if NULL) */
68 char *in_place_extension = NULL;
69
70 /* The mode to use to read/write files, either "r"/"w" or "rb"/"wb". */
71 char const *read_mode = "r";
72 char const *write_mode = "w";
73
74 #if O_BINARY
75 /* Additional flag for binary mode on platforms with O_BINARY/O_TEXT. */
76 bool binary_mode = false;
77 #endif
78
79 /* Do we need to be pedantically POSIX compliant? */
80 enum posixicity_types posixicity;
81
82 /* How long should the `l' command's output line be? */
83 countT lcmd_out_line_len = 70;
84
85 /* The complete compiled SED program that we are going to run: */
86 static struct vector *the_program = NULL;
87
88 struct localeinfo localeinfo;
89
90 /* When exiting between temporary file creation and the rename
91 associated with a sed -i invocation, remove that file. */
92 static void
93 cleanup (void)
94 {
95 IF_LINT (free (in_place_extension));
96 remove_cleanup_file ();
97 }
98
99 static void
100 contact (int errmsg)
101 {
102 FILE *out = errmsg ? stderr : stdout;
103 fprintf (out, _("GNU sed home page: <https://www.gnu.org/software/sed/>.\n\
104 General help using GNU software: <https://www.gnu.org/gethelp/>.\n"));
105
106 /* Only print the bug report address for `sed --help', otherwise we'll
107 get reports for other people's bugs. */
108 if (!errmsg)
109 fprintf (out, _("E-mail bug reports to: <%s>.\n"), PACKAGE_BUGREPORT);
110 }
111
112 static void
113 selinux_support (void)
114 {
115 putchar ('\n');
116 #if HAVE_SELINUX_SELINUX_H
117 puts (_("This sed program was built with SELinux support."));
118 if (is_selinux_enabled ())
119 puts (_("SELinux is enabled on this system."));
120 else
121 puts (_("SELinux is disabled on this system."));
122 #else
123 puts (_("This sed program was built without SELinux support."));
124 #endif
125 putchar ('\n');
126 }
127
128 _Noreturn static void
129 usage (int status)
130 {
131 FILE *out = status ? stderr : stdout;
132
133 fprintf (out, _("\
134 Usage: %s [OPTION]... {script-only-if-no-other-script} [input-file]...\n\
135 \n"), program_name);
136
137 fprintf (out, _(" -n, --quiet, --silent\n\
138 suppress automatic printing of pattern space\n"));
139 fprintf (out, _(" --debug\n\
140 annotate program execution\n"));
141 fprintf (out, _(" -e script, --expression=script\n\
142 add the script to the commands to be executed\n"));
143 fprintf (out, _(" -f script-file, --file=script-file\n\
144 add the contents of script-file to the commands" \
145 " to be executed\n"));
146 #ifdef HAVE_READLINK
147 fprintf (out, _(" --follow-symlinks\n\
148 follow symlinks when processing in place\n"));
149 #endif
150 fprintf (out, _(" -i[SUFFIX], --in-place[=SUFFIX]\n\
151 edit files in place (makes backup if SUFFIX supplied)\n"));
152 #if O_BINARY
153 fprintf (out, _(" -b, --binary\n\
154 open files in binary mode (CR+LFs are not" \
155 " processed specially)\n"));
156 #endif
157 fprintf (out, _(" -l N, --line-length=N\n\
158 specify the desired line-wrap length for the `l' command\n"));
159 fprintf (out, _(" --posix\n\
160 disable all GNU extensions.\n"));
161 fprintf (out, _(" -E, -r, --regexp-extended\n\
162 use extended regular expressions in the script\n\
163 (for portability use POSIX -E).\n"));
164 fprintf (out, _(" -s, --separate\n\
165 consider files as separate rather than as a single,\n\
166 continuous long stream.\n"));
167 fprintf (out, _(" --sandbox\n\
168 operate in sandbox mode (disable e/r/w commands).\n"));
169 fprintf (out, _(" -u, --unbuffered\n\
170 load minimal amounts of data from the input files and flush\n\
171 the output buffers more often\n"));
172 fprintf (out, _(" -z, --null-data\n\
173 separate lines by NUL characters\n"));
174 fprintf (out, _(" --help display this help and exit\n"));
175 fprintf (out, _(" --version output version information and exit\n"));
176 fprintf (out, _("\n\
177 If no -e, --expression, -f, or --file option is given, then the first\n\
178 non-option argument is taken as the sed script to interpret. All\n\
179 remaining arguments are names of input files; if no input files are\n\
180 specified, then the standard input is read.\n\
181 \n"));
182 contact (status);
183
184 ck_fclose (NULL);
185 exit (status);
186 }
187
188 int
189 main (int argc, char **argv)
190 {
191 #define SHORTOPTS "bsnrzuEe:f:l:i::V:"
192
193 enum { SANDBOX_OPTION = CHAR_MAX+1,
194 DEBUG_OPTION
195 };
196
197 static const struct option longopts[] = {
198 {"binary", 0, NULL, 'b'},
199 {"regexp-extended", 0, NULL, 'r'},
200 {"debug", 0, NULL, DEBUG_OPTION},
201 {"expression", 1, NULL, 'e'},
202 {"file", 1, NULL, 'f'},
203 {"in-place", 2, NULL, 'i'},
204 {"line-length", 1, NULL, 'l'},
205 {"null-data", 0, NULL, 'z'},
206 {"zero-terminated", 0, NULL, 'z'},
207 {"quiet", 0, NULL, 'n'},
208 {"posix", 0, NULL, 'p'},
209 {"silent", 0, NULL, 'n'},
210 {"sandbox", 0, NULL, SANDBOX_OPTION},
211 {"separate", 0, NULL, 's'},
212 {"unbuffered", 0, NULL, 'u'},
213 {"version", 0, NULL, 'v'},
214 {"help", 0, NULL, 'h'},
215 #ifdef HAVE_READLINK
216 {"follow-symlinks", 0, NULL, 'F'},
217 #endif
218 {NULL, 0, NULL, 0}
219 };
220
221 int opt;
222 int return_code;
223 const char *cols = getenv ("COLS");
224
225 set_program_name (argv[0]);
226 initialize_main (&argc, &argv);
227 #if HAVE_SETLOCALE
228 /* Set locale according to user's wishes. */
229 setlocale (LC_ALL, "");
230 #endif
231 initialize_mbcs ();
232 init_localeinfo (&localeinfo);
233
234 /* Arrange to remove any un-renamed temporary file,
235 upon premature exit. */
236 atexit (cleanup);
237
238 #if ENABLE_NLS
239
240 /* Tell program which translations to use and where to find. */
241 bindtextdomain (PACKAGE, LOCALEDIR);
242 textdomain (PACKAGE);
243 #endif
244
245 if (getenv ("POSIXLY_CORRECT") != NULL)
246 posixicity = POSIXLY_CORRECT;
247 else
248 posixicity = POSIXLY_EXTENDED;
249
250 /* If environment variable `COLS' is set, use its value for
251 the baseline setting of `lcmd_out_line_len'. The "-1"
252 is to avoid gratuitous auto-line-wrap on ttys.
253 */
254 if (cols)
255 {
256 countT t = atoi (cols);
257 if (t > 1)
258 lcmd_out_line_len = t-1;
259 }
260
261 while ((opt = getopt_long (argc, argv, SHORTOPTS, longopts, NULL)) != EOF)
262 {
263 switch (opt)
264 {
265 case 'n':
266 no_default_output = true;
267 break;
268 case 'e':
269 the_program = compile_string (the_program, optarg, strlen (optarg));
270 break;
271 case 'f':
272 the_program = compile_file (the_program, optarg);
273 break;
274
275 case 'z':
276 buffer_delimiter = 0;
277 break;
278
279 case 'F':
280 follow_symlinks = true;
281 break;
282
283 case 'i':
284 separate_files = true;
285 IF_LINT (free (in_place_extension));
286 if (optarg == NULL)
287 /* use no backups */
288 in_place_extension = xstrdup ("*");
289
290 else if (strchr (optarg, '*') != NULL)
291 in_place_extension = xstrdup (optarg);
292
293 else
294 {
295 in_place_extension = XCALLOC (strlen (optarg) + 2, char);
296 in_place_extension[0] = '*';
297 strcpy (in_place_extension + 1, optarg);
298 }
299
300 break;
301
302 case 'l':
303 lcmd_out_line_len = atoi (optarg);
304 break;
305
306 case 'p':
307 posixicity = POSIXLY_BASIC;
308 break;
309
310 case 'b':
311 read_mode = "rb";
312 write_mode = "wb";
313 #if O_BINARY
314 binary_mode = true;
315 #endif
316 break;
317
318 case 'E':
319 case 'r':
320 extended_regexp_flags = REG_EXTENDED;
321 break;
322
323 case 's':
324 separate_files = true;
325 break;
326
327 case SANDBOX_OPTION:
328 sandbox = true;
329 break;
330
331 case DEBUG_OPTION:
332 debug = true;
333 break;
334
335 case 'u':
336 unbuffered = true;
337 break;
338
339 case 'v':
340 version_etc (stdout, program_name, PACKAGE_NAME, Version,
341 AUTHORS, (char *) NULL);
342 selinux_support ();
343 contact (false);
344 ck_fclose (NULL);
345 exit (EXIT_SUCCESS);
346 case 'h':
347 usage (EXIT_SUCCESS);
348 default:
349 usage (EXIT_BAD_USAGE);
350 }
351 }
352
353 if (!the_program)
354 {
355 if (optind < argc)
356 {
357 char *arg = argv[optind++];
358 the_program = compile_string (the_program, arg, strlen (arg));
359 }
360 else
361 usage (EXIT_BAD_USAGE);
362 }
363 check_final_program (the_program);
364
365 #if O_BINARY
366 if (binary_mode)
367 {
368 if (set_binary_mode ( fileno (stdin), O_BINARY) == -1)
369 panic (_("failed to set binary mode on STDIN"));
370 if (set_binary_mode ( fileno (stdout), O_BINARY) == -1)
371 panic (_("failed to set binary mode on STDOUT"));
372 }
373 #endif
374
375 if (debug)
376 debug_print_program (the_program);
377
378 return_code = process_files (the_program, argv+optind);
379
380 finish_program (the_program);
381 ck_fclose (NULL);
382
383 return return_code;
384 }