summaryrefslogtreecommitdiff
path: root/src/sync.c
blob: 7c518b5faec003689b12b81cfc139da170161d27 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
/* sync - update the super block Copyright (C) 1994-2025 Free Software Foundation, Inc. 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 3 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, see <https://www.gnu.org/licenses/>. *//* Written by Jim Meyering */#include <config.h>#include <getopt.h>#include <stdio.h>#include <sys/types.h>#include"system.h"/* The official name of this program (e.g., no 'g' prefix). */#define PROGRAM_NAME"sync"#define AUTHORS \ proper_name ("Jim Meyering"), \ proper_name ("Giuseppe Scrivano")#ifndef HAVE_SYNCFS# define HAVE_SYNCFS 0#endifenum sync_mode { MODE_FILE, MODE_DATA, MODE_FILE_SYSTEM, MODE_SYNC };static struct option const long_options[] ={{"data", no_argument,nullptr,'d'},{"file-system", no_argument,nullptr,'f'},{GETOPT_HELP_OPTION_DECL},{GETOPT_VERSION_OPTION_DECL},{nullptr,0,nullptr,0}};voidusage(int status){if(status != EXIT_SUCCESS)emit_try_help();else{printf(_("Usage: %s [OPTION] [FILE]...\n"), program_name);fputs(_("\Synchronize cached writes to persistent storage\n\\n\If one or more files are specified, sync only them,\n\or their containing file systems.\n\\n\"), stdout);fputs(_("\ -d, --data sync only file data, no unneeded metadata\n\"), stdout);fputs(_("\ -f, --file-system sync the file systems that contain the files\n\"), stdout);fputs(HELP_OPTION_DESCRIPTION, stdout);fputs(VERSION_OPTION_DESCRIPTION, stdout);emit_ancillary_info(PROGRAM_NAME);}exit(status);}/* Sync the specified FILE, or file systems associated with FILE. Return 1 on success. */static boolsync_arg(enum sync_mode mode,char const*file){bool ret =true;int open_flags = O_RDONLY | O_NONBLOCK;int fd;#if defined _AIX || defined __CYGWIN__/* AIX 7.1, CYGWIN 2.9.0, fsync requires write access to file. */if(mode == MODE_FILE) open_flags = O_WRONLY | O_NONBLOCK;#endif/* Note O_PATH might be supported with syncfs(), though as of Linux 3.18 is not. */ fd =open(file, open_flags);if(fd <0){/* Use the O_RDONLY errno, which is significant with directories for example. */int rd_errno = errno;if(open_flags != (O_WRONLY | O_NONBLOCK)) fd =open(file, O_WRONLY | O_NONBLOCK);if(fd <0){error(0, rd_errno,_("error opening %s"),quoteaf(file));return false;}}/* We used O_NONBLOCK above to not hang with fifos, so reset that here. */int fdflags =fcntl(fd, F_GETFL);if(fdflags == -1||fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) <0){error(0, errno,_("couldn't reset non-blocking mode %s"),quoteaf(file)); ret =false;}if(ret ==true){int sync_status = -1;switch(mode){case MODE_DATA: sync_status =fdatasync(fd);break;case MODE_FILE: sync_status =fsync(fd);break;case MODE_FILE_SYSTEM:#if HAVE_SYNCFS sync_status =syncfs(fd);break;#endifcase MODE_SYNC:default:unreachable();}if(sync_status <0){error(0, errno,_("error syncing %s"),quoteaf(file)); ret =false;}}if(close(fd) <0){error(0, errno,_("failed to close %s"),quoteaf(file)); ret =false;}return ret;}intmain(int argc,char**argv){int c;bool args_specified;bool arg_data =false, arg_file_system =false;enum sync_mode mode;bool ok =true;initialize_main(&argc, &argv);set_program_name(argv[0]);setlocale(LC_ALL,"");bindtextdomain(PACKAGE, LOCALEDIR);textdomain(PACKAGE);atexit(close_stdout);while((c =getopt_long(argc, argv,"df", long_options,nullptr))!= -1){switch(c){case'd': arg_data =true;break;case'f': arg_file_system =true;break; case_GETOPT_HELP_CHAR;case_GETOPT_VERSION_CHAR(PROGRAM_NAME, AUTHORS);default:usage(EXIT_FAILURE);}} args_specified = optind < argc;if(arg_data && arg_file_system)error(EXIT_FAILURE,0,_("cannot specify both --data and --file-system"));if(!args_specified && arg_data)error(EXIT_FAILURE,0,_("--data needs at least one argument"));if(! args_specified || (arg_file_system && ! HAVE_SYNCFS)) mode = MODE_SYNC;else if(arg_file_system) mode = MODE_FILE_SYSTEM;else if(! arg_data) mode = MODE_FILE;else mode = MODE_DATA;if(mode == MODE_SYNC)sync();else{for(; optind < argc; optind++) ok &=sync_arg(mode, argv[optind]);}return ok ? EXIT_SUCCESS : EXIT_FAILURE;}
close