1ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// Copyright 2017 Google Inc. All rights reserved.
2ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang//
3ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// Licensed under the Apache License, Version 2.0 (the "License");
4ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// you may not use this file except in compliance with the License.
5ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// You may obtain a copy of the License at
6ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang//
7ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang//     http://www.apache.org/licenses/LICENSE-2.0
8ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang//
9ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// Unless required by applicable law or agreed to in writing, software
10ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// distributed under the License is distributed on an "AS IS" BASIS,
11ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// See the License for the specific language governing permissions and
13ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// limitations under the License.
14ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
15ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang#include "launcher_internal.h"
16ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
17ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang#include <limits.h>
18ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang#include <stdio.h>
19ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang#include <stdlib.h>
20ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
21ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangextern "C" {
22ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang// Cpython built-in C functions.
23ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang/*
24ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang   read_directory(archive) -> files dict (new reference)
25ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
26ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang   Given a path to a Zip archive, build a dict, mapping file names
27ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang   (local to the archive, using SEP as a separator) to toc entries.
28ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang*/
29ced27516f5ff24d91382b5e9fb513f0682617a2eNan ZhangPyObject *read_directory(const char *archive);
30ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
31ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang/* Given a path to a Zip file and a toc_entry, return the (uncompressed)
32ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang   data as a new reference. */
33ced27516f5ff24d91382b5e9fb513f0682617a2eNan ZhangPyObject *get_data(const char *archive, PyObject *toc_entry);
34ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
35ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
36ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangnamespace android {
37ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangnamespace cpython2 {
38ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangnamespace python_launcher {
3933bb4bb92b10c7a34b36085a9c8df6cfe78c0db5Nan Zhangnamespace internal {
40ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
41ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangint RunModule(const char *module, int set_argv0) {
42ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *runpy, *runmodule, *runargs, *result;
43ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  runpy = PyImport_ImportModule("runpy");
44ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (runpy == NULL) {
45ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    fprintf(stderr, "Could not import runpy module\n");
46ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
47ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
48ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
49ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (runmodule == NULL) {
50ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    fprintf(stderr, "Could not access runpy._run_module_as_main\n");
51ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(runpy);
52ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
53ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
54ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  runargs = Py_BuildValue("(si)", module, set_argv0);
55ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (runargs == NULL) {
56ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    fprintf(stderr,
57ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang            "Could not create arguments for runpy._run_module_as_main\n");
58ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(runpy);
59ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(runmodule);
60ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
61ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
62ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  result = PyObject_Call(runmodule, runargs, NULL);
63ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (result == NULL) {
64ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    PyErr_Print();
65ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
66ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(runpy);
67ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(runmodule);
68ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(runargs);
69ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (result == NULL) {
70ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
71ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
72ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(result);
73ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  return 0;
74ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
75ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
76ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangstd::string GetEntryPointFilePath(const char *launcher_path) {
77ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *files;
78ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  files = read_directory(launcher_path);
79ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (files == NULL) {
80ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return std::string();
81ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
82ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *toc_entry;
83ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // Return value: Borrowed reference.
84ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  toc_entry = PyDict_GetItemString(files, ENTRYPOINT_FILE);
85ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (toc_entry == NULL) {
86ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(files);
87ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return std::string();
88ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
89ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *py_data;
90ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  py_data = get_data(launcher_path, toc_entry);
91ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (py_data == NULL) {
92ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(files);
93ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return std::string();
94ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
95ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // PyString_AsString returns a NUL-terminated representation of the "py_data",
96ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // "data" must not be modified in any way. And it must not be deallocated.
97ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  char *data = PyString_AsString(py_data);
98ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (data == NULL) {
99ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(py_data);
100ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(files);
101ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return std::string();
102ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
103ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
104ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  char *res = strdup(data); /* deep copy of data */
105ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(py_data);
106ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(files);
107ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
108ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  int i = 0;
109ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  /* Strip newline and other trailing whitespace. */
110ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  for (i = strlen(res) - 1; i >= 0 && isspace(res[i]); i--) {
111ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    res[i] = '\0';
112ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
113ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  /* Check for the file extension. */
114ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  i = strlen(res);
115ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (i > 3 && strcmp(res + i - 3, ".py") == 0) {
116ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    res[i - 3] = '\0';
117ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  } else {
118ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    PyErr_Format(PyExc_ValueError, "Invalid entrypoint in %s: %s",
119ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang                 ENTRYPOINT_FILE, res);
120ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return std::string();
121ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
122ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  return std::string(res);
123ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
124ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
125ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangint RunModuleNameFromEntryPoint(const char *launcher_path, std::string entrypoint) {
126ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (entrypoint.empty()) {
127ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
128ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
129ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // Has to pass to free to avoid a memory leak after use.
130ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  char *arr = strdup(entrypoint.c_str());
131ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // Replace file system path seperator with Python package/module seperator.
132ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  char *ch;
133ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  for (ch = arr; *ch; ch++) {
134ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    if (*ch == '/') {
135ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang      *ch = '.';
136ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    }
137ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
138ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
139ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (AddPathToPythonSysPath(launcher_path) < 0) {
140ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    free(arr);
141ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
142ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
143ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // Calculate the runfiles path size. Extra space for '\0'.
144ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  size_t size = snprintf(nullptr, 0, "%s/%s", launcher_path, RUNFILES) + 1;
145ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  char runfiles_path[size];
146ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  snprintf(runfiles_path, size, "%s/%s", launcher_path, RUNFILES);
147ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (AddPathToPythonSysPath(runfiles_path) < 0) {
148ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    free(arr);
149ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
150ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
151ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  int ret =  RunModule(arr, 0);
152ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  free(arr);
153ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  return ret;
154ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
155ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
156ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangint AddPathToPythonSysPath(const char *path) {
157ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (path == NULL) {
158ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
159ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
160ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *py_path;
161ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  py_path = PyString_FromString(path);
162ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (py_path == NULL) {
163ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
164ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
165ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *sys_path;
166ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  // Return value: Borrowed reference.
167ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  sys_path = PySys_GetObject(const_cast<char*>("path"));
168ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (sys_path == NULL) {
169ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(py_path);
170ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
171ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
172ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyList_Insert(sys_path, 0, py_path);
173ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(py_path);
174ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  return 0;
175ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
176ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
177ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangint RunMainFromImporter(const char *launcher_path) {
178ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  PyObject *py_launcher_path, *importer;
179ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  py_launcher_path = PyString_FromString(launcher_path);
180ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (py_launcher_path == NULL) {
181ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
182ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
183ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  importer = PyImport_GetImporter(py_launcher_path);
184ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (importer == NULL) {
185ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    Py_DECREF(py_launcher_path);
186ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return -1;
187ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
188ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (importer != Py_None && importer->ob_type != &PyNullImporter_Type) {
189ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    /* Launcher path is usable as an import source, so
190ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang       put it in sys.path[0] and import __main__ */
191ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    if (AddPathToPythonSysPath(launcher_path) < 0) {
192ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang      Py_DECREF(importer);
193ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang      Py_DECREF(py_launcher_path);
194ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang      return -1;
195ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    }
196ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
197ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(importer);
198ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  Py_DECREF(py_launcher_path);
199ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  return RunModule("__main__", 0);
200ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
201ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}  // namespace internal
202ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang
203ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhangint RunEntryPointOrMainModule(const char *launcher_path) {
204ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  std::string entrypoint = internal::GetEntryPointFilePath(launcher_path);
205ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  if (entrypoint.empty()) {
206ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    // If entry point can not be found or can not be executed, we try to
207ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    // run __main__.py within the .par file.
208ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    fprintf(stderr, "Cannot find valid entry point to execute par file!\n");
209ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    fprintf(stdout, "Start trying to run __main__ module within par file.\n");
210ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang    return internal::RunMainFromImporter(launcher_path);
211ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  }
212ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang  return internal::RunModuleNameFromEntryPoint(launcher_path, entrypoint);
213ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}
214ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}  // namespace python_launcher
215ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}  // namespace cpython2
216ced27516f5ff24d91382b5e9fb513f0682617a2eNan Zhang}  // namespace android
217