1 : #include "shared.hh"
2 : #include "globals.hh"
3 : #include "gc.hh"
4 : #include "store.hh"
5 : #include "util.hh"
6 :
7 : #include "config.h"
8 :
9 : #include <iostream>
10 : #include <cctype>
11 :
12 : #include <sys/stat.h>
13 : #include <unistd.h>
14 :
15 : #include <aterm2.h>
16 :
17 :
18 : namespace nix {
19 :
20 :
21 : volatile sig_atomic_t blockInt = 0;
22 :
23 :
24 : static void sigintHandler(int signo)
25 0 : {
26 0 : if (!blockInt) {
27 0 : _isInterrupted = 1;
28 0 : blockInt = 1;
29 : }
30 345 : }
31 690 :
32 0 :
33 : Path makeRootName(const Path & gcRoot, int & counter)
34 2 : {
35 2 : counter++;
36 2 : if (counter == 1)
37 2 : return gcRoot;
38 : else
39 0 : return (format("%1%-%2%") % gcRoot % counter).str();
40 : }
41 :
42 :
43 : void printGCWarning()
44 67 : {
45 67 : static bool haveWarned = false;
46 67 : warnOnce(haveWarned,
47 : "warning: you did not specify `--add-root'; "
48 : "the result might be removed by the garbage collector");
49 : }
50 :
51 :
52 : static void setLogType(string lt)
53 1 : {
54 1 : if (lt == "pretty") logType = ltPretty;
55 1 : else if (lt == "escapes") logType = ltEscapes;
56 0 : else if (lt == "flat") logType = ltFlat;
57 0 : else throw UsageError("unknown log type");
58 : }
59 :
60 :
61 : struct RemoveTempRoots
62 : {
63 : ~RemoveTempRoots()
64 680 : {
65 340 : removeTempRoots();
66 : }
67 : };
68 :
69 :
70 : void initDerivationsHelpers();
71 :
72 :
73 : /* Initialize and reorder arguments, then call the actual argument
74 : processor. */
75 : static void initAndRun(int argc, char * * argv)
76 345 : {
77 345 : string root = getEnv("NIX_ROOT");
78 345 : if (root != "") {
79 0 : if (chroot(root.c_str()) != 0)
80 14 : throw SysError(format("changing root to `%1%'") % root);
81 : }
82 :
83 : /* Setup Nix paths. */
84 345 : nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR)));
85 345 : nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR));
86 345 : nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR));
87 345 : nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR));
88 345 : nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db");
89 345 : nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
90 345 : nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
91 :
92 : /* Get some settings from the configuration file. */
93 345 : thisSystem = querySetting("system", SYSTEM);
94 : {
95 345 : int n;
96 345 : if (!string2Int(querySetting("build-max-jobs", "1"), n) || n < 0)
97 0 : throw Error("invalid value for configuration setting `build-max-jobs'");
98 345 : maxBuildJobs = n;
99 : }
100 :
101 : /* Catch SIGINT. */
102 345 : struct sigaction act, oact;
103 345 : act.sa_handler = sigintHandler;
104 345 : sigfillset(&act.sa_mask);
105 345 : act.sa_flags = 0;
106 345 : if (sigaction(SIGINT, &act, &oact))
107 0 : throw SysError("installing handler for SIGINT");
108 345 : if (sigaction(SIGTERM, &act, &oact))
109 0 : throw SysError("installing handler for SIGTERM");
110 345 : if (sigaction(SIGHUP, &act, &oact))
111 0 : throw SysError("installing handler for SIGHUP");
112 :
113 : /* Ignore SIGPIPE. */
114 345 : act.sa_handler = SIG_IGN;
115 345 : act.sa_flags = 0;
116 345 : if (sigaction(SIGPIPE, &act, &oact))
117 0 : throw SysError("ignoring SIGPIPE");
118 :
119 : /* There is no privacy in the Nix system ;-) At least not for
120 : now. In particular, store objects should be readable by
121 : everybody. This prevents nasty surprises when using a shared
122 : store (with the setuid() hack). */
123 345 : umask(0022);
124 :
125 : /* Process the NIX_LOG_TYPE environment variable. */
126 345 : string lt = getEnv("NIX_LOG_TYPE");
127 345 : if (lt != "") setLogType(lt);
128 :
129 : /* ATerm stuff. !!! find a better place to put this */
130 345 : initDerivationsHelpers();
131 :
132 : /* Put the arguments in a vector. */
133 345 : Strings args, remaining;
134 1703 : while (argc--) args.push_back(*argv++);
135 345 : args.erase(args.begin());
136 :
137 : /* Expand compound dash options (i.e., `-qlf' -> `-q -l -f'), and
138 : ignore options for the ATerm library. */
139 1358 : for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
140 1013 : string arg = *i;
141 1013 : if (string(arg, 0, 4) == "-at-") ;
142 1013 : else if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-') {
143 151 : for (unsigned int j = 1; j < arg.length(); j++)
144 119 : if (isalpha(arg[j]))
145 118 : remaining.push_back((string) "-" + arg[j]);
146 : else {
147 1 : remaining.push_back(string(arg, j));
148 1 : break;
149 : }
150 980 : } else remaining.push_back(arg);
151 : }
152 345 : args = remaining;
153 345 : remaining.clear();
154 :
155 : /* Process default options. */
156 1437 : for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
157 1097 : string arg = *i;
158 1097 : if (arg == "--verbose" || arg == "-v")
159 88 : verbosity = (Verbosity) ((int) verbosity + 1);
160 1009 : else if (arg == "--log-type") {
161 1 : ++i;
162 1 : if (i == args.end()) throw UsageError("`--log-type' requires an argument");
163 1 : setLogType(*i);
164 : }
165 1008 : else if (arg == "--build-output" || arg == "-B")
166 : ; /* !!! obsolete - remove eventually */
167 1008 : else if (arg == "--no-build-output" || arg == "-Q")
168 0 : buildVerbosity = lvlVomit;
169 1008 : else if (arg == "--help") {
170 4 : printHelp();
171 4 : return;
172 : }
173 1004 : else if (arg == "--version") {
174 1 : std::cout << format("%1% (Nix) %2%") % programId % NIX_VERSION << std::endl;
175 1 : return;
176 : }
177 1003 : else if (arg == "--keep-failed" || arg == "-K")
178 0 : keepFailed = true;
179 1003 : else if (arg == "--keep-going" || arg == "-k")
180 0 : keepGoing = true;
181 1003 : else if (arg == "--fallback")
182 2 : tryFallback = true;
183 1001 : else if (arg == "--max-jobs" || arg == "-j") {
184 1 : ++i;
185 1 : if (i == args.end()) throw UsageError("`--max-jobs' requires an argument");
186 1 : int n;
187 1 : if (!string2Int(*i, n) || n < 0)
188 0 : throw UsageError(format("`--max-jobs' requires a non-negative integer"));
189 1 : maxBuildJobs = n;
190 : }
191 1000 : else if (arg == "--readonly-mode")
192 1 : readOnlyMode = true;
193 999 : else remaining.push_back(arg);
194 : }
195 :
196 : /* Automatically clean up the temporary roots file when we
197 : exit. */
198 340 : RemoveTempRoots removeTempRoots; /* unused variable - don't remove */
199 :
200 340 : run(remaining);
201 :
202 291 : closeDB(); /* it's fine if the DB isn't actually open */
203 : }
204 :
205 :
206 : }
207 :
208 :
209 : static char buf[1024];
210 :
211 : int main(int argc, char * * argv)
212 345 : {
213 : using namespace nix;
214 :
215 : /* If we are setuid root, we have to get rid of the excess
216 : privileges ASAP. */
217 345 : switchToNixUser();
218 :
219 : /* ATerm setup. */
220 345 : ATerm bottomOfStack;
221 345 : ATinit(argc, argv, &bottomOfStack);
222 :
223 : /* Turn on buffering for cerr. */
224 : #if HAVE_PUBSETBUF
225 345 : std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
226 : #endif
227 :
228 345 : try {
229 345 : try {
230 345 : initAndRun(argc, argv);
231 49 : } catch (...) {
232 : /* Subtle: we have to make sure that any `interrupted'
233 : condition is discharged before we reach printMsg()
234 : below, since otherwise it will throw an (uncaught)
235 : exception. */
236 49 : blockInt = 1; /* ignore further SIGINTs */
237 49 : _isInterrupted = 0;
238 49 : throw;
239 : }
240 49 : } catch (UsageError & e) {
241 2 : printMsg(lvlError,
242 : format(
243 : "error: %1%\n"
244 : "Try `%2% --help' for more information.")
245 : % e.what() % programId);
246 2 : return 1;
247 47 : } catch (Error & e) {
248 47 : printMsg(lvlError, format("error: %1%") % e.msg());
249 47 : return 1;
250 0 : } catch (std::exception & e) {
251 0 : printMsg(lvlError, format("error: %1%") % e.what());
252 0 : return 1;
253 : }
254 :
255 296 : return 0;
256 345 : }
257 :
258 :
|